@firecms/core 3.0.1 → 3.1.0-canary.7d91b7c
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.
- package/README.md +1 -1
- package/dist/components/AIIcon.d.ts +16 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
- package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
- package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
- package/dist/components/EntityCollectionView/Board.d.ts +2 -0
- package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
- package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
- package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
- package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
- package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
- package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
- package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
- package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
- package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
- package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
- package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
- package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
- package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
- package/dist/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
- package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
- package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
- package/dist/components/VirtualTable/types.d.ts +2 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/contexts/index.d.ts +10 -0
- package/dist/core/DrawerNavigationGroup.d.ts +45 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/validation.d.ts +3 -2
- package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
- package/dist/hooks/useCollapsedGroups.d.ts +4 -1
- package/dist/index.es.js +5266 -1578
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5260 -1573
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +5 -0
- package/dist/preview/components/DatePreview.d.ts +13 -3
- package/dist/preview/components/ImagePreview.d.ts +5 -1
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
- package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
- package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +50 -2
- package/dist/types/datasource.d.ts +0 -1
- package/dist/types/plugins.d.ts +62 -1
- package/dist/types/properties.d.ts +259 -4
- package/dist/util/__tests__/conditions.test.d.ts +1 -0
- package/dist/util/__tests__/objects.test.d.ts +1 -0
- package/dist/util/conditions.d.ts +26 -0
- package/dist/util/entities.d.ts +2 -3
- package/dist/util/index.d.ts +2 -1
- package/dist/util/property_utils.d.ts +2 -1
- package/dist/util/resolutions.d.ts +3 -3
- package/package.json +14 -11
- package/src/app/Scaffold.tsx +14 -15
- package/src/components/AIIcon.tsx +39 -0
- package/src/components/ArrayContainer.tsx +1 -4
- package/src/components/ClearFilterSortButton.tsx +19 -16
- package/src/components/ConfirmationDialog.tsx +0 -2
- package/src/components/DeleteEntityDialog.tsx +2 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
- package/src/components/EntityCollectionView/Board.tsx +324 -0
- package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
- package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
- package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
- package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +733 -0
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +519 -203
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
- package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
- package/src/components/EntityCollectionView/ViewModeToggle.tsx +199 -0
- package/src/components/EntityCollectionView/board_types.ts +113 -0
- package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
- package/src/components/ErrorTooltip.tsx +2 -1
- package/src/components/HomePage/DefaultHomePage.tsx +47 -10
- package/src/components/HomePage/HomePageDnD.tsx +56 -41
- package/src/components/HomePage/NavigationCard.tsx +20 -18
- package/src/components/HomePage/NavigationGroup.tsx +17 -16
- package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
- package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
- package/src/components/ReferenceWidget.tsx +2 -4
- package/src/components/SelectableTable/SelectableTable.tsx +75 -67
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
- package/src/components/UnsavedChangesDialog.tsx +0 -2
- package/src/components/UserDisplay.tsx +4 -4
- package/src/components/VirtualTable/VirtualTable.tsx +272 -118
- package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
- package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -50
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
- package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
- package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
- package/src/components/VirtualTable/types.tsx +2 -0
- package/src/components/common/useColumnsIds.tsx +95 -3
- package/src/components/index.tsx +4 -0
- package/src/contexts/BreacrumbsContext.tsx +15 -8
- package/src/contexts/index.ts +10 -0
- package/src/core/DefaultAppBar.tsx +40 -27
- package/src/core/DefaultDrawer.tsx +42 -56
- package/src/core/DrawerNavigationGroup.tsx +118 -0
- package/src/core/DrawerNavigationItem.tsx +4 -3
- package/src/core/EntityEditView.tsx +41 -43
- package/src/core/EntitySidePanel.tsx +28 -26
- package/src/core/SideDialogs.tsx +4 -2
- package/src/core/field_configs.tsx +14 -9
- package/src/core/index.tsx +1 -0
- package/src/form/EntityForm.tsx +69 -60
- package/src/form/PropertyFieldBinding.tsx +61 -46
- package/src/form/components/ErrorFocus.tsx +3 -3
- package/src/form/components/StorageItemPreview.tsx +2 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +22 -18
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
- package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
- package/src/form/validation.ts +245 -160
- package/src/hooks/useBreadcrumbsController.tsx +18 -0
- package/src/hooks/useBuildNavigationController.tsx +46 -23
- package/src/hooks/useCollapsedGroups.ts +12 -4
- package/src/hooks/useValidateAuthenticator.tsx +1 -1
- package/src/internal/useBuildDataSource.ts +68 -34
- package/src/internal/useBuildSideDialogsController.tsx +11 -8
- package/src/internal/useBuildSideEntityController.tsx +2 -4
- package/src/internal/useRestoreScroll.tsx +26 -14
- package/src/preview/PropertyPreview.tsx +41 -32
- package/src/preview/PropertyPreviewProps.tsx +6 -0
- package/src/preview/components/DatePreview.tsx +72 -4
- package/src/preview/components/EmptyValue.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +37 -21
- package/src/preview/components/StorageThumbnail.tsx +16 -12
- package/src/preview/components/UrlComponentPreview.tsx +28 -25
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
- package/src/routes/CustomCMSRoute.tsx +1 -0
- package/src/routes/FireCMSRoute.tsx +26 -13
- package/src/types/analytics.ts +10 -0
- package/src/types/collections.ts +57 -3
- package/src/types/datasource.ts +54 -56
- package/src/types/plugins.tsx +69 -1
- package/src/types/properties.ts +347 -27
- package/src/util/__tests__/conditions.test.ts +506 -0
- package/src/util/__tests__/objects.test.ts +196 -0
- package/src/util/callbacks.ts +6 -3
- package/src/util/collections.ts +51 -6
- package/src/util/conditions.ts +339 -0
- package/src/util/entities.ts +29 -30
- package/src/util/entity_cache.ts +2 -1
- package/src/util/index.ts +2 -1
- package/src/util/join_collections.ts +10 -8
- package/src/util/objects.ts +31 -13
- package/src/util/{references.ts → previews.ts} +16 -2
- package/src/util/property_utils.tsx +37 -11
- package/src/util/resolutions.ts +62 -58
- /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
|
@@ -34,7 +34,7 @@ export type FilterFormFieldProps<CustomProps> = {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
type VirtualTableHeaderProps<M extends Record<string, any>> = {
|
|
37
|
-
resizeHandleRef: RefObject<HTMLDivElement>;
|
|
37
|
+
resizeHandleRef: RefObject<HTMLDivElement | null>;
|
|
38
38
|
columnIndex: number;
|
|
39
39
|
isResizingIndex: number;
|
|
40
40
|
column: VirtualTableColumn<any>;
|
|
@@ -45,22 +45,26 @@ type VirtualTableHeaderProps<M extends Record<string, any>> = {
|
|
|
45
45
|
onClickResizeColumn?: (columnIndex: number, column: VirtualTableColumn) => void;
|
|
46
46
|
createFilterField?: (props: FilterFormFieldProps<any>) => React.ReactNode;
|
|
47
47
|
AdditionalHeaderWidget?: (props: { onHover: boolean }) => React.ReactNode;
|
|
48
|
+
isDragging?: boolean;
|
|
49
|
+
isDraggable?: boolean;
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
51
53
|
function VirtualTableHeader<M extends Record<string, any>>({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
resizeHandleRef,
|
|
55
|
+
columnIndex,
|
|
56
|
+
isResizingIndex,
|
|
57
|
+
sort,
|
|
58
|
+
onColumnSort,
|
|
59
|
+
onFilterUpdate,
|
|
60
|
+
filter,
|
|
61
|
+
column,
|
|
62
|
+
onClickResizeColumn,
|
|
63
|
+
createFilterField,
|
|
64
|
+
AdditionalHeaderWidget,
|
|
65
|
+
isDragging,
|
|
66
|
+
isDraggable
|
|
67
|
+
}: VirtualTableHeaderProps<M>) {
|
|
64
68
|
|
|
65
69
|
const [onHover, setOnHover] = useState(false);
|
|
66
70
|
|
|
@@ -85,14 +89,16 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
85
89
|
return (
|
|
86
90
|
<ErrorBoundary>
|
|
87
91
|
<div
|
|
88
|
-
className={cls("flex py-0 px-3 h-full text-xs uppercase font-semibold relative select-none items-center
|
|
92
|
+
className={cls("flex py-0 px-3 h-full text-xs uppercase font-semibold relative select-none items-center",
|
|
93
|
+
isDragging
|
|
94
|
+
? "bg-primary-bg dark:bg-primary-bg-dark"
|
|
95
|
+
: "bg-surface-50 dark:bg-surface-900",
|
|
89
96
|
"text-text-secondary hover:text-text-primary dark:text-text-secondary-dark dark:hover:text-text-primary-dark",
|
|
90
|
-
"hover:bg-surface-100 dark:hover:bg-surface-800 hover:bg-opacity-50 dark:hover:bg-opacity-50",
|
|
91
|
-
column.frozen ? "sticky left-0 z-10" : "relative z-0"
|
|
97
|
+
!isDragging && "hover:bg-surface-100 dark:hover:bg-surface-800 hover:bg-opacity-50 hover:bg-surface-100/50 dark:hover:bg-opacity-50 dark:hover:bg-surface-800/50",
|
|
98
|
+
column.frozen ? "sticky left-0 z-10" : "relative z-0",
|
|
99
|
+
isDraggable && "cursor-grab"
|
|
92
100
|
)}
|
|
93
101
|
style={{
|
|
94
|
-
// transition: "color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
|
95
|
-
// fontSize: "0.750rem",
|
|
96
102
|
left: column.frozen ? 0 : undefined,
|
|
97
103
|
minWidth: column.width,
|
|
98
104
|
maxWidth: column.width
|
|
@@ -123,11 +129,11 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
123
129
|
<>
|
|
124
130
|
|
|
125
131
|
{AdditionalHeaderWidget &&
|
|
126
|
-
<AdditionalHeaderWidget onHover={onHover || openFilter}/>}
|
|
132
|
+
<AdditionalHeaderWidget onHover={onHover || openFilter} />}
|
|
127
133
|
|
|
128
134
|
{column.sortable && (sort || hovered || openFilter) &&
|
|
129
135
|
<Badge color="secondary"
|
|
130
|
-
|
|
136
|
+
invisible={!sort}>
|
|
131
137
|
<IconButton
|
|
132
138
|
size={"small"}
|
|
133
139
|
className={onHover || openFilter ? "bg-white dark:bg-surface-950" : undefined}
|
|
@@ -136,11 +142,11 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
136
142
|
}}
|
|
137
143
|
>
|
|
138
144
|
{!sort &&
|
|
139
|
-
<ArrowUpwardIcon/>}
|
|
145
|
+
<ArrowUpwardIcon />}
|
|
140
146
|
{sort === "asc" &&
|
|
141
|
-
<ArrowUpwardIcon/>}
|
|
147
|
+
<ArrowUpwardIcon />}
|
|
142
148
|
{sort === "desc" &&
|
|
143
|
-
<ArrowUpwardIcon className={"rotate-180"}/>}
|
|
149
|
+
<ArrowUpwardIcon className={"rotate-180"} />}
|
|
144
150
|
</IconButton>
|
|
145
151
|
</Badge>
|
|
146
152
|
}
|
|
@@ -148,7 +154,7 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
148
154
|
|
|
149
155
|
{column.filter && createFilterField && <div>
|
|
150
156
|
<Badge color="secondary"
|
|
151
|
-
|
|
157
|
+
invisible={!filter}>
|
|
152
158
|
|
|
153
159
|
<Popover
|
|
154
160
|
open={openFilter}
|
|
@@ -160,16 +166,16 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
160
166
|
className={onHover || openFilter ? "bg-white dark:bg-surface-950" : undefined}
|
|
161
167
|
size={"small"}
|
|
162
168
|
onClick={handleSettingsClick}>
|
|
163
|
-
<FilterListIcon size={"small"}/>
|
|
169
|
+
<FilterListIcon size={"small"} />
|
|
164
170
|
</IconButton>}
|
|
165
171
|
>
|
|
166
172
|
<FilterForm column={column}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
filter={filter}
|
|
174
|
+
onHover={onHover}
|
|
175
|
+
onFilterUpdate={update}
|
|
176
|
+
createFilterField={createFilterField}
|
|
177
|
+
hidden={hidden}
|
|
178
|
+
setHidden={setHidden} />
|
|
173
179
|
|
|
174
180
|
</Popover>
|
|
175
181
|
|
|
@@ -179,11 +185,17 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
179
185
|
|
|
180
186
|
{column.resizable && <div
|
|
181
187
|
ref={resizeHandleRef}
|
|
188
|
+
data-no-dnd="true"
|
|
182
189
|
className={cls(
|
|
183
190
|
"absolute h-full w-[6px] top-0 right-0 cursor-col-resize",
|
|
184
191
|
hovered && "bg-surface-300 dark:bg-surface-700"
|
|
185
192
|
)}
|
|
186
|
-
|
|
193
|
+
onPointerDown={(e) => {
|
|
194
|
+
e.stopPropagation();
|
|
195
|
+
if (onClickResizeColumn) {
|
|
196
|
+
onClickResizeColumn(columnIndex, column);
|
|
197
|
+
}
|
|
198
|
+
}}
|
|
187
199
|
/>}
|
|
188
200
|
</div>
|
|
189
201
|
|
|
@@ -192,14 +204,14 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
|
|
|
192
204
|
}, equal) as React.FunctionComponent<VirtualTableHeaderProps<any>>;
|
|
193
205
|
|
|
194
206
|
function FilterForm<M>({
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
207
|
+
column,
|
|
208
|
+
onFilterUpdate,
|
|
209
|
+
filter,
|
|
210
|
+
onHover,
|
|
211
|
+
createFilterField,
|
|
212
|
+
hidden,
|
|
213
|
+
setHidden
|
|
214
|
+
}: FilterFormProps<M>) {
|
|
203
215
|
|
|
204
216
|
const id = column.key;
|
|
205
217
|
|
|
@@ -233,17 +245,17 @@ function FilterForm<M>({
|
|
|
233
245
|
if (!filterField) return null;
|
|
234
246
|
return (
|
|
235
247
|
<form noValidate={true}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
248
|
+
onSubmit={(e) => {
|
|
249
|
+
e.stopPropagation();
|
|
250
|
+
e.preventDefault();
|
|
251
|
+
submit();
|
|
252
|
+
}}
|
|
253
|
+
className={"text-surface-900 dark:text-white"}>
|
|
242
254
|
<div
|
|
243
255
|
className={cls(defaultBorderMixin, "py-4 px-6 typography-label border-b")}>
|
|
244
256
|
{column.title ?? id}
|
|
245
257
|
</div>
|
|
246
|
-
{filterField && <div className="m-4">
|
|
258
|
+
{filterField && <div className="m-4 w-[400px]">
|
|
247
259
|
{filterField}
|
|
248
260
|
</div>}
|
|
249
261
|
<div className="flex justify-end m-4">
|
|
@@ -251,13 +263,10 @@ function FilterForm<M>({
|
|
|
251
263
|
className="mr-4"
|
|
252
264
|
disabled={!filterIsSet}
|
|
253
265
|
variant={"text"}
|
|
254
|
-
color="primary"
|
|
255
266
|
type="reset"
|
|
256
267
|
aria-label="filter clear"
|
|
257
268
|
onClick={reset}>Clear</Button>
|
|
258
269
|
<Button
|
|
259
|
-
variant="outlined"
|
|
260
|
-
color="primary"
|
|
261
270
|
type="submit">Filter</Button>
|
|
262
271
|
</div>
|
|
263
272
|
</form>
|
|
@@ -1,25 +1,132 @@
|
|
|
1
|
-
import React, { createRef, useCallback, useEffect, useState } from "react";
|
|
1
|
+
import React, { createRef, useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { VirtualTableColumn, VirtualTableWhereFilterOp } from "./VirtualTableProps";
|
|
4
4
|
import { ErrorBoundary } from "../ErrorBoundary";
|
|
5
5
|
import { VirtualTableHeader } from "./VirtualTableHeader";
|
|
6
6
|
import { VirtualTableContextProps } from "./types";
|
|
7
7
|
import { cls, defaultBorderMixin } from "@firecms/ui";
|
|
8
|
+
import { useSortable } from "@dnd-kit/sortable";
|
|
9
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
10
|
+
|
|
11
|
+
// Sortable column header wrapper
|
|
12
|
+
const SortableColumnHeader = ({
|
|
13
|
+
column,
|
|
14
|
+
columnIndex,
|
|
15
|
+
columnRefs,
|
|
16
|
+
isResizing,
|
|
17
|
+
onFilterUpdate,
|
|
18
|
+
filter,
|
|
19
|
+
sortByProperty,
|
|
20
|
+
currentSort,
|
|
21
|
+
onColumnSort,
|
|
22
|
+
onClickResizeColumn,
|
|
23
|
+
createFilterField,
|
|
24
|
+
isDragging,
|
|
25
|
+
isDraggable
|
|
26
|
+
}: {
|
|
27
|
+
column: VirtualTableColumn;
|
|
28
|
+
columnIndex: number;
|
|
29
|
+
columnRefs: React.RefObject<HTMLDivElement | null>[];
|
|
30
|
+
isResizing: number;
|
|
31
|
+
onFilterUpdate: any;
|
|
32
|
+
filter: [VirtualTableWhereFilterOp, any] | undefined;
|
|
33
|
+
sortByProperty: string | undefined;
|
|
34
|
+
currentSort: "asc" | "desc" | undefined;
|
|
35
|
+
onColumnSort: any;
|
|
36
|
+
onClickResizeColumn: (index: number) => void;
|
|
37
|
+
createFilterField: any;
|
|
38
|
+
isDragging: boolean;
|
|
39
|
+
isDraggable: boolean;
|
|
40
|
+
}) => {
|
|
41
|
+
const [isPressing, setIsPressing] = useState(false);
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
attributes,
|
|
45
|
+
listeners,
|
|
46
|
+
setNodeRef,
|
|
47
|
+
transform,
|
|
48
|
+
transition,
|
|
49
|
+
} = useSortable({
|
|
50
|
+
id: column.key,
|
|
51
|
+
disabled: !isDraggable || column.frozen
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const style = {
|
|
55
|
+
// Only use translate, ignore any scale transforms
|
|
56
|
+
transform: transform ? `translateX(${transform.x}px)` : undefined,
|
|
57
|
+
// Don't transition the dragged item - only other items should animate
|
|
58
|
+
transition: isDragging ? undefined : transition,
|
|
59
|
+
minWidth: column.width,
|
|
60
|
+
maxWidth: column.width,
|
|
61
|
+
width: column.width,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Combine our press handlers with dnd-kit listeners
|
|
65
|
+
const combinedListeners = isDraggable ? {
|
|
66
|
+
...listeners,
|
|
67
|
+
onPointerDown: (e: React.PointerEvent) => {
|
|
68
|
+
setIsPressing(true);
|
|
69
|
+
listeners?.onPointerDown?.(e);
|
|
70
|
+
},
|
|
71
|
+
onPointerUp: () => setIsPressing(false),
|
|
72
|
+
onPointerCancel: () => setIsPressing(false),
|
|
73
|
+
} : {};
|
|
74
|
+
|
|
75
|
+
// Reset pressing state when drag ends
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
if (!isDragging) {
|
|
78
|
+
setIsPressing(false);
|
|
79
|
+
}
|
|
80
|
+
}, [isDragging]);
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div
|
|
84
|
+
ref={setNodeRef}
|
|
85
|
+
style={style}
|
|
86
|
+
className={cls(
|
|
87
|
+
"flex-shrink-0 h-full",
|
|
88
|
+
column.frozen && "sticky left-0 z-10"
|
|
89
|
+
)}
|
|
90
|
+
{...attributes}
|
|
91
|
+
{...combinedListeners}
|
|
92
|
+
>
|
|
93
|
+
<VirtualTableHeader
|
|
94
|
+
resizeHandleRef={columnRefs[columnIndex]}
|
|
95
|
+
columnIndex={columnIndex}
|
|
96
|
+
isResizingIndex={isResizing}
|
|
97
|
+
onFilterUpdate={onFilterUpdate}
|
|
98
|
+
filter={filter}
|
|
99
|
+
sort={sortByProperty === column.key ? currentSort : undefined}
|
|
100
|
+
onColumnSort={onColumnSort}
|
|
101
|
+
onClickResizeColumn={onClickResizeColumn}
|
|
102
|
+
column={column}
|
|
103
|
+
createFilterField={createFilterField}
|
|
104
|
+
AdditionalHeaderWidget={column.AdditionalHeaderWidget}
|
|
105
|
+
isDragging={isDragging || isPressing}
|
|
106
|
+
isDraggable={isDraggable} />
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
8
110
|
|
|
9
111
|
export const VirtualTableHeaderRow = ({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
112
|
+
columns,
|
|
113
|
+
currentSort,
|
|
114
|
+
onColumnSort,
|
|
115
|
+
onFilterUpdate,
|
|
116
|
+
sortByProperty,
|
|
117
|
+
filter,
|
|
118
|
+
onColumnResize,
|
|
119
|
+
onColumnResizeEnd,
|
|
120
|
+
createFilterField,
|
|
121
|
+
AddColumnComponent,
|
|
122
|
+
onColumnsOrderChange,
|
|
123
|
+
data,
|
|
124
|
+
cellRenderer: CellRenderer,
|
|
125
|
+
rowHeight = 54,
|
|
126
|
+
draggingColumnId
|
|
127
|
+
}: VirtualTableContextProps<any>) => {
|
|
128
|
+
|
|
129
|
+
const columnRefs = useMemo(() => columns.map(() => createRef<HTMLDivElement>()), [columns.length]);
|
|
23
130
|
const [isResizing, setIsResizing] = useState(-1);
|
|
24
131
|
|
|
25
132
|
const adjustWidthColumn = useCallback((index: number, width: number, end: boolean) => {
|
|
@@ -99,33 +206,42 @@ export const VirtualTableHeaderRow = ({
|
|
|
99
206
|
}, [setCursorDocument]);
|
|
100
207
|
|
|
101
208
|
return (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
209
|
+
<>
|
|
210
|
+
<div
|
|
211
|
+
className={cls(defaultBorderMixin, "z-20 sticky min-w-full flex w-fit flex-row top-0 left-0 h-12 border-b bg-surface-50 dark:bg-surface-900")}>
|
|
212
|
+
{columns.map((column, columnIndex) => {
|
|
213
|
+
const filterForThisProperty: [VirtualTableWhereFilterOp, any] | undefined =
|
|
214
|
+
column && filter && filter[column.key]
|
|
215
|
+
? filter[column.key]
|
|
216
|
+
: undefined;
|
|
217
|
+
|
|
218
|
+
const isDraggable = !column.frozen && !!onColumnsOrderChange;
|
|
219
|
+
const isDragging = draggingColumnId === column.key;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<ErrorBoundary key={"header_" + column.key}>
|
|
223
|
+
<SortableColumnHeader
|
|
224
|
+
column={column}
|
|
225
|
+
columnIndex={columnIndex}
|
|
226
|
+
columnRefs={columnRefs}
|
|
227
|
+
isResizing={isResizing}
|
|
228
|
+
onFilterUpdate={onFilterUpdate}
|
|
229
|
+
filter={filterForThisProperty}
|
|
230
|
+
sortByProperty={sortByProperty}
|
|
231
|
+
currentSort={currentSort}
|
|
232
|
+
onColumnSort={onColumnSort}
|
|
233
|
+
onClickResizeColumn={onClickResizeColumn}
|
|
234
|
+
createFilterField={createFilterField}
|
|
235
|
+
isDragging={isDragging}
|
|
236
|
+
isDraggable={isDraggable}
|
|
237
|
+
/>
|
|
238
|
+
</ErrorBoundary>
|
|
239
|
+
);
|
|
240
|
+
})}
|
|
241
|
+
|
|
242
|
+
{AddColumnComponent && <AddColumnComponent />}
|
|
243
|
+
|
|
244
|
+
</div>
|
|
245
|
+
</>
|
|
130
246
|
);
|
|
131
247
|
};
|
|
@@ -38,7 +38,7 @@ export interface VirtualTableProps<T extends Record<string, any>> {
|
|
|
38
38
|
* @param sortBy
|
|
39
39
|
*/
|
|
40
40
|
checkFilterCombination?: (filterValues: VirtualTableFilterValues<Extract<keyof T, string>>,
|
|
41
|
-
|
|
41
|
+
sortBy?: [string, "asc" | "desc"]) => boolean;
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* A callback function when scrolling the table to near the end
|
|
@@ -162,6 +162,12 @@ export interface VirtualTableProps<T extends Record<string, any>> {
|
|
|
162
162
|
*/
|
|
163
163
|
initialScroll?: number;
|
|
164
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Callback when columns are reordered via drag-and-drop.
|
|
167
|
+
* @param columns The new column order
|
|
168
|
+
*/
|
|
169
|
+
onColumnsOrderChange?: (columns: VirtualTableColumn[]) => void;
|
|
170
|
+
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
export type CellRendererParams<T = any> = {
|
|
@@ -172,6 +178,13 @@ export type CellRendererParams<T = any> = {
|
|
|
172
178
|
rowIndex: number;
|
|
173
179
|
width: number;
|
|
174
180
|
isScrolling?: boolean;
|
|
181
|
+
// Sortable props for dnd-kit integration
|
|
182
|
+
sortableNodeRef?: (node: HTMLElement | null) => void;
|
|
183
|
+
sortableStyle?: React.CSSProperties;
|
|
184
|
+
sortableAttributes?: Record<string, any>;
|
|
185
|
+
isDragging?: boolean;
|
|
186
|
+
isDraggable?: boolean;
|
|
187
|
+
frozen?: boolean;
|
|
175
188
|
};
|
|
176
189
|
|
|
177
190
|
/**
|
|
@@ -29,7 +29,7 @@ export const VirtualTableRow = React.memo<VirtualTableRowProps<any>>(
|
|
|
29
29
|
return (
|
|
30
30
|
<div
|
|
31
31
|
className={cls(
|
|
32
|
-
"flex min-w-full text-sm border-b border-surface-200 dark:border-surface-800 border-opacity-40 dark:border-opacity-40",
|
|
32
|
+
"flex min-w-full text-sm border-b border-surface-200 dark:border-surface-800 border-opacity-40 border-surface-200/40 dark:border-opacity-40 dark:border-surface-800/40",
|
|
33
33
|
rowClassName ? rowClassName(rowData) : "",
|
|
34
34
|
{
|
|
35
35
|
"hover:bg-opacity-95": hoverRow,
|
|
@@ -6,6 +6,7 @@ export function VirtualTableDateField(props: {
|
|
|
6
6
|
name: string;
|
|
7
7
|
error: Error | undefined;
|
|
8
8
|
mode?: "date" | "date_time";
|
|
9
|
+
timezone?: string;
|
|
9
10
|
internalValue: Date | undefined | null;
|
|
10
11
|
updateValue: (newValue: (Date | null)) => void;
|
|
11
12
|
focused: boolean;
|
|
@@ -18,6 +19,7 @@ export function VirtualTableDateField(props: {
|
|
|
18
19
|
disabled,
|
|
19
20
|
error,
|
|
20
21
|
mode,
|
|
22
|
+
timezone,
|
|
21
23
|
internalValue,
|
|
22
24
|
updateValue
|
|
23
25
|
} = props;
|
|
@@ -31,6 +33,7 @@ export function VirtualTableDateField(props: {
|
|
|
31
33
|
inputClassName={cls("w-full h-full", focusedDisabled)}
|
|
32
34
|
className={cls("w-full h-full", focusedDisabled)}
|
|
33
35
|
mode={mode}
|
|
36
|
+
timezone={timezone}
|
|
34
37
|
locale={locale}
|
|
35
38
|
/>
|
|
36
39
|
);
|
|
@@ -62,14 +62,24 @@ export function VirtualTableSelect(props: {
|
|
|
62
62
|
key={`${enumKey}`}
|
|
63
63
|
enumKey={String(enumKey)}
|
|
64
64
|
enumValues={enumValues}
|
|
65
|
-
size={small ? "small" : "medium"}/>;
|
|
65
|
+
size={small ? "small" : "medium"} />;
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
+
// When the dropdown closes (including on escape), restore focus to the trigger
|
|
69
|
+
const handleOpenChange = useCallback((open: boolean) => {
|
|
70
|
+
if (!open && ref.current) {
|
|
71
|
+
// Use setTimeout to ensure focus is restored after Radix finishes its cleanup
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
ref.current?.focus({ preventScroll: true });
|
|
74
|
+
}, 0);
|
|
75
|
+
}
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
68
78
|
return (
|
|
69
79
|
multiple
|
|
70
80
|
? <MultiSelect
|
|
71
81
|
inputRef={ref}
|
|
72
|
-
className="w-full h-full p-0 bg-transparent"
|
|
82
|
+
className="w-full h-full p-0 bg-transparent outline-none"
|
|
73
83
|
position={"item-aligned"}
|
|
74
84
|
disabled={disabled}
|
|
75
85
|
includeClear={false}
|
|
@@ -77,7 +87,8 @@ export function VirtualTableSelect(props: {
|
|
|
77
87
|
value={validValue
|
|
78
88
|
? ((internalValue as any[]).map(v => v.toString()))
|
|
79
89
|
: ([])}
|
|
80
|
-
onValueChange={onChange}
|
|
90
|
+
onValueChange={onChange}
|
|
91
|
+
onOpenChange={handleOpenChange}>
|
|
81
92
|
{enumValues?.map((enumConfig) => (
|
|
82
93
|
<MultiSelectItem
|
|
83
94
|
key={enumConfig.id}
|
|
@@ -85,7 +96,7 @@ export function VirtualTableSelect(props: {
|
|
|
85
96
|
<EnumValuesChip
|
|
86
97
|
enumKey={enumConfig.id}
|
|
87
98
|
enumValues={enumValues}
|
|
88
|
-
size={small ? "small" : "medium"}/>
|
|
99
|
+
size={small ? "small" : "medium"} />
|
|
89
100
|
</MultiSelectItem>
|
|
90
101
|
))}
|
|
91
102
|
</MultiSelect>
|
|
@@ -93,7 +104,8 @@ export function VirtualTableSelect(props: {
|
|
|
93
104
|
inputRef={ref}
|
|
94
105
|
size={"large"}
|
|
95
106
|
fullWidth={true}
|
|
96
|
-
className="w-full h-full p-0 bg-transparent"
|
|
107
|
+
className="w-full h-full p-0 bg-transparent outline-none [&_button]:ring-0 [&_button]:ring-offset-0"
|
|
108
|
+
inputClassName="ring-0 ring-offset-0 focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-offset-0"
|
|
97
109
|
position={"item-aligned"}
|
|
98
110
|
disabled={disabled}
|
|
99
111
|
padding={false}
|
|
@@ -101,6 +113,7 @@ export function VirtualTableSelect(props: {
|
|
|
101
113
|
? internalValue?.toString()
|
|
102
114
|
: ""}
|
|
103
115
|
onValueChange={onChange}
|
|
116
|
+
onOpenChange={handleOpenChange}
|
|
104
117
|
renderValue={renderValue}>
|
|
105
118
|
{enumValues?.map((enumConfig) => (
|
|
106
119
|
<SelectItem
|
|
@@ -109,7 +122,7 @@ export function VirtualTableSelect(props: {
|
|
|
109
122
|
<EnumValuesChip
|
|
110
123
|
enumKey={enumConfig.id}
|
|
111
124
|
enumValues={enumValues}
|
|
112
|
-
size={small ? "small" : "medium"}/>
|
|
125
|
+
size={small ? "small" : "medium"} />
|
|
113
126
|
</SelectItem>
|
|
114
127
|
))}
|
|
115
128
|
</Select>
|
|
@@ -40,4 +40,6 @@ export type VirtualTableContextProps<T extends any> = {
|
|
|
40
40
|
rowClassName?: (rowData: T) => string | undefined;
|
|
41
41
|
endAdornment?: React.ReactNode;
|
|
42
42
|
AddColumnComponent?: React.ComponentType;
|
|
43
|
+
onColumnsOrderChange?: (columns: VirtualTableColumn[]) => void;
|
|
44
|
+
draggingColumnId?: string | null;
|
|
43
45
|
};
|