UNPKG

expo-osm-sdk

Version:

OpenStreetMap component for React Native with Expo

401 lines 19.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const react_native_1 = require("react-native"); // Dynamic imports for MapLibre component let MapLibreOSMView = null; const loadMapLibreComponent = async () => { try { if (typeof window !== 'undefined') { // Check if MapLibre GL is available await Promise.resolve().then(() => __importStar(require('maplibre-gl'))); // Load our MapLibre component const module = await Promise.resolve().then(() => __importStar(require('./OSMView.maplibre.web'))); MapLibreOSMView = module.default; return true; } return false; } catch (error) { console.log('🗺️ MapLibre not available, using fallback UI'); return false; } }; /** * Smart Web component for OSMView. * * Automatically detects if MapLibre GL is available: * - If available: Uses real interactive maps with MapLibre GL JS * - If not available: Uses safe fallback UI * * This provides the best experience while maintaining safety. */ const OSMView = (0, react_1.forwardRef)((props, ref) => { const [mapLibreAvailable, setMapLibreAvailable] = (0, react_1.useState)(null); // Check for MapLibre availability on mount (0, react_1.useEffect)(() => { loadMapLibreComponent().then(setMapLibreAvailable); }, []); // While checking availability, show loading if (mapLibreAvailable === null) { return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.container, props.style], children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.loadingContainer, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.loadingText, children: "\uD83D\uDDFA\uFE0F Initializing Map..." }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.loadingSubtext, children: "Checking for MapLibre GL availability" })] }) })); } // If MapLibre is available, use the real map component if (mapLibreAvailable && MapLibreOSMView) { return (0, jsx_runtime_1.jsx)(MapLibreOSMView, { ...props, ref: ref }); } // Otherwise, use the safe fallback component return (0, jsx_runtime_1.jsx)(FallbackOSMView, { ...props, ref: ref }); }); /** * Safe fallback component when MapLibre is not available. * * SAFETY: This component safely handles ALL OSMViewProps without breaking, * provides useful fallback UI, and calls event handlers appropriately. * It also implements the OSMViewRef interface with safe fallback methods. */ const FallbackOSMView = (0, react_1.forwardRef)((props, ref) => { // SAFE: Destructure all props with safe defaults const { style, initialCenter = { latitude: 0, longitude: 0 }, initialZoom = 10, markers = [], polylines = [], polygons = [], circles = [], overlays = [], showUserLocation = false, followUserLocation = false, showsCompass = false, showsScale = false, showsZoomControls = false, // Event handlers - safely extracted onMapReady, onRegionChange, onPress, onLongPress, onMarkerPress, onUserLocationChange, // Other props are safely ignored ...restProps } = props; // Safe refs for avoiding memory leaks const hasCalledOnMapReady = (0, react_1.useRef)(false); // SAFE: Call onMapReady once like the native component would (0, react_1.useEffect)(() => { if (onMapReady && !hasCalledOnMapReady.current) { hasCalledOnMapReady.current = true; // Simulate native map ready with small delay const timer = setTimeout(() => { try { onMapReady(); } catch (error) { console.warn('OSMView.web: onMapReady handler error:', error); } }, 100); return () => clearTimeout(timer); } // Return undefined for code paths that don't set up cleanup return undefined; }, [onMapReady]); // SAFE: Count total overlay elements const totalOverlays = markers.length + polylines.length + polygons.length + circles.length + overlays.length; // SAFE: Implement ref methods that won't crash but provide useful feedback (0, react_1.useImperativeHandle)(ref, () => ({ // Zoom methods - safe fallbacks zoomIn: async () => { console.log('OSMView.web: zoomIn() called - not available on web'); return Promise.resolve(); }, zoomOut: async () => { console.log('OSMView.web: zoomOut() called - not available on web'); return Promise.resolve(); }, setZoom: async (zoom) => { console.log(`OSMView.web: setZoom(${zoom}) called - not available on web`); return Promise.resolve(); }, // Camera methods - safe fallbacks animateToLocation: async (latitude, longitude, zoom) => { console.log(`OSMView.web: animateToLocation(${latitude}, ${longitude}, ${zoom}) called - not available on web`); return Promise.resolve(); }, animateToRegion: async (region, duration) => { console.log('OSMView.web: animateToRegion() called - not available on web'); return Promise.resolve(); }, fitToMarkers: async (markerIds, padding) => { console.log('OSMView.web: fitToMarkers() called - not available on web'); return Promise.resolve(); }, // Location methods - safe fallbacks getCurrentLocation: async () => { console.log('OSMView.web: getCurrentLocation() called - not available on web'); return Promise.resolve(initialCenter); }, startLocationTracking: async () => { console.log('OSMView.web: startLocationTracking() called - not available on web'); return Promise.resolve(); }, stopLocationTracking: async () => { console.log('OSMView.web: stopLocationTracking() called - not available on web'); return Promise.resolve(); }, waitForLocation: async (timeoutSeconds = 30) => { console.log(`OSMView.web: waitForLocation(${timeoutSeconds}) called - not available on web`); return Promise.resolve(initialCenter); }, // Marker methods - safe fallbacks addMarker: async (marker) => { console.log('OSMView.web: addMarker() called - not available on web'); return Promise.resolve(); }, removeMarker: async (markerId) => { console.log(`OSMView.web: removeMarker(${markerId}) called - not available on web`); return Promise.resolve(); }, updateMarker: async (markerId, updates) => { console.log(`OSMView.web: updateMarker(${markerId}) called - not available on web`); return Promise.resolve(); }, animateMarker: async (markerId, animation) => { console.log(`OSMView.web: animateMarker(${markerId}) called - not available on web`); return Promise.resolve(); }, showInfoWindow: async (markerId) => { console.log(`OSMView.web: showInfoWindow(${markerId}) called - not available on web`); return Promise.resolve(); }, hideInfoWindow: async (markerId) => { console.log(`OSMView.web: hideInfoWindow(${markerId}) called - not available on web`); return Promise.resolve(); }, // Overlay methods - safe fallbacks addPolyline: async (polyline) => { console.log('OSMView.web: addPolyline() called - not available on web'); return Promise.resolve(); }, removePolyline: async (polylineId) => { console.log(`OSMView.web: removePolyline(${polylineId}) called - not available on web`); return Promise.resolve(); }, updatePolyline: async (polylineId, updates) => { console.log(`OSMView.web: updatePolyline(${polylineId}) called - not available on web`); return Promise.resolve(); }, addPolygon: async (polygon) => { console.log('OSMView.web: addPolygon() called - not available on web'); return Promise.resolve(); }, removePolygon: async (polygonId) => { console.log(`OSMView.web: removePolygon(${polygonId}) called - not available on web`); return Promise.resolve(); }, updatePolygon: async (polygonId, updates) => { console.log(`OSMView.web: updatePolygon(${polygonId}) called - not available on web`); return Promise.resolve(); }, addCircle: async (circle) => { console.log('OSMView.web: addCircle() called - not available on web'); return Promise.resolve(); }, removeCircle: async (circleId) => { console.log(`OSMView.web: removeCircle(${circleId}) called - not available on web`); return Promise.resolve(); }, updateCircle: async (circleId, updates) => { console.log(`OSMView.web: updateCircle(${circleId}) called - not available on web`); return Promise.resolve(); }, addOverlay: async (overlay) => { console.log('OSMView.web: addOverlay() called - not available on web'); return Promise.resolve(); }, removeOverlay: async (overlayId) => { console.log(`OSMView.web: removeOverlay(${overlayId}) called - not available on web`); return Promise.resolve(); }, updateOverlay: async (overlayId, updates) => { console.log(`OSMView.web: updateOverlay(${overlayId}) called - not available on web`); return Promise.resolve(); }, // Map utilities - safe fallbacks coordinateForPoint: async (point) => { console.log(`OSMView.web: coordinateForPoint(${point.x}, ${point.y}) called - not available on web`); return Promise.resolve(initialCenter); }, pointForCoordinate: async (coordinate) => { console.log('OSMView.web: pointForCoordinate() called - not available on web'); return Promise.resolve({ x: 0, y: 0 }); }, takeSnapshot: async (format, quality) => { console.log(`OSMView.web: takeSnapshot(${format}, ${quality}) called - not available on web`); return Promise.resolve('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='); }, // Helper methods isViewReady: async () => { return Promise.resolve(true); // Web fallback is always "ready" }, }), [initialCenter]); // SAFE: Handle press events if provided const handlePress = () => { if (onPress) { try { // Simulate a press at the center of the map onPress(initialCenter); } catch (error) { console.warn('OSMView.web: onPress handler error:', error); } } }; return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.container, style], onTouchStart: handlePress, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.content, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.title, children: "\uD83D\uDDFA\uFE0F expo-osm-sdk" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.subtitle, children: "Web Fallback" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.description, children: "Native map component not available on web platform." }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.configCard, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.configTitle, children: "\uD83D\uDCCA Map Configuration" }), (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.configText, children: ["\uD83D\uDCCD Center: ", initialCenter.latitude.toFixed(4), ", ", initialCenter.longitude.toFixed(4)] }), (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.configText, children: ["\uD83D\uDD0D Zoom Level: ", initialZoom] }), totalOverlays > 0 && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.overlayInfo, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.configText, children: "\uD83C\uDFAF Map Elements:" }), markers.length > 0 && (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.overlayText, children: ["\uD83D\uDCCC ", markers.length, " markers"] }), polylines.length > 0 && (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.overlayText, children: ["\uD83D\uDCCF ", polylines.length, " polylines"] }), polygons.length > 0 && (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.overlayText, children: ["\uD83D\uDD36 ", polygons.length, " polygons"] }), circles.length > 0 && (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.overlayText, children: ["\u2B55 ", circles.length, " circles"] }), overlays.length > 0 && (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.overlayText, children: ["\uD83C\uDFA8 ", overlays.length, " custom overlays"] })] })), (showUserLocation || followUserLocation || showsCompass || showsScale || showsZoomControls) && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.featuresInfo, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.configText, children: "\u2699\uFE0F Enabled Features:" }), showUserLocation && (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.featureText, children: "\u2022 User location display" }), followUserLocation && (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.featureText, children: "\u2022 Follow user location" }), showsCompass && (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.featureText, children: "\u2022 Compass control" }), showsScale && (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.featureText, children: "\u2022 Scale indicator" }), showsZoomControls && (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.featureText, children: "\u2022 Zoom controls" })] }))] }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.suggestion, children: "\uD83D\uDCA1 For web maps, consider: react-leaflet, mapbox-gl, or Google Maps" }), onPress && ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.interactionHint, children: "\uD83D\uDC46 Tap anywhere to trigger onPress event" }))] }) })); }); const styles = react_native_1.StyleSheet.create({ container: { flex: 1, backgroundColor: '#f8fafc', alignItems: 'center', justifyContent: 'center', borderWidth: 2, borderColor: '#e2e8f0', borderRadius: 12, padding: 20, minHeight: 200, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f8fafc', padding: 20, }, loadingText: { fontSize: 18, fontWeight: '600', color: '#2d3748', marginBottom: 8, }, loadingSubtext: { fontSize: 14, color: '#718096', textAlign: 'center', lineHeight: 20, }, content: { alignItems: 'center', maxWidth: 500, width: '100%', }, title: { fontSize: 24, fontWeight: 'bold', color: '#1a202c', marginBottom: 4, textAlign: 'center', }, subtitle: { fontSize: 14, color: '#718096', marginBottom: 16, fontWeight: '500', textAlign: 'center', }, description: { fontSize: 14, color: '#4a5568', textAlign: 'center', marginBottom: 16, lineHeight: 20, }, configCard: { backgroundColor: '#ffffff', padding: 16, borderRadius: 12, width: '100%', marginBottom: 16, borderWidth: 1, borderColor: '#e2e8f0', shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.05, shadowRadius: 2, elevation: 1, }, configTitle: { fontSize: 16, fontWeight: '600', color: '#2d3748', marginBottom: 12, textAlign: 'center', }, configText: { fontSize: 14, color: '#4a5568', marginBottom: 6, fontFamily: 'monospace', }, overlayInfo: { marginTop: 8, paddingTop: 8, borderTopWidth: 1, borderTopColor: '#e2e8f0', }, overlayText: { fontSize: 13, color: '#718096', marginLeft: 8, marginBottom: 2, }, featuresInfo: { marginTop: 8, paddingTop: 8, borderTopWidth: 1, borderTopColor: '#e2e8f0', }, featureText: { fontSize: 13, color: '#718096', marginLeft: 8, marginBottom: 2, }, suggestion: { fontSize: 12, color: '#718096', textAlign: 'center', fontStyle: 'italic', marginBottom: 8, }, interactionHint: { fontSize: 12, color: '#3182ce', textAlign: 'center', fontWeight: '500', backgroundColor: '#ebf8ff', paddingHorizontal: 12, paddingVertical: 6, borderRadius: 16, }, }); // Set display names for debugging OSMView.displayName = 'OSMView'; FallbackOSMView.displayName = 'FallbackOSMView'; exports.default = OSMView; //# sourceMappingURL=OSMView.web.js.map