@zekidev/ui 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,171 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+
3
+ // src/sections/map/leaflet-map-inner.tsx
4
+ require('leaflet/dist/leaflet.css');
5
+ var _react = require('react');
6
+ var _leaflet = require('leaflet'); var _leaflet2 = _interopRequireDefault(_leaflet);
7
+ var _jsxruntime = require('react/jsx-runtime');
8
+ var OSM_ATTR = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
9
+ var CARTO_ATTR = `${OSM_ATTR} &copy; <a href="https://carto.com/attributions">CARTO</a>`;
10
+ var ESRI_ATTR = "Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community";
11
+ var TILES = {
12
+ // OpenStreetMap
13
+ standard: {
14
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
15
+ attribution: OSM_ATTR
16
+ },
17
+ // CartoDB Positron — clean, minimal, ideal for data overlays
18
+ light: {
19
+ url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
20
+ attribution: CARTO_ATTR
21
+ },
22
+ // CartoDB Dark Matter
23
+ dark: {
24
+ url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
25
+ attribution: CARTO_ATTR
26
+ },
27
+ // CartoDB Voyager — colorful, modern
28
+ voyager: {
29
+ url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
30
+ attribution: CARTO_ATTR
31
+ },
32
+ // OpenTopoMap — topographic with elevation contours
33
+ topo: {
34
+ url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
35
+ attribution: `${OSM_ATTR}, <a href="https://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a>`,
36
+ maxZoom: 17
37
+ },
38
+ // ESRI World Imagery — satellite/aerial photography
39
+ satellite: {
40
+ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
41
+ attribution: ESRI_ATTR,
42
+ maxZoom: 18
43
+ },
44
+ // ESRI World Street Map — detailed street basemap
45
+ streets: {
46
+ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
47
+ attribution: ESRI_ATTR,
48
+ maxZoom: 18
49
+ }
50
+ };
51
+ var markerIcon = new _leaflet2.default.Icon({
52
+ iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
53
+ iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
54
+ shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
55
+ iconSize: [25, 41],
56
+ iconAnchor: [12, 41],
57
+ popupAnchor: [1, -34],
58
+ shadowSize: [41, 41]
59
+ });
60
+ async function geocodeAddress(address) {
61
+ try {
62
+ const res = await fetch(
63
+ `https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURIComponent(address)}`,
64
+ { headers: { "Accept-Language": "en", "User-Agent": "LandingBuilder/1.0" } }
65
+ );
66
+ if (!res.ok) return null;
67
+ const data = await res.json();
68
+ if (!data.length) return null;
69
+ return [parseFloat(data[0].lat), parseFloat(data[0].lon)];
70
+ } catch (e) {
71
+ return null;
72
+ }
73
+ }
74
+ async function geocodeAll(locations) {
75
+ const result = [];
76
+ for (const loc of locations) {
77
+ if (loc.lat != null && loc.lng != null) {
78
+ result.push({ ...loc, coords: [loc.lat, loc.lng] });
79
+ continue;
80
+ }
81
+ if (loc.address) {
82
+ const coords = await geocodeAddress(loc.address);
83
+ if (coords) result.push({ ...loc, coords });
84
+ await new Promise((r) => setTimeout(r, 1e3));
85
+ }
86
+ }
87
+ return result;
88
+ }
89
+ function buildPopup(loc) {
90
+ const parts = [];
91
+ parts.push(`<strong style="display:block;font-size:13px">${loc.name}</strong>`);
92
+ if (loc.address)
93
+ parts.push(`<span style="display:block;font-size:11px;color:#6b7280;margin-top:2px">${loc.address}</span>`);
94
+ if (loc.phone)
95
+ parts.push(`<span style="display:block;font-size:11px;margin-top:2px">${loc.phone}</span>`);
96
+ if (loc.hours)
97
+ parts.push(`<span style="display:block;font-size:11px;color:#6b7280;margin-top:2px">${loc.hours}</span>`);
98
+ if (loc.address)
99
+ parts.push(
100
+ `<a href="https://maps.google.com/?q=${encodeURIComponent(loc.address)}" target="_blank" rel="noopener noreferrer" style="display:block;font-size:11px;color:#2563eb;margin-top:4px">Ver en Google Maps \u2192</a>`
101
+ );
102
+ return parts.join("");
103
+ }
104
+ function LeafletMapInner({ locations, mapStyle = "standard", className }) {
105
+ const containerRef = _react.useRef.call(void 0, null);
106
+ const mapRef = _react.useRef.call(void 0, null);
107
+ const tileRef = _react.useRef.call(void 0, null);
108
+ const [loading, setLoading] = _react.useState.call(void 0, !!_optionalChain([locations, 'optionalAccess', _ => _.length]));
109
+ _react.useEffect.call(void 0, () => {
110
+ if (!containerRef.current || mapRef.current) return;
111
+ const tile = _nullishCoalesce(TILES[mapStyle], () => ( TILES.standard));
112
+ const map = _leaflet2.default.map(containerRef.current, { scrollWheelZoom: false });
113
+ const tileLayer = _leaflet2.default.tileLayer(tile.url, { attribution: tile.attribution, maxZoom: _nullishCoalesce(tile.maxZoom, () => ( 19)) }).addTo(map);
114
+ map.setView([20, 0], 2);
115
+ mapRef.current = map;
116
+ tileRef.current = tileLayer;
117
+ return () => {
118
+ map.remove();
119
+ mapRef.current = null;
120
+ tileRef.current = null;
121
+ };
122
+ }, []);
123
+ _react.useEffect.call(void 0, () => {
124
+ if (!mapRef.current) return;
125
+ const tile = _nullishCoalesce(TILES[mapStyle], () => ( TILES.standard));
126
+ _optionalChain([tileRef, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.remove, 'call', _4 => _4()]);
127
+ tileRef.current = _leaflet2.default.tileLayer(tile.url, { attribution: tile.attribution, maxZoom: _nullishCoalesce(tile.maxZoom, () => ( 19)) }).addTo(mapRef.current);
128
+ }, [mapStyle]);
129
+ _react.useEffect.call(void 0, () => {
130
+ if (!_optionalChain([locations, 'optionalAccess', _5 => _5.length])) {
131
+ setLoading(false);
132
+ return;
133
+ }
134
+ let cancelled = false;
135
+ setLoading(true);
136
+ geocodeAll(locations).then((geocoded) => {
137
+ if (cancelled || !mapRef.current) return;
138
+ mapRef.current.eachLayer((layer) => {
139
+ if (layer instanceof _leaflet2.default.Marker) layer.remove();
140
+ });
141
+ geocoded.forEach((loc) => {
142
+ _leaflet2.default.marker(loc.coords, { icon: markerIcon }).addTo(mapRef.current).bindPopup(buildPopup(loc));
143
+ });
144
+ if (geocoded.length === 1) {
145
+ mapRef.current.setView(geocoded[0].coords, 14);
146
+ } else if (geocoded.length > 1) {
147
+ mapRef.current.fitBounds(
148
+ geocoded.map((l) => l.coords),
149
+ { padding: [48, 48] }
150
+ );
151
+ }
152
+ setLoading(false);
153
+ });
154
+ return () => {
155
+ cancelled = true;
156
+ };
157
+ }, [locations]);
158
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: `relative ${_nullishCoalesce(className, () => ( ""))}`, children: [
159
+ loading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "absolute inset-0 z-[1000] flex items-center justify-center bg-muted/80 rounded-xl", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-2 text-muted-foreground text-sm", children: [
160
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { className: "animate-spin h-6 w-6", viewBox: "0 0 24 24", fill: "none", children: [
161
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
162
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
163
+ ] }),
164
+ "Geocoding addresses\u2026"
165
+ ] }) }),
166
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: containerRef, style: { height: "100%", width: "100%" } })
167
+ ] });
168
+ }
169
+
170
+
171
+ exports.LeafletMapInner = LeafletMapInner;
@@ -0,0 +1,171 @@
1
+ "use client";
2
+
3
+ // src/sections/map/leaflet-map-inner.tsx
4
+ import "leaflet/dist/leaflet.css";
5
+ import { useEffect, useRef, useState } from "react";
6
+ import L from "leaflet";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var OSM_ATTR = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
9
+ var CARTO_ATTR = `${OSM_ATTR} &copy; <a href="https://carto.com/attributions">CARTO</a>`;
10
+ var ESRI_ATTR = "Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community";
11
+ var TILES = {
12
+ // OpenStreetMap
13
+ standard: {
14
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
15
+ attribution: OSM_ATTR
16
+ },
17
+ // CartoDB Positron — clean, minimal, ideal for data overlays
18
+ light: {
19
+ url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
20
+ attribution: CARTO_ATTR
21
+ },
22
+ // CartoDB Dark Matter
23
+ dark: {
24
+ url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
25
+ attribution: CARTO_ATTR
26
+ },
27
+ // CartoDB Voyager — colorful, modern
28
+ voyager: {
29
+ url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
30
+ attribution: CARTO_ATTR
31
+ },
32
+ // OpenTopoMap — topographic with elevation contours
33
+ topo: {
34
+ url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
35
+ attribution: `${OSM_ATTR}, <a href="https://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a>`,
36
+ maxZoom: 17
37
+ },
38
+ // ESRI World Imagery — satellite/aerial photography
39
+ satellite: {
40
+ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
41
+ attribution: ESRI_ATTR,
42
+ maxZoom: 18
43
+ },
44
+ // ESRI World Street Map — detailed street basemap
45
+ streets: {
46
+ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
47
+ attribution: ESRI_ATTR,
48
+ maxZoom: 18
49
+ }
50
+ };
51
+ var markerIcon = new L.Icon({
52
+ iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
53
+ iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
54
+ shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
55
+ iconSize: [25, 41],
56
+ iconAnchor: [12, 41],
57
+ popupAnchor: [1, -34],
58
+ shadowSize: [41, 41]
59
+ });
60
+ async function geocodeAddress(address) {
61
+ try {
62
+ const res = await fetch(
63
+ `https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURIComponent(address)}`,
64
+ { headers: { "Accept-Language": "en", "User-Agent": "LandingBuilder/1.0" } }
65
+ );
66
+ if (!res.ok) return null;
67
+ const data = await res.json();
68
+ if (!data.length) return null;
69
+ return [parseFloat(data[0].lat), parseFloat(data[0].lon)];
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
74
+ async function geocodeAll(locations) {
75
+ const result = [];
76
+ for (const loc of locations) {
77
+ if (loc.lat != null && loc.lng != null) {
78
+ result.push({ ...loc, coords: [loc.lat, loc.lng] });
79
+ continue;
80
+ }
81
+ if (loc.address) {
82
+ const coords = await geocodeAddress(loc.address);
83
+ if (coords) result.push({ ...loc, coords });
84
+ await new Promise((r) => setTimeout(r, 1e3));
85
+ }
86
+ }
87
+ return result;
88
+ }
89
+ function buildPopup(loc) {
90
+ const parts = [];
91
+ parts.push(`<strong style="display:block;font-size:13px">${loc.name}</strong>`);
92
+ if (loc.address)
93
+ parts.push(`<span style="display:block;font-size:11px;color:#6b7280;margin-top:2px">${loc.address}</span>`);
94
+ if (loc.phone)
95
+ parts.push(`<span style="display:block;font-size:11px;margin-top:2px">${loc.phone}</span>`);
96
+ if (loc.hours)
97
+ parts.push(`<span style="display:block;font-size:11px;color:#6b7280;margin-top:2px">${loc.hours}</span>`);
98
+ if (loc.address)
99
+ parts.push(
100
+ `<a href="https://maps.google.com/?q=${encodeURIComponent(loc.address)}" target="_blank" rel="noopener noreferrer" style="display:block;font-size:11px;color:#2563eb;margin-top:4px">Ver en Google Maps \u2192</a>`
101
+ );
102
+ return parts.join("");
103
+ }
104
+ function LeafletMapInner({ locations, mapStyle = "standard", className }) {
105
+ const containerRef = useRef(null);
106
+ const mapRef = useRef(null);
107
+ const tileRef = useRef(null);
108
+ const [loading, setLoading] = useState(!!locations?.length);
109
+ useEffect(() => {
110
+ if (!containerRef.current || mapRef.current) return;
111
+ const tile = TILES[mapStyle] ?? TILES.standard;
112
+ const map = L.map(containerRef.current, { scrollWheelZoom: false });
113
+ const tileLayer = L.tileLayer(tile.url, { attribution: tile.attribution, maxZoom: tile.maxZoom ?? 19 }).addTo(map);
114
+ map.setView([20, 0], 2);
115
+ mapRef.current = map;
116
+ tileRef.current = tileLayer;
117
+ return () => {
118
+ map.remove();
119
+ mapRef.current = null;
120
+ tileRef.current = null;
121
+ };
122
+ }, []);
123
+ useEffect(() => {
124
+ if (!mapRef.current) return;
125
+ const tile = TILES[mapStyle] ?? TILES.standard;
126
+ tileRef.current?.remove();
127
+ tileRef.current = L.tileLayer(tile.url, { attribution: tile.attribution, maxZoom: tile.maxZoom ?? 19 }).addTo(mapRef.current);
128
+ }, [mapStyle]);
129
+ useEffect(() => {
130
+ if (!locations?.length) {
131
+ setLoading(false);
132
+ return;
133
+ }
134
+ let cancelled = false;
135
+ setLoading(true);
136
+ geocodeAll(locations).then((geocoded) => {
137
+ if (cancelled || !mapRef.current) return;
138
+ mapRef.current.eachLayer((layer) => {
139
+ if (layer instanceof L.Marker) layer.remove();
140
+ });
141
+ geocoded.forEach((loc) => {
142
+ L.marker(loc.coords, { icon: markerIcon }).addTo(mapRef.current).bindPopup(buildPopup(loc));
143
+ });
144
+ if (geocoded.length === 1) {
145
+ mapRef.current.setView(geocoded[0].coords, 14);
146
+ } else if (geocoded.length > 1) {
147
+ mapRef.current.fitBounds(
148
+ geocoded.map((l) => l.coords),
149
+ { padding: [48, 48] }
150
+ );
151
+ }
152
+ setLoading(false);
153
+ });
154
+ return () => {
155
+ cancelled = true;
156
+ };
157
+ }, [locations]);
158
+ return /* @__PURE__ */ jsxs("div", { className: `relative ${className ?? ""}`, children: [
159
+ loading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-[1000] flex items-center justify-center bg-muted/80 rounded-xl", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-muted-foreground text-sm", children: [
160
+ /* @__PURE__ */ jsxs("svg", { className: "animate-spin h-6 w-6", viewBox: "0 0 24 24", fill: "none", children: [
161
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
162
+ /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
163
+ ] }),
164
+ "Geocoding addresses\u2026"
165
+ ] }) }),
166
+ /* @__PURE__ */ jsx("div", { ref: containerRef, style: { height: "100%", width: "100%" } })
167
+ ] });
168
+ }
169
+ export {
170
+ LeafletMapInner
171
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zekidev/ui",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {