From cb56b3ad8f532a26c7d097fd746bbcada8b9d3e2 Mon Sep 17 00:00:00 2001 From: Pavel Denisjuk Date: Tue, 2 Jul 2024 21:30:19 +0200 Subject: [PATCH 01/26] WIP: PB translations --- apps/admin/src/App.tsx | 2 + packages/app-file-manager/tsconfig.build.json | 2 +- packages/app-file-manager/tsconfig.json | 6 +- .../app-page-builder-elements/package.json | 1 + .../src/attributes/ElementAttribute.ts | 35 ++++++ .../src/contexts/Renderer.tsx | 3 +- .../src/createRenderer.tsx | 35 +++++- .../src/hooks/useRenderer.ts | 11 +- .../src/renderers/button.tsx | 103 ++++++++++++++++-- .../app-page-builder-elements/src/types.ts | 4 +- .../tsconfig.build.json | 1 + .../app-page-builder-elements/tsconfig.json | 8 +- packages/app-page-builder/package.json | 1 + .../plugins/pageDetails/header/index.tsx | 4 +- .../src/editor/components/Element.tsx | 2 +- .../ElementControlsOverlay.tsx | 2 +- .../getElementTitle.ts | 6 +- .../app-page-builder/src/editor/index.tsx | 1 + .../elementVariables/basic/button/index.tsx | 8 +- .../plugins/elements/button/PeButton.tsx | 45 ++++++-- .../src/pageEditor/Editor.tsx | 2 + .../src/translations/HeadlessCms.tsx | 63 +++++++++++ .../src/translations/PageEditorConfig.tsx | 72 ++++++++++++ .../src/translations/TranslationContext.tsx | 45 ++++++++ .../src/translations/TranslationItem.tsx | 23 ++++ .../src/translations/index.ts | 1 + packages/app-page-builder/tsconfig.build.json | 1 + packages/app-page-builder/tsconfig.json | 3 + .../HeadlessCmsContentEntry.tsx | 6 +- .../src/components/PeTextRenderer.tsx | 29 +++-- .../react-composition/src/makeDecoratable.tsx | 13 +-- yarn.lock | 2 + 32 files changed, 474 insertions(+), 66 deletions(-) create mode 100644 packages/app-page-builder-elements/src/attributes/ElementAttribute.ts create mode 100644 packages/app-page-builder/src/translations/HeadlessCms.tsx create mode 100644 packages/app-page-builder/src/translations/PageEditorConfig.tsx create mode 100644 packages/app-page-builder/src/translations/TranslationContext.tsx create mode 100644 packages/app-page-builder/src/translations/TranslationItem.tsx create mode 100644 packages/app-page-builder/src/translations/index.ts diff --git a/apps/admin/src/App.tsx b/apps/admin/src/App.tsx index ac6cee40cd1..c1d8b043cc7 100644 --- a/apps/admin/src/App.tsx +++ b/apps/admin/src/App.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Admin } from "@webiny/app-serverless-cms"; import { Cognito } from "@webiny/app-admin-users-cognito"; import { Extensions } from "./Extensions"; +import { HeadlessCms } from "@webiny/app-page-builder/translations/HeadlessCms"; import "./App.scss"; export const App = () => { @@ -9,6 +10,7 @@ export const App = () => { + ); }; diff --git a/packages/app-file-manager/tsconfig.build.json b/packages/app-file-manager/tsconfig.build.json index 74817e22279..217862e1934 100644 --- a/packages/app-file-manager/tsconfig.build.json +++ b/packages/app-file-manager/tsconfig.build.json @@ -5,9 +5,9 @@ { "path": "../app/tsconfig.build.json" }, { "path": "../app-aco/tsconfig.build.json" }, { "path": "../app-admin/tsconfig.build.json" }, - { "path": "../app-i18n/tsconfig.build.json" }, { "path": "../app-headless-cms/tsconfig.build.json" }, { "path": "../app-headless-cms-common/tsconfig.build.json" }, + { "path": "../app-i18n/tsconfig.build.json" }, { "path": "../app-security/tsconfig.build.json" }, { "path": "../app-tenancy/tsconfig.build.json" }, { "path": "../error/tsconfig.build.json" }, diff --git a/packages/app-file-manager/tsconfig.json b/packages/app-file-manager/tsconfig.json index df85064dc1e..c6f1dd20495 100644 --- a/packages/app-file-manager/tsconfig.json +++ b/packages/app-file-manager/tsconfig.json @@ -5,9 +5,9 @@ { "path": "../app" }, { "path": "../app-aco" }, { "path": "../app-admin" }, - { "path": "../app-i18n" }, { "path": "../app-headless-cms" }, { "path": "../app-headless-cms-common" }, + { "path": "../app-i18n" }, { "path": "../app-security" }, { "path": "../app-tenancy" }, { "path": "../error" }, @@ -32,12 +32,12 @@ "@webiny/app-aco": ["../app-aco/src"], "@webiny/app-admin/*": ["../app-admin/src/*"], "@webiny/app-admin": ["../app-admin/src"], - "@webiny/app-i18n/*": ["../app-i18n/src/*"], - "@webiny/app-i18n": ["../app-i18n/src"], "@webiny/app-headless-cms/*": ["../app-headless-cms/src/*"], "@webiny/app-headless-cms": ["../app-headless-cms/src"], "@webiny/app-headless-cms-common/*": ["../app-headless-cms-common/src/*"], "@webiny/app-headless-cms-common": ["../app-headless-cms-common/src"], + "@webiny/app-i18n/*": ["../app-i18n/src/*"], + "@webiny/app-i18n": ["../app-i18n/src"], "@webiny/app-security/*": ["../app-security/src/*"], "@webiny/app-security": ["../app-security/src"], "@webiny/app-tenancy/*": ["../app-tenancy/src/*"], diff --git a/packages/app-page-builder-elements/package.json b/packages/app-page-builder-elements/package.json index 19bf17d3e14..8ad50883243 100644 --- a/packages/app-page-builder-elements/package.json +++ b/packages/app-page-builder-elements/package.json @@ -18,6 +18,7 @@ "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@webiny/lexical-editor": "0.0.0", + "@webiny/react-composition": "0.0.0", "@webiny/theme": "0.0.0", "facepaint": "^1.2.1" }, diff --git a/packages/app-page-builder-elements/src/attributes/ElementAttribute.ts b/packages/app-page-builder-elements/src/attributes/ElementAttribute.ts new file mode 100644 index 00000000000..09b0670469c --- /dev/null +++ b/packages/app-page-builder-elements/src/attributes/ElementAttribute.ts @@ -0,0 +1,35 @@ +import { Element } from "~/types"; + +export interface GetElementAttributeValue { + (element: Element): TValue | undefined; +} + +export interface ElementAttributeParams { + name: string; + getValue?: GetElementAttributeValue; +} + +export class ElementAttribute { + private params: ElementAttributeParams; + + constructor(params: ElementAttributeParams) { + this.params = params; + } + + getValue(element: Element): TValue | undefined { + if (!this.params.getValue) { + return this.getValueFromDefaultLocation(element); + } + + const value = this.params.getValue(element); + if (!value) { + return undefined; + } + + return value as TValue; + } + + private getValueFromDefaultLocation(element: Element) { + return element.data.attributes[this.params.name]; + } +} diff --git a/packages/app-page-builder-elements/src/contexts/Renderer.tsx b/packages/app-page-builder-elements/src/contexts/Renderer.tsx index c0dc67bfa40..928ba3438c9 100644 --- a/packages/app-page-builder-elements/src/contexts/Renderer.tsx +++ b/packages/app-page-builder-elements/src/contexts/Renderer.tsx @@ -10,6 +10,7 @@ export const RendererProvider = ({ children, element, attributes, + inputs, meta }: RendererProviderProps) => { const getElement = () => element; @@ -18,7 +19,7 @@ export const RendererProvider = ({ const pageElements = usePageElements(); // @ts-expect-error Resolve the `getElement` issue. - const value: RendererContextValue = { ...pageElements, getElement, getAttributes, meta }; + const value: RendererContextValue = { ...pageElements, getElement, getAttributes, meta, inputs }; return {children}; }; diff --git a/packages/app-page-builder-elements/src/createRenderer.tsx b/packages/app-page-builder-elements/src/createRenderer.tsx index d0f439f5901..78ed7bcbc34 100644 --- a/packages/app-page-builder-elements/src/createRenderer.tsx +++ b/packages/app-page-builder-elements/src/createRenderer.tsx @@ -4,16 +4,21 @@ import { Renderer, Element } from "~/types"; import { Theme, StylesObject } from "@webiny/theme/types"; import { RendererProvider } from "~/contexts/Renderer"; import { CSSObject, ClassNames } from "@emotion/react"; +import { ElementAttribute } from "~/attributes/ElementAttribute"; interface GetStylesParams { theme: Theme; element: Element; } -export type CreateRendererOptions = Partial<{ +export type CreateRendererOptions< + TRenderComponentProps, + TAttributes = Record +> = Partial<{ propsAreEqual: (prevProps: TRenderComponentProps, nextProps: TRenderComponentProps) => boolean; themeStyles: StylesObject | ((params: GetStylesParams) => StylesObject); baseStyles: StylesObject | ((params: GetStylesParams) => StylesObject); + attributes: TAttributes; }>; const DEFAULT_RENDERER_STYLES: StylesObject = { @@ -23,10 +28,17 @@ const DEFAULT_RENDERER_STYLES: StylesObject = { boxSizing: "border-box" }; -export function createRenderer>( +export type GetInputs = { + inputs?: { [K in keyof T]?: T[K] extends ElementAttribute ? P : never }; +}; + +export function createRenderer< + TRenderComponentProps = Record, + TAttributes extends Record = Record +>( RendererComponent: React.ComponentType, - options: CreateRendererOptions = {} -): Renderer { + options: CreateRendererOptions = {} +): Renderer> { return function Renderer(props) { const { getElementStyles, @@ -42,9 +54,21 @@ export function createRenderer>( return null; } - const { element, meta, ...componentProps } = props; + const { element, meta, inputs = {}, ...componentProps } = props; const attributes = getElementAttributes(element); + const inputAttributes: TAttributes = options.attributes ?? ({} as TAttributes); + const inputsValues = Object.keys(inputAttributes).reduce((values, key) => { + const attribute = key in inputAttributes ? inputAttributes[key] : undefined; + if (attribute) { + // @ts-expect-error + const inputValue = key in inputs ? inputs[key] : attribute.getValue(element); + + return { ...values, [key]: inputValue }; + } + return values; + }, {}); + const styles: CSSObject[] = [DEFAULT_RENDERER_STYLES]; if (options.baseStyles) { @@ -91,6 +115,7 @@ export function createRenderer>( element={element} attributes={{ ...attributes, className: o }} meta={{ ...meta, calculatedStyles: styles }} + inputs={inputsValues} > {React.createElement( `pb-${element.type}`, diff --git a/packages/app-page-builder-elements/src/hooks/useRenderer.ts b/packages/app-page-builder-elements/src/hooks/useRenderer.ts index e6fab17224d..9c5c49ff646 100644 --- a/packages/app-page-builder-elements/src/hooks/useRenderer.ts +++ b/packages/app-page-builder-elements/src/hooks/useRenderer.ts @@ -1,7 +1,12 @@ import { useContext } from "react"; import { RendererContext } from "~/contexts/Renderer"; -import { RendererContextValue } from "~/types"; -export function useRenderer(): RendererContextValue { - return useContext(RendererContext); +export function useRenderer() { + const context = useContext(RendererContext); + + if (!context) { + throw Error(`Missing "RendererProvider" context provider in the component hierarchy!`); + } + + return context; } diff --git a/packages/app-page-builder-elements/src/renderers/button.tsx b/packages/app-page-builder-elements/src/renderers/button.tsx index c44c354baaf..9cc9b8307c9 100644 --- a/packages/app-page-builder-elements/src/renderers/button.tsx +++ b/packages/app-page-builder-elements/src/renderers/button.tsx @@ -1,11 +1,13 @@ import React, { useMemo } from "react"; -import { usePageElements } from "~/hooks/usePageElements"; -import { LinkComponent } from "~/types"; import styled, { CSSObject } from "@emotion/styled"; import { ClassNames } from "@emotion/react"; +import { makeDecoratable } from "@webiny/react-composition"; +import { usePageElements } from "~/hooks/usePageElements"; +import { LinkComponent, Element } from "~/types"; import { DefaultLinkComponent } from "~/renderers/components"; import { createRenderer } from "~/createRenderer"; import { useRenderer } from "~/hooks/useRenderer"; +import { ElementAttribute } from "~/attributes/ElementAttribute"; const ICON_POSITION_FLEX_DIRECTION: Record = { right: { flexDirection: "row-reverse" }, @@ -101,26 +103,97 @@ export interface Props { action?: ButtonElementData["action"]; } +const isButtonElement = (element: Element): element is Element => { + return "buttonText" in element.data; +}; + +export const getValueFromElement = (element: Element) => { + if (isButtonElement(element)) { + return element.data.buttonText; + } + return null; +}; + +const attributes = { + buttonText: new ElementAttribute({ + name: "buttonText", + getValue: (element: Element) => { + return element.data.buttonText; + } + }), + iconPosition: new ElementAttribute({ + name: "iconPosition", + getValue: (element: Element) => { + return element.data.icon?.position; + } + }), + iconColor: new ElementAttribute({ + name: "iconColor", + getValue: (element: Element) => { + return element.data.icon?.color; + } + }), + iconSvg: new ElementAttribute({ + name: "iconSvg", + getValue: (element: Element) => { + return element.data.icon?.svg; + } + }), + iconWidth: new ElementAttribute({ + name: "iconWidth", + getValue: (element: Element) => { + return element.data.icon?.width; + } + }), + actionType: new ElementAttribute({ + name: "actionType", + getValue: (element: Element) => { + return element.data.action?.actionType; + } + }), + actionNewTab: new ElementAttribute({ + name: "actionNewTab", + getValue: (element: Element) => { + return element.data.action?.newTab; + } + }), + actionHref: new ElementAttribute({ + name: "actionHref", + getValue: (element: Element) => { + return element.data.action?.href; + } + }) +}; + +type GetInputValues = { [K in keyof T]?: T[K] extends ElementAttribute ? P : never }; + export const createButton = (params: CreateButtonParams = {}) => { const LinkComponent = params?.linkComponent || DefaultLinkComponent; - return createRenderer( + const Renderer = createRenderer( props => { const { getStyles } = usePageElements(); - const { getElement } = useRenderer(); + const { getElement, inputs: untypedInputs } = useRenderer(); const element = getElement(); - const { link, icon } = element.data; + const { link } = element.data; - const buttonText = props.buttonText || element.data.buttonText; - const action = props.action?.href ? props.action : element.data.action; + const inputs = untypedInputs as GetInputValues; + const buttonText = inputs.buttonText || props.buttonText || ""; let buttonInnerContent = ; + const action: ButtonElementData["action"] = { + href: inputs.actionHref || "", + newTab: inputs.actionNewTab || false, + actionType: inputs.actionType || "link" + }; + let StyledButtonBody = ButtonBody, StyledButtonIcon; - if (icon && icon.svg) { - const { position = "left", color } = icon; + if (inputs.iconSvg) { + const position = inputs.iconPosition || "left"; + const color = inputs.iconColor || "#000"; StyledButtonBody = styled(StyledButtonBody)({ display: "flex", @@ -129,7 +202,7 @@ export const createButton = (params: CreateButtonParams = {}) => { StyledButtonIcon = styled(ButtonIcon)( { - width: icon.width, + width: inputs.iconWidth, ...ICON_POSITION_MARGIN[position] }, getStyles(theme => { @@ -142,7 +215,10 @@ export const createButton = (params: CreateButtonParams = {}) => { buttonInnerContent = ( <> - + {buttonInnerContent} ); @@ -215,7 +291,10 @@ export const createButton = (params: CreateButtonParams = {}) => { prevProps.buttonText === nextProps.buttonText && prevProps.action === nextProps.action ); - } + }, + attributes } ); + + return makeDecoratable("ButtonElement", Renderer); }; diff --git a/packages/app-page-builder-elements/src/types.ts b/packages/app-page-builder-elements/src/types.ts index cdc30e46dd3..b098e13e1b5 100644 --- a/packages/app-page-builder-elements/src/types.ts +++ b/packages/app-page-builder-elements/src/types.ts @@ -97,6 +97,7 @@ export interface RendererContextValue extends PageElementsContextValue { getAttributes: GetAttributes; beforeRenderer: React.ComponentType | null; afterRenderer: React.ComponentType | null; + inputs: Record; meta: RendererProviderMeta; } @@ -108,6 +109,7 @@ export interface RendererProviderProps { element: Element; attributes: HTMLAttributes; meta: RendererProviderMeta; + inputs: Record; children: React.ReactNode; } @@ -128,7 +130,7 @@ export interface PageProviderProps { export type Renderer< T = Record, TElementData = Record -> = React.ComponentType & T>; +> = React.FunctionComponent & T>; export type ElementAttributesModifier = (args: { element: Element; diff --git a/packages/app-page-builder-elements/tsconfig.build.json b/packages/app-page-builder-elements/tsconfig.build.json index 58a9bc11a38..e1cb04f697f 100644 --- a/packages/app-page-builder-elements/tsconfig.build.json +++ b/packages/app-page-builder-elements/tsconfig.build.json @@ -3,6 +3,7 @@ "include": ["src"], "references": [ { "path": "../lexical-editor/tsconfig.build.json" }, + { "path": "../react-composition/tsconfig.build.json" }, { "path": "../theme/tsconfig.build.json" } ], "compilerOptions": { diff --git a/packages/app-page-builder-elements/tsconfig.json b/packages/app-page-builder-elements/tsconfig.json index 33e3a51328c..93419bd2508 100644 --- a/packages/app-page-builder-elements/tsconfig.json +++ b/packages/app-page-builder-elements/tsconfig.json @@ -1,7 +1,11 @@ { "extends": "../../tsconfig.json", "include": ["src", "__tests__"], - "references": [{ "path": "../lexical-editor" }, { "path": "../theme" }], + "references": [ + { "path": "../lexical-editor" }, + { "path": "../react-composition" }, + { "path": "../theme" } + ], "compilerOptions": { "rootDirs": ["./src", "./__tests__"], "outDir": "./dist", @@ -11,6 +15,8 @@ "~tests/*": ["./__tests__/*"], "@webiny/lexical-editor/*": ["../lexical-editor/src/*"], "@webiny/lexical-editor": ["../lexical-editor/src"], + "@webiny/react-composition/*": ["../react-composition/src/*"], + "@webiny/react-composition": ["../react-composition/src"], "@webiny/theme/*": ["../theme/src/*"], "@webiny/theme": ["../theme/src"] }, diff --git a/packages/app-page-builder/package.json b/packages/app-page-builder/package.json index aa6e1b200eb..783e3dae13f 100644 --- a/packages/app-page-builder/package.json +++ b/packages/app-page-builder/package.json @@ -28,6 +28,7 @@ "@webiny/app": "0.0.0", "@webiny/app-aco": "0.0.0", "@webiny/app-admin": "0.0.0", + "@webiny/app-headless-cms": "0.0.0", "@webiny/app-i18n": "0.0.0", "@webiny/app-page-builder-elements": "0.0.0", "@webiny/app-plugin-admin-welcome-screen": "0.0.0", diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/header/index.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/header/index.tsx index dbeb31f4083..545578f803b 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/header/index.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/header/index.tsx @@ -25,8 +25,8 @@ const plugins: PbPageDetailsPlugin[] = [ { name: "pb-page-details-header-edit", type: "pb-page-details-header-right", - render(props) { - return ; + render() { + return ; } }, { diff --git a/packages/app-page-builder/src/editor/components/Element.tsx b/packages/app-page-builder/src/editor/components/Element.tsx index bcfd04a501c..a907c9fd8f5 100644 --- a/packages/app-page-builder/src/editor/components/Element.tsx +++ b/packages/app-page-builder/src/editor/components/Element.tsx @@ -104,7 +104,7 @@ const ElementComponent = ({ id: elementId, className = "", isActive }: ElementPr
{renderPlugins("pb-editor-page-element-action", { element, plugin })} - {pluginElementType} + {pluginElementType} | ${element.id}
); diff --git a/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/ElementControlsOverlay.tsx b/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/ElementControlsOverlay.tsx index 56088cfd275..649fbad7d3f 100644 --- a/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/ElementControlsOverlay.tsx +++ b/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/ElementControlsOverlay.tsx @@ -258,7 +258,7 @@ export const ElementControlsOverlay = (props: Props) => { return "block | unknown"; } - return getElementTitle(element.type); + return getElementTitle(element.type, element.id); }, [element.data.blockId]); // Z-index of element controls overlay depends on the depth of the page element. diff --git a/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/getElementTitle.ts b/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/getElementTitle.ts index 6584e32f359..13f11566978 100644 --- a/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/getElementTitle.ts +++ b/packages/app-page-builder/src/editor/contexts/EditorPageElementsProvider/getElementTitle.ts @@ -7,7 +7,7 @@ const titlesCache: Record = {}; * Returns element title from element's plugin. If plugin is not found, it will * return the element type. A simple cache was added to avoid unnecessary lookups. */ -export const getElementTitle = (elementType: string): string => { +export const getElementTitle = (elementType: string, suffix?: string): string => { if (elementType in titlesCache) { return titlesCache[elementType]; } @@ -30,5 +30,9 @@ export const getElementTitle = (elementType: string): string => { titlesCache[elementType] = elementType.charAt(0).toUpperCase() + elementType.slice(1); } + titlesCache[elementType] = suffix + ? `${titlesCache[elementType]} | ${suffix}` + : titlesCache[elementType]; + return titlesCache[elementType]; }; diff --git a/packages/app-page-builder/src/editor/index.tsx b/packages/app-page-builder/src/editor/index.tsx index 5a6cfd536b3..795f9b3b3a1 100644 --- a/packages/app-page-builder/src/editor/index.tsx +++ b/packages/app-page-builder/src/editor/index.tsx @@ -1,4 +1,5 @@ export { DefaultEditorConfig } from "./defaultConfig/DefaultEditorConfig"; export * from "./config"; export * from "./hooks"; +export * from "./contexts/EditorProvider"; export { default as DropZone } from "../editor/components/DropZone"; diff --git a/packages/app-page-builder/src/editor/plugins/elementVariables/basic/button/index.tsx b/packages/app-page-builder/src/editor/plugins/elementVariables/basic/button/index.tsx index 6a30e09c020..4820107c854 100644 --- a/packages/app-page-builder/src/editor/plugins/elementVariables/basic/button/index.tsx +++ b/packages/app-page-builder/src/editor/plugins/elementVariables/basic/button/index.tsx @@ -10,13 +10,17 @@ export default { getVariableValue(element) { const variables = useElementVariables(element); + if (!variables.length) { + return null; + } + return { label: - variables?.find((variable: PbBlockVariable) => + variables.find((variable: PbBlockVariable) => variable.id.endsWith(".label") )?.value || null, url: - variables?.find((variable: PbBlockVariable) => variable.id.endsWith(".url")) + variables.find((variable: PbBlockVariable) => variable.id.endsWith(".url")) ?.value || null }; }, diff --git a/packages/app-page-builder/src/editor/plugins/elements/button/PeButton.tsx b/packages/app-page-builder/src/editor/plugins/elements/button/PeButton.tsx index fc4ef20c737..cd4306c2b4e 100644 --- a/packages/app-page-builder/src/editor/plugins/elements/button/PeButton.tsx +++ b/packages/app-page-builder/src/editor/plugins/elements/button/PeButton.tsx @@ -1,9 +1,14 @@ import React from "react"; import { PbButtonElementClickHandlerPlugin } from "~/types"; -import { createButton } from "@webiny/app-page-builder-elements/renderers/button"; +import { + createButton, + getValueFromElement +} from "@webiny/app-page-builder-elements/renderers/button"; import { plugins } from "@webiny/plugins"; import { useElementVariableValue } from "~/editor/hooks/useElementVariableValue"; import { Element } from "@webiny/app-page-builder-elements/types"; +import { TranslationItem } from "~/translations"; +import { usePage } from "~/pageEditor"; const Button = createButton({ clickHandlers: () => { @@ -28,18 +33,44 @@ interface Props { const PeButton = (props: Props) => { const { element } = props; + const [page] = usePage(); const variableValue = useElementVariableValue(element); + if (variableValue) { return ( -