@firecms/core 3.0.1 → 3.1.0-canary.768c91f
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
|
@@ -49,7 +49,8 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
49
49
|
size,
|
|
50
50
|
height,
|
|
51
51
|
width,
|
|
52
|
-
interactive
|
|
52
|
+
interactive,
|
|
53
|
+
fill
|
|
53
54
|
} = props;
|
|
54
55
|
|
|
55
56
|
const property = resolveProperty({
|
|
@@ -60,7 +61,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
if (property === null) {
|
|
63
|
-
content = <EmptyValue/>;
|
|
64
|
+
content = <EmptyValue />;
|
|
64
65
|
} else if (property.Preview) {
|
|
65
66
|
content = createElement(property.Preview as React.ComponentType<PropertyPreviewProps>,
|
|
66
67
|
{
|
|
@@ -74,7 +75,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
74
75
|
customProps: property.customProps
|
|
75
76
|
});
|
|
76
77
|
} else if (value === undefined || value === null) {
|
|
77
|
-
content = <EmptyValue/>;
|
|
78
|
+
content = <EmptyValue />;
|
|
78
79
|
} else if (property.dataType === "string") {
|
|
79
80
|
const stringProperty = property as ResolvedStringProperty;
|
|
80
81
|
if (typeof value === "string") {
|
|
@@ -84,20 +85,23 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
84
85
|
interactive={interactive}
|
|
85
86
|
storeUrl={property.storage?.storeUrl ?? false}
|
|
86
87
|
size={props.size}
|
|
87
|
-
|
|
88
|
+
fill={fill}
|
|
89
|
+
storagePathOrDownloadUrl={filePath} />;
|
|
88
90
|
} else if (stringProperty.url) {
|
|
89
91
|
if (typeof stringProperty.url === "boolean")
|
|
90
92
|
content =
|
|
91
93
|
<UrlComponentPreview size={props.size}
|
|
92
|
-
|
|
94
|
+
url={value}
|
|
95
|
+
fill={fill} />;
|
|
93
96
|
else if (typeof stringProperty.url === "string")
|
|
94
97
|
content =
|
|
95
98
|
<UrlComponentPreview size={props.size}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
url={value}
|
|
100
|
+
interactive={interactive}
|
|
101
|
+
fill={fill}
|
|
102
|
+
previewType={stringProperty.url} />;
|
|
99
103
|
} else if (stringProperty.markdown) {
|
|
100
|
-
content = <Markdown source={value} size={"small"}/>;
|
|
104
|
+
content = <Markdown source={value} size={"small"} />;
|
|
101
105
|
} else if (stringProperty.userSelect) {
|
|
102
106
|
content = <UserPreview
|
|
103
107
|
value={value}
|
|
@@ -116,13 +120,13 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
116
120
|
reference={new EntityReference(value, stringProperty.reference.path)}
|
|
117
121
|
/>;
|
|
118
122
|
} else {
|
|
119
|
-
content = <EmptyValue/>;
|
|
123
|
+
content = <EmptyValue />;
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
} else {
|
|
123
127
|
content = <StringPropertyPreview {...props}
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
property={stringProperty}
|
|
129
|
+
value={value} />;
|
|
126
130
|
}
|
|
127
131
|
} else {
|
|
128
132
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
@@ -137,43 +141,43 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
137
141
|
if (arrayProperty.of) {
|
|
138
142
|
if (Array.isArray(arrayProperty.of)) {
|
|
139
143
|
content = <ArrayPropertyPreview {...props}
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
value={value}
|
|
145
|
+
property={property as ResolvedArrayProperty} />;
|
|
142
146
|
} else if (arrayProperty.of.dataType === "reference") {
|
|
143
147
|
content = <ArrayOfReferencesPreview {...props}
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
value={value}
|
|
149
|
+
property={property as ResolvedArrayProperty} />;
|
|
146
150
|
} else if (arrayProperty.of.dataType === "string") {
|
|
147
151
|
if (arrayProperty.of.enumValues) {
|
|
148
152
|
content = <ArrayPropertyEnumPreview
|
|
149
153
|
{...props}
|
|
150
154
|
value={value as string[]}
|
|
151
|
-
property={property as ResolvedArrayProperty}/>;
|
|
155
|
+
property={property as ResolvedArrayProperty} />;
|
|
152
156
|
} else if (arrayProperty.of.storage) {
|
|
153
157
|
content = <ArrayOfStorageComponentsPreview
|
|
154
158
|
{...props}
|
|
155
159
|
value={value}
|
|
156
|
-
property={property as ResolvedArrayProperty}/>;
|
|
160
|
+
property={property as ResolvedArrayProperty} />;
|
|
157
161
|
} else {
|
|
158
162
|
content = <ArrayOfStringsPreview
|
|
159
163
|
{...props}
|
|
160
164
|
value={value as string[]}
|
|
161
|
-
property={property as ResolvedArrayProperty}/>;
|
|
165
|
+
property={property as ResolvedArrayProperty} />;
|
|
162
166
|
}
|
|
163
167
|
} else if (arrayProperty.of.dataType === "number" && arrayProperty.of.enumValues) {
|
|
164
168
|
content = <ArrayPropertyEnumPreview
|
|
165
169
|
{...props}
|
|
166
170
|
value={value as string[]}
|
|
167
|
-
property={property as ResolvedArrayProperty}/>;
|
|
171
|
+
property={property as ResolvedArrayProperty} />;
|
|
168
172
|
} else {
|
|
169
173
|
content = <ArrayPropertyPreview {...props}
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
value={value}
|
|
175
|
+
property={property as ResolvedArrayProperty} />;
|
|
172
176
|
}
|
|
173
177
|
} else if (arrayProperty.oneOf) {
|
|
174
178
|
content = <ArrayOneOfPreview {...props}
|
|
175
|
-
|
|
176
|
-
|
|
179
|
+
value={value}
|
|
180
|
+
property={property as ResolvedArrayProperty} />;
|
|
177
181
|
}
|
|
178
182
|
} else {
|
|
179
183
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
@@ -182,13 +186,18 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
182
186
|
if (typeof value === "object") {
|
|
183
187
|
content =
|
|
184
188
|
<MapPropertyPreview {...props}
|
|
185
|
-
|
|
189
|
+
value={value as Record<string, CMSType>}
|
|
190
|
+
property={property as ResolvedMapProperty} />;
|
|
186
191
|
} else {
|
|
187
192
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
188
193
|
}
|
|
189
194
|
} else if (property.dataType === "date") {
|
|
190
195
|
if (value instanceof Date) {
|
|
191
|
-
content = <DatePreview
|
|
196
|
+
content = <DatePreview
|
|
197
|
+
date={value}
|
|
198
|
+
mode={property.mode}
|
|
199
|
+
timezone={property.timezone}
|
|
200
|
+
/>;
|
|
192
201
|
} else {
|
|
193
202
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
194
203
|
}
|
|
@@ -207,20 +216,20 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
207
216
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
208
217
|
}
|
|
209
218
|
} else {
|
|
210
|
-
content = <EmptyValue/>;
|
|
219
|
+
content = <EmptyValue />;
|
|
211
220
|
}
|
|
212
221
|
|
|
213
222
|
} else if (property.dataType === "boolean") {
|
|
214
223
|
if (typeof value === "boolean") {
|
|
215
|
-
content = <BooleanPreview value={value} size={size} property={property}/>;
|
|
224
|
+
content = <BooleanPreview value={value} size={size} property={property} />;
|
|
216
225
|
} else {
|
|
217
226
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
218
227
|
}
|
|
219
228
|
} else if (property.dataType === "number") {
|
|
220
229
|
if (typeof value === "number") {
|
|
221
230
|
content = <NumberPropertyPreview {...props}
|
|
222
|
-
|
|
223
|
-
|
|
231
|
+
value={value}
|
|
232
|
+
property={property as ResolvedNumberProperty} />;
|
|
224
233
|
} else {
|
|
225
234
|
content = buildWrongValueType(propertyKey, property.dataType, value);
|
|
226
235
|
}
|
|
@@ -229,7 +238,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
229
238
|
}
|
|
230
239
|
|
|
231
240
|
return content === undefined || content === null || (Array.isArray(content) && content.length === 0)
|
|
232
|
-
? <EmptyValue/>
|
|
241
|
+
? <EmptyValue />
|
|
233
242
|
: content;
|
|
234
243
|
}, equal);
|
|
235
244
|
|
|
@@ -237,6 +246,6 @@ function buildWrongValueType(name: string | undefined, dataType: string, value:
|
|
|
237
246
|
console.warn(`Unexpected value for property ${name}, of type ${dataType}`, value);
|
|
238
247
|
return (
|
|
239
248
|
<ErrorView title={"Unexpected value"}
|
|
240
|
-
|
|
249
|
+
error={`${JSON.stringify(value)}`} />
|
|
241
250
|
);
|
|
242
251
|
}
|
|
@@ -52,4 +52,10 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
|
|
|
52
52
|
*/
|
|
53
53
|
interactive?: boolean;
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* If true, image previews will fill their container completely.
|
|
57
|
+
* Only applies to image type properties.
|
|
58
|
+
*/
|
|
59
|
+
fill?: boolean;
|
|
60
|
+
|
|
55
61
|
}
|
|
@@ -5,18 +5,86 @@ import * as locales from "date-fns/locale";
|
|
|
5
5
|
import { useCustomizationController } from "../../hooks";
|
|
6
6
|
import { defaultDateFormat } from "../../util";
|
|
7
7
|
|
|
8
|
+
export interface DatePreviewProps {
|
|
9
|
+
date: Date;
|
|
10
|
+
/**
|
|
11
|
+
* Display mode: "date" for date-only, "date_time" for date and time
|
|
12
|
+
*/
|
|
13
|
+
mode?: "date" | "date_time";
|
|
14
|
+
/**
|
|
15
|
+
* IANA timezone identifier (e.g., "America/New_York")
|
|
16
|
+
* When specified, the date will be displayed in this timezone
|
|
17
|
+
*/
|
|
18
|
+
timezone?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
8
21
|
/**
|
|
9
22
|
* @group Preview components
|
|
10
23
|
*/
|
|
11
24
|
export function DatePreview({
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
date,
|
|
26
|
+
mode = "date_time",
|
|
27
|
+
timezone
|
|
28
|
+
}: DatePreviewProps): React.ReactElement {
|
|
14
29
|
|
|
15
30
|
const customizationController = useCustomizationController();
|
|
16
31
|
// @ts-ignore
|
|
17
32
|
const dateUtilsLocale = customizationController?.locale ? locales[customizationController?.locale] : undefined;
|
|
18
|
-
|
|
19
|
-
|
|
33
|
+
|
|
34
|
+
if (!date) {
|
|
35
|
+
return <></>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// If timezone is specified, format in that timezone using Intl.DateTimeFormat
|
|
39
|
+
if (timezone) {
|
|
40
|
+
const options: Intl.DateTimeFormatOptions = {
|
|
41
|
+
year: "numeric",
|
|
42
|
+
month: "short",
|
|
43
|
+
day: "numeric",
|
|
44
|
+
timeZone: timezone
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
if (mode === "date_time") {
|
|
48
|
+
options.hour = "2-digit";
|
|
49
|
+
options.minute = "2-digit";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const formatter = new Intl.DateTimeFormat(customizationController?.locale ?? "en-US", options);
|
|
53
|
+
const formattedDate = formatter.format(date);
|
|
54
|
+
|
|
55
|
+
// Get timezone abbreviation
|
|
56
|
+
const tzFormatter = new Intl.DateTimeFormat("en-US", {
|
|
57
|
+
timeZone: timezone,
|
|
58
|
+
timeZoneName: "short"
|
|
59
|
+
});
|
|
60
|
+
const parts = tzFormatter.formatToParts(date);
|
|
61
|
+
const tzAbbrev = parts.find(p => p.type === "timeZoneName")?.value ?? "";
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<span className="flex items-center gap-1">
|
|
65
|
+
{formattedDate}
|
|
66
|
+
{tzAbbrev && (
|
|
67
|
+
<span className="text-xs text-slate-500 dark:text-slate-400">
|
|
68
|
+
({tzAbbrev})
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
</span>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// No timezone specified: use local formatting with date-fns
|
|
76
|
+
let dateFormat: string;
|
|
77
|
+
if (mode === "date") {
|
|
78
|
+
// Date-only format (no time)
|
|
79
|
+
dateFormat = customizationController?.dateTimeFormat
|
|
80
|
+
? customizationController.dateTimeFormat.replace(/[, ]*[HhKk].*$/, "").trim()
|
|
81
|
+
: "PP"; // e.g., "Apr 29, 2024"
|
|
82
|
+
} else {
|
|
83
|
+
// Full date-time format
|
|
84
|
+
dateFormat = customizationController?.dateTimeFormat ?? defaultDateFormat;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const formattedDate = format(date, dateFormat, { locale: dateUtilsLocale });
|
|
20
88
|
|
|
21
89
|
return (
|
|
22
90
|
<>
|
|
@@ -6,5 +6,5 @@ import React from "react";
|
|
|
6
6
|
export function EmptyValue() {
|
|
7
7
|
|
|
8
8
|
return <div
|
|
9
|
-
className="rounded-full bg-surface-200 bg-opacity-30 dark:bg-opacity-20 w-5 h-2 inline-block"/>;
|
|
9
|
+
className="rounded-full bg-surface-200 bg-opacity-30 bg-surface-200/30 dark:bg-opacity-20 dark:bg-surface-200/20 w-5 h-2 inline-block"/>;
|
|
10
10
|
}
|
|
@@ -9,39 +9,55 @@ import { ContentCopyIcon, IconButton, OpenInNewIcon, Tooltip } from "@firecms/ui
|
|
|
9
9
|
*/
|
|
10
10
|
export interface ImagePreviewProps {
|
|
11
11
|
size: PreviewSize,
|
|
12
|
-
url: string
|
|
12
|
+
url: string,
|
|
13
|
+
/**
|
|
14
|
+
* If true, image fills its container completely with object-fit cover
|
|
15
|
+
*/
|
|
16
|
+
fill?: boolean
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* @group Preview components
|
|
17
21
|
*/
|
|
18
22
|
export function ImagePreview({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
size,
|
|
24
|
+
url,
|
|
25
|
+
fill
|
|
26
|
+
}: ImagePreviewProps) {
|
|
22
27
|
|
|
23
28
|
const imageSize = useMemo(() => getThumbnailMeasure(size), [size]);
|
|
24
29
|
|
|
30
|
+
// Fill mode - image fills its container completely
|
|
31
|
+
if (fill) {
|
|
32
|
+
return (
|
|
33
|
+
<img src={url}
|
|
34
|
+
className={"w-full h-full object-cover"}
|
|
35
|
+
key={"fill_image_preview_" + url}
|
|
36
|
+
loading="lazy"
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
25
41
|
if (size === "small") {
|
|
26
42
|
return (
|
|
27
43
|
<img src={url}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
className={"rounded-md"}
|
|
45
|
+
key={"tiny_image_preview_" + url}
|
|
46
|
+
style={{
|
|
47
|
+
position: "relative",
|
|
48
|
+
objectFit: "cover",
|
|
49
|
+
width: imageSize,
|
|
50
|
+
height: imageSize,
|
|
51
|
+
maxHeight: "100%"
|
|
52
|
+
}} />
|
|
37
53
|
);
|
|
38
54
|
}
|
|
39
55
|
|
|
40
56
|
const imageStyle: CSSProperties =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
57
|
+
{
|
|
58
|
+
maxWidth: "100%",
|
|
59
|
+
maxHeight: "100%"
|
|
60
|
+
};
|
|
45
61
|
|
|
46
62
|
return (
|
|
47
63
|
<div
|
|
@@ -53,8 +69,8 @@ export function ImagePreview({
|
|
|
53
69
|
key={"image_preview_" + url}>
|
|
54
70
|
|
|
55
71
|
<img src={url}
|
|
56
|
-
|
|
57
|
-
|
|
72
|
+
className={"rounded-md"}
|
|
73
|
+
style={imageStyle} />
|
|
58
74
|
|
|
59
75
|
<div className={"flex flex-row gap-2 absolute bottom-[-4px] right-[-4px] invisible group-hover:visible"}>
|
|
60
76
|
{navigator && <Tooltip
|
|
@@ -69,7 +85,7 @@ export function ImagePreview({
|
|
|
69
85
|
return navigator.clipboard.writeText(url);
|
|
70
86
|
}}>
|
|
71
87
|
<ContentCopyIcon className={"text-surface-700 dark:text-surface-300"}
|
|
72
|
-
|
|
88
|
+
size={"smallest"} />
|
|
73
89
|
</IconButton>
|
|
74
90
|
</Tooltip>}
|
|
75
91
|
|
|
@@ -85,7 +101,7 @@ export function ImagePreview({
|
|
|
85
101
|
onClick={(e: any) => e.stopPropagation()}
|
|
86
102
|
>
|
|
87
103
|
<OpenInNewIcon className={"text-surface-700 dark:text-surface-300"}
|
|
88
|
-
|
|
104
|
+
size={"smallest"} />
|
|
89
105
|
</IconButton>
|
|
90
106
|
</Tooltip>
|
|
91
107
|
</div>
|
|
@@ -12,6 +12,7 @@ type StorageThumbnailProps = {
|
|
|
12
12
|
storeUrl: boolean;
|
|
13
13
|
size: PreviewSize;
|
|
14
14
|
interactive?: boolean;
|
|
15
|
+
fill?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -22,18 +23,20 @@ export const StorageThumbnail = React.memo<StorageThumbnailProps>(StorageThumbna
|
|
|
22
23
|
function areEqual(prevProps: StorageThumbnailProps, nextProps: StorageThumbnailProps) {
|
|
23
24
|
return prevProps.size === nextProps.size &&
|
|
24
25
|
prevProps.storagePathOrDownloadUrl === nextProps.storagePathOrDownloadUrl &&
|
|
25
|
-
prevProps.storeUrl === nextProps.storeUrl&&
|
|
26
|
-
prevProps.interactive === nextProps.interactive
|
|
26
|
+
prevProps.storeUrl === nextProps.storeUrl &&
|
|
27
|
+
prevProps.interactive === nextProps.interactive &&
|
|
28
|
+
prevProps.fill === nextProps.fill;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
const URL_CACHE: Record<string, DownloadConfig> = {};
|
|
30
32
|
|
|
31
33
|
export function StorageThumbnailInternal({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
storeUrl,
|
|
35
|
+
interactive,
|
|
36
|
+
storagePathOrDownloadUrl,
|
|
37
|
+
size,
|
|
38
|
+
fill
|
|
39
|
+
}: StorageThumbnailProps) {
|
|
37
40
|
|
|
38
41
|
const [error, setError] = React.useState<Error | undefined>(undefined);
|
|
39
42
|
const storage = useStorageSource();
|
|
@@ -70,11 +73,12 @@ export function StorageThumbnailInternal({
|
|
|
70
73
|
|
|
71
74
|
return downloadConfig?.url
|
|
72
75
|
? <UrlComponentPreview previewType={previewType}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
url={downloadConfig.url}
|
|
77
|
+
interactive={interactive}
|
|
78
|
+
size={size}
|
|
79
|
+
fill={fill}
|
|
80
|
+
hint={storagePathOrDownloadUrl} />
|
|
81
|
+
: renderSkeletonImageThumbnail(size, fill);
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
function getFiletype(input: string): FileType {
|
|
@@ -11,31 +11,33 @@ import { EmptyValue } from "./EmptyValue";
|
|
|
11
11
|
* @group Preview components
|
|
12
12
|
*/
|
|
13
13
|
export function UrlComponentPreview({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
url,
|
|
15
|
+
previewType,
|
|
16
|
+
size,
|
|
17
|
+
hint,
|
|
18
|
+
interactive = true,
|
|
19
|
+
fill
|
|
20
|
+
}: {
|
|
20
21
|
url: string,
|
|
21
22
|
previewType?: PreviewType,
|
|
22
23
|
size: PreviewSize,
|
|
23
24
|
hint?: string,
|
|
24
25
|
// for video controls
|
|
25
|
-
interactive?: boolean
|
|
26
|
+
interactive?: boolean,
|
|
27
|
+
fill?: boolean
|
|
26
28
|
}): React.ReactElement {
|
|
27
29
|
|
|
28
30
|
if (!previewType) {
|
|
29
|
-
if (!url || !url.trim()) return <EmptyValue/>;
|
|
31
|
+
if (!url || !url.trim()) return <EmptyValue />;
|
|
30
32
|
return (
|
|
31
33
|
<a className="flex gap-4 break-words items-center font-medium text-primary visited:text-primary dark:visited:text-primary dark:text-primary"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<OpenInNewIcon size={"small"}/>
|
|
34
|
+
href={url}
|
|
35
|
+
rel="noopener noreferrer"
|
|
36
|
+
onMouseDown={(e: React.MouseEvent) => {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
}}
|
|
39
|
+
target="_blank">
|
|
40
|
+
<OpenInNewIcon size={"small"} />
|
|
39
41
|
{url}
|
|
40
42
|
</a>
|
|
41
43
|
);
|
|
@@ -43,16 +45,17 @@ export function UrlComponentPreview({
|
|
|
43
45
|
|
|
44
46
|
if (previewType === "image") {
|
|
45
47
|
return <ImagePreview url={url}
|
|
46
|
-
|
|
48
|
+
size={size}
|
|
49
|
+
fill={fill} />;
|
|
47
50
|
} else if (previewType === "audio") {
|
|
48
51
|
return <audio controls
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
className={"max-w-100%"}
|
|
53
|
+
src={url}>
|
|
51
54
|
Your browser does not support the
|
|
52
55
|
<code>audio</code> element.
|
|
53
56
|
</audio>;
|
|
54
57
|
} else if (previewType === "video") {
|
|
55
|
-
return <VideoPreview size={size} src={url} interactive={interactive}/>;
|
|
58
|
+
return <VideoPreview size={size} src={url} interactive={interactive} />;
|
|
56
59
|
} else {
|
|
57
60
|
return (
|
|
58
61
|
<Tooltip title={hint}>
|
|
@@ -66,7 +69,7 @@ export function UrlComponentPreview({
|
|
|
66
69
|
width: getThumbnailMeasure(size),
|
|
67
70
|
height: getThumbnailMeasure(size)
|
|
68
71
|
}}>
|
|
69
|
-
<DescriptionIcon className="text-surface-700 dark:text-surface-300"/>
|
|
72
|
+
<DescriptionIcon className="text-surface-700 dark:text-surface-300" />
|
|
70
73
|
{hint && <Typography
|
|
71
74
|
className="max-w-full truncate rtl text-left"
|
|
72
75
|
variant={"caption"}>{hint}</Typography>}
|
|
@@ -77,10 +80,10 @@ export function UrlComponentPreview({
|
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
function VideoPreview({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
size,
|
|
84
|
+
src,
|
|
85
|
+
interactive
|
|
86
|
+
}: { size: PreviewSize, src: string, interactive: boolean }) {
|
|
84
87
|
|
|
85
88
|
const imageSize = useMemo(() => {
|
|
86
89
|
if (size === "small")
|
|
@@ -106,6 +109,6 @@ function VideoPreview({
|
|
|
106
109
|
}}
|
|
107
110
|
{...videoProps}
|
|
108
111
|
className={cls("max-w-100% rounded", { "pointer-events-none": !interactive })}>
|
|
109
|
-
<source src={src}/>
|
|
112
|
+
<source src={src} />
|
|
110
113
|
</video>;
|
|
111
114
|
}
|
|
@@ -12,12 +12,12 @@ import { ErrorBoundary } from "../../components";
|
|
|
12
12
|
* @group Preview components
|
|
13
13
|
*/
|
|
14
14
|
export function ArrayOfStorageComponentsPreview({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
propertyKey,
|
|
16
|
+
// entity,
|
|
17
|
+
value,
|
|
18
|
+
property: inputProperty,
|
|
19
|
+
size
|
|
20
|
+
}: PropertyPreviewProps<any[]>) {
|
|
21
21
|
|
|
22
22
|
const authController = useAuthController();
|
|
23
23
|
const customizationController = useCustomizationController();
|
|
@@ -28,6 +28,8 @@ export function ArrayOfStorageComponentsPreview({
|
|
|
28
28
|
authController
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
if (!property) return null;
|
|
32
|
+
|
|
31
33
|
if (Array.isArray(property.of)) {
|
|
32
34
|
throw Error("Using array properties instead of single one in `of` in ArrayProperty");
|
|
33
35
|
}
|
|
@@ -47,7 +49,7 @@ export function ArrayOfStorageComponentsPreview({
|
|
|
47
49
|
value={v}
|
|
48
50
|
// entity={entity}
|
|
49
51
|
property={property.of as ResolvedProperty<string>}
|
|
50
|
-
size={childSize}/>
|
|
52
|
+
size={childSize} />
|
|
51
53
|
</ErrorBoundary>
|
|
52
54
|
)}
|
|
53
55
|
</div>
|
|
@@ -10,12 +10,12 @@ import { ErrorBoundary } from "../../components";
|
|
|
10
10
|
* @group Preview components
|
|
11
11
|
*/
|
|
12
12
|
export function ArrayOfStringsPreview({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
propertyKey,
|
|
14
|
+
value,
|
|
15
|
+
property: inputProperty,
|
|
16
|
+
// entity,
|
|
17
|
+
size
|
|
18
|
+
}: PropertyPreviewProps<string[]>) {
|
|
19
19
|
const authController = useAuthController();
|
|
20
20
|
const customizationController = useCustomizationController();
|
|
21
21
|
const property = resolveArrayProperty({
|
|
@@ -25,6 +25,8 @@ export function ArrayOfStringsPreview({
|
|
|
25
25
|
authController
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
+
if (!property) return null;
|
|
29
|
+
|
|
28
30
|
if (Array.isArray(property.of)) {
|
|
29
31
|
throw Error("Using array properties instead of single one in `of` in ArrayProperty");
|
|
30
32
|
}
|
|
@@ -43,10 +45,10 @@ export function ArrayOfStringsPreview({
|
|
|
43
45
|
<div key={`preview_array_strings_${propertyKey}_${index}`}>
|
|
44
46
|
<ErrorBoundary>
|
|
45
47
|
<StringPropertyPreview propertyKey={propertyKey}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
property={stringProperty}
|
|
49
|
+
value={v}
|
|
48
50
|
// entity={entity}
|
|
49
|
-
|
|
51
|
+
size={size} />
|
|
50
52
|
</ErrorBoundary>
|
|
51
53
|
</div>
|
|
52
54
|
)}
|