-
Notifications
You must be signed in to change notification settings - Fork 623
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(app-headless-cms): add parent field context (#4048)
- Loading branch information
Showing
31 changed files
with
532 additions
and
286 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
packages/app-headless-cms/src/admin/components/ContentEntryForm/FieldElement.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React from "react"; | ||
import get from "lodash/get"; | ||
import { makeDecoratable } from "@webiny/app-admin"; | ||
import { i18n } from "@webiny/app/i18n"; | ||
import { CmsModelField, CmsEditorContentModel, BindComponent } from "~/types"; | ||
import Label from "./Label"; | ||
import { useBind } from "./useBind"; | ||
import { useRenderPlugins } from "./useRenderPlugins"; | ||
import { ModelFieldProvider } from "../ModelFieldProvider"; | ||
|
||
const t = i18n.ns("app-headless-cms/admin/components/content-form"); | ||
|
||
export interface FieldElementProps { | ||
field: CmsModelField; | ||
Bind: BindComponent; | ||
contentModel: CmsEditorContentModel; | ||
} | ||
|
||
export const FieldElement = makeDecoratable("FieldElement", (props: FieldElementProps) => { | ||
const renderPlugins = useRenderPlugins(); | ||
const { field, Bind, contentModel } = props; | ||
const getBind = useBind({ Bind, field }); | ||
|
||
if (typeof field.renderer === "function") { | ||
return ( | ||
<ModelFieldProvider field={field}> | ||
{field.renderer({ field, getBind, Label, contentModel })} | ||
</ModelFieldProvider> | ||
); | ||
} | ||
|
||
const renderPlugin = renderPlugins.find( | ||
plugin => plugin.renderer.rendererName === get(field, "renderer.name") | ||
); | ||
|
||
if (!renderPlugin) { | ||
return t`Cannot render "{fieldName}" field - field renderer missing.`({ | ||
fieldName: <strong>{field.fieldId}</strong> | ||
}); | ||
} | ||
|
||
return ( | ||
<ModelFieldProvider field={field}> | ||
{renderPlugin.renderer.render({ field, getBind, Label, contentModel })} | ||
</ModelFieldProvider> | ||
); | ||
}); | ||
|
||
/** | ||
* @deprecated Use `FieldElement` instead. | ||
*/ | ||
export const RenderFieldElement = FieldElement; | ||
|
||
/** | ||
* @deprecated Use `FieldElementProps` instead. | ||
*/ | ||
export type RenderFieldElementProps = FieldElementProps; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
packages/app-headless-cms/src/admin/components/ContentEntryForm/ParentValue.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React, { createContext, useCallback, useContext, useEffect, useRef } from "react"; | ||
import get from "lodash/get"; | ||
import { CmsModelField } from "@webiny/app-headless-cms-common/types"; | ||
import { useModelField } from "~/admin/components/ModelFieldProvider"; | ||
import { useForm, FormAPI } from "@webiny/form"; | ||
|
||
declare global { | ||
// eslint-disable-next-line | ||
namespace JSX { | ||
interface IntrinsicElements { | ||
"hcms-parent-field-provider": React.HTMLProps<HTMLDivElement>; | ||
} | ||
} | ||
} | ||
|
||
interface ParentField { | ||
value: any; | ||
setValue: (fieldId: string, cb: (prevValue: any) => any) => void; | ||
field: CmsModelField; | ||
getParentField(level: number): ParentField | undefined; | ||
path: string; | ||
} | ||
|
||
const ParentField = createContext<ParentField | undefined>(undefined); | ||
|
||
export function useParentField(level = 0): ParentField | undefined { | ||
const parent = useContext(ParentField); | ||
|
||
if (!parent) { | ||
return undefined; | ||
} | ||
|
||
return level === 0 ? parent : parent.getParentField(level); | ||
} | ||
|
||
interface ParentFieldProviderProps { | ||
value: any; | ||
path: string; | ||
children: React.ReactNode; | ||
} | ||
|
||
export const ParentFieldProvider = ({ path, value, children }: ParentFieldProviderProps) => { | ||
const parent = useContext(ParentField); | ||
const form = useForm(); | ||
const formRef = useRef<FormAPI>(); | ||
|
||
let field: CmsModelField | undefined; | ||
try { | ||
const fieldContext = useModelField(); | ||
field = fieldContext.field; | ||
} catch { | ||
field = undefined; | ||
} | ||
|
||
const getParentField = (level = 0) => { | ||
return parent ? (level === 0 ? parent : parent.getParentField(level - 1)) : undefined; | ||
}; | ||
|
||
useEffect(() => { | ||
formRef.current = form; | ||
}, [form.data]); | ||
|
||
const setValue = useCallback<ParentField["setValue"]>((fieldId, cb) => { | ||
const fieldPath = `${path}.${fieldId}`; | ||
if (!path || !formRef.current) { | ||
return; | ||
} | ||
|
||
formRef.current.setValue(fieldPath, cb(get(formRef.current.data, fieldPath))); | ||
}, []); | ||
|
||
const context: ParentField | undefined = field | ||
? { | ||
value, | ||
field, | ||
getParentField, | ||
path, | ||
setValue | ||
} | ||
: undefined; | ||
|
||
return ( | ||
<hcms-parent-field-provider data-path={path} data-field-type={field?.type}> | ||
<ParentField.Provider value={context}>{children}</ParentField.Provider> | ||
</hcms-parent-field-provider> | ||
); | ||
}; |
50 changes: 0 additions & 50 deletions
50
packages/app-headless-cms/src/admin/components/ContentEntryForm/RenderFieldElement.tsx
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.