Skip to content

Commit

Permalink
fix(app-page-builder): add ResponsiveElementsProvider to fix blocks p…
Browse files Browse the repository at this point in the history
…review
  • Loading branch information
Pavel910 authored and adrians5j committed Nov 8, 2023
1 parent 3b7a462 commit 206482e
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ import { Content as ContentType } from "@webiny/app-page-builder-elements/types"
import { Content } from "@webiny/app-page-builder-elements/components/Content";
import { PbPageBlock, PbEditorElement } from "~/types";
import { addElementId } from "~/editor/helpers";
import { PageElementsProvider } from "~/contexts/PageBuilder/PageElementsProvider";

export const PreviewBlock = ({ element }: { element: PbPageBlock | PbEditorElement }) => {
const elementsWithIds = addElementId(element.content);

return (
<PageElementsProvider>
<Content content={elementsWithIds as ContentType} />
</PageElementsProvider>
);
return <Content content={elementsWithIds as ContentType} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useMemo } from "react";
import { Theme } from "@webiny/app-theme/types";
import { usePageBuilder } from "~/hooks/usePageBuilder";
import { mediaToContainer } from "./mediaToContainer";
import { PageElementsProvider } from "~/contexts/PageBuilder/PageElementsProvider";
import styled from "@emotion/styled";

const ResponsiveContainer = styled.div`
container-type: inline-size;
container-name: page-canvas;
`;

export const ResponsiveElementsProvider: React.FC = ({ children }) => {
const pageBuilder = usePageBuilder();

// We override all `@media` usages in breakpoints with `@container page-canvas`. This is what
// enables us responsive design inside the Page Builder's page editor.
const containerizedTheme = useMemo(() => {
const theme = pageBuilder.theme as Theme;

// On a couple of occasions, we've seen the `theme` object being `null` for a brief moment. This
// would happen when the theme is being loaded via a dynamic import, e.g. in a multi-theme setup.
if (!theme) {
return null;
}

return {
...pageBuilder.theme,
breakpoints: {
...theme.breakpoints,
...Object.keys(theme.breakpoints).reduce((result, breakpointName) => {
const breakpoint = theme.breakpoints[breakpointName];
return {
...result,
[breakpointName]: mediaToContainer(breakpoint)
};
}, {})
}
} as Theme;
}, [pageBuilder.theme]);

return (
<ResponsiveContainer>
<PageElementsProvider theme={containerizedTheme!}>{children}</PageElementsProvider>
</ResponsiveContainer>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ResponsiveElementsProvider";
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const minWidthRegExp = new RegExp("min-width:[ ]*([0-9a-z]*)");
const maxWidthRegExp = new RegExp("max-width:[ ]*([0-9a-z]*)");

/**
* At the moment, we only support basic transformations (check tests).
* If this won't be good enoough, we can potentially check this
* library: https://www.npmjs.com/package/media-query-parser
*/
export const mediaToContainer = (mediaQuery: string): string => {
const [, minWidth] = mediaQuery.match(minWidthRegExp) || [];
const [, maxWidth] = mediaQuery.match(maxWidthRegExp) || [];

const widthRules = [
minWidth && `(min-width: ${minWidth})`,
maxWidth && `(max-width: ${maxWidth})`
]
.filter(Boolean)
.join(" and ");

return `@container page-canvas ${widthRules}`;
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ const PageBlocks: React.FC = () => {

return (
<SplitView>
<LeftPanel>
<LeftPanel span={4}>
<BlocksByCategoriesDataList
filter={filter}
setFilter={setFilter}
canCreate={canCreate()}
/>
</LeftPanel>
<RightPanel>
<RightPanel span={8}>
<PageBlocksDataList
filter={filter}
canCreate={canCreate()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { i18n } from "@webiny/app/i18n";
import { useSnackbar } from "@webiny/app-admin/hooks/useSnackbar";
import { useConfirmationDialog } from "@webiny/app-admin/hooks/useConfirmationDialog";
import useExportBlockDialog from "~/editor/plugins/defaultBar/components/ExportBlockButton/useExportBlockDialog";
import { addElementId } from "~/editor/helpers";

import { PbPageBlock } from "~/types";
import {
Expand All @@ -25,20 +24,20 @@ import {
DELETE_PAGE_BLOCK
} from "./graphql";
import { CreatableItem } from "./PageBlocks";
import { Content } from "@webiny/app-page-builder-elements/components/Content";
import { Content as ContentType } from "@webiny/app-page-builder-elements/types";
import { PreviewBlock } from "~/admin/components/PreviewBlock";
import { ResponsiveElementsProvider } from "~/admin/components/ResponsiveElementsProvider";

const t = i18n.ns("app-page-builder/admin/page-blocks/data-list");

const List = styled("div")({
display: "flex",
flexDirection: "column",
padding: "8px",
margin: "17px 50px",
backgroundColor: "white",
boxShadow:
"0px 2px 1px -1px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%)"
});
const List = styled("div")`
display: flex;
flex-direction: column;
padding: 8px;
margin: 17px 50px;
background-color: white;
box-shadow: 0px 2px 1px -1px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%),
0px 1px 3px 0px rgb(0 0 0 / 12%);
`;

const ListItem = styled.div`
position: relative;
Expand All @@ -51,10 +50,6 @@ const ListItem = styled.div`
:last-of-type {
margin-bottom: 0;
}
img {
position: relative;
width: 100%;
}
`;

const ListItemText = styled("div")({
Expand Down Expand Up @@ -248,12 +243,12 @@ const PageBlocksDataList = ({ filter, canCreate, canEdit, canDelete }: PageBlock
}

return (
<>
<List>
{isLoading && <CircularProgress />}
<List>
{isLoading && <CircularProgress label={"Loading blocks..."} />}
<ResponsiveElementsProvider>
{filteredBlocksData.map(pageBlock => (
<ListItem key={pageBlock.id}>
<Content content={addElementId(pageBlock.content) as ContentType} />
<PreviewBlock element={pageBlock} />
<ListItemText>{pageBlock.name}</ListItemText>
<Controls>
<ExportButton
Expand Down Expand Up @@ -285,8 +280,8 @@ const PageBlocksDataList = ({ filter, canCreate, canEdit, canDelete }: PageBlock
</Controls>
</ListItem>
))}
</List>
</>
</ResponsiveElementsProvider>
</List>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ import { Theme } from "@webiny/app-theme/types";
import { plugins } from "@webiny/plugins";
import { PbRenderElementPlugin } from "~/types";

export const PageElementsProvider: React.FC = ({ children }) => {
interface PageElementsProviderProps {
theme?: Theme;
children: React.ReactNode;
}

export const PageElementsProvider = ({ theme, children }: PageElementsProviderProps) => {
const pageBuilder = usePageBuilder();

const getRenderers = useCallback(() => {
Expand Down Expand Up @@ -68,7 +73,7 @@ export const PageElementsProvider: React.FC = ({ children }) => {
return (
<PbPageElementsProvider
// We can assign `Theme` here because we know at this point we're using the new elements rendering engine.
theme={pageBuilder.theme as Theme}
theme={theme ?? (pageBuilder.theme as Theme)}
renderers={getRenderers}
modifiers={modifiers}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useInViewport } from "react-in-viewport";
import styled from "@emotion/styled";
import BlockPreview from "./BlockPreview";
import { PbEditorBlockPlugin } from "~/types";
import { ResponsiveElementsProvider } from "~/admin/components/ResponsiveElementsProvider";

interface RenderRowProps {
index: number;
Expand Down Expand Up @@ -47,6 +48,11 @@ const BlockRow = (props: RenderRowProps) => {
);
};

const BlocksResponsiveContainer = styled.div`
flex: 1 1 auto;
width: 100%;
`;

interface BlocksListProps extends Omit<RenderRowProps, "index" | "key" | "style"> {
category: string;
}
Expand Down Expand Up @@ -87,11 +93,8 @@ const BlocksList: React.FC<BlocksListProps> = props => {
}

return (
<div style={{ flex: "1 1 auto" }}>
<div
style={{ width: "800px", margin: "0 auto" }}
data-testid={"pb-editor-page-blocks-list"}
>
<BlocksResponsiveContainer data-testid={"pb-editor-page-blocks-list"}>
<ResponsiveElementsProvider>
{blocks.map((block, index) => (
<BlockRow
key={block.name}
Expand All @@ -102,8 +105,8 @@ const BlocksList: React.FC<BlocksListProps> = props => {
onDelete={props.onDelete}
/>
))}
</div>
</div>
</ResponsiveElementsProvider>
</BlocksResponsiveContainer>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export const BlockPreview = styled("div")({
export const blockStyle = css({
position: "relative",
width: "100%",
maxWidth: 800,
boxSizing: "border-box",
overflow: "hidden",
border: "1px solid var(--mdc-theme-on-background)",
Expand Down

0 comments on commit 206482e

Please sign in to comment.