UNPKG

@pnp/spfx-controls-react

Version:

Reusable React controls for SharePoint Framework solutions

204 lines • 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MaplibreWorldMap = void 0; var tslib_1 = require("tslib"); /* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/no-floating-promises */ require("maplibre-gl/dist/maplibre-gl.css"); var maplibre_1 = tslib_1.__importDefault(require("react-map-gl/maplibre")); var react_1 = tslib_1.__importStar(require("react")); var react_components_1 = require("@fluentui/react-components"); var MapNavigation_1 = tslib_1.__importDefault(require("./MapNavigation")); var Marker_1 = tslib_1.__importDefault(require("./Marker")); var css_1 = require("@emotion/css"); var ControlStrings_1 = tslib_1.__importDefault(require("ControlStrings")); var useCleanMapStyle_1 = require("./useCleanMapStyle"); var MULTI_STYLE_URLS = { satellite: function (key) { return "https://api.maptiler.com/maps/satellite/style.json?key=".concat(key); }, streets: function (key) { return "https://api.maptiler.com/maps/streets/style.json?key=".concat(key); }, topo: function (key) { return "https://api.maptiler.com/maps/topo-v2/style.json?key=".concat(key); }, demo: "https://demotiles.maplibre.org/style.json", // Free demo style (no key required) }; var useStyles = function () { return ({ container: (0, css_1.css)({ padding: '20px', }), mapContainer: (0, css_1.css)({ position: 'relative', marginTop: '20px', }), searchOverlay: (0, css_1.css)({ position: 'absolute', zIndex: 1000, maxWidth: '300px', padding: '8px', }), searchResults: (0, css_1.css)({ marginTop: '4px', fontSize: '12px', color: '#666', }), }); }; /** * Main Maplibre world map component. * expects each data to already include a `coordinates: [lon, lat]` tuple. */ var MaplibreWorldMap = function (_a) { var data = _a.data, onClick = _a.onClick, mapStyleUrl = _a.mapStyleUrl, mapKey = _a.mapKey, style = _a.style, _b = _a.fitPadding, fitPadding = _b === void 0 ? 20 : _b, theme = _a.theme, marker = _a.marker, title = _a.title, search = _a.search; var mapRef = (0, react_1.useRef)(null); var styles = useStyles(); // Determine the final map style URL based on provided props var finalMapStyleUrl = (0, react_1.useMemo)(function () { // If user provides both mapKey and mapStyleUrl, use the mapStyleUrl as-is (assuming it already includes the key) if (mapKey && mapStyleUrl) { // Check if the URL already contains a key parameter if (mapStyleUrl.includes('?key=') || mapStyleUrl.includes('&key=')) { return mapStyleUrl; } else { // Add the key to the URL var separator = mapStyleUrl.includes('?') ? '&' : '?'; return "".concat(mapStyleUrl).concat(separator, "key=").concat(mapKey); } } // If only mapKey is provided, use the default streets style with the user's key if (mapKey && !mapStyleUrl) { return MULTI_STYLE_URLS.streets(mapKey); } // If only mapStyleUrl is provided, use it as-is if (!mapKey && mapStyleUrl) { return mapStyleUrl; } // If neither is provided, use the demo style (no key required) return MULTI_STYLE_URLS.demo; }, [mapKey, mapStyleUrl]); var cleanStyle = (0, useCleanMapStyle_1.useCleanMapStyle)(finalMapStyleUrl); var _c = (0, react_1.useState)(''), searchTerm = _c[0], setSearchTerm = _c[1]; var _d = (0, react_1.useState)(data), filteredData = _d[0], setFilteredData = _d[1]; var initialViewState = (0, react_1.useState)({ longitude: 0, latitude: 20, zoom: 1 })[0]; // Search configuration with defaults var searchConfig = (0, react_1.useMemo)(function () { var _a, _b, _c, _d; return (tslib_1.__assign({ enabled: (_a = search === null || search === void 0 ? void 0 : search.enabled) !== null && _a !== void 0 ? _a : true, placeholder: (_b = search === null || search === void 0 ? void 0 : search.placeholder) !== null && _b !== void 0 ? _b : ControlStrings_1.default.worldMapSearchLocations, searchField: (_c = search === null || search === void 0 ? void 0 : search.searchField) !== null && _c !== void 0 ? _c : ControlStrings_1.default.worldMapSearchField, zoomLevel: (_d = search === null || search === void 0 ? void 0 : search.zoomLevel) !== null && _d !== void 0 ? _d : 8, position: tslib_1.__assign({ top: '10px', left: '10px' }, search === null || search === void 0 ? void 0 : search.position) }, search)); }, [search]); // Reset to initial view when search is cleared var resetToInitialView = (0, react_1.useCallback)(function () { if (mapRef.current) { if (data.length > 0) { // Fit to all data var lons = data.map(function (c) { return c.coordinates[0]; }); var lats = data.map(function (c) { return c.coordinates[1]; }); mapRef.current.getMap().fitBounds([ [Math.min.apply(Math, lons), Math.min.apply(Math, lats)], [Math.max.apply(Math, lons), Math.max.apply(Math, lats)], ], { padding: fitPadding, duration: 1000 }); } else { // Reset to initial view state mapRef.current.getMap().flyTo({ center: [initialViewState.longitude, initialViewState.latitude], zoom: initialViewState.zoom, duration: 1000, }); } } }, [data, fitPadding, initialViewState]); // Filter data based on search term var handleSearch = (0, react_1.useCallback)(function (term) { var _a, _b; setSearchTerm(term); if (!term.trim()) { setFilteredData(data); (_a = search === null || search === void 0 ? void 0 : search.onSearchChange) === null || _a === void 0 ? void 0 : _a.call(search, term, data); resetToInitialView(); return; } var filtered = data.filter(function (item) { var searchValue = typeof searchConfig.searchField === 'function' ? searchConfig.searchField(item) : item[searchConfig.searchField]; return searchValue === null || searchValue === void 0 ? void 0 : searchValue.toLowerCase().includes(term.toLowerCase()); }); setFilteredData(filtered); (_b = search === null || search === void 0 ? void 0 : search.onSearchChange) === null || _b === void 0 ? void 0 : _b.call(search, term, filtered); // Auto-zoom to first result if (filtered.length > 0 && mapRef.current) { var firstResult = filtered[0]; mapRef.current.getMap().flyTo({ center: firstResult.coordinates, zoom: searchConfig.zoomLevel, duration: 1000, }); } }, [data, search, searchConfig, resetToInitialView]); // Handle search clear var handleSearchClear = (0, react_1.useCallback)(function () { var _a; setSearchTerm(''); setFilteredData(data); (_a = search === null || search === void 0 ? void 0 : search.onSearchChange) === null || _a === void 0 ? void 0 : _a.call(search, '', data); resetToInitialView(); }, [data, search, resetToInitialView]); // Update filtered data when data prop changes (0, react_1.useEffect)(function () { if (!searchTerm.trim()) { setFilteredData(data); } else { handleSearch(searchTerm); } }, [data, searchTerm, handleSearch]); var defaultMapStyles = (0, react_1.useMemo)(function () { return ({ width: '100%', height: '600px', fontFamily: theme === null || theme === void 0 ? void 0 : theme.fontFamilyBase, paddingTop: '20px', paddingBottom: '20px', }); }, [theme]); // Fit map to loaded markers (0, react_1.useEffect)(function () { if (!mapRef.current || filteredData.length === 0) return; var lons = filteredData.map(function (c) { return c.coordinates[0]; }); var lats = filteredData.map(function (c) { return c.coordinates[1]; }); mapRef.current.getMap().fitBounds([ [Math.min.apply(Math, lons), Math.min.apply(Math, lats)], [Math.max.apply(Math, lons), Math.max.apply(Math, lats)], ], { padding: fitPadding }); }, [filteredData, fitPadding]); if (!cleanStyle) { return react_1.default.createElement(react_components_1.Text, null, ControlStrings_1.default.worldMapLoadintText); } return (react_1.default.createElement("div", { className: styles.container }, react_1.default.createElement(react_components_1.Subtitle1, null, title !== null && title !== void 0 ? title : ControlStrings_1.default.worldMapTitle), react_1.default.createElement("div", { className: styles.mapContainer }, react_1.default.createElement(maplibre_1.default, { ref: mapRef, initialViewState: { longitude: 0, latitude: 20, zoom: 1 }, style: tslib_1.__assign({}, (style !== null && style !== void 0 ? style : defaultMapStyles)), mapStyle: cleanStyle, pixelRatio: window.devicePixelRatio }, react_1.default.createElement(MapNavigation_1.default, { mapRef: mapRef, initialViewState: { longitude: 0, latitude: 20, zoom: 1 } }), filteredData.map(function (dataItem) { return (react_1.default.createElement(Marker_1.default, tslib_1.__assign({ key: dataItem.id, data: dataItem, onClick: function (e) { return onClick === null || onClick === void 0 ? void 0 : onClick(dataItem); } }, marker))); })), searchConfig.enabled && (react_1.default.createElement("div", { className: styles.searchOverlay, style: { top: searchConfig.position.top, left: searchConfig.position.left, right: searchConfig.position.right, bottom: searchConfig.position.bottom, } }, react_1.default.createElement(react_components_1.SearchBox, { placeholder: searchConfig.placeholder, value: searchTerm, onChange: function (_, data) { return handleSearch((data === null || data === void 0 ? void 0 : data.value) || ''); }, dismiss: { onClick: handleSearchClear, }, size: "medium", style: { width: '100%', minWidth: '250px' } }), searchTerm && (react_1.default.createElement("div", { className: styles.searchResults }, filteredData.length, ' ', filteredData.length === 1 ? ControlStrings_1.default.worldMapLocationLabel : ControlStrings_1.default.worldMapLocationPluralLabel, ' ', ControlStrings_1.default.worldMapFoundLabel))))))); }; exports.MaplibreWorldMap = MaplibreWorldMap; exports.default = exports.MaplibreWorldMap; //# sourceMappingURL=WorldMapControl.js.map