@firecms/core 3.0.0-beta.12 → 3.0.0-beta.14

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 (120) hide show
  1. package/dist/app/Scaffold.d.ts +4 -0
  2. package/dist/components/ArrayContainer.d.ts +13 -11
  3. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
  4. package/dist/components/EntityJsonPreview.d.ts +3 -0
  5. package/dist/components/EntityPreview.d.ts +4 -2
  6. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  7. package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
  8. package/dist/components/index.d.ts +1 -0
  9. package/dist/core/DefaultAppBar.d.ts +8 -2
  10. package/dist/core/EntityEditView.d.ts +8 -1
  11. package/dist/core/FireCMS.d.ts +2 -2
  12. package/dist/form/EntityForm.d.ts +5 -1
  13. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  14. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  15. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
  16. package/dist/hooks/data/save.d.ts +1 -1
  17. package/dist/hooks/useBuildNavigationController.d.ts +2 -9
  18. package/dist/index.es.js +9251 -8721
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/index.umd.js +16686 -16160
  21. package/dist/index.umd.js.map +1 -1
  22. package/dist/internal/useBuildDataSource.d.ts +3 -2
  23. package/dist/internal/useBuildSideEntityController.d.ts +3 -3
  24. package/dist/types/collections.d.ts +26 -2
  25. package/dist/types/fields.d.ts +4 -1
  26. package/dist/types/firecms.d.ts +3 -2
  27. package/dist/types/navigation.d.ts +9 -0
  28. package/dist/types/plugins.d.ts +13 -0
  29. package/dist/types/properties.d.ts +22 -1
  30. package/dist/types/side_entity_controller.d.ts +4 -0
  31. package/dist/util/callbacks.d.ts +2 -0
  32. package/dist/util/createFormexStub.d.ts +2 -0
  33. package/dist/util/index.d.ts +1 -0
  34. package/dist/util/navigation_utils.d.ts +2 -1
  35. package/dist/util/objects.d.ts +1 -1
  36. package/dist/util/property_utils.d.ts +2 -2
  37. package/dist/util/references.d.ts +2 -2
  38. package/dist/util/resolutions.d.ts +11 -6
  39. package/package.json +9 -6
  40. package/src/app/Scaffold.tsx +13 -3
  41. package/src/components/ArrayContainer.tsx +414 -282
  42. package/src/components/ClearFilterSortButton.tsx +1 -1
  43. package/src/components/ConfirmationDialog.tsx +9 -9
  44. package/src/components/DeleteEntityDialog.tsx +4 -2
  45. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -6
  46. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
  47. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
  48. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
  49. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +58 -29
  50. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
  51. package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -6
  52. package/src/components/EntityJsonPreview.tsx +66 -0
  53. package/src/components/EntityPreview.tsx +27 -16
  54. package/src/components/EntityView.tsx +4 -1
  55. package/src/components/ErrorView.tsx +1 -1
  56. package/src/components/HomePage/DefaultHomePage.tsx +2 -1
  57. package/src/components/HomePage/NavigationCardBinding.tsx +3 -1
  58. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -1
  59. package/src/components/SelectableTable/SelectableTable.tsx +140 -143
  60. package/src/components/VirtualTable/VirtualTable.tsx +37 -31
  61. package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
  62. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
  63. package/src/components/common/default_entity_actions.tsx +15 -4
  64. package/src/components/index.tsx +2 -0
  65. package/src/core/DefaultAppBar.tsx +17 -5
  66. package/src/core/EntityEditView.tsx +135 -47
  67. package/src/core/EntitySidePanel.tsx +15 -20
  68. package/src/core/FireCMS.tsx +19 -12
  69. package/src/form/EntityForm.tsx +32 -24
  70. package/src/form/PropertyFieldBinding.tsx +8 -6
  71. package/src/form/components/CustomIdField.tsx +3 -1
  72. package/src/form/components/LabelWithIcon.tsx +1 -1
  73. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -1
  74. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
  75. package/src/form/field_bindings/BlockFieldBinding.tsx +1 -1
  76. package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
  77. package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
  78. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +6 -2
  79. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
  80. package/src/form/field_bindings/RepeatFieldBinding.tsx +9 -2
  81. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
  82. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +227 -156
  83. package/src/hooks/data/save.ts +24 -35
  84. package/src/hooks/useBuildNavigationController.tsx +42 -17
  85. package/src/hooks/useFireCMSContext.tsx +0 -30
  86. package/src/internal/useBuildDataSource.ts +9 -5
  87. package/src/internal/useBuildSideEntityController.tsx +26 -20
  88. package/src/preview/PropertyPreview.tsx +4 -2
  89. package/src/preview/components/ImagePreview.tsx +2 -2
  90. package/src/preview/components/ReferencePreview.tsx +1 -1
  91. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +5 -4
  92. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
  93. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
  94. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
  95. package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
  96. package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
  97. package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
  98. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
  99. package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
  100. package/src/routes/FireCMSRoute.tsx +15 -4
  101. package/src/types/collections.ts +31 -2
  102. package/src/types/fields.tsx +5 -1
  103. package/src/types/firecms.tsx +3 -3
  104. package/src/types/navigation.ts +11 -0
  105. package/src/types/plugins.tsx +17 -0
  106. package/src/types/properties.ts +27 -1
  107. package/src/types/side_entity_controller.tsx +5 -0
  108. package/src/util/callbacks.ts +119 -0
  109. package/src/util/createFormexStub.tsx +62 -0
  110. package/src/util/index.ts +1 -0
  111. package/src/util/join_collections.ts +3 -1
  112. package/src/util/navigation_from_path.ts +5 -1
  113. package/src/util/navigation_utils.ts +84 -20
  114. package/src/util/objects.ts +54 -17
  115. package/src/util/property_utils.tsx +7 -3
  116. package/src/util/references.ts +8 -6
  117. package/src/util/resolutions.ts +17 -9
  118. package/src/util/useStorageUploadController.tsx +21 -2
  119. package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
  120. package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
@@ -7,13 +7,19 @@ import {
7
7
  getEntityImagePreviewPropertyKey,
8
8
  getEntityPreviewKeys,
9
9
  getEntityTitlePropertyKey,
10
+ getPropertyInPath,
10
11
  getValueInPath,
11
12
  IconForView,
12
13
  resolveCollection
13
14
  } from "../util";
14
15
  import { cls, defaultBorderMixin, IconButton, KeyboardTabIcon, Skeleton, Tooltip, Typography } from "@firecms/ui";
15
16
  import { PreviewSize, PropertyPreview, SkeletonPropertyComponent } from "../preview";
16
- import { useCustomizationController, useNavigationController, useSideEntityController } from "../hooks";
17
+ import {
18
+ useAuthController,
19
+ useCustomizationController,
20
+ useNavigationController,
21
+ useSideEntityController
22
+ } from "../hooks";
17
23
  import { useAnalyticsController } from "../hooks/useAnalyticsController";
18
24
 
19
25
  export type EntityPreviewProps = {
@@ -21,11 +27,13 @@ export type EntityPreviewProps = {
21
27
  actions?: React.ReactNode,
22
28
  collection?: EntityCollection,
23
29
  hover?: boolean;
24
- previewProperties?: string[],
30
+ previewKeys?: string[],
25
31
  disabled?: boolean,
26
32
  entity: Entity<any>,
27
33
  includeId?: boolean,
34
+ includeTitle?: boolean,
28
35
  includeEntityLink?: boolean,
36
+ includeImage?: boolean,
29
37
  onClick?: (e: React.SyntheticEvent) => void;
30
38
  };
31
39
 
@@ -38,14 +46,17 @@ export function EntityPreview({
38
46
  disabled,
39
47
  hover,
40
48
  collection: collectionProp,
41
- previewProperties,
49
+ previewKeys,
42
50
  onClick,
43
51
  size,
44
52
  includeId = true,
53
+ includeTitle = true,
45
54
  includeEntityLink = true,
46
- entity
55
+ includeImage = true,
56
+ entity,
47
57
  }: EntityPreviewProps) {
48
58
 
59
+ const authController = useAuthController();
49
60
  const analyticsController = useAnalyticsController();
50
61
  const sideEntityController = useSideEntityController();
51
62
  const customizationController = useCustomizationController();
@@ -62,14 +73,15 @@ export function EntityPreview({
62
73
  collection,
63
74
  path: entity.path,
64
75
  values: entity.values,
65
- propertyConfigs: customizationController.propertyConfigs
76
+ propertyConfigs: customizationController.propertyConfigs,
77
+ authController
66
78
  }), [collection]);
67
79
 
68
- const listProperties = useMemo(() => getEntityPreviewKeys(resolvedCollection, customizationController.propertyConfigs, previewProperties, size === "medium" || size === "large" ? 3 : 1),
69
- [previewProperties, resolvedCollection, size]);
80
+ const listProperties = useMemo(() => previewKeys ?? getEntityPreviewKeys(authController, resolvedCollection, customizationController.propertyConfigs, previewKeys, size === "medium" || size === "large" ? 3 : 1),
81
+ [previewKeys, resolvedCollection, size]);
70
82
 
71
- const titleProperty = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
72
- const imagePropertyKey = getEntityImagePreviewPropertyKey(resolvedCollection);
83
+ const titleProperty = includeTitle ? getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs) : undefined;
84
+ const imagePropertyKey = includeImage ? getEntityImagePreviewPropertyKey(resolvedCollection) : undefined;
73
85
  const imageProperty = imagePropertyKey ? resolvedCollection.properties[imagePropertyKey] : undefined;
74
86
  const usedImageProperty = imageProperty && "of" in imageProperty ? imageProperty.of : imageProperty;
75
87
  const restProperties = listProperties.filter(p => p !== titleProperty && p !== imagePropertyKey);
@@ -96,9 +108,7 @@ export function EntityPreview({
96
108
  </div>
97
109
 
98
110
 
99
- <div className={"flex flex-col grow-1 w-full m-1 shrink-1"} style={{
100
- "maxWidth": "calc(100% - 96px)"
101
- }}>
111
+ <div className={"flex flex-col grow w-full m-1 shrink min-w-0"}>
102
112
 
103
113
  {size !== "small" && includeId && (
104
114
  entity
@@ -128,9 +138,10 @@ export function EntityPreview({
128
138
  )}
129
139
 
130
140
  {restProperties && restProperties.map((key) => {
131
- const childProperty = resolvedCollection.properties[key as string];
141
+ const childProperty = getPropertyInPath(resolvedCollection.properties, key);
132
142
  if (!childProperty) return null;
133
143
 
144
+ const valueInPath = getValueInPath(entity.values, key);
134
145
  return (
135
146
  <div key={"ref_prev_" + key}
136
147
  className={cls("truncate", restProperties.length > 1 ? "my-0.5" : "my-0")}>
@@ -138,7 +149,7 @@ export function EntityPreview({
138
149
  entity
139
150
  ? <PropertyPreview
140
151
  propertyKey={key as string}
141
- value={getValueInPath(entity.values, key)}
152
+ value={valueInPath}
142
153
  property={childProperty as ResolvedProperty}
143
154
  size={"small"}/>
144
155
  : <SkeletonPropertyComponent
@@ -155,7 +166,7 @@ export function EntityPreview({
155
166
  <Tooltip title={`See details for ${entity.id}`} className={"shrink-0"}>
156
167
  <IconButton
157
168
  color={"inherit"}
158
- size={"medium"}
169
+ size={"small"}
159
170
  className={size !== "small" ? "self-start" : ""}
160
171
  onClick={(e) => {
161
172
  e.stopPropagation();
@@ -170,7 +181,7 @@ export function EntityPreview({
170
181
  updateUrl: true
171
182
  });
172
183
  }}>
173
- <KeyboardTabIcon size={"medium"}/>
184
+ <KeyboardTabIcon size={"small"}/>
174
185
  </IconButton>
175
186
  </Tooltip>}
176
187
 
@@ -5,6 +5,7 @@ import { resolveCollection } from "../util";
5
5
  import { cls, defaultBorderMixin, IconButton, OpenInNewIcon } from "@firecms/ui";
6
6
  import { CustomizationController } from "../types/customization_controller";
7
7
  import { useCustomizationController } from "../hooks/useCustomizationController";
8
+ import { useAuthController } from "../hooks";
8
9
 
9
10
  /**
10
11
  * @group Components
@@ -24,13 +25,15 @@ export function EntityView<M extends Record<string, any>>(
24
25
  className
25
26
  }: EntityViewProps<M>) {
26
27
 
28
+ const authController = useAuthController();
27
29
  const customizationController: CustomizationController = useCustomizationController();
28
30
  const resolvedCollection: ResolvedEntityCollection<M> = useMemo(() => resolveCollection<M>({
29
31
  collection,
30
32
  path,
31
33
  entityId: entity.id,
32
34
  values: entity.values,
33
- propertyConfigs: customizationController.propertyConfigs
35
+ propertyConfigs: customizationController.propertyConfigs,
36
+ authController
34
37
  }), [collection, path, entity, customizationController.propertyConfigs]);
35
38
 
36
39
  const properties: ResolvedProperties = resolvedCollection.properties;
@@ -26,7 +26,7 @@ export function ErrorView({
26
26
  tooltip
27
27
  }: ErrorViewProps): React.ReactElement {
28
28
  const component = error instanceof Error ? error.message : error;
29
- console.warn("ErrorView", error)
29
+ // console.warn("ErrorView", error)
30
30
 
31
31
  const body = (
32
32
  <div
@@ -114,6 +114,7 @@ export function DefaultHomePage({
114
114
  );
115
115
  })}
116
116
  </>;
117
+
117
118
  additionalPluginChildrenStart = <div className={"flex flex-col gap-2"}>
118
119
  {customizationController.plugins.filter(plugin => plugin.homePage?.additionalChildrenStart)
119
120
  .map((plugin, i) => {
@@ -179,7 +180,7 @@ export function DefaultHomePage({
179
180
 
180
181
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
181
182
  {thisGroupCollections.map((entry) => (
182
- <div key={`nav_${entry.group}_${entry.name}`} className="col-span-1">
183
+ <div key={`nav_${entry.group}_${entry.path}_${entry.name}`} className="col-span-1">
183
184
  <NavigationCardBinding
184
185
  {...entry}
185
186
  onClick={() => {
@@ -7,6 +7,7 @@ import { useUserConfigurationPersistence } from "../../hooks/useUserConfiguratio
7
7
  import { IconButton, StarIcon } from "@firecms/ui";
8
8
  import { NavigationCard } from "./NavigationCard";
9
9
  import { SmallNavigationCard } from "./SmallNavigationCard";
10
+ import React from "react";
10
11
 
11
12
  /**
12
13
  * This is the component used in the home page to render a card for each
@@ -47,6 +48,7 @@ export function NavigationCardBinding({
47
48
  ? [
48
49
  <IconButton
49
50
  key={"favourite"}
51
+ size={"small"}
50
52
  onClick={(e) => {
51
53
  e.preventDefault();
52
54
  e.stopPropagation();
@@ -61,7 +63,7 @@ export function NavigationCardBinding({
61
63
  }
62
64
  }}>
63
65
  <StarIcon
64
- size={18}
66
+ size={"small"}
65
67
  className={favourite ? "text-secondary" : "text-surface-400 dark:text-surface-500"}/>
66
68
  </IconButton>
67
69
  ]
@@ -101,6 +101,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
101
101
  maxSelection,
102
102
  }: ReferenceSelectionInnerProps<M>) {
103
103
 
104
+ const authController = useAuthController();
104
105
  const sideDialogContext = useSideDialogContext();
105
106
  const sideEntityController = useSideEntityController();
106
107
  const navigation = useNavigationController();
@@ -253,7 +254,8 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
253
254
  collection: collection,
254
255
  path: fullPath,
255
256
  values: {},
256
- propertyConfigs: customizationController.propertyConfigs
257
+ propertyConfigs: customizationController.propertyConfigs,
258
+ authController
257
259
  }), [collection, customizationController.propertyConfigs, fullPath]);
258
260
 
259
261
  const displayedColumnIds = useColumnIds(resolvedCollection, false);
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useRef } from "react";
1
+ import React, { useCallback, useEffect, useMemo, useRef } from "react";
2
2
  import {
3
3
  CollectionSize,
4
4
  Entity,
@@ -119,150 +119,147 @@ export type SelectableTableProps<M extends Record<string, any>> = {
119
119
  * @see VirtualTable
120
120
  * @group Components
121
121
  */
122
- export const SelectableTable = React.memo<SelectableTableProps<any>>(
123
- function SelectableTable<M extends Record<string, any>>
124
- ({
125
- onValueChange,
126
- cellRenderer,
127
- onEntityClick,
128
- onColumnResize,
129
- hoverRow = true,
130
- size = "m",
131
- inlineEditing = false,
132
- tableController:
133
- {
134
- data,
135
- dataLoading,
136
- noMoreToLoad,
137
- dataLoadingError,
138
- filterValues,
139
- setFilterValues,
140
- sortBy,
141
- setSortBy,
142
- itemCount,
143
- setItemCount,
144
- pageSize = 50,
145
- paginationEnabled,
146
- checkFilterCombination,
147
- setPopupCell
148
- },
149
- filterable = true,
150
- onScroll,
151
- initialScroll,
152
- emptyComponent,
153
- columns,
154
- forceFilter,
155
- highlightedRow,
156
- endAdornment,
157
- AddColumnComponent
158
- }: SelectableTableProps<M>) {
159
-
160
- const ref = useRef<HTMLDivElement>(null);
161
-
162
- const [selectedCell, setSelectedCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
163
-
164
- const loadNextPage = () => {
165
- if (!paginationEnabled || dataLoading || noMoreToLoad)
166
- return;
167
- if (itemCount !== undefined)
168
- setItemCount?.(itemCount + pageSize);
122
+ export const SelectableTable = function SelectableTable<M extends Record<string, any>>
123
+ ({
124
+ onValueChange,
125
+ cellRenderer,
126
+ onEntityClick,
127
+ onColumnResize,
128
+ hoverRow = true,
129
+ size = "m",
130
+ inlineEditing = false,
131
+ tableController:
132
+ {
133
+ data,
134
+ dataLoading,
135
+ noMoreToLoad,
136
+ dataLoadingError,
137
+ filterValues,
138
+ setFilterValues,
139
+ sortBy,
140
+ setSortBy,
141
+ itemCount,
142
+ setItemCount,
143
+ pageSize = 50,
144
+ paginationEnabled,
145
+ checkFilterCombination,
146
+ setPopupCell
147
+ },
148
+ filterable = true,
149
+ onScroll,
150
+ initialScroll,
151
+ emptyComponent,
152
+ columns,
153
+ forceFilter,
154
+ highlightedRow,
155
+ endAdornment,
156
+ AddColumnComponent
157
+ }: SelectableTableProps<M>) {
158
+
159
+ const ref = useRef<HTMLDivElement>(null);
160
+
161
+ const [selectedCell, setSelectedCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
162
+
163
+ const loadNextPage = () => {
164
+ if (!paginationEnabled || dataLoading || noMoreToLoad)
165
+ return;
166
+ if (itemCount !== undefined)
167
+ setItemCount?.(itemCount + pageSize);
168
+ };
169
+
170
+ const resetPagination = useCallback(() => {
171
+ setItemCount?.(pageSize);
172
+ }, [pageSize]);
173
+
174
+ const onRowClick = useCallback(({ rowData }: {
175
+ rowData: Entity<M>
176
+ }) => {
177
+ if (inlineEditing)
178
+ return;
179
+ return onEntityClick && onEntityClick(rowData);
180
+ }, [onEntityClick, inlineEditing]);
181
+
182
+ useOutsideAlerter(ref,
183
+ () => {
184
+ if (selectedCell) {
185
+ unselect();
186
+ }
187
+ },
188
+ Boolean(selectedCell));
189
+
190
+ const select = useCallback((cell?: SelectedCellProps<M>) => {
191
+ setSelectedCell(cell);
192
+ }, []);
193
+
194
+ const unselect = useCallback(() => {
195
+ setSelectedCell(undefined);
196
+ }, []);
197
+
198
+ // on ESC key press
199
+ useEffect(() => {
200
+ const escFunction = (event: any) => {
201
+ if (event.keyCode === 27) {
202
+ unselect();
203
+ }
169
204
  };
205
+ document.addEventListener("keydown", escFunction, false);
206
+ return () => {
207
+ document.removeEventListener("keydown", escFunction, false);
208
+ };
209
+ }, [unselect]);
210
+
211
+ const onFilterUpdate = useCallback((updatedFilterValues?: FilterValues<any>) => {
212
+ setFilterValues?.({ ...updatedFilterValues, ...forceFilter } as FilterValues<any>);
213
+ }, [forceFilter]);
214
+
215
+ const contextValue = useMemo(() => ({
216
+ setPopupCell: setPopupCell as ((cell?: SelectedCellProps<M>) => void),
217
+ select,
218
+ onValueChange,
219
+ size: size ?? "m",
220
+ selectedCell
221
+ }), [setPopupCell, select, onValueChange, size, selectedCell]);
222
+
223
+ return (
224
+ <SelectableTableContext.Provider
225
+ value={contextValue}>
226
+ <div className="h-full w-full flex flex-col bg-white dark:bg-surface-950"
227
+ ref={ref}>
228
+
229
+ <VirtualTable
230
+ data={data}
231
+ columns={columns}
232
+ cellRenderer={cellRenderer}
233
+ onRowClick={inlineEditing ? undefined : (onEntityClick ? onRowClick : undefined)}
234
+ onEndReached={loadNextPage}
235
+ onResetPagination={resetPagination}
236
+ error={dataLoadingError}
237
+ onColumnResize={onColumnResize}
238
+ rowHeight={getRowHeight(size)}
239
+ loading={dataLoading}
240
+ filter={filterValues}
241
+ onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
242
+ sortBy={sortBy}
243
+ onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
244
+ hoverRow={hoverRow}
245
+ initialScroll={initialScroll}
246
+ onScroll={onScroll}
247
+ checkFilterCombination={checkFilterCombination}
248
+ createFilterField={filterable ? createFilterField : undefined}
249
+ rowClassName={useCallback((entity: Entity<M>) => {
250
+ return highlightedRow?.(entity) ? "bg-surface-100 bg-opacity-75 dark:bg-surface-800 dark:bg-opacity-75" : "";
251
+ }, [highlightedRow])}
252
+ className="flex-grow"
253
+ emptyComponent={emptyComponent}
254
+ endAdornment={endAdornment}
255
+ AddColumnComponent={AddColumnComponent}
256
+ />
257
+
258
+ </div>
259
+ </SelectableTableContext.Provider>
260
+ );
170
261
 
171
- const resetPagination = useCallback(() => {
172
- setItemCount?.(pageSize);
173
- }, [pageSize]);
174
-
175
- const onRowClick = useCallback(({ rowData }: {
176
- rowData: Entity<M>
177
- }) => {
178
- if (inlineEditing)
179
- return;
180
- return onEntityClick && onEntityClick(rowData);
181
- }, [onEntityClick, inlineEditing]);
182
-
183
- useOutsideAlerter(ref,
184
- () => {
185
- if (selectedCell) {
186
- unselect();
187
- }
188
- },
189
- Boolean(selectedCell));
190
-
191
- // on ESC key press
192
- useEffect(() => {
193
- const escFunction = (event: any) => {
194
- if (event.keyCode === 27) {
195
- unselect();
196
- }
197
- };
198
- document.addEventListener("keydown", escFunction, false);
199
- return () => {
200
- document.removeEventListener("keydown", escFunction, false);
201
- };
202
- });
203
-
204
- const select = useCallback((cell?: SelectedCellProps<M>) => {
205
- setSelectedCell(cell);
206
- }, []);
207
-
208
- const unselect = useCallback(() => {
209
- setSelectedCell(undefined);
210
- }, []);
211
-
212
- const onFilterUpdate = useCallback((updatedFilterValues?: FilterValues<any>) => {
213
- setFilterValues?.({ ...updatedFilterValues, ...forceFilter } as FilterValues<any>);
214
- }, [forceFilter]);
215
-
216
- return (
217
- <SelectableTableContext.Provider
218
- value={{
219
- setPopupCell: setPopupCell as ((cell?: SelectedCellProps<M>) => void),
220
- select,
221
- onValueChange,
222
- size: size ?? "m",
223
- selectedCell,
224
- }}
225
- >
226
- <div className="h-full w-full flex flex-col bg-white dark:bg-surface-950"
227
- ref={ref}>
228
-
229
- <VirtualTable
230
- data={data}
231
- columns={columns}
232
- cellRenderer={cellRenderer}
233
- onRowClick={inlineEditing ? undefined : (onEntityClick ? onRowClick : undefined)}
234
- onEndReached={loadNextPage}
235
- onResetPagination={resetPagination}
236
- error={dataLoadingError}
237
- onColumnResize={onColumnResize}
238
- rowHeight={getRowHeight(size)}
239
- loading={dataLoading}
240
- filter={filterValues}
241
- onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
242
- sortBy={sortBy}
243
- onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
244
- hoverRow={hoverRow}
245
- initialScroll={initialScroll}
246
- onScroll={onScroll}
247
- checkFilterCombination={checkFilterCombination}
248
- createFilterField={filterable ? createFilterField : undefined}
249
- rowClassName={useCallback((entity: Entity<M>) => {
250
- return highlightedRow?.(entity) ? "bg-surface-100 bg-opacity-75 dark:bg-surface-800 dark:bg-opacity-75" : "";
251
- }, [highlightedRow])}
252
- className="flex-grow"
253
- emptyComponent={emptyComponent}
254
- endAdornment={endAdornment}
255
- AddColumnComponent={AddColumnComponent}
256
- />
257
-
258
- </div>
259
- </SelectableTableContext.Provider>
260
- );
261
-
262
- },
263
- () => false,
264
- // equal
265
- );
262
+ };
266
263
 
267
264
  function createFilterField({
268
265
  id,
@@ -115,7 +115,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
115
115
  endAdornment,
116
116
  AddColumnComponent,
117
117
  initialScroll = 0,
118
- debug
119
118
  }: VirtualTableProps<T>) {
120
119
 
121
120
  const sortByProperty: string | undefined = sortBy ? sortBy[0] : undefined;
@@ -131,7 +130,8 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
131
130
  // Set initial scroll position
132
131
  useEffect(() => {
133
132
  if (tableRef.current && initialScroll) {
134
- tableRef.current.scrollTo(0, initialScroll);
133
+ const { scrollLeft } = tableRef.current;
134
+ tableRef.current.scrollTo(scrollLeft, initialScroll);
135
135
  }
136
136
  }, [tableRef, initialScroll]);
137
137
 
@@ -139,17 +139,45 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
139
139
  setColumns(columnsProp);
140
140
  }, [columnsProp]);
141
141
 
142
- const [measureRef, bounds] = useMeasure();
142
+ const [_, setForceUpdate] = useState(false);
143
+ useEffect(() => {
144
+ // Create a ResizeObserver to detect size changes more aggressively
145
+ if (tableRef.current) {
146
+ const resizeObserver = new ResizeObserver(() => {
147
+ // Force a re-render when size changes
148
+ setForceUpdate(prev => !prev);
149
+ });
150
+
151
+ resizeObserver.observe(tableRef.current);
152
+
153
+ return () => {
154
+ if (tableRef.current) {
155
+ resizeObserver.unobserve(tableRef.current);
156
+ }
157
+ resizeObserver.disconnect();
158
+ };
159
+ }
160
+ return () => {
161
+ }
162
+ }, [tableRef]);
163
+
164
+ const [measureRef, bounds] = useMeasure({
165
+ debounce: 50,
166
+ polyfill: ResizeObserver,
167
+ scroll: true,
168
+ // This is important for handling zooming in react-flow
169
+ offsetSize: true
170
+ });
143
171
 
144
172
  const onColumnResizeInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
145
- if (debug)
146
- console.log("onColumnResizeInternal", params);
147
- setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
148
- }, [columns]);
173
+ setColumns(prevColumns =>
174
+ prevColumns.map((column) =>
175
+ column.key === params.column.key ? params.column : column
176
+ )
177
+ );
178
+ }, []);
149
179
 
150
180
  const onColumnResizeEndInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
151
- if (debug)
152
- console.log("onColumnResizeEndInternal", params);
153
181
  setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
154
182
  if (onColumnResize) {
155
183
  onColumnResize(params);
@@ -160,14 +188,10 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
160
188
  const filterRef = useRef<VirtualTableFilterValues<any> | undefined>();
161
189
 
162
190
  useEffect(() => {
163
- if (debug)
164
- console.log("Filter updated", filterInput);
165
191
  filterRef.current = filterInput;
166
192
  }, [filterInput]);
167
193
 
168
194
  const scrollToTop = useCallback(() => {
169
- if (debug)
170
- console.log("scrollToTop");
171
195
  endReachCallbackThreshold.current = 0;
172
196
  if (tableRef.current) {
173
197
  tableRef.current.scrollTo(tableRef.current?.scrollLeft, 0);
@@ -176,9 +200,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
176
200
 
177
201
  const onColumnSort = useCallback((key: string) => {
178
202
 
179
- if (debug)
180
- console.log("onColumnSort", key);
181
-
182
203
  const isDesc = sortByProperty === key && currentSort === "desc";
183
204
  const isAsc = sortByProperty === key && currentSort === "asc";
184
205
  const newSort = isAsc ? "desc" : (isDesc ? undefined : "asc");
@@ -206,12 +227,8 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
206
227
  }, [checkFilterCombination, currentSort, onFilterUpdate, onResetPagination, onSortByUpdate, scrollToTop, sortByProperty]);
207
228
 
208
229
  const maxScroll = Math.max((data?.length ?? 0) * rowHeight - bounds.height, 0);
209
- if (debug)
210
- console.log("maxScroll", maxScroll);
211
230
 
212
231
  const onEndReachedInternal = useCallback((scrollOffset: number) => {
213
- if (debug)
214
- console.log("onEndReachedInternal", scrollOffset, endReachCallbackThreshold.current + endOffset);
215
232
  if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current + endOffset) {
216
233
  endReachCallbackThreshold.current = scrollOffset;
217
234
  onEndReached();
@@ -227,12 +244,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
227
244
  scrollOffset: number,
228
245
  scrollUpdateWasRequested: boolean;
229
246
  }) => {
230
- if (debug)
231
- console.log("onScroll", {
232
- scrollDirection,
233
- scrollOffset,
234
- scrollUpdateWasRequested
235
- });
236
247
  if (onScrollProp) {
237
248
  debouncedScroll({
238
249
  scrollDirection,
@@ -245,8 +256,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
245
256
  }, [maxScroll, onEndReachedInternal]);
246
257
 
247
258
  const onFilterUpdateInternal = useCallback((column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, any]) => {
248
- if (debug)
249
- console.log("onFilterUpdateInternal", column, filterForProperty);
250
259
 
251
260
  endReachCallbackThreshold.current = 0;
252
261
  const filter = filterRef.current;
@@ -309,9 +318,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
309
318
  AddColumnComponent
310
319
  };
311
320
 
312
- if (debug)
313
- console.log("VirtualTable render", virtualListController);
314
-
315
321
  return (
316
322
  <div
317
323
  ref={measureRef}
@@ -162,11 +162,6 @@ export interface VirtualTableProps<T extends Record<string, any>> {
162
162
  */
163
163
  initialScroll?: number;
164
164
 
165
- /**
166
- * Debug mode
167
- */
168
- debug?: boolean;
169
-
170
165
  }
171
166
 
172
167
  export type CellRendererParams<T = any> = {