UNPKG

text-editor-studio-ts

Version:

A powerful mobile-responsive rich text editor built with Lexical and React

275 lines (274 loc) 9.52 kB
import { jsxs, jsx } from "react/jsx-runtime"; import { useRef } from "react"; import { calculateZoomLevel } from "@lexical/utils"; import { B as Button } from "./index-BwW17RmP.js"; function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } const Direction = { east: 1 << 0, north: 1 << 3, south: 1 << 1, west: 1 << 2 }; function ImageResizer({ onResizeStart, onResizeEnd, buttonRef, imageRef, maxWidth, editor, showCaption, setShowCaption, captionsEnabled }) { const controlWrapperRef = useRef(null); const userSelect = useRef({ priority: "", value: "default" }); const positioningRef = useRef({ currentHeight: 0, currentWidth: 0, direction: 0, isResizing: false, ratio: 0, startHeight: 0, startWidth: 0, startX: 0, startY: 0 }); const editorRootElement = editor.getRootElement(); const maxWidthContainer = maxWidth ? maxWidth : editorRootElement !== null ? editorRootElement.getBoundingClientRect().width - 20 : 100; const maxHeightContainer = editorRootElement !== null ? editorRootElement.getBoundingClientRect().height - 20 : 100; const minWidth = 100; const minHeight = 100; const setStartCursor = (direction) => { const ew = direction === Direction.east || direction === Direction.west; const ns = direction === Direction.north || direction === Direction.south; const nwse = direction & Direction.north && direction & Direction.west || direction & Direction.south && direction & Direction.east; const cursorDir = ew ? "ew" : ns ? "ns" : nwse ? "nwse" : "nesw"; if (editorRootElement !== null) { editorRootElement.style.setProperty( "cursor", `${cursorDir}-resize`, "important" ); } if (document.body !== null) { document.body.style.setProperty( "cursor", `${cursorDir}-resize`, "important" ); userSelect.current.value = document.body.style.getPropertyValue( "-webkit-user-select" ); userSelect.current.priority = document.body.style.getPropertyPriority( "-webkit-user-select" ); document.body.style.setProperty( "-webkit-user-select", `none`, "important" ); } }; const setEndCursor = () => { if (editorRootElement !== null) { editorRootElement.style.setProperty("cursor", "text"); } if (document.body !== null) { document.body.style.setProperty("cursor", "default"); document.body.style.setProperty( "-webkit-user-select", userSelect.current.value, userSelect.current.priority ); } }; const handlePointerDown = (event, direction) => { if (!editor.isEditable()) { return; } const image = imageRef.current; const controlWrapper = controlWrapperRef.current; if (image !== null && controlWrapper !== null) { event.preventDefault(); const { width, height } = image.getBoundingClientRect(); const zoom = calculateZoomLevel(image); const positioning = positioningRef.current; positioning.startWidth = width; positioning.startHeight = height; positioning.ratio = width / height; positioning.currentWidth = width; positioning.currentHeight = height; positioning.startX = event.clientX / zoom; positioning.startY = event.clientY / zoom; positioning.isResizing = true; positioning.direction = direction; setStartCursor(direction); onResizeStart(); controlWrapper.classList.add("touch-action-none"); image.style.height = `${height}px`; image.style.width = `${width}px`; document.addEventListener("pointermove", handlePointerMove); document.addEventListener("pointerup", handlePointerUp); } }; const handlePointerMove = (event) => { const image = imageRef.current; const positioning = positioningRef.current; const isHorizontal = positioning.direction & (Direction.east | Direction.west); const isVertical = positioning.direction & (Direction.south | Direction.north); if (image !== null && positioning.isResizing) { const zoom = calculateZoomLevel(image); if (isHorizontal && isVertical) { let diff = Math.floor(positioning.startX - event.clientX / zoom); diff = positioning.direction & Direction.east ? -diff : diff; const width = clamp( positioning.startWidth + diff, minWidth, maxWidthContainer ); const height = width / positioning.ratio; image.style.width = `${width}px`; image.style.height = `${height}px`; positioning.currentHeight = height; positioning.currentWidth = width; } else if (isVertical) { let diff = Math.floor(positioning.startY - event.clientY / zoom); diff = positioning.direction & Direction.south ? -diff : diff; const height = clamp( positioning.startHeight + diff, minHeight, maxHeightContainer ); image.style.height = `${height}px`; positioning.currentHeight = height; } else { let diff = Math.floor(positioning.startX - event.clientX / zoom); diff = positioning.direction & Direction.east ? -diff : diff; const width = clamp( positioning.startWidth + diff, minWidth, maxWidthContainer ); image.style.width = `${width}px`; positioning.currentWidth = width; } } }; const handlePointerUp = () => { const image = imageRef.current; const positioning = positioningRef.current; const controlWrapper = controlWrapperRef.current; if (image !== null && controlWrapper !== null && positioning.isResizing) { const width = positioning.currentWidth; const height = positioning.currentHeight; positioning.startWidth = 0; positioning.startHeight = 0; positioning.ratio = 0; positioning.startX = 0; positioning.startY = 0; positioning.currentWidth = 0; positioning.currentHeight = 0; positioning.isResizing = false; controlWrapper.classList.remove("touch-action-none"); setEndCursor(); onResizeEnd(width, height); document.removeEventListener("pointermove", handlePointerMove); document.removeEventListener("pointerup", handlePointerUp); } }; return /* @__PURE__ */ jsxs("div", { ref: controlWrapperRef, children: [ !showCaption && captionsEnabled && /* @__PURE__ */ jsx( Button, { className: "image-caption-button absolute bottom-1 left-1/2 -translate-x-1/2", ref: buttonRef, variant: "BorderStyle", onClick: () => { setShowCaption(!showCaption); }, children: "Add Caption" } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-n absolute -top-2.5 left-1/2 h-3 w-3 -translate-x-1/2 cursor-ns-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.north); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-ne absolute -right-2.5 -top-2.5 h-3 w-3 cursor-nesw-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.north | Direction.east); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-e absolute -right-2.5 top-1/2 h-3 w-3 -translate-y-1/2 cursor-ew-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.east); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-se absolute -bottom-2.5 -right-2.5 h-3 w-3 cursor-nwse-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.south | Direction.east); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-s absolute -bottom-2.5 left-1/2 h-3 w-3 -translate-x-1/2 cursor-ns-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.south); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-sw absolute -bottom-2.5 -left-2.5 h-3 w-3 cursor-nesw-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.south | Direction.west); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-w absolute -left-2.5 top-1/2 h-3 w-3 -translate-y-1/2 cursor-ew-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.west); } } ), /* @__PURE__ */ jsx( "div", { className: "image-resizer image-resizer-nw absolute -left-2.5 -top-2.5 h-3 w-3 cursor-nwse-resize bg-background-presentation-action-primary", onPointerDown: (event) => { handlePointerDown(event, Direction.north | Direction.west); } } ) ] }); } export { ImageResizer as I }; //# sourceMappingURL=image-resizer-CFedlLqf.js.map