@firecms/core 3.1.0-canary.24c8270 → 3.1.0-canary.501d471

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 (224) hide show
  1. package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +4 -0
  2. package/dist/components/ErrorBoundary.d.ts +3 -1
  3. package/dist/components/HomePage/DefaultHomePage.d.ts +0 -1
  4. package/dist/components/LanguageToggle.d.ts +1 -0
  5. package/dist/components/UnsavedChangesDialog.d.ts +1 -0
  6. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -0
  7. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  8. package/dist/components/VirtualTable/VirtualTableProps.d.ts +6 -1
  9. package/dist/components/VirtualTable/types.d.ts +1 -0
  10. package/dist/components/index.d.ts +1 -0
  11. package/dist/core/DrawerNavigationGroup.d.ts +2 -2
  12. package/dist/editor/components/SlashCommandMenu.d.ts +6 -0
  13. package/dist/editor/components/editor-bubble-item.d.ts +8 -0
  14. package/dist/editor/components/editor-bubble.d.ts +8 -0
  15. package/dist/editor/components/image-bubble.d.ts +5 -0
  16. package/dist/editor/components/index.d.ts +16 -0
  17. package/dist/editor/components/table-bubble.d.ts +5 -0
  18. package/dist/editor/editor.d.ts +30 -0
  19. package/dist/editor/extensions/HighlightDecorationExtension.d.ts +24 -0
  20. package/dist/editor/extensions/Image/index.d.ts +6 -0
  21. package/dist/editor/extensions/Image.d.ts +6 -0
  22. package/dist/editor/extensions/TextLoadingDecorationExtension.d.ts +16 -0
  23. package/dist/editor/extensions/clipboard.d.ts +7 -0
  24. package/dist/editor/extensions/custom-keymap.d.ts +1 -0
  25. package/dist/editor/extensions/drag-and-drop.d.ts +9 -0
  26. package/dist/editor/hooks/useProseMirror.d.ts +13 -0
  27. package/dist/editor/hooks/useProseMirrorContext.d.ts +9 -0
  28. package/dist/editor/index.d.ts +2 -0
  29. package/dist/editor/markdown.d.ts +5 -0
  30. package/dist/editor/nodeViews/ImageComponent.d.ts +3 -0
  31. package/dist/editor/nodeViews/ReactNodeView.d.ts +29 -0
  32. package/dist/editor/nodeViews/TaskItemComponent.d.ts +3 -0
  33. package/dist/editor/nodeViews/index.d.ts +6 -0
  34. package/dist/editor/plugins/index.d.ts +2 -0
  35. package/dist/editor/plugins/inputrules.d.ts +6 -0
  36. package/dist/editor/plugins/placeholderPlugin.d.ts +3 -0
  37. package/dist/editor/plugins/slashCommandPlugin.d.ts +12 -0
  38. package/dist/editor/schema.d.ts +2 -0
  39. package/dist/editor/selectors/ai-selector.d.ts +0 -0
  40. package/dist/editor/selectors/color-selector.d.ts +10 -0
  41. package/dist/editor/selectors/link-selector.d.ts +8 -0
  42. package/dist/editor/selectors/node-selector.d.ts +15 -0
  43. package/dist/editor/selectors/text-buttons.d.ts +1 -0
  44. package/dist/editor/types.d.ts +5 -0
  45. package/dist/editor/useProseMirror.d.ts +16 -0
  46. package/dist/editor/utils/prosemirror-utils.d.ts +6 -0
  47. package/dist/editor/utils/remove_classes.d.ts +1 -0
  48. package/dist/editor/utils/useDebouncedCallback.d.ts +1 -0
  49. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  50. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  51. package/dist/hooks/index.d.ts +1 -0
  52. package/dist/hooks/useBuildNavigationController.d.ts +0 -1
  53. package/dist/hooks/useCollapsedGroups.d.ts +3 -3
  54. package/dist/hooks/useTranslation.d.ts +17 -0
  55. package/dist/i18n/FireCMSi18nProvider.d.ts +33 -0
  56. package/dist/index.d.ts +5 -0
  57. package/dist/index.es.js +29889 -18645
  58. package/dist/index.es.js.map +1 -1
  59. package/dist/index.umd.js +29883 -18659
  60. package/dist/index.umd.js.map +1 -1
  61. package/dist/locales/de.d.ts +2 -0
  62. package/dist/locales/en.d.ts +10 -0
  63. package/dist/locales/es.d.ts +10 -0
  64. package/dist/locales/fr.d.ts +2 -0
  65. package/dist/locales/hi.d.ts +2 -0
  66. package/dist/locales/it.d.ts +2 -0
  67. package/dist/locales/pt.d.ts +7 -0
  68. package/dist/types/collections.d.ts +38 -0
  69. package/dist/types/customization_controller.d.ts +2 -1
  70. package/dist/types/firecms.d.ts +2 -1
  71. package/dist/types/index.d.ts +1 -0
  72. package/dist/types/navigation.d.ts +2 -2
  73. package/dist/types/plugins.d.ts +7 -0
  74. package/dist/types/properties.d.ts +9 -8
  75. package/dist/types/storage.d.ts +1 -0
  76. package/dist/types/translations.d.ts +669 -0
  77. package/dist/util/index.d.ts +1 -0
  78. package/dist/util/lazy_eager.d.ts +7 -0
  79. package/dist/util/objects.d.ts +1 -0
  80. package/dist/util/useStorageUploadController.d.ts +10 -1
  81. package/package.json +45 -9
  82. package/src/app/Scaffold.tsx +7 -5
  83. package/src/components/AIIcon.tsx +3 -1
  84. package/src/components/ArrayContainer.tsx +6 -4
  85. package/src/components/ClearFilterSortButton.tsx +6 -3
  86. package/src/components/ConfirmationDialog.tsx +4 -2
  87. package/src/components/DeleteEntityDialog.tsx +10 -7
  88. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +9 -3
  89. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +6 -3
  90. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -1
  91. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -2
  92. package/src/components/EntityCollectionView/BoardSortableList.tsx +3 -1
  93. package/src/components/EntityCollectionView/CollectionDataErrorBanner.tsx +43 -0
  94. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +16 -43
  95. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +17 -25
  96. package/src/components/EntityCollectionView/EntityCollectionView.tsx +24 -18
  97. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -3
  98. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +4 -2
  99. package/src/components/EntityCollectionView/FiltersDialog.tsx +8 -5
  100. package/src/components/EntityCollectionView/ViewModeToggle.tsx +11 -8
  101. package/src/components/EntityJsonPreview.tsx +2 -1
  102. package/src/components/EntityView.tsx +3 -2
  103. package/src/components/ErrorBoundary.tsx +27 -15
  104. package/src/components/HomePage/DefaultHomePage.tsx +19 -13
  105. package/src/components/HomePage/HomePageDnD.tsx +3 -1
  106. package/src/components/HomePage/NavigationGroup.tsx +3 -1
  107. package/src/components/HomePage/RenameGroupDialog.tsx +15 -13
  108. package/src/components/LanguageToggle.tsx +66 -0
  109. package/src/components/NotFoundPage.tsx +5 -3
  110. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +9 -7
  111. package/src/components/ReferenceWidget.tsx +3 -2
  112. package/src/components/SearchIconsView.tsx +3 -1
  113. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +11 -0
  114. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +15 -2
  115. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +11 -0
  116. package/src/components/UnsavedChangesDialog.tsx +6 -4
  117. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +1 -0
  118. package/src/components/VirtualTable/VirtualTable.tsx +5 -3
  119. package/src/components/VirtualTable/VirtualTableHeader.tsx +21 -18
  120. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +8 -3
  121. package/src/components/VirtualTable/VirtualTableProps.tsx +7 -1
  122. package/src/components/VirtualTable/types.tsx +1 -0
  123. package/src/components/common/default_entity_actions.tsx +4 -0
  124. package/src/components/common/useDataSourceTableController.tsx +5 -14
  125. package/src/components/index.tsx +1 -0
  126. package/src/core/DefaultAppBar.tsx +14 -10
  127. package/src/core/DefaultDrawer.tsx +8 -2
  128. package/src/core/DrawerNavigationGroup.tsx +5 -3
  129. package/src/core/EntityEditView.tsx +53 -7
  130. package/src/core/EntityEditViewFormActions.tsx +24 -17
  131. package/src/core/EntitySidePanel.tsx +6 -4
  132. package/src/core/FireCMS.tsx +33 -6
  133. package/src/core/field_configs.tsx +4 -2
  134. package/src/editor/components/SlashCommandMenu.tsx +516 -0
  135. package/src/editor/components/editor-bubble-item.tsx +32 -0
  136. package/src/editor/components/editor-bubble.tsx +118 -0
  137. package/src/editor/components/image-bubble.tsx +156 -0
  138. package/src/editor/components/index.ts +14 -0
  139. package/src/editor/components/table-bubble.tsx +165 -0
  140. package/src/editor/editor.tsx +455 -0
  141. package/src/editor/extensions/HighlightDecorationExtension.ts +114 -0
  142. package/src/editor/extensions/Image/index.ts +133 -0
  143. package/src/editor/extensions/Image.ts +159 -0
  144. package/src/editor/extensions/TextLoadingDecorationExtension.tsx +107 -0
  145. package/src/editor/extensions/clipboard.ts +72 -0
  146. package/src/editor/extensions/custom-keymap.ts +24 -0
  147. package/src/editor/extensions/drag-and-drop.tsx +480 -0
  148. package/src/editor/hooks/useProseMirror.ts +124 -0
  149. package/src/editor/hooks/useProseMirrorContext.ts +15 -0
  150. package/src/editor/index.ts +2 -0
  151. package/src/editor/markdown.ts +172 -0
  152. package/src/editor/nodeViews/ImageComponent.tsx +20 -0
  153. package/src/editor/nodeViews/ReactNodeView.tsx +89 -0
  154. package/src/editor/nodeViews/TaskItemComponent.tsx +29 -0
  155. package/src/editor/nodeViews/index.ts +35 -0
  156. package/src/editor/plugins/index.ts +58 -0
  157. package/src/editor/plugins/inputrules.ts +82 -0
  158. package/src/editor/plugins/placeholderPlugin.ts +55 -0
  159. package/src/editor/plugins/slashCommandPlugin.ts +61 -0
  160. package/src/editor/schema.ts +240 -0
  161. package/src/editor/selectors/ai-selector.tsx +111 -0
  162. package/src/editor/selectors/color-selector.tsx +200 -0
  163. package/src/editor/selectors/link-selector.tsx +118 -0
  164. package/src/editor/selectors/node-selector.tsx +157 -0
  165. package/src/editor/selectors/text-buttons.tsx +86 -0
  166. package/src/editor/types.ts +6 -0
  167. package/src/editor/useProseMirror.ts +126 -0
  168. package/src/editor/utils/prosemirror-utils.ts +108 -0
  169. package/src/editor/utils/remove_classes.ts +17 -0
  170. package/src/editor/utils/useDebouncedCallback.ts +25 -0
  171. package/src/form/EntityForm.tsx +80 -7
  172. package/src/form/EntityFormActions.tsx +19 -12
  173. package/src/form/PropertyFieldBinding.tsx +7 -5
  174. package/src/form/components/LocalChangesMenu.tsx +13 -13
  175. package/src/form/components/StorageItemPreview.tsx +3 -2
  176. package/src/form/components/StorageUploadProgress.tsx +18 -3
  177. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +18 -5
  178. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +22 -9
  179. package/src/form/field_bindings/BlockFieldBinding.tsx +26 -9
  180. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  181. package/src/form/field_bindings/KeyValueFieldBinding.tsx +46 -24
  182. package/src/form/field_bindings/MapFieldBinding.tsx +27 -11
  183. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +73 -36
  184. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +15 -1
  185. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +25 -11
  186. package/src/form/field_bindings/ReferenceFieldBinding.tsx +25 -11
  187. package/src/form/field_bindings/RepeatFieldBinding.tsx +21 -6
  188. package/src/form/field_bindings/SelectFieldBinding.tsx +7 -5
  189. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +28 -10
  190. package/src/form/field_bindings/SwitchFieldBinding.tsx +31 -14
  191. package/src/form/field_bindings/TextFieldBinding.tsx +10 -7
  192. package/src/form/field_bindings/UserSelectFieldBinding.tsx +7 -5
  193. package/src/hooks/index.tsx +1 -0
  194. package/src/hooks/useBuildNavigationController.tsx +20 -13
  195. package/src/hooks/useCollapsedGroups.ts +7 -6
  196. package/src/hooks/useTranslation.ts +31 -0
  197. package/src/i18n/FireCMSi18nProvider.tsx +160 -0
  198. package/src/index.ts +5 -0
  199. package/src/locales/de.ts +718 -0
  200. package/src/locales/en.ts +730 -0
  201. package/src/locales/es.ts +730 -0
  202. package/src/locales/fr.ts +718 -0
  203. package/src/locales/hi.ts +718 -0
  204. package/src/locales/it.ts +718 -0
  205. package/src/locales/pt.ts +727 -0
  206. package/src/preview/PropertyPreview.tsx +3 -2
  207. package/src/preview/components/ReferencePreview.tsx +2 -1
  208. package/src/preview/components/UrlComponentPreview.tsx +4 -2
  209. package/src/preview/components/UserPreview.tsx +3 -1
  210. package/src/preview/property_previews/MapPropertyPreview.tsx +49 -27
  211. package/src/routes/FireCMSRoute.tsx +63 -54
  212. package/src/types/collections.ts +40 -0
  213. package/src/types/customization_controller.tsx +2 -1
  214. package/src/types/firecms.tsx +2 -1
  215. package/src/types/index.ts +1 -0
  216. package/src/types/navigation.ts +2 -2
  217. package/src/types/plugins.tsx +8 -0
  218. package/src/types/properties.ts +12 -10
  219. package/src/types/storage.ts +2 -1
  220. package/src/types/translations.ts +752 -0
  221. package/src/util/index.ts +1 -0
  222. package/src/util/lazy_eager.tsx +33 -0
  223. package/src/util/objects.ts +15 -0
  224. package/src/util/useStorageUploadController.tsx +23 -29
@@ -13,6 +13,7 @@ import {
13
13
  defaultBorderMixin,
14
14
  ExpandablePanel,
15
15
  IconButton,
16
+ CloseIcon,
16
17
  Menu,
17
18
  MenuItem,
18
19
  RemoveIcon,
@@ -22,6 +23,7 @@ import {
22
23
  import { getDefaultValueForDataType, getIconForProperty } from "../../util";
23
24
  import { useCustomizationController } from "../../hooks";
24
25
  import { getIn } from "@firecms/formex";
26
+ import { useTranslation } from "../../hooks/useTranslation";
25
27
 
26
28
  type MapEditViewRowState = [number, {
27
29
  key: string,
@@ -54,6 +56,7 @@ export function KeyValueFieldBinding({
54
56
  throw Error(`Your property ${propertyKey} needs to have the 'keyValue' prop in order to use this field binding`);
55
57
  }
56
58
 
59
+ const { t } = useTranslation();
57
60
  const initialValues = getIn(context.formex.initialValues, propertyKey);
58
61
 
59
62
  const mapFormView = <MapEditView value={value}
@@ -62,12 +65,28 @@ export function KeyValueFieldBinding({
62
65
  initialValue={initialValues}
63
66
  fieldName={property.name ?? propertyKey}/>;
64
67
 
65
- const title = <LabelWithIconAndTooltip
66
- propertyKey={propertyKey}
67
- icon={getIconForProperty(property, "small")}
68
- required={property.validation?.required}
69
- title={property.name}
70
- className={"text-text-secondary dark:text-text-secondary-dark"}/>;
68
+ const title = (
69
+ <div className="flex items-center w-full">
70
+ <LabelWithIconAndTooltip
71
+ propertyKey={propertyKey}
72
+ icon={getIconForProperty(property, "small")}
73
+ required={property.validation?.required}
74
+ title={property.name}
75
+ className={"text-text-secondary dark:text-text-secondary-dark flex-grow"}/>
76
+ {(property.nullable || property.clearable) && !disabled && (
77
+ <IconButton
78
+ size="small"
79
+ onClick={(e) => {
80
+ e.stopPropagation();
81
+ e.preventDefault();
82
+ setValue(null);
83
+ }}
84
+ >
85
+ <CloseIcon size={"small"}/>
86
+ </IconButton>
87
+ )}
88
+ </div>
89
+ );
71
90
 
72
91
  return (
73
92
  <>
@@ -103,6 +122,7 @@ function MapEditView<T extends Record<string, any>>({
103
122
  fieldName,
104
123
  disabled
105
124
  }: MapEditViewParams<T>) {
125
+ const { t } = useTranslation();
106
126
  const [internalState, setInternalState] = React.useState<MapEditViewRowState[]>(
107
127
  Object.keys(initialValue ?? {}).map((key) => [getRandomId(), {
108
128
  key,
@@ -230,7 +250,7 @@ function MapEditView<T extends Record<string, any>>({
230
250
  }]]);
231
251
  }
232
252
  }>
233
- {fieldName ? `Add to ${fieldName}` : "Add"}
253
+ {fieldName ? t("add_to_field", { fieldName }) : t("add_entry")}
234
254
  </Button>
235
255
 
236
256
  </div>;
@@ -261,12 +281,13 @@ function MapKeyValueRow<T extends Record<string, any>>({
261
281
  }) {
262
282
 
263
283
  const { locale } = useCustomizationController();
284
+ const { t } = useTranslation();
264
285
 
265
286
  function buildInput(entryValue: any, fieldKey: string, dataType: DataType) {
266
287
  if (dataType === "string" || dataType === "number") {
267
288
  return <TextField
268
289
  key={dataType}
269
- placeholder={"value"}
290
+ placeholder={t("value")}
270
291
  value={entryValue}
271
292
  type={dataType === "number" ? "number" : "text"}
272
293
  size={"medium"}
@@ -325,7 +346,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
325
346
  <ArrayContainer value={entryValue}
326
347
  newDefaultEntry={""}
327
348
  droppableId={rowId.toString()}
328
- addLabel={fieldKey ? `Add to ${fieldKey}` : "Add"}
349
+ addLabel={fieldKey ? t("add_to_field", { fieldName: fieldKey }) : t("add_entry")}
329
350
  size={"small"}
330
351
  disabled={disabled || !fieldKey}
331
352
  canAddElements={true}
@@ -370,7 +391,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
370
391
  } else {
371
392
  return <Typography
372
393
  variant={"caption"}>
373
- {`Data type ${dataType} not supported yet`}
394
+ {t("data_type_not_supported", { dataType })}
374
395
  </Typography>;
375
396
  }
376
397
  }
@@ -386,7 +407,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
386
407
  <div className="w-[300px] max-w-[30%]">
387
408
  <TextField
388
409
  value={fieldKey}
389
- placeholder={"key"}
410
+ placeholder={t("key")}
390
411
  disabled={disabled || (entryValue !== undefined && entryValue !== null && entryValue !== "")}
391
412
  size={"medium"}
392
413
  onChange={(event) => {
@@ -404,17 +425,17 @@ function MapKeyValueRow<T extends Record<string, any>>({
404
425
  </IconButton>}
405
426
  >
406
427
  <MenuItem dense
407
- onClick={() => doUpdateDataType("string")}>string</MenuItem>
428
+ onClick={() => doUpdateDataType("string")}>{t("string")}</MenuItem>
408
429
  <MenuItem dense
409
- onClick={() => doUpdateDataType("number")}>number</MenuItem>
430
+ onClick={() => doUpdateDataType("number")}>{t("number")}</MenuItem>
410
431
  <MenuItem dense
411
- onClick={() => doUpdateDataType("boolean")}>boolean</MenuItem>
432
+ onClick={() => doUpdateDataType("boolean")}>{t("boolean")}</MenuItem>
412
433
  <MenuItem dense
413
- onClick={() => doUpdateDataType("date")}>date</MenuItem>
434
+ onClick={() => doUpdateDataType("date")}>{t("date")}</MenuItem>
414
435
  <MenuItem dense
415
- onClick={() => doUpdateDataType("map")}>map</MenuItem>
436
+ onClick={() => doUpdateDataType("map")}>{t("map")}</MenuItem>
416
437
  <MenuItem dense
417
- onClick={() => doUpdateDataType("array")}>array</MenuItem>
438
+ onClick={() => doUpdateDataType("array")}>{t("array")}</MenuItem>
418
439
  </Menu>
419
440
 
420
441
  <IconButton aria-label="delete"
@@ -446,6 +467,7 @@ function ArrayKeyValueRow<T>({
446
467
  }) {
447
468
 
448
469
  const { locale } = useCustomizationController();
470
+ const { t } = useTranslation();
449
471
  const [selectedDataType, setSelectedDataType] = useState<DataType>(getDataType(value) ?? "string");
450
472
 
451
473
  function doUpdateDataType(dataType: DataType) {
@@ -487,7 +509,7 @@ function ArrayKeyValueRow<T>({
487
509
  }}/>;
488
510
  } else if (dataType === "array") {
489
511
  return <Typography variant={"caption"}>
490
- Arrays of arrays are not supported.
512
+ {t("arrays_of_arrays_not_supported")}
491
513
  </Typography>;
492
514
  } else if (dataType === "map") {
493
515
  return <div className={cls(defaultBorderMixin, "ml-2 pl-2 border-l border-solid")}>
@@ -499,7 +521,7 @@ function ArrayKeyValueRow<T>({
499
521
  } else {
500
522
  return <Typography
501
523
  variant={"caption"}>
502
- {`Data type ${dataType} not supported yet`}
524
+ {t("data_type_not_supported", { dataType })}
503
525
  </Typography>;
504
526
  }
505
527
  }
@@ -519,15 +541,15 @@ function ArrayKeyValueRow<T>({
519
541
  <ArrowDropDownIcon/>
520
542
  </IconButton>}>
521
543
  <MenuItem dense
522
- onClick={() => doUpdateDataType("string")}>string</MenuItem>
544
+ onClick={() => doUpdateDataType("string")}>{t("string")}</MenuItem>
523
545
  <MenuItem dense
524
- onClick={() => doUpdateDataType("number")}>number</MenuItem>
546
+ onClick={() => doUpdateDataType("number")}>{t("number")}</MenuItem>
525
547
  <MenuItem dense
526
- onClick={() => doUpdateDataType("boolean")}>boolean</MenuItem>
548
+ onClick={() => doUpdateDataType("boolean")}>{t("boolean")}</MenuItem>
527
549
  <MenuItem dense
528
- onClick={() => doUpdateDataType("map")}>map</MenuItem>
550
+ onClick={() => doUpdateDataType("map")}>{t("map")}</MenuItem>
529
551
  <MenuItem dense
530
- onClick={() => doUpdateDataType("date")}>date</MenuItem>
552
+ onClick={() => doUpdateDataType("date")}>{t("date")}</MenuItem>
531
553
  </Menu>
532
554
 
533
555
  </Typography>
@@ -6,7 +6,8 @@ import { getIconForProperty, isHidden, isReadOnly, pick } from "../../util";
6
6
  import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
7
7
  import { FormEntry } from "../components/FormEntry";
8
8
  import { PropertyFieldBinding } from "../PropertyFieldBinding";
9
- import { cls, ExpandablePanel, InputLabel, Select, SelectItem } from "@firecms/ui";
9
+ import { cls, ExpandablePanel, InputLabel, Select, SelectItem, IconButton, CloseIcon } from "@firecms/ui";
10
+ import { useTranslation } from "../../hooks";
10
11
 
11
12
  /**
12
13
  * Field that renders the children property fields
@@ -27,7 +28,8 @@ export function MapFieldBinding({
27
28
  includeDescription,
28
29
  autoFocus,
29
30
  context,
30
- onPropertyChange
31
+ onPropertyChange,
32
+ setValue
31
33
  }: FieldProps<Record<string, any>>) {
32
34
 
33
35
  const pickOnlySomeKeys = property.pickOnlySomeKeys || false;
@@ -91,7 +93,7 @@ export function MapFieldBinding({
91
93
  }
92
94
  </div>
93
95
 
94
- {/*{pickOnlySomeKeys && buildPickKeysSelect(disabled, property.properties, setValue, value)}*/}
96
+ {/*{pickOnlySomeKeys && buildPickKeysSelect(disabled, property.properties, setValue, value, t)}*/}
95
97
 
96
98
  </>
97
99
  ;
@@ -107,12 +109,26 @@ export function MapFieldBinding({
107
109
  }}
108
110
  className={property.widthPercentage !== undefined ? "mt-8" : undefined}
109
111
  innerClassName={"px-2 md:px-4 pb-2 md:pb-4 pt-1 md:pt-2 bg-white dark:bg-surface-900"}
110
- title={<LabelWithIconAndTooltip
111
- propertyKey={propertyKey}
112
- icon={getIconForProperty(property, "small")}
113
- required={property.validation?.required}
114
- title={property.name}
115
- className={"text-text-secondary dark:text-text-secondary-dark"} />}>
112
+ title={<div className="flex items-center w-full">
113
+ <LabelWithIconAndTooltip
114
+ propertyKey={propertyKey}
115
+ icon={getIconForProperty(property, "small")}
116
+ required={property.validation?.required}
117
+ title={property.name}
118
+ className={"text-text-secondary dark:text-text-secondary-dark flex-grow"} />
119
+ {(property.nullable || property.clearable) && !disabled && (
120
+ <IconButton
121
+ size="small"
122
+ onClick={(e) => {
123
+ e.stopPropagation();
124
+ e.preventDefault();
125
+ setValue(null);
126
+ }}
127
+ >
128
+ <CloseIcon size={"small"}/>
129
+ </IconButton>
130
+ )}
131
+ </div>}>
116
132
  {mapFormView}
117
133
  </ExpandablePanel>}
118
134
 
@@ -128,7 +144,7 @@ export function MapFieldBinding({
128
144
  );
129
145
  }
130
146
 
131
- const buildPickKeysSelect = (disabled: boolean, properties: Properties, setValue: (value: any) => void, value: any) => {
147
+ const buildPickKeysSelect = (disabled: boolean, properties: Properties, setValue: (value: any) => void, value: any, t: any) => {
132
148
 
133
149
  const keys = Object.keys(properties)
134
150
  .filter((key) => !value || !(key in value));
@@ -143,7 +159,7 @@ const buildPickKeysSelect = (disabled: boolean, properties: Properties, setValue
143
159
  if (!keys.length) return <></>;
144
160
 
145
161
  return <div className={"m-4"}>
146
- <InputLabel>Add property</InputLabel>
162
+ <InputLabel>{t("add_property")}</InputLabel>
147
163
  <Select
148
164
  value={""}
149
165
  size={"large"}
@@ -11,9 +11,14 @@ import {
11
11
  useAuthController,
12
12
  useStorageSource
13
13
  } from "../../index";
14
- import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin } from "@firecms/ui";
15
- import { FireCMSEditor, FireCMSEditorProps } from "@firecms/editor";
14
+ import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin, IconButton, CloseIcon } from "@firecms/ui";
15
+ import type { FireCMSEditorProps } from "../../editor";
16
16
  import { resolveProperty, resolveStorageFilenameString, resolveStoragePathString } from "../../util";
17
+ import { isImageFile, resizeImage } from "../../util/useStorageUploadController";
18
+ import { lazyEager } from "../../util/lazy_eager";
19
+ import { CircularProgressCenter } from "../../components/CircularProgressCenter";
20
+
21
+ const FireCMSEditor = lazyEager<typeof import("../../editor/editor")["FireCMSEditor"]>(() => import("../../editor/editor"), "FireCMSEditor");
17
22
 
18
23
  interface MarkdownEditorFieldProps {
19
24
  highlight?: { from: number, to: number };
@@ -50,17 +55,17 @@ export function MarkdownEditorFieldBinding({
50
55
  const internalValue = useRef<string | null>(value);
51
56
 
52
57
  const onContentChange = useCallback((content: string) => {
53
- if (content === value || (value === null && content === "")) {
58
+ if (content === value || ((value === null || value === undefined) && content === "")) {
54
59
  return;
55
60
  }
56
61
  internalValue.current = content;
57
62
  setValue(content);
58
- }, [setValue]);
63
+ }, [setValue, value]);
59
64
 
60
65
  useEffect(() => {
61
66
  if (internalValue.current !== value) {
62
67
  internalValue.current = value;
63
- setFieldVersion(fieldVersion + 1);
68
+ setFieldVersion(v => v + 1);
64
69
  }
65
70
  }, [value]);
66
71
 
@@ -112,42 +117,74 @@ export function MarkdownEditorFieldBinding({
112
117
  // Extract markdown config from property - can be boolean or object
113
118
  const markdownConfig = typeof property.markdown === 'object' ? property.markdown : undefined;
114
119
 
115
- const editor = <FireCMSEditor
116
- content={value}
117
- onMarkdownContentChange={onContentChange}
118
- version={context.formex.version + fieldVersion}
119
- highlight={highlight}
120
- disabled={disabled}
121
- markdownConfig={markdownConfig}
122
- handleImageUpload={async (file: File) => {
123
- const storagePath = storagePathBuilder(file);
124
- const fileName = await fileNameBuilder(file);
125
- const result = await storageSource.uploadFile({
126
- file,
127
- fileName,
128
- path: storagePath,
129
- });
130
- const downloadConfig = await storageSource.getDownloadURL(result.path);
131
- const url = downloadConfig.url;
132
- if (!url) {
133
- throw new Error("Error uploading image");
134
- }
135
- return url;
136
- }}
137
- {...editorProps}
138
- />;
120
+ const handleImageUpload = async (file: File) => {
121
+ const imageResize = storage?.imageResize;
122
+ const legacyCompression = storage?.imageCompression;
123
+ if ((imageResize || legacyCompression) && isImageFile(file)) {
124
+ file = await resizeImage(file, imageResize, legacyCompression);
125
+ }
126
+
127
+ const storagePath = storagePathBuilder(file);
128
+ const fileName = await fileNameBuilder(file);
129
+ const result = await storageSource.uploadFile({
130
+ file,
131
+ fileName,
132
+ path: storagePath,
133
+ });
134
+ const downloadConfig = await storageSource.getDownloadURL(result.path);
135
+ const url = downloadConfig.url;
136
+ if (!url) {
137
+ throw new Error("Error uploading image");
138
+ }
139
+ return url;
140
+ };
141
+
142
+ const editor = (
143
+ <React.Suspense fallback={<CircularProgressCenter />}>
144
+ <FireCMSEditor
145
+ key={context.formex.version + fieldVersion}
146
+ content={value}
147
+ onMarkdownContentChange={onContentChange}
148
+ version={context.formex.version + fieldVersion}
149
+ highlight={highlight}
150
+ disabled={disabled}
151
+ markdownConfig={markdownConfig}
152
+ handleImageUpload={handleImageUpload}
153
+ {...editorProps}
154
+ />
155
+ </React.Suspense>
156
+ );
139
157
 
140
158
  if (minimalistView)
141
- return editor;
159
+ return (
160
+ <>
161
+ {editor}
162
+ </>
163
+ );
142
164
 
143
165
  return (
144
166
  <>
145
- <LabelWithIconAndTooltip
146
- propertyKey={propertyKey}
147
- icon={getIconForProperty(property, "small")}
148
- required={property.validation?.required}
149
- title={property.name}
150
- className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
167
+ <div className="flex items-center w-full">
168
+ <LabelWithIconAndTooltip
169
+ propertyKey={propertyKey}
170
+ icon={getIconForProperty(property, "small")}
171
+ required={property.validation?.required}
172
+ title={property.name}
173
+ className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
174
+ <div className="flex-grow"/>
175
+ {(property.nullable || property.clearable) && !disabled && (
176
+ <IconButton
177
+ size="small"
178
+ onClick={(e) => {
179
+ e.stopPropagation();
180
+ e.preventDefault();
181
+ setValue(null);
182
+ }}
183
+ >
184
+ <CloseIcon size={"small"}/>
185
+ </IconButton>
186
+ )}
187
+ </div>
151
188
  <div
152
189
  className={cls("rounded-md", fieldBackgroundMixin, disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin)}>
153
190
  {editor}
@@ -4,7 +4,7 @@ import { EnumType, FieldProps, ResolvedProperty } from "../../types";
4
4
  import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
5
5
  import { EnumValuesChip } from "../../preview";
6
6
  import { enumToObjectEntries, getIconForProperty, getLabelOrConfigFrom } from "../../util";
7
- import { CloseIcon, MultiSelect, MultiSelectItem } from "@firecms/ui";
7
+ import { CloseIcon, MultiSelect, MultiSelectItem, IconButton } from "@firecms/ui";
8
8
  import { useClearRestoreValue } from "../useClearRestoreValue";
9
9
 
10
10
  /**
@@ -93,6 +93,20 @@ export function MultiSelectFieldBinding({
93
93
  required={property.validation?.required}
94
94
  title={property.name}
95
95
  className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>}
96
+ endAdornment={
97
+ (property.nullable || property.clearable) && !disabled && value !== null && value !== undefined ? (
98
+ <IconButton
99
+ size="small"
100
+ onClick={(e) => {
101
+ e.stopPropagation();
102
+ e.preventDefault();
103
+ setValue(null);
104
+ }}
105
+ >
106
+ <CloseIcon size={"small"}/>
107
+ </IconButton>
108
+ ) : undefined
109
+ }
96
110
  onValueChange={(updatedValue: string[]) => {
97
111
  let newValue: EnumType[] | null;
98
112
  if (of && (of as ResolvedProperty)?.dataType === "number") {
@@ -8,7 +8,7 @@ import { ReferencePreview } from "../../preview";
8
8
  import { getIconForProperty, IconForView } from "../../util";
9
9
  import { useClearRestoreValue } from "../useClearRestoreValue";
10
10
  import { EntityPreviewContainer } from "../../components/EntityPreview";
11
- import { cls } from "@firecms/ui";
11
+ import { cls, IconButton, CloseIcon } from "@firecms/ui";
12
12
 
13
13
  /**
14
14
  * Field that opens a reference selection dialog and stores the entity ID as a string.
@@ -98,16 +98,30 @@ function ReferenceAsStringFieldBindingInternal({
98
98
 
99
99
  {collection && <>
100
100
 
101
- {referenceValue && <ReferencePreview
102
- disabled={!path}
103
- previewProperties={property.reference?.previewProperties}
104
- hover={!disabled}
105
- size={size}
106
- onClick={disabled || isSubmitting ? undefined : onEntryClick}
107
- reference={referenceValue}
108
- includeEntityLink={property.reference?.includeEntityLink}
109
- includeId={property.reference?.includeId}
110
- />}
101
+ {referenceValue && <div className="flex items-center gap-2">
102
+ <ReferencePreview
103
+ disabled={!path}
104
+ previewProperties={property.reference?.previewProperties}
105
+ hover={!disabled}
106
+ size={size}
107
+ onClick={disabled || isSubmitting ? undefined : onEntryClick}
108
+ reference={referenceValue}
109
+ includeEntityLink={property.reference?.includeEntityLink}
110
+ includeId={property.reference?.includeId}
111
+ />
112
+ {(property.nullable || property.clearable) && !disabled && (
113
+ <IconButton
114
+ size="small"
115
+ onClick={(e) => {
116
+ e.stopPropagation();
117
+ e.preventDefault();
118
+ setValue(null);
119
+ }}
120
+ >
121
+ <CloseIcon size={"small"}/>
122
+ </IconButton>
123
+ )}
124
+ </div>}
111
125
 
112
126
  {!value && <div className="justify-center text-left">
113
127
  <EntityPreviewContainer
@@ -9,7 +9,7 @@ import { EmptyValue, ReferencePreview } from "../../preview";
9
9
  import { getIconForProperty, getReferenceFrom, IconForView } from "../../util";
10
10
  import { useClearRestoreValue } from "../useClearRestoreValue";
11
11
  import { EntityPreviewContainer } from "../../components/EntityPreview";
12
- import { cls } from "@firecms/ui";
12
+ import { cls, IconButton, CloseIcon } from "@firecms/ui";
13
13
 
14
14
  /**
15
15
  * Field that opens a reference selection dialog.
@@ -97,16 +97,30 @@ function ReferenceFieldBindingInternal({
97
97
 
98
98
  {collection && <>
99
99
 
100
- {value && <ReferencePreview
101
- disabled={!property.path}
102
- previewProperties={property.previewProperties}
103
- hover={!disabled}
104
- size={size}
105
- onClick={disabled || isSubmitting ? undefined : onEntryClick}
106
- reference={value}
107
- includeEntityLink={property.includeEntityLink}
108
- includeId={property.includeId}
109
- />}
100
+ {value && <div className="flex items-center gap-2">
101
+ <ReferencePreview
102
+ disabled={!property.path}
103
+ previewProperties={property.previewProperties}
104
+ hover={!disabled}
105
+ size={size}
106
+ onClick={disabled || isSubmitting ? undefined : onEntryClick}
107
+ reference={value}
108
+ includeEntityLink={property.includeEntityLink}
109
+ includeId={property.includeId}
110
+ />
111
+ {(property.nullable || property.clearable) && !disabled && (
112
+ <IconButton
113
+ size="small"
114
+ onClick={(e) => {
115
+ e.stopPropagation();
116
+ e.preventDefault();
117
+ setValue(null);
118
+ }}
119
+ >
120
+ <CloseIcon size={"small"}/>
121
+ </IconButton>
122
+ )}
123
+ </div>}
110
124
 
111
125
  {!value && <div className="justify-center text-left">
112
126
  <EntityPreviewContainer className={cls("px-6 h-16 text-sm font-medium flex items-center gap-6",
@@ -4,9 +4,10 @@ import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
4
4
  import { ArrayContainer, ArrayEntryParams, ErrorBoundary } from "../../components";
5
5
  import { getArrayResolvedProperties, getDefaultValueFor, getIconForProperty, mergeDeep } from "../../util";
6
6
  import { PropertyFieldBinding } from "../PropertyFieldBinding";
7
- import { ExpandablePanel, Typography } from "@firecms/ui";
7
+ import { ExpandablePanel, Typography, IconButton, CloseIcon } from "@firecms/ui";
8
8
  import { useClearRestoreValue } from "../useClearRestoreValue";
9
9
  import { useAuthController } from "../../hooks";
10
+ import { useTranslation } from "../../hooks/useTranslation";
10
11
 
11
12
  /**
12
13
  * Generic array field that allows reordering and renders the child property
@@ -34,6 +35,7 @@ export function RepeatFieldBinding<T extends Array<any>>({
34
35
 
35
36
  const authController = useAuthController();
36
37
  const minimalistView = minimalistViewProp || property.minimalistView;
38
+ const { t } = useTranslation();
37
39
 
38
40
  if (!property.of)
39
41
  throw Error("RepeatFieldBinding misconfiguration. Property `of` not set");
@@ -87,7 +89,7 @@ export function RepeatFieldBinding<T extends Array<any>>({
87
89
  const canAddElements = !property.disabled && !isSubmitting && !disabled && (property.canAddElements || property.canAddElements === undefined);
88
90
  const sortable = property.sortable === undefined ? true : property.sortable;
89
91
  const arrayContainer = <ArrayContainer droppableId={propertyKey}
90
- addLabel={property.name ? "Add entry to " + property.name : "Add entry"}
92
+ addLabel={property.name ? t("add_to_field", { fieldName: property.name }) : t("add_entry")}
91
93
  value={value}
92
94
  buildEntry={buildEntry}
93
95
  onInternalIdAdded={setLastAddedId}
@@ -99,15 +101,28 @@ export function RepeatFieldBinding<T extends Array<any>>({
99
101
  className={property.widthPercentage !== undefined ? "mt-8" : undefined}
100
102
  />;
101
103
 
102
- const title = (<>
104
+ const title = (<div className="flex items-center w-full">
103
105
  <LabelWithIconAndTooltip
104
106
  propertyKey={propertyKey}
105
107
  icon={getIconForProperty(property, "small")}
106
108
  required={property.validation?.required}
107
109
  title={property.name}
108
- className={"h-8 flex flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
109
- {Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
110
- </>);
110
+ className={"text-text-secondary dark:text-text-secondary-dark"}/>
111
+ {Array.isArray(value) && <span className={"text-sm text-text-secondary dark:text-text-secondary-dark ml-1"}>({value.length})</span>}
112
+ <div className="flex-grow"/>
113
+ {(property.nullable || property.clearable) && !disabled && (
114
+ <IconButton
115
+ size="small"
116
+ onClick={(e) => {
117
+ e.stopPropagation();
118
+ e.preventDefault();
119
+ setValue(null);
120
+ }}
121
+ >
122
+ <CloseIcon size={"small"}/>
123
+ </IconButton>
124
+ )}
125
+ </div>);
111
126
 
112
127
  return (
113
128
 
@@ -66,11 +66,13 @@ export function SelectFieldBinding<T extends EnumType>({
66
66
  />
67
67
  </PropertyIdCopyTooltip>}
68
68
  endAdornment={
69
- property.clearable && !disabled && <IconButton
70
- size="small"
71
- onClick={handleClearClick}>
72
- <CloseIcon size={"small"}/>
73
- </IconButton>
69
+ (property.nullable || property.clearable) && !disabled && value !== null && value !== undefined ? (
70
+ <IconButton
71
+ size="small"
72
+ onClick={handleClearClick}>
73
+ <CloseIcon size={"small"}/>
74
+ </IconButton>
75
+ ) : undefined
74
76
  }
75
77
  onValueChange={(updatedValue: string) => {
76
78
  const newValue = updatedValue