Skip to content

Commit

Permalink
wip: zoom controls and autozoom
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Mar 2, 2024
1 parent 72dd57a commit 45f0744
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 68 deletions.
7 changes: 6 additions & 1 deletion packages/core/components/DraggableComponent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import getClassNameFactory from "../../lib/get-class-name-factory";
import { Copy, Trash } from "lucide-react";
import { useModifierHeld } from "../../lib/use-modifier-held";
import { ClipLoader } from "react-spinners";
import { useAppContext } from "../Puck/context";

const getClassName = getClassNameFactory("DraggableComponent", styles);

Expand Down Expand Up @@ -51,6 +52,7 @@ export const DraggableComponent = ({
indicativeHover?: boolean;
style?: CSSProperties;
}) => {
const { state } = useAppContext();
const isModifierHeld = useModifierHeld("Alt");

useEffect(onMount, []);
Expand Down Expand Up @@ -92,7 +94,10 @@ export const DraggableComponent = ({
<ClipLoader aria-label="loading" size={16} color="inherit" />
</div>
)}
<div className={getClassName("overlay")}>
<div
className={getClassName("overlay")}
style={{ zoom: 1 / state.ui.viewport.zoom }}
>
<div className={getClassName("actions")}>
{label && (
<div className={getClassName("actionsLabel")}>{label}</div>
Expand Down
1 change: 0 additions & 1 deletion packages/core/components/DropZone/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export type DropZoneContext<
pathData?: PathData;
registerPath?: (selector: ItemSelector) => void;
mode?: "edit" | "render";
disableZoom?: boolean;
} | null;

export const dropZoneContext = createContext<DropZoneContext>(null);
Expand Down
2 changes: 0 additions & 2 deletions packages/core/components/DropZone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ function DropZoneEdit({ zone, allow, disallow, style }: DropZoneProps) {
registerZoneArea,
areasWithZones,
hoveringComponent,
disableZoom = false,
} = ctx! || {};

let content = data.content || [];
Expand Down Expand Up @@ -172,7 +171,6 @@ function DropZoneEdit({ zone, allow, disallow, style }: DropZoneProps) {
isDisabled: !isEnabled,
isAreaSelected,
hasChildren: content.length > 0,
zoomEnabled: !disableZoom,
})}
>
<Droppable
Expand Down
8 changes: 0 additions & 8 deletions packages/core/components/DropZone/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@
width: 100%;
}

.DropZone--zoomEnabled {
zoom: 1.33;
}

.DropZone--zoomEnabled .DropZone-renderWrapper {
zoom: 0.75;
}

.DropZone-content {
min-height: 128px;
height: 100%;
Expand Down
141 changes: 141 additions & 0 deletions packages/core/components/Puck/components/Canvas/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { getBox } from "css-box-model";
import {
ReactNode,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useAppContext } from "../../context";
import { ViewportControls } from "../../../ViewportControls";
import styles from "../../styles.module.css";
import { getClassNameFactory } from "../../../../lib";
import { Preview } from "../Preview";

const getClassName = getClassNameFactory("Puck", styles);

export const Canvas = () => {
const { dispatch, state, overrides } = useAppContext();
const { ui } = state;
const frameRef = useRef<HTMLDivElement>(null);

const [rootHeight, setRootHeight] = useState(0);
const [autoZoom, setAutoZoom] = useState(1);

const defaultRender = useMemo<
React.FunctionComponent<{ children?: ReactNode }>
>(() => {
const PuckDefault = ({ children }: { children?: ReactNode }) => (
<>{children}</>
);

return PuckDefault;
}, []);

const CustomPreview = useMemo(
() => overrides.preview || defaultRender,
[overrides]
);

// TODO deal with window resize
const resetAutoZoom = useCallback(() => {
if (frameRef.current) {
const frame = frameRef.current;

const box = getBox(frame);
const frameWidth = box.contentBox.width;
const frameHeight = box.contentBox.height;

const viewportHeight =
ui.viewport.height === "auto" ? frameHeight : ui.viewport.height;

if (ui.viewport.width > frameWidth || viewportHeight > frameHeight) {
const widthZoom = Math.min(frameWidth / ui.viewport.width, 1);
const heightZoom = Math.min(frameHeight / viewportHeight, 1);

let zoom = widthZoom;

if (widthZoom < heightZoom) {
setRootHeight(viewportHeight / zoom);
} else {
setRootHeight(viewportHeight);
zoom = heightZoom;
}

setAutoZoom(zoom);

dispatch({
type: "setUi",
ui: {
...ui,
viewport: {
...ui.viewport,
zoom,
},
},
});
} else {
setAutoZoom(1);

if (ui.viewport.zoom === autoZoom) {
setRootHeight(viewportHeight);

dispatch({
type: "setUi",
ui: {
...ui,
viewport: {
...ui.viewport,
zoom: 1,
},
},
});
} else {
setRootHeight(viewportHeight / ui.viewport.zoom);
}
}
}
}, [frameRef, ui.leftSideBarVisible, ui, autoZoom]);

// Auto zoom
useEffect(() => {
resetAutoZoom();
}, [
frameRef,
ui.leftSideBarVisible,
ui.rightSideBarVisible,
ui.viewport.width,
]);

return (
<div
className={getClassName("canvas")}
onClick={() =>
dispatch({
type: "setUi",
ui: { itemSelector: null },
recordHistory: true,
})
}
>
<div className={getClassName("canvasControls")}>
<ViewportControls autoZoom={autoZoom} />
</div>
<div className={getClassName("frame")} ref={frameRef}>
<div
className={getClassName("root")}
style={{
width: ui.viewport.width,
height: rootHeight,
transform: `scale(${ui.viewport.zoom})`,
}}
>
<CustomPreview>
<Preview />
</CustomPreview>
</div>
</div>
</div>
);
};
14 changes: 5 additions & 9 deletions packages/core/components/Puck/components/Preview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DropZone, dropZoneContext } from "../../../DropZone";
import { DropZone } from "../../../DropZone";
import { rootDroppableId } from "../../../../lib/root-droppable-id";
import { useCallback, useContext, useRef } from "react";
import { useCallback, useRef } from "react";
import { useAppContext } from "../../context";
import AutoFrame from "@measured/auto-frame-component";
import styles from "./styles.module.css";
Expand All @@ -22,8 +22,6 @@ export const Preview = ({ id = "puck-preview" }: { id?: string }) => {
// DEPRECATED
const rootProps = state.data.root.props || state.data.root;

const { disableZoom = false } = useContext(dropZoneContext) || {};

const ref = useRef<HTMLIFrameElement>(null);

return (
Expand All @@ -40,11 +38,9 @@ export const Preview = ({ id = "puck-preview" }: { id?: string }) => {
data-rfd-iframe
ref={ref}
>
<div style={{ zoom: disableZoom ? 1 : 0.75 }}>
<Page dispatch={dispatch} state={state} {...rootProps}>
<DropZone zone={rootDroppableId} />
</Page>
</div>
<Page dispatch={dispatch} state={state} {...rootProps}>
<DropZone zone={rootDroppableId} />
</Page>
</AutoFrame>
</div>
);
Expand Down
3 changes: 2 additions & 1 deletion packages/core/components/Puck/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export const defaultAppState: AppState = {
componentList: {},
isDragging: false,
viewport: {
width: viewports.desktop,
width: viewports.large.width,
height: viewports.large.height,
zoom: 1,
},
},
Expand Down
32 changes: 3 additions & 29 deletions packages/core/components/Puck/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
useEffect,
useMemo,
useReducer,
useRef,
useState,
} from "react";
import { DragDropContext, DragStart, DragUpdate } from "@measured/dnd";
Expand Down Expand Up @@ -42,7 +43,7 @@ import { Overrides } from "../../types/Overrides";
import { loadOverrides } from "../../lib/load-overrides";
import { usePuckHistory } from "../../lib/use-puck-history";
import { useHistoryStore } from "../../lib/use-history-store";
import { ViewportControls } from "../ViewportControls";
import { Canvas } from "./components/Canvas";

const getClassName = getClassNameFactory("Puck", styles);

Expand Down Expand Up @@ -281,10 +282,6 @@ export function Puck<
[loadedOverrides]
);

const CustomPreview = useMemo(
() => loadedOverrides.preview || defaultRender,
[loadedOverrides]
);
const CustomHeader = useMemo(
() => loadedOverrides.header || defaultHeaderRender,
[loadedOverrides]
Expand All @@ -294,8 +291,6 @@ export function Puck<
[loadedOverrides]
);

const disableZoom = children || loadedOverrides.puck ? true : false;

return (
<div className="Puck">
<AppProvider
Expand Down Expand Up @@ -387,7 +382,6 @@ export function Puck<
placeholderStyle,
mode: "edit",
areaId: "root",
disableZoom,
}}
>
<CustomPuck>
Expand All @@ -397,7 +391,6 @@ export function Puck<
leftSideBarVisible,
menuOpen,
rightSideBarVisible,
disableZoom,
})}
>
<CustomHeader
Expand Down Expand Up @@ -488,26 +481,7 @@ export function Puck<
<Outline />
</SidebarSection>
</div>
<div
className={getClassName("canvas")}
onClick={() => setItemSelector(null)}
>
<div className={getClassName("canvasControls")}>
<ViewportControls />
</div>
<div className={getClassName("frame")}>
<div
className={getClassName("root")}
style={{
width: ui.viewport.width,
}}
>
<CustomPreview>
<Preview />
</CustomPreview>
</div>
</div>
</div>
<Canvas />
<div className={getClassName("rightSideBar")}>
<SidebarSection
noPadding
Expand Down
15 changes: 13 additions & 2 deletions packages/core/components/Puck/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
display: flex;
height: 100%;
justify-content: center;
overflow: auto;
overflow: hidden;
padding: var(--puck-space-px);
position: relative;
width: 100%;
Expand All @@ -187,7 +187,18 @@
background: white;
border: 1px solid var(--puck-color-grey-09);
min-width: 321px;
transition: width 150ms ease-out;
transition: width 150ms ease-out, transform 150ms ease-out,
height 150ms ease-out;
position: absolute;
transform-origin: top;
top: 0;
bottom: 0;
}

@media (min-width: 1198px) {
.Puck-root {
min-width: unset;
}
}

.Puck-rightSideBar {
Expand Down
Loading

0 comments on commit 45f0744

Please sign in to comment.