From 6ec259a0e71174651bae95d4628138bf6fd68742 Mon Sep 17 00:00:00 2001
From: kj_sh604
Date: Sun, 15 Mar 2026 16:19:35 -0400
Subject: refactor: packages/
---
.../excalidraw/components/hyperlink/helpers.ts | 99 ++++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 packages/excalidraw/components/hyperlink/helpers.ts
(limited to 'packages/excalidraw/components/hyperlink/helpers.ts')
diff --git a/packages/excalidraw/components/hyperlink/helpers.ts b/packages/excalidraw/components/hyperlink/helpers.ts
new file mode 100644
index 0000000..75c5dad
--- /dev/null
+++ b/packages/excalidraw/components/hyperlink/helpers.ts
@@ -0,0 +1,99 @@
+import type { GlobalPoint, Radians } from "@excalidraw/math";
+import { pointFrom, pointRotateRads } from "@excalidraw/math";
+import { MIME_TYPES } from "../../constants";
+import type { Bounds } from "../../element/bounds";
+import { getElementAbsoluteCoords } from "../../element/bounds";
+import { hitElementBoundingBox } from "../../element/collision";
+import type {
+ ElementsMap,
+ NonDeletedExcalidrawElement,
+} from "../../element/types";
+import { DEFAULT_LINK_SIZE } from "../../renderer/renderElement";
+import type { AppState, UIAppState } from "../../types";
+
+export const EXTERNAL_LINK_IMG = document.createElement("img");
+EXTERNAL_LINK_IMG.src = `data:${MIME_TYPES.svg}, ${encodeURIComponent(
+ ``,
+)}`;
+
+export const ELEMENT_LINK_IMG = document.createElement("img");
+ELEMENT_LINK_IMG.src = `data:${MIME_TYPES.svg}, ${encodeURIComponent(
+ ``,
+)}`;
+
+export const getLinkHandleFromCoords = (
+ [x1, y1, x2, y2]: Bounds,
+ angle: Radians,
+ appState: Pick,
+): Bounds => {
+ const size = DEFAULT_LINK_SIZE;
+ const linkWidth = size / appState.zoom.value;
+ const linkHeight = size / appState.zoom.value;
+ const linkMarginY = size / appState.zoom.value;
+ const centerX = (x1 + x2) / 2;
+ const centerY = (y1 + y2) / 2;
+ const centeringOffset = (size - 8) / (2 * appState.zoom.value);
+ const dashedLineMargin = 4 / appState.zoom.value;
+
+ // Same as `ne` resize handle
+ const x = x2 + dashedLineMargin - centeringOffset;
+ const y = y1 - dashedLineMargin - linkMarginY + centeringOffset;
+
+ const [rotatedX, rotatedY] = pointRotateRads(
+ pointFrom(x + linkWidth / 2, y + linkHeight / 2),
+ pointFrom(centerX, centerY),
+ angle,
+ );
+ return [
+ rotatedX - linkWidth / 2,
+ rotatedY - linkHeight / 2,
+ linkWidth,
+ linkHeight,
+ ];
+};
+
+export const isPointHittingLinkIcon = (
+ element: NonDeletedExcalidrawElement,
+ elementsMap: ElementsMap,
+ appState: AppState,
+ [x, y]: GlobalPoint,
+) => {
+ const threshold = 4 / appState.zoom.value;
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
+ const [linkX, linkY, linkWidth, linkHeight] = getLinkHandleFromCoords(
+ [x1, y1, x2, y2],
+ element.angle,
+ appState,
+ );
+ const hitLink =
+ x > linkX - threshold &&
+ x < linkX + threshold + linkWidth &&
+ y > linkY - threshold &&
+ y < linkY + linkHeight + threshold;
+ return hitLink;
+};
+
+export const isPointHittingLink = (
+ element: NonDeletedExcalidrawElement,
+ elementsMap: ElementsMap,
+ appState: AppState,
+ [x, y]: GlobalPoint,
+ isMobile: boolean,
+) => {
+ if (!element.link || appState.selectedElementIds[element.id]) {
+ return false;
+ }
+ if (
+ !isMobile &&
+ appState.viewModeEnabled &&
+ hitElementBoundingBox(x, y, element, elementsMap)
+ ) {
+ return true;
+ }
+ return isPointHittingLinkIcon(
+ element,
+ elementsMap,
+ appState,
+ pointFrom(x, y),
+ );
+};
--
cgit v1.2.3