expo-osm-sdk
Version:
OpenStreetMap component for React Native with Expo
401 lines • 19.1 kB
JavaScript
"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