diff --git a/bun.lockb b/bun.lockb index c422350..6b3f159 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 667f1ba..81d9907 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,6 @@ "sonner": "^1.5.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", - "usehooks-ts": "^3.1.0", "zod": "^3.23.8", "zustand": "^4.5.4" }, diff --git a/src/components/editor/action.ts b/src/components/editor/action.ts index 1bdf46c..79a3730 100644 --- a/src/components/editor/action.ts +++ b/src/components/editor/action.ts @@ -35,7 +35,6 @@ type EditorActionMap = { elementDetails: EditorElement; }; CHANGE_CLICKED_ELEMENT: { - elementRef?: React.RefObject<HTMLDivElement>; elementDetails?: EditorElement; }; CHANGE_CURRENT_TAB_VALUE: { @@ -320,7 +319,6 @@ const actionHandlers: { return updateEditorHistory(editor, { ...editor.state, selectedElement: payload.elementDetails ?? emptyElement, - selectedElementRef: payload.elementRef, currentTabValue: newTabValue, }); }, diff --git a/src/components/editor/elements/element-helper.tsx b/src/components/editor/elements/element-helper.tsx index 1888637..929c1e0 100644 --- a/src/components/editor/elements/element-helper.tsx +++ b/src/components/editor/elements/element-helper.tsx @@ -7,10 +7,10 @@ import { GripVerticalIcon, Trash2Icon, } from "lucide-react"; -import { useRef } from "react"; +import { useCallback, useEffect, useState } from "react"; import { createPortal } from "react-dom"; -import { useResizeObserver } from "usehooks-ts"; import { useEditor } from "~/components/editor/provider"; +import { isValidSelectEditorElement } from "~/components/editor/util"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; import { cn } from "~/lib/utils"; @@ -18,13 +18,30 @@ import { cn } from "~/lib/utils"; export default function ElementHelper() { const { editor, dispatch } = useEditor(); const element = editor.state.selectedElement; - const elementRef = editor.state.selectedElementRef; - const emptyRef = useRef<HTMLDivElement>(null); - const { width, height } = useResizeObserver({ - ref: elementRef ?? emptyRef, - box: "border-box", - }); + const [layerStyle, setLayerStyle] = useState<React.CSSProperties>({}); + + const updateLayerStyle = useCallback((id: string) => { + const el = document.querySelector(`[data-element-id="${id}"]`); + + if (!el) { + return; + } + + const resizeObserver = new ResizeObserver(() => { + const { top, left, width, height } = el.getBoundingClientRect(); + setLayerStyle({ top, left, width, height }); + }); + + resizeObserver.observe(el, { box: "border-box" }); + return () => { + resizeObserver.unobserve(el); + }; + }, []); + + useEffect(() => { + return updateLayerStyle(element.id); + }, [element.id, updateLayerStyle]); const handleMoveUp = (e: React.MouseEvent) => { e.stopPropagation(); @@ -34,6 +51,7 @@ export default function ElementHelper() { elementId: element.id, }, }); + updateLayerStyle(element.id); }; const handleMoveDown = (e: React.MouseEvent) => { @@ -44,6 +62,7 @@ export default function ElementHelper() { elementId: element.id, }, }); + updateLayerStyle(element.id); }; const handleDeleteElement = () => { @@ -58,14 +77,9 @@ export default function ElementHelper() { return ( typeof window !== "undefined" && createPortal( - !editor.state.isPreviewMode && elementRef?.current && ( + !editor.state.isPreviewMode && isValidSelectEditorElement(element) && ( <div - style={{ - top: elementRef.current.getBoundingClientRect().top, - left: elementRef.current.getBoundingClientRect().left, - width, - height, - }} + style={layerStyle} className={cn( "fixed z-50", !editor.state.isPreviewMode && "ring-1 ring-primary", diff --git a/src/components/editor/elements/element-wrapper.tsx b/src/components/editor/elements/element-wrapper.tsx index e6482d3..9e5114c 100644 --- a/src/components/editor/elements/element-wrapper.tsx +++ b/src/components/editor/elements/element-wrapper.tsx @@ -1,4 +1,3 @@ -import { useRef } from "react"; import { useEditor } from "~/components/editor/provider"; import type { EditorElement } from "~/components/editor/type"; import { cn } from "~/lib/utils"; @@ -16,15 +15,12 @@ export default function ElementWrapper({ const { editor, dispatch } = useEditor(); const isRoot = element.type === "__body"; - const rootRef = useRef<HTMLDivElement>(null); - const handleClick = (e: React.MouseEvent) => { e.stopPropagation(); dispatch({ type: "CHANGE_CLICKED_ELEMENT", payload: { - elementRef: rootRef, elementDetails: element, }, }); @@ -33,7 +29,7 @@ export default function ElementWrapper({ return ( <div {...props} - ref={rootRef} + data-element-id={element.id} style={element.styles} className={cn( "relative w-full transition-all", diff --git a/src/components/editor/type.ts b/src/components/editor/type.ts index 26a22b1..543a5af 100644 --- a/src/components/editor/type.ts +++ b/src/components/editor/type.ts @@ -35,7 +35,6 @@ export type InferEditorElement<K extends EditorElementType> = Extract< export type EditorState = { elements: EditorElement[]; selectedElement: EditorElement; - selectedElementRef?: React.RefObject<HTMLDivElement>; currentTabValue: EditorTabTypeValue; device: DeviceType; isPreviewMode: boolean;