@firecms/core 3.0.1 → 3.1.0-canary.24c8270

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +1 -1
  2. package/dist/components/AIIcon.d.ts +16 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
  7. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
  8. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
  9. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  10. package/dist/components/EntityCollectionView/Board.d.ts +2 -0
  11. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  12. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  13. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  14. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  15. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  16. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  17. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  18. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  19. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
  20. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  21. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
  22. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  23. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  24. package/dist/components/ErrorBoundary.d.ts +1 -1
  25. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
  26. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  27. package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
  28. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
  29. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  30. package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
  31. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
  32. package/dist/components/VirtualTable/types.d.ts +2 -0
  33. package/dist/components/index.d.ts +3 -0
  34. package/dist/contexts/index.d.ts +10 -0
  35. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  36. package/dist/core/index.d.ts +1 -0
  37. package/dist/form/components/ErrorFocus.d.ts +1 -1
  38. package/dist/form/validation.d.ts +3 -2
  39. package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
  40. package/dist/hooks/useCollapsedGroups.d.ts +4 -1
  41. package/dist/index.es.js +5316 -1592
  42. package/dist/index.es.js.map +1 -1
  43. package/dist/index.umd.js +5309 -1586
  44. package/dist/index.umd.js.map +1 -1
  45. package/dist/internal/useRestoreScroll.d.ts +1 -1
  46. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  47. package/dist/preview/components/DatePreview.d.ts +13 -3
  48. package/dist/preview/components/ImagePreview.d.ts +5 -1
  49. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  50. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  51. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  52. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  53. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  54. package/dist/types/analytics.d.ts +1 -1
  55. package/dist/types/collections.d.ts +50 -2
  56. package/dist/types/datasource.d.ts +0 -1
  57. package/dist/types/plugins.d.ts +62 -1
  58. package/dist/types/properties.d.ts +259 -4
  59. package/dist/util/__tests__/conditions.test.d.ts +1 -0
  60. package/dist/util/__tests__/objects.test.d.ts +1 -0
  61. package/dist/util/conditions.d.ts +26 -0
  62. package/dist/util/entities.d.ts +2 -3
  63. package/dist/util/index.d.ts +2 -1
  64. package/dist/util/property_utils.d.ts +2 -1
  65. package/dist/util/resolutions.d.ts +3 -3
  66. package/package.json +14 -11
  67. package/src/app/Scaffold.tsx +14 -15
  68. package/src/components/AIIcon.tsx +39 -0
  69. package/src/components/ArrayContainer.tsx +1 -4
  70. package/src/components/ClearFilterSortButton.tsx +19 -16
  71. package/src/components/ConfirmationDialog.tsx +0 -2
  72. package/src/components/DeleteEntityDialog.tsx +2 -4
  73. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
  74. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
  75. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
  76. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
  77. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
  78. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
  79. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  80. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  81. package/src/components/EntityCollectionView/Board.tsx +324 -0
  82. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  83. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  84. package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
  85. package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
  86. package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
  87. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +733 -0
  88. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
  89. package/src/components/EntityCollectionView/EntityCollectionView.tsx +519 -203
  90. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
  91. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
  92. package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
  93. package/src/components/EntityCollectionView/ViewModeToggle.tsx +199 -0
  94. package/src/components/EntityCollectionView/board_types.ts +113 -0
  95. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  96. package/src/components/ErrorTooltip.tsx +2 -1
  97. package/src/components/HomePage/DefaultHomePage.tsx +47 -10
  98. package/src/components/HomePage/HomePageDnD.tsx +56 -41
  99. package/src/components/HomePage/NavigationCard.tsx +20 -18
  100. package/src/components/HomePage/NavigationGroup.tsx +17 -16
  101. package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
  102. package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
  103. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
  104. package/src/components/ReferenceWidget.tsx +2 -4
  105. package/src/components/SelectableTable/SelectableTable.tsx +75 -67
  106. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
  107. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
  108. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
  109. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
  110. package/src/components/UnsavedChangesDialog.tsx +0 -2
  111. package/src/components/UserDisplay.tsx +4 -4
  112. package/src/components/VirtualTable/VirtualTable.tsx +272 -118
  113. package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
  114. package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -50
  115. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
  116. package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
  117. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  118. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
  119. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
  120. package/src/components/VirtualTable/types.tsx +2 -0
  121. package/src/components/common/useColumnsIds.tsx +95 -3
  122. package/src/components/common/useDataSourceTableController.tsx +21 -4
  123. package/src/components/index.tsx +4 -0
  124. package/src/contexts/BreacrumbsContext.tsx +15 -8
  125. package/src/contexts/index.ts +10 -0
  126. package/src/core/DefaultAppBar.tsx +40 -27
  127. package/src/core/DefaultDrawer.tsx +42 -56
  128. package/src/core/DrawerNavigationGroup.tsx +118 -0
  129. package/src/core/DrawerNavigationItem.tsx +4 -3
  130. package/src/core/EntityEditView.tsx +41 -43
  131. package/src/core/EntitySidePanel.tsx +28 -26
  132. package/src/core/SideDialogs.tsx +4 -2
  133. package/src/core/field_configs.tsx +14 -9
  134. package/src/core/index.tsx +1 -0
  135. package/src/form/EntityForm.tsx +69 -60
  136. package/src/form/PropertyFieldBinding.tsx +61 -46
  137. package/src/form/components/ErrorFocus.tsx +3 -3
  138. package/src/form/components/StorageItemPreview.tsx +2 -1
  139. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
  140. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
  141. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
  142. package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
  143. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +22 -18
  144. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  145. package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
  146. package/src/form/validation.ts +245 -160
  147. package/src/hooks/useBreadcrumbsController.tsx +18 -0
  148. package/src/hooks/useBuildNavigationController.tsx +71 -28
  149. package/src/hooks/useCollapsedGroups.ts +12 -4
  150. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  151. package/src/internal/useBuildDataSource.ts +68 -34
  152. package/src/internal/useBuildSideDialogsController.tsx +11 -8
  153. package/src/internal/useBuildSideEntityController.tsx +24 -24
  154. package/src/internal/useRestoreScroll.tsx +26 -14
  155. package/src/preview/PropertyPreview.tsx +41 -32
  156. package/src/preview/PropertyPreviewProps.tsx +6 -0
  157. package/src/preview/components/DatePreview.tsx +72 -4
  158. package/src/preview/components/EmptyValue.tsx +1 -1
  159. package/src/preview/components/ImagePreview.tsx +37 -21
  160. package/src/preview/components/StorageThumbnail.tsx +16 -12
  161. package/src/preview/components/UrlComponentPreview.tsx +28 -25
  162. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
  163. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
  164. package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
  165. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
  166. package/src/routes/CustomCMSRoute.tsx +1 -0
  167. package/src/routes/FireCMSRoute.tsx +26 -13
  168. package/src/types/analytics.ts +10 -0
  169. package/src/types/collections.ts +57 -3
  170. package/src/types/datasource.ts +54 -56
  171. package/src/types/plugins.tsx +69 -1
  172. package/src/types/properties.ts +347 -27
  173. package/src/util/__tests__/conditions.test.ts +506 -0
  174. package/src/util/__tests__/objects.test.ts +196 -0
  175. package/src/util/callbacks.ts +6 -3
  176. package/src/util/collections.ts +51 -6
  177. package/src/util/conditions.ts +339 -0
  178. package/src/util/entities.ts +29 -30
  179. package/src/util/entity_cache.ts +2 -1
  180. package/src/util/index.ts +2 -1
  181. package/src/util/join_collections.ts +10 -8
  182. package/src/util/objects.ts +31 -13
  183. package/src/util/{references.ts → previews.ts} +16 -2
  184. package/src/util/property_utils.tsx +37 -11
  185. package/src/util/resolutions.ts +62 -58
  186. /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
@@ -21,6 +21,16 @@ import { VirtualTableRow } from "./VirtualTableRow";
21
21
  import { VirtualTableCell } from "./VirtualTableCell";
22
22
  import { AssignmentIcon, CenteredView, cls, Typography } from "@firecms/ui";
23
23
  import { useDebounceCallback } from "../common/useDebouncedCallback";
24
+ import {
25
+ closestCenter,
26
+ DndContext,
27
+ DragEndEvent,
28
+ DragStartEvent,
29
+ PointerSensor,
30
+ useSensor,
31
+ useSensors
32
+ } from "@dnd-kit/core";
33
+ import { arrayMove, horizontalListSortingStrategy, SortableContext, useSortable } from "@dnd-kit/sortable";
24
34
 
25
35
  const VirtualListContext = createContext<VirtualTableContextProps<any>>({} as any);
26
36
  VirtualListContext.displayName = "VirtualListContext";
@@ -32,52 +42,52 @@ type InnerElementProps = {
32
42
 
33
43
  // eslint-disable-next-line react/display-name
34
44
  const innerElementType = forwardRef<HTMLDivElement, InnerElementProps>(({
35
- children,
36
- ...rest
37
- }: InnerElementProps, ref) => {
38
-
39
- return (
40
- <VirtualListContext.Consumer>
41
- {(virtualTableProps) => {
42
- const customView = virtualTableProps.customView;
43
- return (
44
- <>
45
+ children,
46
+ ...rest
47
+ }: InnerElementProps, ref) => {
48
+
49
+ return (
50
+ <VirtualListContext.Consumer>
51
+ {(virtualTableProps) => {
52
+ const customView = virtualTableProps.customView;
53
+ return (
54
+ <>
55
+ <div
56
+ id={"virtual-table"}
57
+ style={{
58
+ position: "relative",
59
+ height: "100%"
60
+ }}>
45
61
  <div
46
- id={"virtual-table"}
62
+ ref={ref}
63
+ {...rest}
47
64
  style={{
48
- position: "relative",
49
- height: "100%"
65
+ ...rest?.style,
66
+ minHeight: "100%",
67
+ position: "relative"
50
68
  }}>
51
- <div
52
- ref={ref}
53
- {...rest}
54
- style={{
55
- ...rest?.style,
56
- minHeight: "100%",
57
- position: "relative"
58
- }}>
59
- <VirtualTableHeaderRow {...virtualTableProps}/>
60
- {!customView && children}
61
- </div>
62
-
69
+ <VirtualTableHeaderRow {...virtualTableProps} />
70
+ {!customView && children}
63
71
  </div>
64
72
 
65
- {customView && <div style={{
66
- position: "sticky",
67
- top: "48px",
68
- flexGrow: 1,
69
- height: "calc(100% - 48px)",
70
- marginTop: "calc(48px - 100vh)",
71
- left: 0
72
- }}>{customView}</div>}
73
-
74
- </>
75
- );
76
- }}
77
- </VirtualListContext.Consumer>
78
- );
79
- })
80
- ;
73
+ </div>
74
+
75
+ {customView && <div style={{
76
+ position: "sticky",
77
+ top: "48px",
78
+ flexGrow: 1,
79
+ height: "calc(100% - 48px)",
80
+ marginTop: "calc(48px - 100vh)",
81
+ left: 0
82
+ }}>{customView}</div>}
83
+
84
+ </>
85
+ );
86
+ }}
87
+ </VirtualListContext.Consumer>
88
+ );
89
+ })
90
+ ;
81
91
 
82
92
  /**
83
93
  * This is a Table component that allows displaying arbitrary data, not
@@ -89,33 +99,34 @@ const innerElementType = forwardRef<HTMLDivElement, InnerElementProps>(({
89
99
  */
90
100
  export const VirtualTable = React.memo<VirtualTableProps<any>>(
91
101
  function VirtualTable<T extends Record<string, any>>({
92
- data,
93
- onResetPagination,
94
- onEndReached,
95
- endOffset = 600,
96
- rowHeight = 54,
97
- columns: columnsProp,
98
- onRowClick,
99
- onColumnResize,
100
- filter: filterInput,
101
- checkFilterCombination,
102
- onFilterUpdate,
103
- sortBy,
104
- error,
105
- emptyComponent,
106
- onSortByUpdate,
107
- onScroll: onScrollProp,
108
- loading,
109
- cellRenderer,
110
- hoverRow,
111
- createFilterField,
112
- rowClassName,
113
- style,
114
- className,
115
- endAdornment,
116
- AddColumnComponent,
117
- initialScroll = 0,
118
- }: VirtualTableProps<T>) {
102
+ data,
103
+ onResetPagination,
104
+ onEndReached,
105
+ endOffset = 600,
106
+ rowHeight = 54,
107
+ columns: columnsProp,
108
+ onRowClick,
109
+ onColumnResize,
110
+ filter: filterInput,
111
+ checkFilterCombination,
112
+ onFilterUpdate,
113
+ sortBy,
114
+ error,
115
+ emptyComponent,
116
+ onSortByUpdate,
117
+ onScroll: onScrollProp,
118
+ loading,
119
+ cellRenderer,
120
+ hoverRow,
121
+ createFilterField,
122
+ rowClassName,
123
+ style,
124
+ className,
125
+ endAdornment,
126
+ AddColumnComponent,
127
+ initialScroll = 0,
128
+ onColumnsOrderChange,
129
+ }: VirtualTableProps<T>) {
119
130
 
120
131
  const sortByProperty: string | undefined = sortBy ? sortBy[0] : undefined;
121
132
  const currentSort: "asc" | "desc" | undefined = sortBy ? sortBy[1] : undefined;
@@ -127,6 +138,44 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
127
138
 
128
139
  const debouncedScroll = useDebounceCallback(onScrollProp, 200);
129
140
 
141
+ // Drag and drop state
142
+ const [draggingColumnId, setDraggingColumnId] = useState<string | null>(null);
143
+
144
+ const sensors = useSensors(
145
+ useSensor(PointerSensor, {
146
+ activationConstraint: {
147
+ distance: 5,
148
+ },
149
+ })
150
+ );
151
+
152
+ const handleDragStart = useCallback((event: DragStartEvent) => {
153
+ setDraggingColumnId(event.active.id as string);
154
+ }, []);
155
+
156
+ const handleDragEnd = useCallback((event: DragEndEvent) => {
157
+ const {
158
+ active,
159
+ over
160
+ } = event;
161
+ setDraggingColumnId(null);
162
+
163
+ if (over && active.id !== over.id && onColumnsOrderChange) {
164
+ const oldIndex = columns.findIndex((col) => col.key === active.id);
165
+ const newIndex = columns.findIndex((col) => col.key === over.id);
166
+
167
+ if (oldIndex !== -1 && newIndex !== -1) {
168
+ const newColumns = arrayMove(columns, oldIndex, newIndex);
169
+ setColumns(newColumns);
170
+ onColumnsOrderChange(newColumns);
171
+ }
172
+ }
173
+ }, [columns, onColumnsOrderChange]);
174
+
175
+ const handleDragCancel = useCallback(() => {
176
+ setDraggingColumnId(null);
177
+ }, []);
178
+
130
179
  // Set initial scroll position
131
180
  useEffect(() => {
132
181
  if (tableRef.current && initialScroll) {
@@ -185,7 +234,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
185
234
  }, [columns, onColumnResize]);
186
235
 
187
236
  // saving the current filter as a ref as a workaround for header closure
188
- const filterRef = useRef<VirtualTableFilterValues<any> | undefined>();
237
+ const filterRef = useRef<VirtualTableFilterValues<any> | undefined>(undefined);
189
238
 
190
239
  useEffect(() => {
191
240
  filterRef.current = filterInput;
@@ -236,10 +285,10 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
236
285
  }, [data?.length, onEndReached]);
237
286
 
238
287
  const onScroll = useCallback(({
239
- scrollDirection,
240
- scrollOffset,
241
- scrollUpdateWasRequested
242
- }: {
288
+ scrollDirection,
289
+ scrollOffset,
290
+ scrollUpdateWasRequested
291
+ }: {
243
292
  scrollDirection: "forward" | "backward",
244
293
  scrollOffset: number,
245
294
  scrollUpdateWasRequested: boolean;
@@ -278,21 +327,21 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
278
327
  const empty = !loading && (data?.length ?? 0) === 0;
279
328
  const customView = error
280
329
  ? <CenteredView maxWidth={"2xl"}
281
- className="flex flex-col gap-2">
330
+ className="flex flex-col gap-2">
282
331
 
283
332
  <Typography variant={"h6"}>
284
333
  {"Error"}
285
334
  </Typography>
286
335
 
287
- {error?.message && <SafeLinkRenderer text={error.message}/>}
336
+ {error?.message && <SafeLinkRenderer text={error.message} />}
288
337
 
289
338
  </CenteredView>
290
339
  : (empty
291
340
  ? (loading
292
- ? <CircularProgressCenter/>
341
+ ? <CircularProgressCenter />
293
342
  : <div
294
343
  className="flex flex-col overflow-auto items-center justify-center p-2 gap-2 h-full">
295
- <AssignmentIcon/>
344
+ <AssignmentIcon />
296
345
  {emptyComponent}
297
346
  </div>)
298
347
  : undefined);
@@ -315,14 +364,28 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
315
364
  createFilterField,
316
365
  rowClassName,
317
366
  endAdornment,
318
- AddColumnComponent
319
- }), [data, rowHeight, cellRenderer, columns, currentSort, onRowClick, customView, onColumnResizeInternal, onColumnResizeEndInternal, filterInput, onColumnSort, onFilterUpdateInternal, sortByProperty, hoverRow, createFilterField, rowClassName, endAdornment, AddColumnComponent]);
320
-
321
- return (
367
+ AddColumnComponent,
368
+ onColumnsOrderChange: onColumnsOrderChange ? (newColumns: VirtualTableColumn[]) => {
369
+ setColumns(newColumns);
370
+ onColumnsOrderChange(newColumns);
371
+ } : undefined,
372
+ draggingColumnId
373
+ }), [data, rowHeight, cellRenderer, columns, currentSort, onRowClick, customView, onColumnResizeInternal, onColumnResizeEndInternal, filterInput, onColumnSort, onFilterUpdateInternal, sortByProperty, hoverRow, createFilterField, rowClassName, endAdornment, AddColumnComponent, onColumnsOrderChange, draggingColumnId]);
374
+
375
+ // Get sortable column keys (excluding frozen columns)
376
+ const sortableColumnKeys = columns
377
+ .filter(col => !col.frozen)
378
+ .map(col => col.key);
379
+
380
+ const tableContent = (
322
381
  <div
323
382
  ref={measureRef}
324
383
  style={style}
325
- className={cls("h-full w-full", className)}>
384
+ className={cls(
385
+ "h-full w-full",
386
+ className,
387
+ draggingColumnId && "overflow-hidden"
388
+ )}>
326
389
  <VirtualListContext.Provider
327
390
  value={virtualListController}>
328
391
 
@@ -332,31 +395,107 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
332
395
  width={bounds.width}
333
396
  height={bounds.height}
334
397
  itemCount={(data?.length ?? 0) + (endAdornment ? 1 : 0)}
335
- onScroll={onScroll}
398
+ onScroll={draggingColumnId ? undefined : onScroll}
336
399
  includeAddColumn={Boolean(AddColumnComponent)}
337
- itemSize={rowHeight}/>
400
+ itemSize={rowHeight} />
338
401
 
339
402
  </VirtualListContext.Provider>
340
403
  </div>
341
404
  );
405
+
406
+ // Wrap with DndContext if column reorder is enabled
407
+ if (onColumnsOrderChange) {
408
+ return (
409
+ <DndContext
410
+ sensors={sensors}
411
+ collisionDetection={closestCenter}
412
+ onDragStart={handleDragStart}
413
+ onDragEnd={handleDragEnd}
414
+ onDragCancel={handleDragCancel}
415
+ >
416
+ <SortableContext
417
+ items={sortableColumnKeys}
418
+ strategy={horizontalListSortingStrategy}
419
+ >
420
+ {tableContent}
421
+ </SortableContext>
422
+ </DndContext>
423
+ );
424
+ }
425
+
426
+ return tableContent;
342
427
  },
343
428
  equal
344
429
  );
430
+ // Wrapper that applies sortable transforms to cells
431
+ const SortableCellWrapper = ({
432
+ columnKey,
433
+ width,
434
+ isDragging,
435
+ isDraggable,
436
+ frozen,
437
+ children
438
+ }: {
439
+ columnKey: string;
440
+ width: number;
441
+ isDragging: boolean;
442
+ isDraggable: boolean;
443
+ frozen?: boolean;
444
+ children: React.ReactNode;
445
+ }) => {
446
+ const {
447
+ attributes,
448
+ listeners,
449
+ setNodeRef,
450
+ transform,
451
+ transition,
452
+ } = useSortable({
453
+ id: columnKey,
454
+ disabled: !isDraggable || frozen
455
+ });
456
+
457
+ // Remove tabIndex from attributes to avoid capturing focus before cell content
458
+ const { tabIndex: _tabIndex, ...attrsWithoutTabIndex } = attributes;
459
+
460
+ const style = {
461
+ // Only use translate, ignore any scale transforms
462
+ transform: transform ? `translateX(${transform.x}px)` : undefined,
463
+ // Don't transition the dragged item - only other items should animate
464
+ transition: isDragging ? undefined : transition,
465
+ minWidth: width,
466
+ maxWidth: width,
467
+ width: width,
468
+ };
469
+
470
+ return (
471
+ <div
472
+ ref={setNodeRef}
473
+ style={style}
474
+ className={cls(
475
+ "flex-shrink-0",
476
+ frozen && "sticky left-0 z-10 bg-white dark:bg-surface-950"
477
+ )}
478
+ {...attrsWithoutTabIndex}
479
+ >
480
+ {children}
481
+ </div>
482
+ );
483
+ };
345
484
 
346
485
  function MemoizedList({
347
- outerRef,
348
- width,
349
- height,
350
- itemCount,
351
- onScroll,
352
- itemSize,
353
- includeAddColumn
354
- }: {
355
- outerRef: RefObject<HTMLDivElement>;
486
+ outerRef,
487
+ width,
488
+ height,
489
+ itemCount,
490
+ onScroll,
491
+ itemSize,
492
+ includeAddColumn
493
+ }: {
494
+ outerRef: RefObject<HTMLDivElement | null>;
356
495
  width: number;
357
496
  height: number;
358
497
  itemCount: number;
359
- onScroll: (params: {
498
+ onScroll?: (params: {
360
499
  scrollDirection: "forward" | "backward",
361
500
  scrollOffset: number,
362
501
  scrollUpdateWasRequested: boolean;
@@ -366,20 +505,22 @@ function MemoizedList({
366
505
  }) {
367
506
 
368
507
  const Row = useCallback(({
369
- index,
370
- style
371
- }: any) => {
508
+ index,
509
+ style
510
+ }: any) => {
372
511
  return <VirtualListContext.Consumer>
373
512
  {({
374
- onRowClick,
375
- data,
376
- columns,
377
- rowHeight = 54,
378
- cellRenderer,
379
- hoverRow,
380
- rowClassName,
381
- endAdornment
382
- }) => {
513
+ onRowClick,
514
+ data,
515
+ columns,
516
+ rowHeight = 54,
517
+ cellRenderer,
518
+ hoverRow,
519
+ rowClassName,
520
+ endAdornment,
521
+ draggingColumnId,
522
+ onColumnsOrderChange
523
+ }) => {
383
524
 
384
525
  if (endAdornment && index === (data ?? []).length) {
385
526
  return <div style={{
@@ -411,19 +552,32 @@ function MemoizedList({
411
552
 
412
553
  {columns.map((column: VirtualTableColumn, columnIndex: number) => {
413
554
  const cellData = rowData && rowData[column.key];
414
- return <VirtualTableCell
415
- key={`cell_${column.key}`}
416
- dataKey={column.key}
417
- cellRenderer={cellRenderer}
418
- column={column}
419
- columns={columns}
420
- rowData={rowData}
421
- cellData={cellData}
422
- rowIndex={index}
423
- columnIndex={columnIndex}/>;
555
+ const isDragging = draggingColumnId === column.key;
556
+ const isDraggable = !column.frozen && !!onColumnsOrderChange;
557
+
558
+ return (
559
+ <SortableCellWrapper
560
+ key={`cell_wrapper_${column.key}`}
561
+ columnKey={column.key}
562
+ width={column.width}
563
+ isDragging={isDragging}
564
+ isDraggable={isDraggable}
565
+ frozen={column.frozen}
566
+ >
567
+ <VirtualTableCell
568
+ dataKey={column.key}
569
+ cellRenderer={cellRenderer}
570
+ column={column}
571
+ columns={columns}
572
+ rowData={rowData}
573
+ cellData={cellData}
574
+ rowIndex={index}
575
+ columnIndex={columnIndex} />
576
+ </SortableCellWrapper>
577
+ );
424
578
  })}
425
579
 
426
- {includeAddColumn && <div className={"w-20"}/>}
580
+ {includeAddColumn && <div className={"w-20"} />}
427
581
 
428
582
  </VirtualTableRow>
429
583
  );
@@ -454,6 +608,6 @@ const SafeLinkRenderer: React.FC<{
454
608
  });
455
609
 
456
610
  return (
457
- <div className={"break-all"} dangerouslySetInnerHTML={{ __html: htmlContent }}/>
611
+ <div className={"break-all"} dangerouslySetInnerHTML={{ __html: htmlContent }} />
458
612
  );
459
613
  };
@@ -13,6 +13,13 @@ type VirtualTableCellProps<T extends any> = {
13
13
  rowIndex: any;
14
14
  columnIndex: number;
15
15
  cellRenderer: React.ComponentType<CellRendererParams<T>>;
16
+ // Sortable props
17
+ sortableNodeRef?: (node: HTMLElement | null) => void;
18
+ sortableStyle?: React.CSSProperties;
19
+ sortableAttributes?: Record<string, any>;
20
+ isDragging?: boolean;
21
+ isDraggable?: boolean;
22
+ frozen?: boolean;
16
23
  };
17
24
 
18
25
  export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
@@ -27,7 +34,13 @@ export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
27
34
  column: props.column,
28
35
  columns: props.columns,
29
36
  columnIndex: props.columnIndex,
30
- width: props.column.width
37
+ width: props.column.width,
38
+ sortableNodeRef: props.sortableNodeRef,
39
+ sortableStyle: props.sortableStyle,
40
+ sortableAttributes: props.sortableAttributes,
41
+ isDragging: props.isDragging,
42
+ isDraggable: props.isDraggable,
43
+ frozen: props.frozen
31
44
  } as CellRendererParams<T>
32
45
  );
33
46
  },
@@ -37,6 +50,9 @@ export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
37
50
  equal(a.cellData, b.cellData) &&
38
51
  equal(a.rowIndex, b.rowIndex) &&
39
52
  equal(a.cellRenderer, b.cellRenderer) &&
40
- equal(a.columnIndex, b.columnIndex)
53
+ equal(a.columnIndex, b.columnIndex) &&
54
+ a.isDragging === b.isDragging &&
55
+ a.isDraggable === b.isDraggable &&
56
+ a.frozen === b.frozen
41
57
  }
42
58
  );