@firecms/core 3.4.0 → 3.5.0

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 (92) hide show
  1. package/README.md +4 -0
  2. package/dist/components/LicenseBanner.d.ts +24 -0
  3. package/dist/components/index.d.ts +1 -0
  4. package/dist/contexts/LicenseStatusContext.d.ts +16 -0
  5. package/dist/core/index.d.ts +1 -0
  6. package/dist/core/plugin_translations.d.ts +38 -0
  7. package/dist/core/pro_plugins.d.ts +40 -0
  8. package/dist/de-CBOjCvsy.js +707 -0
  9. package/dist/de-CBOjCvsy.js.map +1 -0
  10. package/dist/editor/extensions/Image.d.ts +11 -0
  11. package/dist/editor/index.d.ts +2 -1
  12. package/dist/editor/lazy_editor.d.ts +6 -0
  13. package/dist/editor-BSo_aS1I.js +4563 -0
  14. package/dist/editor-BSo_aS1I.js.map +1 -0
  15. package/dist/fr-DRfttcG0.js +707 -0
  16. package/dist/fr-DRfttcG0.js.map +1 -0
  17. package/dist/hi-DwieOZNf.js +707 -0
  18. package/dist/hi-DwieOZNf.js.map +1 -0
  19. package/dist/hooks/index.d.ts +2 -0
  20. package/dist/hooks/useLicenseStatus.d.ts +16 -0
  21. package/dist/hooks/useProjectLog.d.ts +11 -6
  22. package/dist/hooks/useTranslation.d.ts +1 -1
  23. package/dist/index.es.js +2373 -10281
  24. package/dist/index.es.js.map +1 -1
  25. package/dist/index.umd.js +13166 -12269
  26. package/dist/index.umd.js.map +1 -1
  27. package/dist/it-l2KXtx9n.js +707 -0
  28. package/dist/it-l2KXtx9n.js.map +1 -0
  29. package/dist/pl-DPZrdKhi.js +709 -0
  30. package/dist/pl-DPZrdKhi.js.map +1 -0
  31. package/dist/pt-BoHpabw1.js +709 -0
  32. package/dist/pt-BoHpabw1.js.map +1 -0
  33. package/dist/types/analytics.d.ts +1 -1
  34. package/dist/types/firecms.d.ts +18 -1
  35. package/dist/types/firecms_context.d.ts +8 -0
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/types/license.d.ts +81 -0
  38. package/dist/types/plugins.d.ts +9 -1
  39. package/dist/types/translations.d.ts +45 -2
  40. package/dist/util/date_fns_locales.d.ts +18 -0
  41. package/dist/util/index.d.ts +1 -0
  42. package/dist/util/lazy_eager.d.ts +3 -3
  43. package/dist/util/local_storage.d.ts +23 -0
  44. package/package.json +4 -5
  45. package/src/app/Scaffold.tsx +7 -0
  46. package/src/components/EntityCollectionView/utils.ts +4 -4
  47. package/src/components/LicenseBanner.tsx +287 -0
  48. package/src/components/index.tsx +1 -0
  49. package/src/contexts/LicenseStatusContext.tsx +50 -0
  50. package/src/core/DefaultAppBar.tsx +28 -16
  51. package/src/core/FireCMS.tsx +73 -47
  52. package/src/core/SideDialogs.tsx +44 -1
  53. package/src/core/index.tsx +1 -0
  54. package/src/core/plugin_translations.ts +87 -0
  55. package/src/core/pro_plugins.ts +79 -0
  56. package/src/editor/components/SlashCommandMenu.tsx +4 -1
  57. package/src/editor/extensions/Image.ts +17 -1
  58. package/src/editor/hooks/useProseMirror.ts +5 -0
  59. package/src/editor/index.ts +11 -1
  60. package/src/editor/lazy_editor.tsx +33 -0
  61. package/src/hooks/index.tsx +2 -0
  62. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -9
  63. package/src/hooks/useBuildModeController.tsx +6 -4
  64. package/src/hooks/useBuildNavigationController.tsx +47 -7
  65. package/src/hooks/useFireCMSContext.tsx +7 -3
  66. package/src/hooks/useLicenseStatus.tsx +32 -0
  67. package/src/hooks/useProjectLog.tsx +27 -9
  68. package/src/hooks/useTranslation.ts +3 -1
  69. package/src/i18n/FireCMSi18nProvider.tsx +169 -42
  70. package/src/locales/de.ts +23 -2
  71. package/src/locales/en.ts +28 -5
  72. package/src/locales/es.ts +23 -2
  73. package/src/locales/fr.ts +23 -2
  74. package/src/locales/hi.ts +23 -2
  75. package/src/locales/it.ts +23 -2
  76. package/src/locales/pl.ts +23 -2
  77. package/src/locales/pt.ts +23 -2
  78. package/src/preview/components/DatePreview.tsx +2 -4
  79. package/src/types/analytics.ts +3 -0
  80. package/src/types/firecms.tsx +19 -1
  81. package/src/types/firecms_context.tsx +9 -0
  82. package/src/types/index.ts +1 -0
  83. package/src/types/license.ts +90 -0
  84. package/src/types/plugins.tsx +10 -1
  85. package/src/types/translations.ts +45 -2
  86. package/src/util/date_fns_locales.ts +168 -0
  87. package/src/util/entity_cache.ts +10 -2
  88. package/src/util/index.ts +1 -0
  89. package/src/util/lazy_eager.tsx +30 -8
  90. package/src/util/local_storage.ts +52 -0
  91. package/src/util/navigation_utils.ts +6 -1
  92. package/src/util/useStorageUploadController.tsx +6 -1
@@ -25,8 +25,16 @@ const LOCAL_STORAGE_PREFIX = "entity_cache::";
25
25
  // In-memory cache to store entities for quick access
26
26
  const entityCache: Map<string, object> = new Map();
27
27
 
28
- // Check `localStorage` availability once during initialization
29
- const isLocalStorageAvailable = typeof localStorage !== "undefined";
28
+ // Check `localStorage` availability once during initialization. Reading it
29
+ // throws where the browser blocks site data, which would fail this module's
30
+ // import and take the whole CMS down with it.
31
+ const isLocalStorageAvailable = (() => {
32
+ try {
33
+ return typeof localStorage !== "undefined";
34
+ } catch {
35
+ return false;
36
+ }
37
+ })();
30
38
 
31
39
  // Define custom replacer for JSON.stringify
32
40
  function customReplacer(key: string): any {
package/src/util/index.ts CHANGED
@@ -28,3 +28,4 @@ export * from "./storage";
28
28
  export * from "./callbacks";
29
29
  export * from "./conditions";
30
30
  export * from "./lazy_eager";
31
+ export * from "./date_fns_locales";
@@ -1,9 +1,35 @@
1
1
  import React from "react";
2
2
 
3
3
  /**
4
- * Returns a React.lazy component that is also preloaded immediately using
5
- * requestIdleCallback or setTimeout.
6
- * This ensures that chunks are split, but fetched in the background before they are actually needed.
4
+ * Prefetch after the page has loaded, never during it.
5
+ *
6
+ * An idle callback scheduled at module evaluation time fires in the gaps between
7
+ * the tasks of the initial load — which is exactly when the critical chunks are
8
+ * still in flight. With a dozen route components each queueing one, the
9
+ * background prefetch was competing with the render path for connections and
10
+ * bandwidth. Waiting for the load event costs the prefetch nothing that matters:
11
+ * it exists to be ready before a navigation, not before first paint.
12
+ */
13
+ function schedulePrefetch(load: () => void) {
14
+ const whenIdle = () => {
15
+ if ("requestIdleCallback" in window) {
16
+ (window as any).requestIdleCallback(load);
17
+ } else {
18
+ setTimeout(load, 500);
19
+ }
20
+ };
21
+
22
+ if (document.readyState === "complete") {
23
+ whenIdle();
24
+ } else {
25
+ window.addEventListener("load", whenIdle, { once: true });
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Returns a React.lazy component that is also preloaded in the background, once
31
+ * the page has finished loading.
32
+ * This ensures that chunks are split, but fetched before they are actually needed.
7
33
  */
8
34
  export function lazyEager<T extends React.ComponentType<any>>(
9
35
  factory: () => Promise<any>,
@@ -22,11 +48,7 @@ export function lazyEager<T extends React.ComponentType<any>>(
22
48
  };
23
49
 
24
50
  if (typeof window !== "undefined") {
25
- if ("requestIdleCallback" in window) {
26
- (window as any).requestIdleCallback(load);
27
- } else {
28
- setTimeout(load, 500);
29
- }
51
+ schedulePrefetch(load);
30
52
  }
31
53
 
32
54
  return React.lazy(load);
@@ -0,0 +1,52 @@
1
+ /**
2
+ * `localStorage` access that never throws.
3
+ *
4
+ * Merely reading `window.localStorage` throws a SecurityError when the browser
5
+ * blocks site data (all cookies blocked, some sandboxed iframes), and `setItem`
6
+ * throws when the quota is full. Nothing the CMS keeps there is worth failing a
7
+ * render over, so a failed read counts as "nothing stored" and a failed write
8
+ * is dropped.
9
+ *
10
+ * @internal
11
+ */
12
+ export function getLocalStorageItem(key: string): string | null {
13
+ try {
14
+ return typeof window !== "undefined" ? window.localStorage.getItem(key) : null;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+
20
+ /**
21
+ * The stored JSON value for `key`, or `fallback` when there is none, it is not
22
+ * valid JSON, or storage cannot be read.
23
+ *
24
+ * @internal
25
+ */
26
+ export function getLocalStorageJSON<T>(key: string, fallback: T): T {
27
+ const item = getLocalStorageItem(key);
28
+ if (!item) return fallback;
29
+ try {
30
+ return JSON.parse(item);
31
+ } catch {
32
+ return fallback;
33
+ }
34
+ }
35
+
36
+ /** @internal */
37
+ export function setLocalStorageItem(key: string, value: string): void {
38
+ try {
39
+ if (typeof window !== "undefined") window.localStorage.setItem(key, value);
40
+ } catch {
41
+ // Blocked or full: the value lives only as long as the page.
42
+ }
43
+ }
44
+
45
+ /** @internal */
46
+ export function removeLocalStorageItem(key: string): void {
47
+ try {
48
+ if (typeof window !== "undefined") window.localStorage.removeItem(key);
49
+ } catch {
50
+ // Blocked: nothing was stored to remove.
51
+ }
52
+ }
@@ -281,7 +281,12 @@ export function resolveCollectionPathIds(path: string, allCollections: EntityCol
281
281
  col,
282
282
  match: col.id
283
283
  }])
284
- .filter(p => p.match && remainingPath.startsWith(p.match))
284
+ // A match has to end where a path segment ends. Matching any prefix made
285
+ // "products-test" resolve to the "products" collection with an entity called
286
+ // "-test" (FirebaseError: Invalid document reference), and any collection whose
287
+ // path merely starts with another's — "products_archive", which the collection
288
+ // editor generates from "Products archive" — resolve to the wrong one.
289
+ .filter(p => p.match && (remainingPath === p.match || remainingPath.startsWith(p.match + "/")))
285
290
  .sort((a, b) => b.match.length - a.match.length);
286
291
 
287
292
  if (potentialMatches.length > 0) {
@@ -1,4 +1,4 @@
1
- import Compressor from "compressorjs";
1
+ import type CompressorType from "compressorjs";
2
2
  import equal from "react-fast-compare";
3
3
 
4
4
  import {
@@ -321,6 +321,11 @@ export async function resizeImage(
321
321
  mimeType = `image/${imageResize.format}`;
322
322
  }
323
323
 
324
+ // Loaded here rather than imported: compressing an image is something a
325
+ // small fraction of sessions ever does, and a static import put the library
326
+ // in `@firecms/core` for everyone.
327
+ const Compressor: typeof CompressorType = (await import("compressorjs")).default;
328
+
324
329
  return new Promise<File>((resolve, reject) => {
325
330
  new Compressor(file, {
326
331
  quality,