UNPKG

react-native-leader-line

Version:

React Native port of leader-line library for drawing arrow lines and connectors

84 lines 3.75 kB
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { getSocketPoint, measureElement } from "../utils/math"; // Helper function to convert BoundingBox to ElementLayout const boundingBoxToLayout = (box) => ({ x: box.x, y: box.y, width: box.width, height: box.height, pageX: box.x, pageY: box.y, timestamp: Date.now(), }); export const useLeaderLine = ({ startElement, endElement, startBox, endBox, startSocket = "center", endSocket = "center", observeChanges = true, }) => { const [connectionPoints, setConnectionPoints] = useState(null); const [isReady, setIsReady] = useState(false); // Use number instead of NodeJS.Timeout for React Native compatibility const intervalRef = useRef(null); const calculateConnectionPoint = useCallback((box, position) => { const layout = boundingBoxToLayout(box); return getSocketPoint(layout, position); }, []); const updateConnectionPoints = useCallback(async () => { try { if (startBox && endBox) { // Use provided bounding boxes const adjustedStartBox = boundingBoxToLayout(startBox); const adjustedEndBox = boundingBoxToLayout(endBox); const points = { start: getSocketPoint(adjustedStartBox, startSocket), end: getSocketPoint(adjustedEndBox, endSocket), }; setConnectionPoints(points); setIsReady(true); } else if ((startElement === null || startElement === void 0 ? void 0 : startElement.current) && (endElement === null || endElement === void 0 ? void 0 : endElement.current)) { // Measure elements const startLayout = await measureElement(startElement); const endLayout = await measureElement(endElement); if (startLayout && endLayout) { const points = { start: getSocketPoint(startLayout, startSocket), end: getSocketPoint(endLayout, endSocket), }; setConnectionPoints(points); setIsReady(true); } } } catch (error) { console.warn("Error calculating connection points:", error); setIsReady(false); } }, [startElement, endElement, startBox, endBox, startSocket, endSocket]); useEffect(() => { updateConnectionPoints(); }, [updateConnectionPoints]); // Use interval-based observation for React Native instead of ResizeObserver useEffect(() => { if (!observeChanges) return; const startEl = startElement === null || startElement === void 0 ? void 0 : startElement.current; const endEl = endElement === null || endElement === void 0 ? void 0 : endElement.current; if (startEl && endEl) { // Poll for changes every 100ms (adjust as needed) intervalRef.current = setInterval(() => { updateConnectionPoints(); }, 100); } return () => { if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; } }; }, [startElement, endElement, observeChanges, updateConnectionPoints]); // Memoize return object to prevent unnecessary re-renders return useMemo(() => ({ connectionPoints, isReady, updateConnectionPoints, calculateConnectionPoint, }), [connectionPoints, isReady, updateConnectionPoints, calculateConnectionPoint]); }; //# sourceMappingURL=useLeaderLine.js.map