@firecms/core 3.0.0-canary.210 → 3.0.0-canary.211

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.210",
4
+ "version": "3.0.0-canary.211",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -50,9 +50,9 @@
50
50
  "./package.json": "./package.json"
51
51
  },
52
52
  "dependencies": {
53
- "@firecms/editor": "^3.0.0-canary.210",
54
- "@firecms/formex": "^3.0.0-canary.210",
55
- "@firecms/ui": "^3.0.0-canary.210",
53
+ "@firecms/editor": "^3.0.0-canary.211",
54
+ "@firecms/formex": "^3.0.0-canary.211",
55
+ "@firecms/ui": "^3.0.0-canary.211",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
57
  "@radix-ui/react-portal": "^1.1.3",
58
58
  "clsx": "^2.1.1",
@@ -62,6 +62,7 @@
62
62
  "markdown-it": "^14.1.0",
63
63
  "notistack": "^3.0.2",
64
64
  "object-hash": "^3.0.0",
65
+ "prism-react-renderer": "^2.4.1",
65
66
  "react-dropzone": "^14.3.5",
66
67
  "react-fast-compare": "^3.2.2",
67
68
  "react-image-file-resizer": "^0.4.8",
@@ -104,7 +105,7 @@
104
105
  "dist",
105
106
  "src"
106
107
  ],
107
- "gitHead": "b8bcb3a2230e8b02644ce5ed0891b273e7e7d630",
108
+ "gitHead": "ee9fd6ecade3bb23be5cfa025117be9fe2b6fd7f",
108
109
  "publishConfig": {
109
110
  "access": "public"
110
111
  },
@@ -0,0 +1,66 @@
1
+ import React, { useRef, useEffect, useCallback } from "react";
2
+ import { Highlight, themes } from "prism-react-renderer";
3
+ import { useModeController } from "../hooks";
4
+
5
+ export function EntityJsonPreview({ values }: { values: object }) {
6
+ const code = JSON.stringify(values, null, "\t");
7
+ const { mode } = useModeController();
8
+ const preRef = useRef<HTMLPreElement>(null);
9
+
10
+ // Global keydown handler
11
+ const handleGlobalKeyDown = useCallback((e: KeyboardEvent) => {
12
+ // Check for Control (Windows/Linux) or Command (macOS) + "a":
13
+ if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a") {
14
+ // If our code view is mounted, perform selection
15
+ if (preRef.current) {
16
+ e.preventDefault();
17
+ e.stopPropagation();
18
+
19
+ const selection = window.getSelection();
20
+ const range = document.createRange();
21
+ range.selectNodeContents(preRef.current);
22
+ if (selection) {
23
+ selection.removeAllRanges();
24
+ selection.addRange(range);
25
+ }
26
+ }
27
+ }
28
+ }, []);
29
+
30
+ // Attach the global keydown listener when component mounts,
31
+ // and remove it when it unmounts.
32
+ useEffect(() => {
33
+ document.addEventListener("keydown", handleGlobalKeyDown);
34
+ return () => {
35
+ document.removeEventListener("keydown", handleGlobalKeyDown);
36
+ };
37
+ }, [handleGlobalKeyDown]);
38
+
39
+ return (
40
+ <Highlight
41
+ theme={mode === "dark" ? themes.vsDark : themes.vsLight}
42
+ code={code}
43
+ language="json"
44
+ >
45
+ {({ style, tokens, getLineProps, getTokenProps }) => (
46
+ <pre
47
+ // Bind the ref to our pre element so we can select its contents.
48
+ ref={preRef}
49
+ style={{
50
+ ...style,
51
+ background: "inherit"
52
+ }}
53
+ className="container mx-auto p-8 rounded text-sm"
54
+ >
55
+ {tokens.map((line, i) => (
56
+ <div key={i} {...getLineProps({ line })} className="text-wrap">
57
+ {line.map((token, key) => (
58
+ <span key={key} {...getTokenProps({ token })} className="word-break" />
59
+ ))}
60
+ </div>
61
+ ))}
62
+ </pre>
63
+ )}
64
+ </Highlight>
65
+ );
66
+ }
@@ -16,12 +16,14 @@ import {
16
16
  useFireCMSContext,
17
17
  useLargeLayout
18
18
  } from "../hooks";
19
- import { CircularProgress, cls, defaultBorderMixin, Tab, Tabs, Typography } from "@firecms/ui";
19
+ import { CircularProgress, cls, CodeIcon, defaultBorderMixin, Tab, Tabs, Typography } from "@firecms/ui";
20
20
  import { getEntityFromCache } from "../util/entity_cache";
21
21
  import { EntityForm, EntityFormProps } from "../form";
22
22
  import { EntityEditViewFormActions } from "./EntityEditViewFormActions";
23
+ import { EntityJsonPreview } from "../components/EntityJsonPreview";
23
24
 
24
- const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
25
+ export const MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
26
+ export const JSON_TAB_VALUE = "__json";
25
27
 
26
28
  export type OnUpdateParams = {
27
29
  entity: Entity<any>,
@@ -141,7 +143,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
141
143
  barActions,
142
144
  status,
143
145
  setStatus,
144
- formProps,
146
+ formProps
145
147
  }: EntityEditViewProps<M> & {
146
148
  entity?: Entity<M>,
147
149
  cachedDirtyValues?: Partial<M>, // dirty cached entity in memory
@@ -186,7 +188,8 @@ export function EntityEditViewInner<M extends Record<string, any>>({
186
188
  const subcollectionsCount = subcollections?.length ?? 0;
187
189
  const customViews = collection.entityViews;
188
190
  const customViewsCount = customViews?.length ?? 0;
189
- const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
191
+ const includeJsonView = true;
192
+ const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0 || includeJsonView;
190
193
 
191
194
  const {
192
195
  resolvedEntityViews,
@@ -229,6 +232,17 @@ export function EntityEditViewInner<M extends Record<string, any>>({
229
232
 
230
233
  const globalLoading = dataLoading && !usedEntity;
231
234
 
235
+ const jsonView = <div
236
+ className={cls("relative flex-1 h-full overflow-auto w-full",
237
+ { "hidden": selectedTab !== JSON_TAB_VALUE })}
238
+ key={"json_view"}
239
+ role="tabpanel">
240
+ <ErrorBoundary>
241
+ <EntityJsonPreview
242
+ values={formContext?.values ?? {}}/>
243
+ </ErrorBoundary>
244
+ </div>;
245
+
232
246
  const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
233
247
  const subcollectionId = subcollection.id ?? subcollection.path;
234
248
  const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
@@ -269,7 +283,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
269
283
  path,
270
284
  entityId,
271
285
  selectedTab: value === MAIN_TAB_VALUE ? undefined : value,
272
- collection,
286
+ collection
273
287
  });
274
288
  }
275
289
  };
@@ -303,7 +317,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
303
317
  onSaved={(params) => {
304
318
  const res = {
305
319
  ...params,
306
- selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab,
320
+ selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab
307
321
  };
308
322
  onSaved?.(res);
309
323
  formProps?.onSaved?.(res);
@@ -350,6 +364,14 @@ export function EntityEditViewInner<M extends Record<string, any>>({
350
364
  onSideTabClick(value);
351
365
  }}>
352
366
 
367
+ {includeJsonView && <Tab
368
+ disabled={!hasAdditionalViews}
369
+ value={JSON_TAB_VALUE}
370
+ innerClassName={"block"}
371
+ className={"text-sm"}>
372
+ <CodeIcon size={"small"}/>
373
+ </Tab>}
374
+
353
375
  <Tab
354
376
  disabled={!hasAdditionalViews}
355
377
  value={MAIN_TAB_VALUE}
@@ -357,6 +379,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
357
379
  {collection.singularName ?? collection.name}
358
380
  </Tab>
359
381
 
382
+
360
383
  {customViewTabs}
361
384
 
362
385
  {subcollectionTabs}
@@ -369,7 +392,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
369
392
  </div>
370
393
  : entityView}
371
394
 
372
- {/*{secondaryForms}*/}
395
+ {jsonView}
373
396
 
374
397
  {customViewsView}
375
398
 
@@ -20,6 +20,7 @@ import {
20
20
  import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, FORM_CONTAINER_WIDTH } from "./common";
21
21
  import { useCustomizationController, useLargeLayout } from "../hooks";
22
22
  import { EntitySidePanel } from "../core/EntitySidePanel";
23
+ import { JSON_TAB_VALUE } from "../core/EntityEditView";
23
24
 
24
25
  const NEW_URL_HASH = "new_side";
25
26
  const SIDE_URL_HASH = "side";
@@ -31,7 +32,7 @@ export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: bool
31
32
  selectedSecondaryForm
32
33
  } = resolvedSelectedEntityView(props.collection?.entityViews, customizationController, props.selectedTab);
33
34
 
34
- const shouldUseSmallLayout = !props.selectedTab || Boolean(selectedSecondaryForm);
35
+ const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === JSON_TAB_VALUE || Boolean(selectedSecondaryForm);
35
36
 
36
37
  let resolvedWidth: string | undefined;
37
38
  if (props.width) {