@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/dist/components/EntityJsonPreview.d.ts +3 -0
- package/dist/core/EntityEditView.d.ts +3 -1
- package/dist/index.es.js +105 -7
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +105 -8
- package/dist/index.umd.js.map +1 -1
- package/package.json +6 -5
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/core/EntityEditView.tsx +30 -7
- package/src/internal/useBuildSideEntityController.tsx +2 -1
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.
|
|
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.
|
|
54
|
-
"@firecms/formex": "^3.0.0-canary.
|
|
55
|
-
"@firecms/ui": "^3.0.0-canary.
|
|
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": "
|
|
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 = "
|
|
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
|
|
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
|
-
{
|
|
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) {
|