@firecms/core 3.0.0-canary.235 → 3.0.0-canary.239

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 (44) hide show
  1. package/dist/components/EntityPreview.d.ts +4 -2
  2. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  3. package/dist/components/index.d.ts +1 -0
  4. package/dist/hooks/useBuildNavigationController.d.ts +2 -9
  5. package/dist/index.es.js +271 -144
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +271 -144
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/collections.d.ts +13 -0
  10. package/dist/types/plugins.d.ts +12 -0
  11. package/dist/types/side_entity_controller.d.ts +4 -0
  12. package/dist/util/callbacks.d.ts +2 -0
  13. package/dist/util/index.d.ts +1 -0
  14. package/package.json +5 -5
  15. package/src/components/ConfirmationDialog.tsx +9 -9
  16. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
  17. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
  18. package/src/components/EntityCollectionView/EntityCollectionView.tsx +2 -0
  19. package/src/components/EntityPreview.tsx +18 -14
  20. package/src/components/ErrorView.tsx +1 -1
  21. package/src/components/HomePage/DefaultHomePage.tsx +1 -1
  22. package/src/components/SelectableTable/SelectableTable.tsx +140 -143
  23. package/src/components/VirtualTable/VirtualTable.tsx +7 -4
  24. package/src/components/index.tsx +2 -0
  25. package/src/core/EntityEditView.tsx +24 -14
  26. package/src/core/EntitySidePanel.tsx +17 -10
  27. package/src/form/components/LabelWithIcon.tsx +1 -1
  28. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -2
  29. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
  30. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
  31. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -1
  32. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
  33. package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
  34. package/src/hooks/useBuildNavigationController.tsx +29 -16
  35. package/src/internal/useBuildSideEntityController.tsx +1 -1
  36. package/src/preview/components/ReferencePreview.tsx +1 -1
  37. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  38. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
  39. package/src/types/collections.ts +16 -0
  40. package/src/types/firecms.tsx +0 -1
  41. package/src/types/plugins.tsx +16 -0
  42. package/src/types/side_entity_controller.tsx +5 -5
  43. package/src/util/callbacks.ts +119 -0
  44. package/src/util/index.ts +1 -0
@@ -293,6 +293,11 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
293
293
  * If set to true, a tab including the JSON representation of the entity will be included.
294
294
  */
295
295
  includeJsonView?: boolean;
296
+ /**
297
+ * If set to true, changes to the entity will be saved in a subcollection.
298
+ * This prop has no effect if the history plugin is not enabled
299
+ */
300
+ history?: boolean;
296
301
  }
297
302
  /**
298
303
  * Parameter passed to the `Actions` prop in the collection configuration.
@@ -437,6 +442,10 @@ export type EntityCustomView<M extends Record<string, any> = any> = {
437
442
  * Name of this custom view.
438
443
  */
439
444
  name: string;
445
+ /**
446
+ * Render this custom view in the tab of the entity view, instead of the name
447
+ */
448
+ tabComponent?: React.ReactNode;
440
449
  /**
441
450
  * If set to true, the actions of the entity (save, discard,delete) will be
442
451
  * included in the view. By default the actions are located in the right or bottom,
@@ -448,6 +457,10 @@ export type EntityCustomView<M extends Record<string, any> = any> = {
448
457
  * Builder for rendering the custom view
449
458
  */
450
459
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
460
+ /**
461
+ * Position of this tab in the entity view. Defaults to `end`.
462
+ */
463
+ position?: "start" | "end";
451
464
  };
452
465
  /**
453
466
  * Parameters passed to the builder in charge of rendering a custom panel for
@@ -131,6 +131,18 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
131
131
  fieldBuilder?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T, any, EC>) => React.ComponentType<FieldProps<T>> | null;
132
132
  fieldBuilderEnabled?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T>) => boolean;
133
133
  };
134
+ collection?: {
135
+ /**
136
+ * Use this method to modify a single collection before it is rendered.
137
+ * @param collection
138
+ */
139
+ modifyCollection?: (collection: EntityCollection) => EntityCollection;
140
+ /**
141
+ * Use this method to modify, add or remove collections.
142
+ * @param collections
143
+ */
144
+ injectCollections?: (collections: EntityCollection[]) => EntityCollection[];
145
+ };
134
146
  };
135
147
  /**
136
148
  * Props passed to the {@link FireCMSPlugin.homePage.CollectionActions} method.
@@ -60,6 +60,10 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
60
60
  * Override some form properties
61
61
  */
62
62
  formProps?: Partial<EntityFormProps<M>>;
63
+ /**
64
+ * Allow the user to open the entity fullscreen
65
+ */
66
+ allowFullScreen?: boolean;
63
67
  }
64
68
  /**
65
69
  * Controller to open the side dialog displaying entity forms
@@ -0,0 +1,2 @@
1
+ import { EntityCallbacks } from "../types";
2
+ export declare const mergeCallbacks: (baseCallbacks?: EntityCallbacks, pluginCallbacks?: EntityCallbacks) => EntityCallbacks | undefined;
@@ -23,3 +23,4 @@ export * from "./join_collections";
23
23
  export * from "./builders";
24
24
  export * from "./useTraceUpdate";
25
25
  export * from "./storage";
26
+ export * from "./callbacks";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.235",
4
+ "version": "3.0.0-canary.239",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -50,9 +50,9 @@
50
50
  "./package.json": "./package.json"
51
51
  },
52
52
  "dependencies": {
53
- "@firecms/editor": "^3.0.0-canary.235",
54
- "@firecms/formex": "^3.0.0-canary.235",
55
- "@firecms/ui": "^3.0.0-canary.235",
53
+ "@firecms/editor": "^3.0.0-canary.239",
54
+ "@firecms/formex": "^3.0.0-canary.239",
55
+ "@firecms/ui": "^3.0.0-canary.239",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
57
  "@radix-ui/react-portal": "^1.1.3",
58
58
  "clsx": "^2.1.1",
@@ -105,7 +105,7 @@
105
105
  "dist",
106
106
  "src"
107
107
  ],
108
- "gitHead": "d3f4ac352f53c76f2b8631e6d0cccec533dd5826",
108
+ "gitHead": "28e265bdb20ddd0d2eb813e9cbc2c082e17c2c65",
109
109
  "publishConfig": {
110
110
  "access": "public"
111
111
  },
@@ -1,15 +1,15 @@
1
1
  import React from "react";
2
2
 
3
- import { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton, Typography } from "@firecms/ui";
3
+ import { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton } from "@firecms/ui";
4
4
 
5
5
  export function ConfirmationDialog({
6
- open,
7
- onAccept,
8
- onCancel,
9
- title,
10
- loading,
11
- body
12
- }: {
6
+ open,
7
+ onAccept,
8
+ onCancel,
9
+ title,
10
+ loading,
11
+ body
12
+ }: {
13
13
  open: boolean,
14
14
  onAccept: () => void,
15
15
  onCancel: () => void,
@@ -38,7 +38,7 @@ export function ConfirmationDialog({
38
38
  type="submit"
39
39
  loading={loading}
40
40
  onClick={onAccept}
41
- >
41
+ autoFocus>
42
42
  Ok
43
43
  </LoadingButton>
44
44
  </DialogActions>
@@ -394,7 +394,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
394
394
  size={size}
395
395
  multiselect={true}
396
396
  path={arrayProperty.of.path}
397
- previewProperties={arrayProperty.of.previewProperties}
397
+ previewProperties={arrayProperty.of.previewKeys}
398
398
  title={arrayProperty.name}
399
399
  forceFilter={arrayProperty.of.forceFilter}
400
400
  includeId={arrayProperty.of.includeId}
@@ -55,7 +55,7 @@ export function CollectionTableToolbar({
55
55
  <Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
56
56
  <Select
57
57
  value={size as string}
58
- className="w-16 h-10"
58
+ className="w-16 ml-2"
59
59
  size={"small"}
60
60
  onValueChange={(v) => onSizeChanged(v as CollectionSize)}
61
61
  renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
@@ -753,6 +753,8 @@ export const EntityCollectionView = React.memo(
753
753
  equal(a.additionalFields, b.additionalFields) &&
754
754
  equal(a.sideDialogWidth, b.sideDialogWidth) &&
755
755
  equal(a.openEntityMode, b.openEntityMode) &&
756
+ equal(a.exportable, b.exportable) &&
757
+ equal(a.history, b.history) &&
756
758
  equal(a.forceFilter, b.forceFilter);
757
759
  }) as React.FunctionComponent<EntityCollectionViewProps<any>>
758
760
 
@@ -7,6 +7,7 @@ import {
7
7
  getEntityImagePreviewPropertyKey,
8
8
  getEntityPreviewKeys,
9
9
  getEntityTitlePropertyKey,
10
+ getPropertyInPath,
10
11
  getValueInPath,
11
12
  IconForView,
12
13
  resolveCollection
@@ -26,11 +27,13 @@ export type EntityPreviewProps = {
26
27
  actions?: React.ReactNode,
27
28
  collection?: EntityCollection,
28
29
  hover?: boolean;
29
- previewProperties?: string[],
30
+ previewKeys?: string[],
30
31
  disabled?: boolean,
31
32
  entity: Entity<any>,
32
33
  includeId?: boolean,
34
+ includeTitle?: boolean,
33
35
  includeEntityLink?: boolean,
36
+ includeImage?: boolean,
34
37
  onClick?: (e: React.SyntheticEvent) => void;
35
38
  };
36
39
 
@@ -43,12 +46,14 @@ export function EntityPreview({
43
46
  disabled,
44
47
  hover,
45
48
  collection: collectionProp,
46
- previewProperties,
49
+ previewKeys,
47
50
  onClick,
48
51
  size,
49
52
  includeId = true,
53
+ includeTitle = true,
50
54
  includeEntityLink = true,
51
- entity
55
+ includeImage = true,
56
+ entity,
52
57
  }: EntityPreviewProps) {
53
58
 
54
59
  const authController = useAuthController();
@@ -72,11 +77,11 @@ export function EntityPreview({
72
77
  authController
73
78
  }), [collection]);
74
79
 
75
- const listProperties = useMemo(() => getEntityPreviewKeys(authController, resolvedCollection, customizationController.propertyConfigs, previewProperties, size === "medium" || size === "large" ? 3 : 1),
76
- [previewProperties, resolvedCollection, size]);
80
+ const listProperties = useMemo(() => previewKeys ?? getEntityPreviewKeys(authController, resolvedCollection, customizationController.propertyConfigs, previewKeys, size === "medium" || size === "large" ? 3 : 1),
81
+ [previewKeys, resolvedCollection, size]);
77
82
 
78
- const titleProperty = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
79
- const imagePropertyKey = getEntityImagePreviewPropertyKey(resolvedCollection);
83
+ const titleProperty = includeTitle ? getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs) : undefined;
84
+ const imagePropertyKey = includeImage ? getEntityImagePreviewPropertyKey(resolvedCollection) : undefined;
80
85
  const imageProperty = imagePropertyKey ? resolvedCollection.properties[imagePropertyKey] : undefined;
81
86
  const usedImageProperty = imageProperty && "of" in imageProperty ? imageProperty.of : imageProperty;
82
87
  const restProperties = listProperties.filter(p => p !== titleProperty && p !== imagePropertyKey);
@@ -103,9 +108,7 @@ export function EntityPreview({
103
108
  </div>
104
109
 
105
110
 
106
- <div className={"flex flex-col grow-1 w-full m-1 shrink-1"} style={{
107
- "maxWidth": "calc(100% - 96px)"
108
- }}>
111
+ <div className={"flex flex-col grow w-full m-1 shrink min-w-0"}>
109
112
 
110
113
  {size !== "small" && includeId && (
111
114
  entity
@@ -135,9 +138,10 @@ export function EntityPreview({
135
138
  )}
136
139
 
137
140
  {restProperties && restProperties.map((key) => {
138
- const childProperty = resolvedCollection.properties[key as string];
141
+ const childProperty = getPropertyInPath(resolvedCollection.properties, key);
139
142
  if (!childProperty) return null;
140
143
 
144
+ const valueInPath = getValueInPath(entity.values, key);
141
145
  return (
142
146
  <div key={"ref_prev_" + key}
143
147
  className={cls("truncate", restProperties.length > 1 ? "my-0.5" : "my-0")}>
@@ -145,7 +149,7 @@ export function EntityPreview({
145
149
  entity
146
150
  ? <PropertyPreview
147
151
  propertyKey={key as string}
148
- value={getValueInPath(entity.values, key)}
152
+ value={valueInPath}
149
153
  property={childProperty as ResolvedProperty}
150
154
  size={"small"}/>
151
155
  : <SkeletonPropertyComponent
@@ -162,7 +166,7 @@ export function EntityPreview({
162
166
  <Tooltip title={`See details for ${entity.id}`} className={"shrink-0"}>
163
167
  <IconButton
164
168
  color={"inherit"}
165
- size={"medium"}
169
+ size={"small"}
166
170
  className={size !== "small" ? "self-start" : ""}
167
171
  onClick={(e) => {
168
172
  e.stopPropagation();
@@ -177,7 +181,7 @@ export function EntityPreview({
177
181
  updateUrl: true
178
182
  });
179
183
  }}>
180
- <KeyboardTabIcon size={"medium"}/>
184
+ <KeyboardTabIcon size={"small"}/>
181
185
  </IconButton>
182
186
  </Tooltip>}
183
187
 
@@ -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
@@ -179,7 +179,7 @@ export function DefaultHomePage({
179
179
 
180
180
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
181
181
  {thisGroupCollections.map((entry) => (
182
- <div key={`nav_${entry.group}_${entry.name}`} className="col-span-1">
182
+ <div key={`nav_${entry.group}_${entry.path}_${entry.name}`} className="col-span-1">
183
183
  <NavigationCardBinding
184
184
  {...entry}
185
185
  onClick={() => {
@@ -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,
@@ -170,10 +170,13 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
170
170
  });
171
171
 
172
172
  const onColumnResizeInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
173
- if (debug)
174
- console.log("onColumnResizeInternal", params);
175
- setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
176
- }, [columns]);
173
+ if (debug) console.log("onColumnResizeInternal", params);
174
+ setColumns(prevColumns =>
175
+ prevColumns.map((column) =>
176
+ column.key === params.column.key ? params.column : column
177
+ )
178
+ );
179
+ }, []);
177
180
 
178
181
  const onColumnResizeEndInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
179
182
  if (debug)
@@ -36,3 +36,5 @@ export * from "./ArrayContainer";
36
36
  export * from "./ReferenceWidget";
37
37
  export * from "./SearchIconsView";
38
38
  export * from "./FieldCaption";
39
+
40
+ export * from "./EntityPreview";