UNPKG

react-native-leader-line

Version:

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

231 lines 8 kB
/** * @fileoverview Hook for Imperative Leader Line API * @description React hook that provides imperative leader line functionality * @version 1.2.0 * @author Federico Garcia * * @example Basic Usage * ```tsx * import React, { useRef } from 'react'; * import { View } from 'react-native'; * import { useImperativeLeaderLine } from 'react-native-leader-line'; * * const MyComponent = () => { * const startRef = useRef(null); * const endRef = useRef(null); * * const { createLine, LeaderLineContainer } = useImperativeLeaderLine(); * * const handleCreateLine = () => { * const line = createLine(startRef, endRef, { * color: 'blue', * size: 4, * endPlug: 'arrow1' * }); * * // Use imperative API * setTimeout(() => line.setOptions({ color: 'red' }), 1000); * setTimeout(() => line.hide(), 2000); * }; * * return ( * <View> * <View ref={startRef} /> * <View ref={endRef} /> * <LeaderLineContainer /> * <Button onPress={handleCreateLine} title="Create Line" /> * </View> * ); * }; * ``` */ import React, { useState, useCallback, useRef } from 'react'; import { View } from 'react-native'; import { LeaderLineImperative } from '../components/LeaderLineImperative'; /** * @hook useImperativeLeaderLine * @description Hook for managing imperative leader lines in React components * @returns {UseImperativeLeaderLineReturn} Imperative API functions and components * * @example Multiple Lines Management * ```tsx * const { createLine, removeLine, removeAllLines, LeaderLineContainer } = useImperativeLeaderLine(); * * const line1 = createLine(ref1, ref2, { color: 'red' }); * const line2 = createLine(ref2, ref3, { color: 'blue' }); * * // Remove specific line * removeLine(line1.id); * * // Remove all lines * removeAllLines(); * ``` */ export function useImperativeLeaderLine() { const [lines, setLines] = useState(new Map()); const lineIdCounter = useRef(0); /** * @function generateLineId * @description Generate a unique ID for a line instance * @returns {string} Unique line ID */ const generateLineId = useCallback(() => { lineIdCounter.current += 1; return `leader-line-${lineIdCounter.current}-${Date.now()}`; }, []); /** * @function createLine * @description Create a new imperative leader line * @param {React.RefObject<any> | Point} start - Start element or point * @param {React.RefObject<any> | Point} end - End element or point * @param {ImperativeLeaderLineOptions} options - Line options * @returns {LeaderLineImperative} Leader line instance with additional methods */ const createLine = useCallback((start, end, options = {}) => { const lineId = generateLineId(); // Create render callback that updates the lines state const renderCallback = (component) => { setLines(prevLines => { var _a; const newLines = new Map(prevLines); if (((_a = component.props.style) === null || _a === void 0 ? void 0 : _a.display) === 'none') { // Component is being removed newLines.delete(lineId); } else { // Component is being added/updated const existingInstance = newLines.get(lineId); if (existingInstance) { newLines.set(lineId, { ...existingInstance, component: React.cloneElement(component, { key: lineId }) }); } } return newLines; }); }; // Create the imperative leader line instance const lineInstance = new LeaderLineImperative(start, end, options, renderCallback); // Add custom remove method that cleans up from hook state const originalRemove = lineInstance.remove.bind(lineInstance); lineInstance.remove = () => { originalRemove(); setLines(prevLines => { const newLines = new Map(prevLines); newLines.delete(lineId); return newLines; }); }; // Add the line to our state when it's first created const initialComponent = React.createElement(View, { key: lineId, style: { position: 'absolute' } }); setLines(prevLines => { const newLines = new Map(prevLines); newLines.set(lineId, { id: lineId, line: lineInstance, component: initialComponent }); return newLines; }); // Extend instance with ID for external reference lineInstance.id = lineId; return lineInstance; }, [generateLineId]); /** * @function removeLine * @description Remove a specific line by ID * @param {string} lineId - ID of the line to remove * @returns {void} */ const removeLine = useCallback((lineId) => { const lineInstance = lines.get(lineId); if (lineInstance) { lineInstance.line.remove(); } }, [lines]); /** * @function removeAllLines * @description Remove all active lines * @returns {void} */ const removeAllLines = useCallback(() => { lines.forEach(lineInstance => { lineInstance.line.remove(); }); setLines(new Map()); }, [lines]); /** * @function getActiveLines * @description Get all currently active line instances * @returns {ImperativeLineInstance[]} Array of active line instances */ const getActiveLines = useCallback(() => { return Array.from(lines.values()); }, [lines]); /** * @component LeaderLineContainer * @description Container component that renders all active leader lines * @returns {React.ReactElement} Container with all line components */ const LeaderLineContainer = useCallback(() => { const lineComponents = Array.from(lines.values()).map(lineInstance => lineInstance.component); return React.createElement(View, { style: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'none' }, key: 'leader-line-container' }, ...lineComponents); }, [lines]); return { createLine, removeLine, removeAllLines, getActiveLines, LeaderLineContainer }; } /** * @hook useLeaderLineCompatibility * @description Hook that provides global leader-line compatibility * @returns {Object} Global LeaderLine constructor and utilities * * @example Global API (leader-line compatibility) * ```tsx * const { LeaderLine } = useLeaderLineCompatibility(); * * // Use like original leader-line * const line = new LeaderLine(startElement, endElement, { * color: 'coral', * size: 4 * }); * ``` */ export function useLeaderLineCompatibility() { const { createLine, LeaderLineContainer } = useImperativeLeaderLine(); // Create a constructor function that mimics the original LeaderLine const LeaderLineConstructor = function (start, end, options = {}) { const line = createLine(start, end, options); // Copy all methods to 'this' for constructor pattern Object.setPrototypeOf(this, line); Object.assign(this, line); return this; }; // Add static methods/properties for compatibility LeaderLineConstructor.prototype = LeaderLineImperative.prototype; return { LeaderLine: LeaderLineConstructor, LeaderLineContainer, createLine }; } export default useImperativeLeaderLine; //# sourceMappingURL=useImperativeLeaderLine.js.map