Skip to content

Commit

Permalink
fix(app-page-builder): optimize Image element renderer (#3984)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavel910 authored Mar 8, 2024
1 parent 477d5ee commit c0c5b23
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 52 deletions.
12 changes: 8 additions & 4 deletions packages/app-page-builder-elements/src/components/Elements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ const getElementKey = (
elementIndex: number,
parentBlockElement?: ElementType
) => {
let parts: string[] = [element.id];

if (parentBlockElement) {
return `${parentBlockElement.id}-${elementIndex}`;
parts = [parentBlockElement.id, elementIndex.toString()];
}
return element.id;
// Add element type for easier debugging and more clarity in the profiler.
parts.push(element.type);

return parts.join("-");
};

export interface ElementsProps {
Expand Down Expand Up @@ -68,8 +73,7 @@ export const Elements = (props: ElementsProps) => {
parentDocumentElement,
isFirstElement: index === 0,
isLastElement: index === elements.length - 1,
elementIndex: index,
collection: elements
elementIndex: index
}}
/>
);
Expand Down
39 changes: 23 additions & 16 deletions packages/app-page-builder-elements/src/renderers/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export interface ImageRendererComponentProps extends Props, CreateImageParams {}

const SUPPORTED_IMAGE_RESIZE_WIDTHS = [100, 300, 500, 750, 1000, 1500, 2500];

const PbImg = styled.img`
max-width: 100%;
width: ${props => props.width};
height: ${props => props.height};
`;

export const ImageRendererComponent = ({
onClick,
renderEmpty,
Expand All @@ -32,31 +38,21 @@ export const ImageRendererComponent = ({
linkComponent
}: ImageRendererComponentProps) => {
const LinkComponent = linkComponent || DefaultLinkComponent;

const { getElement } = useRenderer();

const element = getElement<ImageElementData>();

let content;
if (element.data?.image?.file?.src) {
// Image has its width / height set from its own settings.
const PbImg = styled.img({
width: element.data.image.width,
height: element.data.image.height,
maxWidth: "100%"
});

const { title } = element.data.image;
const { src } = value || element.data?.image?.file;
const { title, width, height, file } = element.data.image;
const { src } = value || file;

// If a fixed image width in pixels was set, let's filter out unneeded
// image resize widths. For example, if 155px was set as the fixed image
// width, then we want the `srcset` attribute to only contain 100w and 300w.
let srcSetWidths: number[] = [];

const imageWidth = element.data.image.width;
if (imageWidth && imageWidth.endsWith("px")) {
const imageWidthInt = parseInt(imageWidth);
if (width && width.endsWith("px")) {
const imageWidthInt = parseInt(width);
for (let i = 0; i < SUPPORTED_IMAGE_RESIZE_WIDTHS.length; i++) {
const supportedResizeWidth = SUPPORTED_IMAGE_RESIZE_WIDTHS[i];
if (imageWidthInt > supportedResizeWidth) {
Expand All @@ -78,7 +74,18 @@ export const ImageRendererComponent = ({
})
.join(", ");

content = <PbImg alt={title} title={title} src={src} srcSet={srcSet} onClick={onClick} />;
content = (
<PbImg
// Image has its width / height set from its own settings.
width={width}
height={height}
alt={title}
title={title}
src={src}
srcSet={srcSet}
onClick={onClick}
/>
);
} else {
content = renderEmpty || null;
}
Expand Down Expand Up @@ -108,7 +115,7 @@ export const imageRendererOptions: CreateRendererOptions<Props> = {
export type ImageRenderer = ReturnType<typeof createImage>;

interface Props {
onClick?: React.MouseEventHandler<HTMLImageElement>;
onClick?: () => void;
renderEmpty?: React.ReactNode;
value?: { id: string; src: string };
link?: { href: string; newTab?: boolean };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export const ElementControlHorizontalDropZones = () => {
{meta.isLastElement && (
<Droppable
isVisible={() => true}
onDrop={source => dropElementAction(source, meta.collection?.length)}
onDrop={source => dropElementAction(source, meta.elementIndex + 1)}
type={type}
>
{({ drop, isOver }) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { ReactComponent as AddImageIcon } from "@webiny/ui/ImageUpload/icons/rou
import { Typography } from "@webiny/ui/Typography";
import { useElementVariableValue } from "~/editor/hooks/useElementVariableValue";
import { createRenderer, useRenderer } from "@webiny/app-page-builder-elements";
import { useActiveElementId } from "~/editor/hooks/useActiveElementId";

const RenderBlank = (props: { onClick?: () => void }) => {
return (
Expand All @@ -22,14 +21,12 @@ const RenderBlank = (props: { onClick?: () => void }) => {
);
};

const emptyLink = { href: "" };

const PeImage = createRenderer(() => {
const { getElement } = useRenderer();
const element = getElement();
const variableValue = useElementVariableValue(element);

const [activeElementId] = useActiveElementId();
const isActive = activeElementId === element.id;

const handler = useEventActionHandler();

const id = element?.id;
Expand All @@ -55,33 +52,20 @@ const PeImage = createRenderer(() => {
[id]
);

if (isActive) {
return (
<FileManager
onChange={onChange}
render={({ showFileManager }) => (
<ImageRendererComponent
onClick={() => showFileManager()}
renderEmpty={<RenderBlank onClick={showFileManager} />}
value={variableValue}
// Even if the link might've been applied via the right sidebar, we still don't
// want to have it rendered in the editor. Because, otherwise, user wouldn't be
// able to click again on the component and bring back the file manager overlay.
link={{ href: "" }}
/>
)}
/>
);
}

return (
<ImageRendererComponent
renderEmpty={<RenderBlank />}
value={variableValue}
// Even if the link might've been applied via the right sidebar, we still don't
// want to have it rendered in the editor. Because, otherwise, user wouldn't be
// able to click again on the component and bring back the file manager overlay.
link={{ href: "" }}
<FileManager
onChange={onChange}
render={({ showFileManager }) => (
<ImageRendererComponent
onClick={showFileManager}
renderEmpty={<RenderBlank onClick={showFileManager} />}
value={variableValue}
// Even if the link might've been applied via the right sidebar, we still don't
// want to have it rendered in the editor. Because, otherwise, user wouldn't be
// able to click again on the component and bring back the file manager overlay.
link={emptyLink}
/>
)}
/>
);
});
Expand Down

0 comments on commit c0c5b23

Please sign in to comment.