{"version":3,"file":"react.mjs","names":[],"sources":["../src/lib/core/LidarControlReact.tsx","../src/lib/hooks/useLidarState.ts","../src/lib/hooks/usePointCloud.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { LidarControl } from './LidarControl';\nimport type { LidarControlReactProps } from './types';\nimport { hasLidarShareParams } from '../utils/share-url';\n\n/**\n * React wrapper component for LidarControl.\n *\n * This component manages the lifecycle of a LidarControl instance,\n * adding it to the map on mount and removing it on unmount.\n *\n * @example\n * ```tsx\n * import { LidarControlReact } from 'maplibre-gl-lidar/react';\n *\n * function MyMap() {\n *   const [map, setMap] = useState<Map | null>(null);\n *\n *   return (\n *     <>\n *       <div ref={mapContainer} />\n *       {map && (\n *         <LidarControlReact\n *           map={map}\n *           title=\"LiDAR Viewer\"\n *           collapsed={false}\n *           onLoad={(pc) => console.log('Loaded:', pc)}\n *         />\n *       )}\n *     </>\n *   );\n * }\n * ```\n *\n * @param props - Component props including map instance and control options\n * @returns null - This component renders nothing directly\n */\nexport function LidarControlReact({\n  map,\n  defaultUrl,\n  onStateChange,\n  onLoad,\n  onError,\n  onControlReady,\n  ...options\n}: LidarControlReactProps): null {\n  const controlRef = useRef<LidarControl | null>(null);\n\n  useEffect(() => {\n    if (!map) return;\n\n    // Create the control instance\n    const control = new LidarControl(options);\n    controlRef.current = control;\n\n    // Register event handlers\n    if (onStateChange) {\n      control.on('statechange', (event) => {\n        onStateChange(event.state);\n      });\n    }\n\n    if (onLoad) {\n      control.on('load', (event) => {\n        // Load events always provide full PointCloudInfo (with 'name' field)\n        if (event.pointCloud && 'name' in event.pointCloud) {\n          onLoad(event.pointCloud);\n        }\n      });\n    }\n\n    if (onError) {\n      control.on('loaderror', (event) => {\n        if (event.error) {\n          onError(event.error);\n        }\n      });\n    }\n\n    // Add control to map\n    map.addControl(control, options.position || 'top-right');\n\n    // Notify that control is ready\n    if (onControlReady) {\n      onControlReady(control);\n    }\n\n    // Load default URL if provided\n    const hasShareUrl =\n      typeof window !== 'undefined' &&\n      options.restoreFromUrl !== false &&\n      hasLidarShareParams(window.location.href);\n\n    if (defaultUrl && !hasShareUrl) {\n      control.loadPointCloud(defaultUrl).catch((err) => {\n        console.error('Failed to load default URL:', err);\n      });\n    }\n\n    // Cleanup on unmount\n    return () => {\n      if (map.hasControl(control)) {\n        map.removeControl(control);\n      }\n      controlRef.current = null;\n    };\n  }, [map]);\n\n  // Update options when they change\n  useEffect(() => {\n    if (controlRef.current) {\n      // Handle collapsed state changes\n      const currentState = controlRef.current.getState();\n      if (options.collapsed !== undefined && options.collapsed !== currentState.collapsed) {\n        if (options.collapsed) {\n          controlRef.current.collapse();\n        } else {\n          controlRef.current.expand();\n        }\n      }\n\n      // Handle style changes\n      if (options.pointSize !== undefined && options.pointSize !== currentState.pointSize) {\n        controlRef.current.setPointSize(options.pointSize);\n      }\n\n      if (options.opacity !== undefined && options.opacity !== currentState.opacity) {\n        controlRef.current.setOpacity(options.opacity);\n      }\n\n      if (options.colorScheme !== undefined && options.colorScheme !== currentState.colorScheme) {\n        controlRef.current.setColorScheme(options.colorScheme);\n      }\n    }\n  }, [options.collapsed, options.pointSize, options.opacity, options.colorScheme]);\n\n  return null;\n}\n","import { useState, useCallback } from 'react';\nimport type { LidarState, ColorScheme } from '../core/types';\n\n/**\n * Default initial state for the LiDAR control\n */\nconst DEFAULT_STATE: LidarState = {\n  collapsed: true,\n  panelWidth: 365,\n  maxHeight: 500,\n  pointClouds: [],\n  activePointCloudId: null,\n  pointSize: 2,\n  opacity: 1.0,\n  colorScheme: 'elevation',\n  colormap: 'viridis',\n  colorRange: {\n    mode: 'percentile',\n    percentileLow: 2,\n    percentileHigh: 98,\n  },\n  showColorbar: true,\n  usePercentile: true,\n  elevationRange: null,\n  pointBudget: 1000000,\n  pickable: false,\n  loading: false,\n  error: null,\n  zOffsetEnabled: false,\n  zOffset: 0,\n  hiddenClassifications: new Set(),\n  availableClassifications: new Set(),\n  terrainEnabled: false,\n};\n\n/**\n * Custom hook for managing LiDAR state in React applications.\n *\n * This hook provides a simple way to track and update the state\n * of a LidarControl from React components.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n *   const { state, setPointSize, setColorScheme, toggle } = useLidarState();\n *\n *   return (\n *     <div>\n *       <button onClick={toggle}>\n *         {state.collapsed ? 'Expand' : 'Collapse'}\n *       </button>\n *       <button onClick={() => setColorScheme('intensity')}>\n *         Show Intensity\n *       </button>\n *       <LidarControlReact\n *         map={map}\n *         collapsed={state.collapsed}\n *         pointSize={state.pointSize}\n *         colorScheme={state.colorScheme}\n *         onStateChange={(newState) => setState(newState)}\n *       />\n *     </div>\n *   );\n * }\n * ```\n *\n * @param initialState - Optional initial state values\n * @returns Object containing state and update functions\n */\nexport function useLidarState(initialState?: Partial<LidarState>) {\n  const [state, setState] = useState<LidarState>({\n    ...DEFAULT_STATE,\n    ...initialState,\n  });\n\n  /**\n   * Sets the collapsed state\n   */\n  const setCollapsed = useCallback((collapsed: boolean) => {\n    setState((prev) => ({ ...prev, collapsed }));\n  }, []);\n\n  /**\n   * Sets the panel width\n   */\n  const setPanelWidth = useCallback((panelWidth: number) => {\n    setState((prev) => ({ ...prev, panelWidth }));\n  }, []);\n\n  /**\n   * Sets the point size\n   */\n  const setPointSize = useCallback((pointSize: number) => {\n    setState((prev) => ({ ...prev, pointSize }));\n  }, []);\n\n  /**\n   * Sets the opacity\n   */\n  const setOpacity = useCallback((opacity: number) => {\n    setState((prev) => ({ ...prev, opacity }));\n  }, []);\n\n  /**\n   * Sets the color scheme\n   */\n  const setColorScheme = useCallback((colorScheme: ColorScheme) => {\n    setState((prev) => ({ ...prev, colorScheme }));\n  }, []);\n\n  /**\n   * Sets whether to use percentile range for coloring\n   */\n  const setUsePercentile = useCallback((usePercentile: boolean) => {\n    setState((prev) => ({ ...prev, usePercentile }));\n  }, []);\n\n  /**\n   * Sets the elevation range filter\n   */\n  const setElevationRange = useCallback((elevationRange: [number, number] | null) => {\n    setState((prev) => ({ ...prev, elevationRange }));\n  }, []);\n\n  /**\n   * Sets the point budget\n   */\n  const setPointBudget = useCallback((pointBudget: number) => {\n    setState((prev) => ({ ...prev, pointBudget }));\n  }, []);\n\n  /**\n   * Sets whether Z offset is enabled\n   */\n  const setZOffsetEnabled = useCallback((zOffsetEnabled: boolean) => {\n    setState((prev) => ({ ...prev, zOffsetEnabled }));\n  }, []);\n\n  /**\n   * Sets the Z offset value\n   */\n  const setZOffset = useCallback((zOffset: number) => {\n    setState((prev) => ({ ...prev, zOffset }));\n  }, []);\n\n  /**\n   * Sets whether 3D terrain is enabled\n   */\n  const setTerrainEnabled = useCallback((terrainEnabled: boolean) => {\n    setState((prev) => ({ ...prev, terrainEnabled }));\n  }, []);\n\n  /**\n   * Resets the state to default values\n   */\n  const reset = useCallback(() => {\n    setState({ ...DEFAULT_STATE, ...initialState });\n  }, [initialState]);\n\n  /**\n   * Toggles the collapsed state\n   */\n  const toggle = useCallback(() => {\n    setState((prev) => ({ ...prev, collapsed: !prev.collapsed }));\n  }, []);\n\n  return {\n    state,\n    setState,\n    setCollapsed,\n    setPanelWidth,\n    setPointSize,\n    setOpacity,\n    setColorScheme,\n    setUsePercentile,\n    setElevationRange,\n    setPointBudget,\n    setZOffsetEnabled,\n    setZOffset,\n    setTerrainEnabled,\n    reset,\n    toggle,\n  };\n}\n","import { useState, useCallback } from 'react';\nimport { PointCloudLoader } from '../loaders/PointCloudLoader';\nimport type { PointCloudData, LoaderOptions } from '../loaders/types';\n\n/**\n * Result of the usePointCloud hook\n */\ninterface UsePointCloudResult {\n  /** The loaded point cloud data or null */\n  data: PointCloudData | null;\n  /** Whether loading is in progress */\n  loading: boolean;\n  /** Error if loading failed */\n  error: Error | null;\n  /** Loading progress (0-1) */\n  progress: number;\n  /** Function to load a point cloud */\n  load: (source: string | File | ArrayBuffer) => Promise<PointCloudData | null>;\n  /** Function to reset the state */\n  reset: () => void;\n}\n\n/**\n * Custom hook for loading point cloud data in React applications.\n *\n * This hook provides a simple way to load point cloud files\n * with loading state and error handling.\n *\n * @example\n * ```tsx\n * function PointCloudLoader() {\n *   const { data, loading, error, load, reset } = usePointCloud();\n *\n *   const handleFile = async (file: File) => {\n *     const result = await load(file);\n *     if (result) {\n *       console.log(`Loaded ${result.pointCount} points`);\n *     }\n *   };\n *\n *   return (\n *     <div>\n *       <input type=\"file\" onChange={(e) => handleFile(e.target.files?.[0])} />\n *       {loading && <p>Loading...</p>}\n *       {error && <p>Error: {error.message}</p>}\n *       {data && <p>Loaded {data.pointCount} points</p>}\n *     </div>\n *   );\n * }\n * ```\n *\n * @param options - Optional loader options\n * @returns Object containing state and functions\n */\nexport function usePointCloud(options?: Partial<LoaderOptions>): UsePointCloudResult {\n  const [data, setData] = useState<PointCloudData | null>(null);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n  const [progress, setProgress] = useState(0);\n\n  const load = useCallback(\n    async (source: string | File | ArrayBuffer): Promise<PointCloudData | null> => {\n      setLoading(true);\n      setError(null);\n      setProgress(0);\n\n      try {\n        const loader = new PointCloudLoader();\n        const result = await loader.load(source);\n        setData(result);\n        return result;\n      } catch (err) {\n        const e = err instanceof Error ? err : new Error(String(err));\n        setError(e);\n        return null;\n      } finally {\n        setLoading(false);\n      }\n    },\n    [options]\n  );\n\n  const reset = useCallback(() => {\n    setData(null);\n    setLoading(false);\n    setError(null);\n    setProgress(0);\n  }, []);\n\n  return { data, loading, error, progress, load, reset };\n}\n"],"mappings":"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"}