@firecms/core 3.0.1 → 3.1.0-canary.1df3b2c

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 (170) 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/EntityCollectionView/Board.d.ts +2 -0
  10. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  11. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  12. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  13. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  14. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  15. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  16. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  17. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  18. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
  19. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  20. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +49 -0
  21. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  22. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  23. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
  24. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  25. package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
  26. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +2 -0
  27. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  28. package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
  29. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
  30. package/dist/components/VirtualTable/types.d.ts +2 -0
  31. package/dist/components/index.d.ts +3 -0
  32. package/dist/contexts/index.d.ts +10 -0
  33. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  34. package/dist/core/index.d.ts +1 -0
  35. package/dist/form/validation.d.ts +3 -2
  36. package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
  37. package/dist/hooks/useCollapsedGroups.d.ts +4 -1
  38. package/dist/index.es.js +5239 -1590
  39. package/dist/index.es.js.map +1 -1
  40. package/dist/index.umd.js +5233 -1585
  41. package/dist/index.umd.js.map +1 -1
  42. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  43. package/dist/preview/components/DatePreview.d.ts +13 -3
  44. package/dist/preview/components/ImagePreview.d.ts +5 -1
  45. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  46. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  47. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  48. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  49. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  50. package/dist/types/collections.d.ts +42 -2
  51. package/dist/types/datasource.d.ts +0 -1
  52. package/dist/types/plugins.d.ts +46 -1
  53. package/dist/types/properties.d.ts +259 -4
  54. package/dist/util/__tests__/conditions.test.d.ts +1 -0
  55. package/dist/util/__tests__/objects.test.d.ts +1 -0
  56. package/dist/util/conditions.d.ts +26 -0
  57. package/dist/util/entities.d.ts +1 -2
  58. package/dist/util/index.d.ts +2 -1
  59. package/dist/util/property_utils.d.ts +2 -1
  60. package/dist/util/resolutions.d.ts +1 -1
  61. package/package.json +10 -7
  62. package/src/app/Scaffold.tsx +14 -15
  63. package/src/components/AIIcon.tsx +39 -0
  64. package/src/components/ArrayContainer.tsx +1 -4
  65. package/src/components/ClearFilterSortButton.tsx +19 -16
  66. package/src/components/ConfirmationDialog.tsx +0 -2
  67. package/src/components/DeleteEntityDialog.tsx +2 -4
  68. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
  69. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
  70. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
  71. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
  72. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
  73. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
  74. package/src/components/EntityCollectionView/Board.tsx +324 -0
  75. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  76. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  77. package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
  78. package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
  79. package/src/components/EntityCollectionView/EntityCard.tsx +231 -0
  80. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +713 -0
  81. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
  82. package/src/components/EntityCollectionView/EntityCollectionView.tsx +485 -203
  83. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
  84. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
  85. package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
  86. package/src/components/EntityCollectionView/ViewModeToggle.tsx +202 -0
  87. package/src/components/EntityCollectionView/board_types.ts +113 -0
  88. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  89. package/src/components/ErrorTooltip.tsx +2 -1
  90. package/src/components/HomePage/DefaultHomePage.tsx +47 -10
  91. package/src/components/HomePage/HomePageDnD.tsx +56 -41
  92. package/src/components/HomePage/NavigationCard.tsx +20 -18
  93. package/src/components/HomePage/NavigationGroup.tsx +17 -16
  94. package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
  95. package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
  96. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
  97. package/src/components/ReferenceWidget.tsx +2 -4
  98. package/src/components/SelectableTable/SelectableTable.tsx +75 -67
  99. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
  100. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
  101. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
  102. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
  103. package/src/components/UnsavedChangesDialog.tsx +0 -2
  104. package/src/components/UserDisplay.tsx +4 -4
  105. package/src/components/VirtualTable/VirtualTable.tsx +170 -19
  106. package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
  107. package/src/components/VirtualTable/VirtualTableHeader.tsx +20 -11
  108. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
  109. package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
  110. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  111. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
  112. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +17 -4
  113. package/src/components/VirtualTable/types.tsx +2 -0
  114. package/src/components/common/useColumnsIds.tsx +95 -3
  115. package/src/components/index.tsx +4 -0
  116. package/src/contexts/BreacrumbsContext.tsx +15 -8
  117. package/src/contexts/index.ts +10 -0
  118. package/src/core/DefaultAppBar.tsx +39 -26
  119. package/src/core/DefaultDrawer.tsx +42 -56
  120. package/src/core/DrawerNavigationGroup.tsx +118 -0
  121. package/src/core/DrawerNavigationItem.tsx +4 -3
  122. package/src/core/EntityEditView.tsx +41 -43
  123. package/src/core/SideDialogs.tsx +4 -2
  124. package/src/core/index.tsx +1 -0
  125. package/src/form/PropertyFieldBinding.tsx +58 -43
  126. package/src/form/components/StorageItemPreview.tsx +2 -1
  127. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
  128. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
  129. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
  130. package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
  131. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +21 -17
  132. package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
  133. package/src/form/validation.ts +245 -160
  134. package/src/hooks/useBreadcrumbsController.tsx +18 -0
  135. package/src/hooks/useBuildNavigationController.tsx +42 -19
  136. package/src/hooks/useCollapsedGroups.ts +12 -4
  137. package/src/internal/useBuildDataSource.ts +69 -34
  138. package/src/internal/useBuildSideDialogsController.tsx +11 -8
  139. package/src/internal/useBuildSideEntityController.tsx +2 -4
  140. package/src/internal/useRestoreScroll.tsx +26 -14
  141. package/src/preview/PropertyPreview.tsx +40 -32
  142. package/src/preview/PropertyPreviewProps.tsx +6 -0
  143. package/src/preview/components/DatePreview.tsx +72 -4
  144. package/src/preview/components/EmptyValue.tsx +1 -1
  145. package/src/preview/components/ImagePreview.tsx +37 -21
  146. package/src/preview/components/StorageThumbnail.tsx +16 -12
  147. package/src/preview/components/UrlComponentPreview.tsx +28 -25
  148. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
  149. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
  150. package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
  151. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
  152. package/src/routes/CustomCMSRoute.tsx +1 -0
  153. package/src/routes/FireCMSRoute.tsx +26 -13
  154. package/src/types/collections.ts +48 -3
  155. package/src/types/datasource.ts +54 -56
  156. package/src/types/plugins.tsx +51 -1
  157. package/src/types/properties.ts +347 -27
  158. package/src/util/__tests__/conditions.test.ts +506 -0
  159. package/src/util/__tests__/objects.test.ts +196 -0
  160. package/src/util/callbacks.ts +6 -3
  161. package/src/util/collections.ts +51 -6
  162. package/src/util/conditions.ts +339 -0
  163. package/src/util/entities.ts +28 -29
  164. package/src/util/entity_cache.ts +2 -1
  165. package/src/util/index.ts +2 -1
  166. package/src/util/objects.ts +31 -13
  167. package/src/util/{references.ts → previews.ts} +14 -0
  168. package/src/util/property_utils.tsx +36 -10
  169. package/src/util/resolutions.ts +57 -55
  170. /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
@@ -0,0 +1,244 @@
1
+ import React, { useCallback, useEffect, useRef } from "react";
2
+ import { CollectionSize, Entity, EntityCollection, EntityTableController, SelectionController } from "../../types";
3
+ import { EntityCard } from "./EntityCard";
4
+ import { CircularProgress, cls, Typography } from "@firecms/ui";
5
+ import { useAuthController, useCustomizationController } from "../../hooks";
6
+
7
+ export type EntityCollectionCardViewProps<M extends Record<string, any> = any> = {
8
+ collection: EntityCollection<M>;
9
+ tableController: EntityTableController<M>;
10
+ onEntityClick?: (entity: Entity<M>) => void;
11
+ selectionController?: SelectionController<M>;
12
+ selectionEnabled?: boolean;
13
+ highlightedEntities?: Entity<M>[];
14
+ emptyComponent?: React.ReactNode;
15
+ onScroll?: (props: {
16
+ scrollDirection: "forward" | "backward";
17
+ scrollOffset: number;
18
+ scrollUpdateWasRequested: boolean;
19
+ }) => void;
20
+ initialScroll?: number;
21
+ /**
22
+ * Size of the cards in the grid view.
23
+ * - "xs": Extra small cards, most cards per row
24
+ * - "s": Small cards
25
+ * - "m": Medium cards (default)
26
+ * - "l": Large cards
27
+ * - "xl": Extra large cards, fewest cards per row
28
+ */
29
+ size?: CollectionSize;
30
+ };
31
+
32
+ /**
33
+ * Get grid column classes based on the size.
34
+ * Smaller size = more columns (smaller cards)
35
+ * Larger size = fewer columns (larger cards)
36
+ */
37
+ function getGridColumnsClass(size: CollectionSize): string {
38
+ switch (size) {
39
+ case "xs":
40
+ // Compact: many small cards
41
+ return "grid-cols-4 sm:grid-cols-5 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10";
42
+ case "s":
43
+ // Small: more cards per row
44
+ return "grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8";
45
+ case "m":
46
+ // Medium: balanced (default)
47
+ return "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6";
48
+ case "l":
49
+ // Large: fewer, bigger cards
50
+ return "grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-4";
51
+ case "xl":
52
+ // Extra large: fewest, biggest cards
53
+ return "grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3";
54
+ default:
55
+ return "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6";
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Card grid view for displaying entities with infinite scroll.
61
+ * Alternative to the EntityCollectionTable for visual browsing.
62
+ */
63
+ export function EntityCollectionCardView<M extends Record<string, any> = any>({
64
+ collection,
65
+ tableController,
66
+ onEntityClick,
67
+ selectionController,
68
+ selectionEnabled = true,
69
+ highlightedEntities,
70
+ emptyComponent,
71
+ onScroll,
72
+ initialScroll,
73
+ size = "m"
74
+ }: EntityCollectionCardViewProps<M>) {
75
+ const authController = useAuthController();
76
+ const customizationController = useCustomizationController();
77
+
78
+ const containerRef = useRef<HTMLDivElement>(null);
79
+ const loadMoreRef = useRef<HTMLDivElement>(null);
80
+ const hasRestoredScroll = useRef(false);
81
+
82
+ const {
83
+ data,
84
+ dataLoading,
85
+ noMoreToLoad,
86
+ dataLoadingError,
87
+ itemCount,
88
+ setItemCount,
89
+ pageSize = 50,
90
+ paginationEnabled
91
+ } = tableController;
92
+
93
+ // Track if we're currently loading to prevent multiple simultaneous load requests
94
+ const isLoadingMore = useRef(false);
95
+
96
+ // Infinite scroll with Intersection Observer
97
+ useEffect(() => {
98
+ if (!paginationEnabled || noMoreToLoad || dataLoading) {
99
+ return;
100
+ }
101
+
102
+ // Reset loading flag when dataLoading becomes false
103
+ if (!dataLoading) {
104
+ isLoadingMore.current = false;
105
+ }
106
+
107
+ const observer = new IntersectionObserver(
108
+ (entries) => {
109
+ if (entries[0].isIntersecting && !dataLoading && !noMoreToLoad && !isLoadingMore.current) {
110
+ // Prevent multiple load requests
111
+ isLoadingMore.current = true;
112
+ // Load more items
113
+ setItemCount?.((itemCount ?? pageSize) + pageSize);
114
+ }
115
+ },
116
+ {
117
+ root: containerRef.current, // Use the scroll container, not viewport
118
+ rootMargin: "400px",
119
+ threshold: 0
120
+ }
121
+ );
122
+
123
+ if (loadMoreRef.current) {
124
+ observer.observe(loadMoreRef.current);
125
+ }
126
+
127
+ return () => observer.disconnect();
128
+ }, [paginationEnabled, noMoreToLoad, dataLoading, itemCount, pageSize, setItemCount]);
129
+
130
+ // Scroll restoration: restore initial scroll position
131
+ useEffect(() => {
132
+ if (containerRef.current && initialScroll && !hasRestoredScroll.current && data.length > 0) {
133
+ containerRef.current.scrollTop = initialScroll;
134
+ hasRestoredScroll.current = true;
135
+ }
136
+ }, [initialScroll, data.length]);
137
+
138
+ // Scroll tracking: call onScroll when user scrolls
139
+ const lastScrollOffset = useRef(0);
140
+ useEffect(() => {
141
+ const container = containerRef.current;
142
+ if (!container || !onScroll) return;
143
+
144
+ const handleScroll = () => {
145
+ const currentOffset = container.scrollTop;
146
+ const direction = currentOffset > lastScrollOffset.current ? "forward" : "backward";
147
+ lastScrollOffset.current = currentOffset;
148
+ onScroll({
149
+ scrollDirection: direction,
150
+ scrollOffset: currentOffset,
151
+ scrollUpdateWasRequested: false
152
+ });
153
+ };
154
+
155
+ container.addEventListener("scroll", handleScroll, { passive: true });
156
+ return () => container.removeEventListener("scroll", handleScroll);
157
+ }, [onScroll]);
158
+
159
+ const handleEntityClick = useCallback((entity: Entity<M>) => {
160
+ onEntityClick?.(entity);
161
+ }, [onEntityClick]);
162
+
163
+ const handleSelectionChange = useCallback((entity: Entity<M>, selected: boolean) => {
164
+ selectionController?.toggleEntitySelection(entity, selected);
165
+ }, [selectionController]);
166
+
167
+ const isEntitySelected = useCallback((entity: Entity<M>) => {
168
+ return selectionController?.isEntitySelected(entity) ?? false;
169
+ }, [selectionController]);
170
+
171
+ const isEntityHighlighted = useCallback((entity: Entity<M>) => {
172
+ return highlightedEntities?.some(e => e.id === entity.id && e.path === entity.path) ?? false;
173
+ }, [highlightedEntities]);
174
+
175
+ // Show empty state
176
+ if (!dataLoading && data.length === 0 && !dataLoadingError) {
177
+ return (
178
+ <div className="flex-1 flex items-center justify-center p-8">
179
+ {emptyComponent ?? (
180
+ <Typography variant="label" color="secondary">
181
+ No entries found
182
+ </Typography>
183
+ )}
184
+ </div>
185
+ );
186
+ }
187
+
188
+ // Show error state
189
+ if (dataLoadingError) {
190
+ return (
191
+ <div className="flex-1 flex items-center justify-center p-8">
192
+ <Typography className="text-red-500">
193
+ Error loading data: {dataLoadingError.message}
194
+ </Typography>
195
+ </div>
196
+ );
197
+ }
198
+
199
+ const gridColumnsClass = getGridColumnsClass(size);
200
+
201
+ return (
202
+ <div
203
+ ref={containerRef}
204
+ className="flex-1 overflow-auto p-4"
205
+ >
206
+ {/* Card Grid with max-width container */}
207
+ <div className="max-w-7xl mx-auto">
208
+ <div className={cls(
209
+ "grid gap-4",
210
+ gridColumnsClass
211
+ )}>
212
+ {data.map((entity) => (
213
+ <EntityCard
214
+ key={`${entity.path}_${entity.id}`}
215
+ entity={entity}
216
+ collection={collection}
217
+ onClick={handleEntityClick}
218
+ selected={isEntitySelected(entity)}
219
+ highlighted={isEntityHighlighted(entity)}
220
+ onSelectionChange={handleSelectionChange}
221
+ selectionEnabled={selectionEnabled}
222
+ size={size}
223
+ />
224
+ ))}
225
+ </div>
226
+
227
+ {/* Load more trigger / Loading indicator */}
228
+ <div
229
+ ref={loadMoreRef}
230
+ className="flex items-center justify-center py-8"
231
+ >
232
+ {dataLoading && (
233
+ <CircularProgress size="small"/>
234
+ )}
235
+ {!dataLoading && noMoreToLoad && data.length > 0 && (
236
+ <Typography variant="caption" color="secondary">
237
+ All {data.length} entries loaded
238
+ </Typography>
239
+ )}
240
+ </div>
241
+ </div>
242
+ </div>
243
+ );
244
+ }