text-editor-studio-ts
Version:
A powerful mobile-responsive rich text editor built with Lexical and React
275 lines (274 loc) • 9.52 kB
JavaScript
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