mehdi-akbari-map 0.0.4 → 0.0.6
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.
- package/dist/components/Map.d.ts +2 -1
- package/dist/components/Map.d.ts.map +1 -1
- package/dist/index.cjs +89 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +89 -63
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +89 -63
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +89 -63
- package/dist/react.js.map +1 -1
- package/dist/utils/createCustomMarkerElement.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/components/Map.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { MapProps } from '../types';
|
|
2
|
+
import type { MapProps } from '../types';
|
|
3
|
+
import '@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css';
|
|
3
4
|
declare const Map: React.FC<MapProps>;
|
|
4
5
|
export default Map;
|
|
5
6
|
//# sourceMappingURL=Map.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Map.d.ts","sourceRoot":"","sources":["../../src/components/Map.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Map.d.ts","sourceRoot":"","sources":["../../src/components/Map.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAyB,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEhE,OAAO,yDAAyD,CAAC;AAEjE,QAAA,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CA2E3B,CAAC;AAEF,eAAe,GAAG,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -36,95 +36,121 @@ module.exports = __toCommonJS(src_exports);
|
|
|
36
36
|
|
|
37
37
|
// src/components/Map.tsx
|
|
38
38
|
var import_react = require("react");
|
|
39
|
+
|
|
40
|
+
// src/utils/createCustomMarkerElement.ts
|
|
41
|
+
function createCustomMarkerElement({
|
|
42
|
+
marker,
|
|
43
|
+
isSelected,
|
|
44
|
+
logoSrc = "",
|
|
45
|
+
showPrice = true
|
|
46
|
+
}) {
|
|
47
|
+
const wrapper = document.createElement("div");
|
|
48
|
+
Object.assign(wrapper.style, {
|
|
49
|
+
display: "flex",
|
|
50
|
+
flexDirection: "column",
|
|
51
|
+
alignItems: "center",
|
|
52
|
+
cursor: "pointer",
|
|
53
|
+
transition: "all 0.3s ease",
|
|
54
|
+
transform: isSelected ? "scale(1.2)" : "scale(1)",
|
|
55
|
+
zIndex: isSelected ? "10" : "1"
|
|
56
|
+
});
|
|
57
|
+
const iconTarget = document.createElement("div");
|
|
58
|
+
Object.assign(iconTarget.style, {
|
|
59
|
+
width: "40px",
|
|
60
|
+
height: "40px",
|
|
61
|
+
borderRadius: "50%",
|
|
62
|
+
backgroundColor: "white",
|
|
63
|
+
border: isSelected ? "3px solid #3b82f6" : "2px solid #ef4444",
|
|
64
|
+
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
|
|
65
|
+
display: "flex",
|
|
66
|
+
alignItems: "center",
|
|
67
|
+
justifyContent: "center",
|
|
68
|
+
overflow: "hidden"
|
|
69
|
+
});
|
|
70
|
+
if (logoSrc) {
|
|
71
|
+
const img = document.createElement("img");
|
|
72
|
+
img.src = logoSrc;
|
|
73
|
+
img.style.width = "80%";
|
|
74
|
+
img.style.height = "80%";
|
|
75
|
+
img.style.objectFit = "contain";
|
|
76
|
+
iconTarget.appendChild(img);
|
|
77
|
+
} else {
|
|
78
|
+
iconTarget.style.backgroundColor = "#ef4444";
|
|
79
|
+
}
|
|
80
|
+
wrapper.appendChild(iconTarget);
|
|
81
|
+
if (showPrice && (marker.name || marker.price)) {
|
|
82
|
+
const label = document.createElement("div");
|
|
83
|
+
Object.assign(label.style, {
|
|
84
|
+
backgroundColor: "white",
|
|
85
|
+
padding: "2px 8px",
|
|
86
|
+
borderRadius: "4px",
|
|
87
|
+
marginTop: "4px",
|
|
88
|
+
fontSize: "11px",
|
|
89
|
+
fontWeight: "bold",
|
|
90
|
+
whiteSpace: "nowrap",
|
|
91
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
92
|
+
border: "1px solid #ddd"
|
|
93
|
+
});
|
|
94
|
+
const labelText = marker.price ? `${marker.price} \u062A` : marker.name;
|
|
95
|
+
label.textContent = labelText || "";
|
|
96
|
+
}
|
|
97
|
+
return wrapper;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/components/Map.tsx
|
|
101
|
+
var import_NeshanMapboxGl = require("@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css");
|
|
39
102
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
40
103
|
var Map = ({
|
|
41
104
|
options,
|
|
42
105
|
markers = [],
|
|
43
106
|
selectedMarkerId = null,
|
|
44
107
|
onMarkerClick,
|
|
45
|
-
onMapLoad,
|
|
46
|
-
children,
|
|
47
108
|
className = "",
|
|
48
109
|
style = { width: "100%", height: "100%" }
|
|
49
110
|
}) => {
|
|
50
111
|
const mapContainerRef = (0, import_react.useRef)(null);
|
|
51
|
-
const
|
|
112
|
+
const [mapInstance, setMapInstance] = (0, import_react.useState)(null);
|
|
52
113
|
const markersRef = (0, import_react.useRef)([]);
|
|
53
114
|
const [mapLib, setMapLib] = (0, import_react.useState)(null);
|
|
54
|
-
const [isLoaded, setIsLoaded] = (0, import_react.useState)(false);
|
|
55
115
|
(0, import_react.useEffect)(() => {
|
|
56
|
-
if (typeof window === "undefined") return;
|
|
57
|
-
let canceled = false;
|
|
58
116
|
import("@neshan-maps-platform/mapbox-gl").then((mod) => {
|
|
59
|
-
|
|
60
|
-
setMapLib(mod.default || mod);
|
|
61
|
-
setIsLoaded(true);
|
|
62
|
-
}
|
|
63
|
-
}).catch((err) => {
|
|
64
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0644\u0648\u062F \u0646\u0642\u0634\u0647 \u0646\u0634\u0627\u0646:", err);
|
|
117
|
+
setMapLib(mod.default || mod);
|
|
65
118
|
});
|
|
66
|
-
return () => {
|
|
67
|
-
canceled = true;
|
|
68
|
-
};
|
|
69
119
|
}, []);
|
|
70
120
|
(0, import_react.useEffect)(() => {
|
|
71
|
-
if (!mapLib || !mapContainerRef.current ||
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
map
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
markersRef.current.forEach((m) => m.remove());
|
|
83
|
-
markersRef.current = [];
|
|
84
|
-
if (mapInstanceRef.current) {
|
|
85
|
-
mapInstanceRef.current.remove();
|
|
86
|
-
mapInstanceRef.current = null;
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
} catch (err) {
|
|
90
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0633\u0627\u062E\u062A \u0646\u0642\u0634\u0647:", err);
|
|
91
|
-
}
|
|
92
|
-
}, [mapLib, options, onMapLoad]);
|
|
121
|
+
if (!mapLib || !mapContainerRef.current || mapInstance) return;
|
|
122
|
+
const map = new mapLib.Map({
|
|
123
|
+
container: mapContainerRef.current,
|
|
124
|
+
...options
|
|
125
|
+
});
|
|
126
|
+
map.on("load", () => {
|
|
127
|
+
setMapInstance(map);
|
|
128
|
+
});
|
|
129
|
+
return () => {
|
|
130
|
+
};
|
|
131
|
+
}, [mapLib]);
|
|
93
132
|
(0, import_react.useEffect)(() => {
|
|
94
|
-
if (!
|
|
95
|
-
markersRef.current.forEach((m) => m.remove());
|
|
96
|
-
markersRef.current = [];
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
133
|
+
if (!mapInstance || !mapLib) return;
|
|
99
134
|
markersRef.current.forEach((m) => m.remove());
|
|
100
135
|
markersRef.current = [];
|
|
101
136
|
markers.forEach((markerData, index) => {
|
|
102
|
-
const
|
|
103
|
-
el
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"></div>
|
|
112
|
-
`;
|
|
113
|
-
el.style.cursor = "pointer";
|
|
114
|
-
el.style.transition = "transform 0.3s ease";
|
|
115
|
-
el.style.transform = markerData.id === selectedMarkerId ? "scale(1.4)" : "scale(1)";
|
|
116
|
-
const marker = new mapLib.Marker({ element: el }).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstanceRef.current);
|
|
137
|
+
const isSelected = markerData.id === selectedMarkerId;
|
|
138
|
+
const el = createCustomMarkerElement({
|
|
139
|
+
marker: markerData,
|
|
140
|
+
isSelected
|
|
141
|
+
});
|
|
142
|
+
const marker = new mapLib.Marker({
|
|
143
|
+
element: el,
|
|
144
|
+
anchor: "bottom"
|
|
145
|
+
}).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstance);
|
|
117
146
|
el.addEventListener("click", (e) => {
|
|
118
147
|
e.stopPropagation();
|
|
119
|
-
onMarkerClick?.(markerData, index,
|
|
148
|
+
onMarkerClick?.(markerData, index, mapInstance);
|
|
120
149
|
});
|
|
121
150
|
markersRef.current.push(marker);
|
|
122
151
|
});
|
|
123
|
-
}, [markers,
|
|
124
|
-
|
|
125
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", background: "#f3f4f6" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "\u062F\u0631 \u062D\u0627\u0644 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0646\u0642\u0634\u0647..." }) });
|
|
126
|
-
}
|
|
127
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: mapContainerRef, className, style, children });
|
|
152
|
+
}, [markers, mapInstance, selectedMarkerId]);
|
|
153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "relative", ...style }, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: mapContainerRef, style: { width: "100%", height: "100%" } }) });
|
|
128
154
|
};
|
|
129
155
|
var Map_default = Map;
|
|
130
156
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/Map.tsx"],"sourcesContent":["\r\n\r\n\r\nexport { default as NeshanMap } from './components/Map';\r\n\r\n\r\nexport type {\r\n MapProps,\r\n MapOptions,\r\n MarkerData,\r\n MapboxMap,\r\n LngLatLike,\r\n} from './types';\r\n\r\n\r\n\r\n\r\n\r\n\r\nimport './styles.css';","\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/Map.tsx","../src/utils/createCustomMarkerElement.ts"],"sourcesContent":["\r\n\r\n\r\nexport { default as NeshanMap } from './components/Map';\r\n\r\n\r\nexport type {\r\n MapProps,\r\n MapOptions,\r\n MarkerData,\r\n MapboxMap,\r\n LngLatLike,\r\n} from './types';\r\n\r\n\r\n\r\n\r\n\r\n\r\nimport './styles.css';","\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport type { MapboxMap, MarkerData, MapProps } from '../types';\r\nimport { createCustomMarkerElement } from '../utils/createCustomMarkerElement';\r\nimport '@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const [mapInstance, setMapInstance] = useState<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n\r\n \r\n useEffect(() => {\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n setMapLib(mod.default || mod);\r\n });\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstance) return;\r\n\r\n const map = new mapLib.Map({\r\n container: mapContainerRef.current,\r\n ...options,\r\n });\r\n\r\n map.on('load', () => {\r\n setMapInstance(map);\r\n });\r\n\r\n return () => {\r\n \r\n };\r\n }, [mapLib]); \r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstance || !mapLib) return;\r\n\r\n \r\n markersRef.current.forEach((m) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData, index) => {\r\n const isSelected = markerData.id === selectedMarkerId;\r\n const el = createCustomMarkerElement({\r\n marker: markerData,\r\n isSelected: isSelected,\r\n });\r\n\r\n \r\n const marker = new mapLib.Marker({ \r\n element: el,\r\n anchor: 'bottom' \r\n })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstance);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstance);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapInstance, selectedMarkerId]); \r\n\r\n return (\r\n <div style={{ position: 'relative', ...style }} className={className}>\r\n <div ref={mapContainerRef} style={{ width: '100%', height: '100%' }} />\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;","import type { MarkerData } from '../types';\r\n\r\ninterface CreateMarkerOptions {\r\n marker: MarkerData;\r\n isSelected: boolean;\r\n logoSrc?: string;\r\n showPrice?: boolean;\r\n}\r\n\r\nexport function createCustomMarkerElement({\r\n marker,\r\n isSelected,\r\n logoSrc = '',\r\n showPrice = true,\r\n}: CreateMarkerOptions): HTMLElement {\r\n const wrapper = document.createElement('div');\r\n \r\n // استایلهای پایه بصورت Inline برای اطمینان از نمایش\r\n Object.assign(wrapper.style, {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n cursor: 'pointer',\r\n transition: 'all 0.3s ease',\r\n transform: isSelected ? 'scale(1.2)' : 'scale(1)',\r\n zIndex: isSelected ? '10' : '1'\r\n });\r\n\r\n // بخش تصویر مارکر\r\n const iconTarget = document.createElement('div');\r\n Object.assign(iconTarget.style, {\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n backgroundColor: 'white',\r\n border: isSelected ? '3px solid #3b82f6' : '2px solid #ef4444',\r\n boxShadow: '0 4px 6px rgba(0,0,0,0.1)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n overflow: 'hidden'\r\n });\r\n\r\n if (logoSrc) {\r\n const img = document.createElement('img');\r\n img.src = logoSrc;\r\n img.style.width = '80%';\r\n img.style.height = '80%';\r\n img.style.objectFit = 'contain';\r\n iconTarget.appendChild(img);\r\n } else {\r\n // یک دایره رنگی ساده اگر لوگو نبود\r\n iconTarget.style.backgroundColor = '#ef4444';\r\n }\r\n\r\n wrapper.appendChild(iconTarget);\r\n\r\n // بخش برچسب قیمت\r\n if (showPrice && (marker.name || marker.price)) {\r\n const label = document.createElement('div');\r\n Object.assign(label.style, {\r\n backgroundColor: 'white',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n marginTop: '4px',\r\n fontSize: '11px',\r\n fontWeight: 'bold',\r\n whiteSpace: 'nowrap',\r\n boxShadow: '0 2px 4px rgba(0,0,0,0.2)',\r\n border: '1px solid #ddd'\r\n });\r\n const labelText = marker.price \r\n ? `${marker.price} ت` \r\n : marker.name;\r\n\r\nlabel.textContent = labelText || '';\r\n }\r\n\r\n return wrapper;\r\n}"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -1,94 +1,120 @@
|
|
|
1
1
|
// src/components/Map.tsx
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// src/utils/createCustomMarkerElement.ts
|
|
5
|
+
function createCustomMarkerElement({
|
|
6
|
+
marker,
|
|
7
|
+
isSelected,
|
|
8
|
+
logoSrc = "",
|
|
9
|
+
showPrice = true
|
|
10
|
+
}) {
|
|
11
|
+
const wrapper = document.createElement("div");
|
|
12
|
+
Object.assign(wrapper.style, {
|
|
13
|
+
display: "flex",
|
|
14
|
+
flexDirection: "column",
|
|
15
|
+
alignItems: "center",
|
|
16
|
+
cursor: "pointer",
|
|
17
|
+
transition: "all 0.3s ease",
|
|
18
|
+
transform: isSelected ? "scale(1.2)" : "scale(1)",
|
|
19
|
+
zIndex: isSelected ? "10" : "1"
|
|
20
|
+
});
|
|
21
|
+
const iconTarget = document.createElement("div");
|
|
22
|
+
Object.assign(iconTarget.style, {
|
|
23
|
+
width: "40px",
|
|
24
|
+
height: "40px",
|
|
25
|
+
borderRadius: "50%",
|
|
26
|
+
backgroundColor: "white",
|
|
27
|
+
border: isSelected ? "3px solid #3b82f6" : "2px solid #ef4444",
|
|
28
|
+
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
|
|
29
|
+
display: "flex",
|
|
30
|
+
alignItems: "center",
|
|
31
|
+
justifyContent: "center",
|
|
32
|
+
overflow: "hidden"
|
|
33
|
+
});
|
|
34
|
+
if (logoSrc) {
|
|
35
|
+
const img = document.createElement("img");
|
|
36
|
+
img.src = logoSrc;
|
|
37
|
+
img.style.width = "80%";
|
|
38
|
+
img.style.height = "80%";
|
|
39
|
+
img.style.objectFit = "contain";
|
|
40
|
+
iconTarget.appendChild(img);
|
|
41
|
+
} else {
|
|
42
|
+
iconTarget.style.backgroundColor = "#ef4444";
|
|
43
|
+
}
|
|
44
|
+
wrapper.appendChild(iconTarget);
|
|
45
|
+
if (showPrice && (marker.name || marker.price)) {
|
|
46
|
+
const label = document.createElement("div");
|
|
47
|
+
Object.assign(label.style, {
|
|
48
|
+
backgroundColor: "white",
|
|
49
|
+
padding: "2px 8px",
|
|
50
|
+
borderRadius: "4px",
|
|
51
|
+
marginTop: "4px",
|
|
52
|
+
fontSize: "11px",
|
|
53
|
+
fontWeight: "bold",
|
|
54
|
+
whiteSpace: "nowrap",
|
|
55
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
56
|
+
border: "1px solid #ddd"
|
|
57
|
+
});
|
|
58
|
+
const labelText = marker.price ? `${marker.price} \u062A` : marker.name;
|
|
59
|
+
label.textContent = labelText || "";
|
|
60
|
+
}
|
|
61
|
+
return wrapper;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/components/Map.tsx
|
|
65
|
+
import "@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css";
|
|
3
66
|
import { jsx } from "react/jsx-runtime";
|
|
4
67
|
var Map = ({
|
|
5
68
|
options,
|
|
6
69
|
markers = [],
|
|
7
70
|
selectedMarkerId = null,
|
|
8
71
|
onMarkerClick,
|
|
9
|
-
onMapLoad,
|
|
10
|
-
children,
|
|
11
72
|
className = "",
|
|
12
73
|
style = { width: "100%", height: "100%" }
|
|
13
74
|
}) => {
|
|
14
75
|
const mapContainerRef = useRef(null);
|
|
15
|
-
const
|
|
76
|
+
const [mapInstance, setMapInstance] = useState(null);
|
|
16
77
|
const markersRef = useRef([]);
|
|
17
78
|
const [mapLib, setMapLib] = useState(null);
|
|
18
|
-
const [isLoaded, setIsLoaded] = useState(false);
|
|
19
79
|
useEffect(() => {
|
|
20
|
-
if (typeof window === "undefined") return;
|
|
21
|
-
let canceled = false;
|
|
22
80
|
import("@neshan-maps-platform/mapbox-gl").then((mod) => {
|
|
23
|
-
|
|
24
|
-
setMapLib(mod.default || mod);
|
|
25
|
-
setIsLoaded(true);
|
|
26
|
-
}
|
|
27
|
-
}).catch((err) => {
|
|
28
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0644\u0648\u062F \u0646\u0642\u0634\u0647 \u0646\u0634\u0627\u0646:", err);
|
|
81
|
+
setMapLib(mod.default || mod);
|
|
29
82
|
});
|
|
30
|
-
return () => {
|
|
31
|
-
canceled = true;
|
|
32
|
-
};
|
|
33
83
|
}, []);
|
|
34
84
|
useEffect(() => {
|
|
35
|
-
if (!mapLib || !mapContainerRef.current ||
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
map
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
markersRef.current.forEach((m) => m.remove());
|
|
47
|
-
markersRef.current = [];
|
|
48
|
-
if (mapInstanceRef.current) {
|
|
49
|
-
mapInstanceRef.current.remove();
|
|
50
|
-
mapInstanceRef.current = null;
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
} catch (err) {
|
|
54
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0633\u0627\u062E\u062A \u0646\u0642\u0634\u0647:", err);
|
|
55
|
-
}
|
|
56
|
-
}, [mapLib, options, onMapLoad]);
|
|
85
|
+
if (!mapLib || !mapContainerRef.current || mapInstance) return;
|
|
86
|
+
const map = new mapLib.Map({
|
|
87
|
+
container: mapContainerRef.current,
|
|
88
|
+
...options
|
|
89
|
+
});
|
|
90
|
+
map.on("load", () => {
|
|
91
|
+
setMapInstance(map);
|
|
92
|
+
});
|
|
93
|
+
return () => {
|
|
94
|
+
};
|
|
95
|
+
}, [mapLib]);
|
|
57
96
|
useEffect(() => {
|
|
58
|
-
if (!
|
|
59
|
-
markersRef.current.forEach((m) => m.remove());
|
|
60
|
-
markersRef.current = [];
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
97
|
+
if (!mapInstance || !mapLib) return;
|
|
63
98
|
markersRef.current.forEach((m) => m.remove());
|
|
64
99
|
markersRef.current = [];
|
|
65
100
|
markers.forEach((markerData, index) => {
|
|
66
|
-
const
|
|
67
|
-
el
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"></div>
|
|
76
|
-
`;
|
|
77
|
-
el.style.cursor = "pointer";
|
|
78
|
-
el.style.transition = "transform 0.3s ease";
|
|
79
|
-
el.style.transform = markerData.id === selectedMarkerId ? "scale(1.4)" : "scale(1)";
|
|
80
|
-
const marker = new mapLib.Marker({ element: el }).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstanceRef.current);
|
|
101
|
+
const isSelected = markerData.id === selectedMarkerId;
|
|
102
|
+
const el = createCustomMarkerElement({
|
|
103
|
+
marker: markerData,
|
|
104
|
+
isSelected
|
|
105
|
+
});
|
|
106
|
+
const marker = new mapLib.Marker({
|
|
107
|
+
element: el,
|
|
108
|
+
anchor: "bottom"
|
|
109
|
+
}).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstance);
|
|
81
110
|
el.addEventListener("click", (e) => {
|
|
82
111
|
e.stopPropagation();
|
|
83
|
-
onMarkerClick?.(markerData, index,
|
|
112
|
+
onMarkerClick?.(markerData, index, mapInstance);
|
|
84
113
|
});
|
|
85
114
|
markersRef.current.push(marker);
|
|
86
115
|
});
|
|
87
|
-
}, [markers,
|
|
88
|
-
|
|
89
|
-
return /* @__PURE__ */ jsx("div", { style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", background: "#f3f4f6" }, children: /* @__PURE__ */ jsx("p", { children: "\u062F\u0631 \u062D\u0627\u0644 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0646\u0642\u0634\u0647..." }) });
|
|
90
|
-
}
|
|
91
|
-
return /* @__PURE__ */ jsx("div", { ref: mapContainerRef, className, style, children });
|
|
116
|
+
}, [markers, mapInstance, selectedMarkerId]);
|
|
117
|
+
return /* @__PURE__ */ jsx("div", { style: { position: "relative", ...style }, className, children: /* @__PURE__ */ jsx("div", { ref: mapContainerRef, style: { width: "100%", height: "100%" } }) });
|
|
92
118
|
};
|
|
93
119
|
var Map_default = Map;
|
|
94
120
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Map.tsx"],"sourcesContent":["\
|
|
1
|
+
{"version":3,"sources":["../src/components/Map.tsx","../src/utils/createCustomMarkerElement.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport type { MapboxMap, MarkerData, MapProps } from '../types';\r\nimport { createCustomMarkerElement } from '../utils/createCustomMarkerElement';\r\nimport '@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const [mapInstance, setMapInstance] = useState<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n\r\n \r\n useEffect(() => {\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n setMapLib(mod.default || mod);\r\n });\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstance) return;\r\n\r\n const map = new mapLib.Map({\r\n container: mapContainerRef.current,\r\n ...options,\r\n });\r\n\r\n map.on('load', () => {\r\n setMapInstance(map);\r\n });\r\n\r\n return () => {\r\n \r\n };\r\n }, [mapLib]); \r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstance || !mapLib) return;\r\n\r\n \r\n markersRef.current.forEach((m) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData, index) => {\r\n const isSelected = markerData.id === selectedMarkerId;\r\n const el = createCustomMarkerElement({\r\n marker: markerData,\r\n isSelected: isSelected,\r\n });\r\n\r\n \r\n const marker = new mapLib.Marker({ \r\n element: el,\r\n anchor: 'bottom' \r\n })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstance);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstance);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapInstance, selectedMarkerId]); \r\n\r\n return (\r\n <div style={{ position: 'relative', ...style }} className={className}>\r\n <div ref={mapContainerRef} style={{ width: '100%', height: '100%' }} />\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;","import type { MarkerData } from '../types';\r\n\r\ninterface CreateMarkerOptions {\r\n marker: MarkerData;\r\n isSelected: boolean;\r\n logoSrc?: string;\r\n showPrice?: boolean;\r\n}\r\n\r\nexport function createCustomMarkerElement({\r\n marker,\r\n isSelected,\r\n logoSrc = '',\r\n showPrice = true,\r\n}: CreateMarkerOptions): HTMLElement {\r\n const wrapper = document.createElement('div');\r\n \r\n // استایلهای پایه بصورت Inline برای اطمینان از نمایش\r\n Object.assign(wrapper.style, {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n cursor: 'pointer',\r\n transition: 'all 0.3s ease',\r\n transform: isSelected ? 'scale(1.2)' : 'scale(1)',\r\n zIndex: isSelected ? '10' : '1'\r\n });\r\n\r\n // بخش تصویر مارکر\r\n const iconTarget = document.createElement('div');\r\n Object.assign(iconTarget.style, {\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n backgroundColor: 'white',\r\n border: isSelected ? '3px solid #3b82f6' : '2px solid #ef4444',\r\n boxShadow: '0 4px 6px rgba(0,0,0,0.1)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n overflow: 'hidden'\r\n });\r\n\r\n if (logoSrc) {\r\n const img = document.createElement('img');\r\n img.src = logoSrc;\r\n img.style.width = '80%';\r\n img.style.height = '80%';\r\n img.style.objectFit = 'contain';\r\n iconTarget.appendChild(img);\r\n } else {\r\n // یک دایره رنگی ساده اگر لوگو نبود\r\n iconTarget.style.backgroundColor = '#ef4444';\r\n }\r\n\r\n wrapper.appendChild(iconTarget);\r\n\r\n // بخش برچسب قیمت\r\n if (showPrice && (marker.name || marker.price)) {\r\n const label = document.createElement('div');\r\n Object.assign(label.style, {\r\n backgroundColor: 'white',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n marginTop: '4px',\r\n fontSize: '11px',\r\n fontWeight: 'bold',\r\n whiteSpace: 'nowrap',\r\n boxShadow: '0 2px 4px rgba(0,0,0,0.2)',\r\n border: '1px solid #ddd'\r\n });\r\n const labelText = marker.price \r\n ? `${marker.price} ت` \r\n : marker.name;\r\n\r\nlabel.textContent = labelText || '';\r\n }\r\n\r\n return wrapper;\r\n}"],"mappings":"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","names":[]}
|
package/dist/react.cjs
CHANGED
|
@@ -37,95 +37,121 @@ module.exports = __toCommonJS(react_exports);
|
|
|
37
37
|
|
|
38
38
|
// src/components/Map.tsx
|
|
39
39
|
var import_react = require("react");
|
|
40
|
+
|
|
41
|
+
// src/utils/createCustomMarkerElement.ts
|
|
42
|
+
function createCustomMarkerElement({
|
|
43
|
+
marker,
|
|
44
|
+
isSelected,
|
|
45
|
+
logoSrc = "",
|
|
46
|
+
showPrice = true
|
|
47
|
+
}) {
|
|
48
|
+
const wrapper = document.createElement("div");
|
|
49
|
+
Object.assign(wrapper.style, {
|
|
50
|
+
display: "flex",
|
|
51
|
+
flexDirection: "column",
|
|
52
|
+
alignItems: "center",
|
|
53
|
+
cursor: "pointer",
|
|
54
|
+
transition: "all 0.3s ease",
|
|
55
|
+
transform: isSelected ? "scale(1.2)" : "scale(1)",
|
|
56
|
+
zIndex: isSelected ? "10" : "1"
|
|
57
|
+
});
|
|
58
|
+
const iconTarget = document.createElement("div");
|
|
59
|
+
Object.assign(iconTarget.style, {
|
|
60
|
+
width: "40px",
|
|
61
|
+
height: "40px",
|
|
62
|
+
borderRadius: "50%",
|
|
63
|
+
backgroundColor: "white",
|
|
64
|
+
border: isSelected ? "3px solid #3b82f6" : "2px solid #ef4444",
|
|
65
|
+
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
|
|
66
|
+
display: "flex",
|
|
67
|
+
alignItems: "center",
|
|
68
|
+
justifyContent: "center",
|
|
69
|
+
overflow: "hidden"
|
|
70
|
+
});
|
|
71
|
+
if (logoSrc) {
|
|
72
|
+
const img = document.createElement("img");
|
|
73
|
+
img.src = logoSrc;
|
|
74
|
+
img.style.width = "80%";
|
|
75
|
+
img.style.height = "80%";
|
|
76
|
+
img.style.objectFit = "contain";
|
|
77
|
+
iconTarget.appendChild(img);
|
|
78
|
+
} else {
|
|
79
|
+
iconTarget.style.backgroundColor = "#ef4444";
|
|
80
|
+
}
|
|
81
|
+
wrapper.appendChild(iconTarget);
|
|
82
|
+
if (showPrice && (marker.name || marker.price)) {
|
|
83
|
+
const label = document.createElement("div");
|
|
84
|
+
Object.assign(label.style, {
|
|
85
|
+
backgroundColor: "white",
|
|
86
|
+
padding: "2px 8px",
|
|
87
|
+
borderRadius: "4px",
|
|
88
|
+
marginTop: "4px",
|
|
89
|
+
fontSize: "11px",
|
|
90
|
+
fontWeight: "bold",
|
|
91
|
+
whiteSpace: "nowrap",
|
|
92
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
93
|
+
border: "1px solid #ddd"
|
|
94
|
+
});
|
|
95
|
+
const labelText = marker.price ? `${marker.price} \u062A` : marker.name;
|
|
96
|
+
label.textContent = labelText || "";
|
|
97
|
+
}
|
|
98
|
+
return wrapper;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/components/Map.tsx
|
|
102
|
+
var import_NeshanMapboxGl = require("@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css");
|
|
40
103
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
41
104
|
var Map = ({
|
|
42
105
|
options,
|
|
43
106
|
markers = [],
|
|
44
107
|
selectedMarkerId = null,
|
|
45
108
|
onMarkerClick,
|
|
46
|
-
onMapLoad,
|
|
47
|
-
children,
|
|
48
109
|
className = "",
|
|
49
110
|
style = { width: "100%", height: "100%" }
|
|
50
111
|
}) => {
|
|
51
112
|
const mapContainerRef = (0, import_react.useRef)(null);
|
|
52
|
-
const
|
|
113
|
+
const [mapInstance, setMapInstance] = (0, import_react.useState)(null);
|
|
53
114
|
const markersRef = (0, import_react.useRef)([]);
|
|
54
115
|
const [mapLib, setMapLib] = (0, import_react.useState)(null);
|
|
55
|
-
const [isLoaded, setIsLoaded] = (0, import_react.useState)(false);
|
|
56
116
|
(0, import_react.useEffect)(() => {
|
|
57
|
-
if (typeof window === "undefined") return;
|
|
58
|
-
let canceled = false;
|
|
59
117
|
import("@neshan-maps-platform/mapbox-gl").then((mod) => {
|
|
60
|
-
|
|
61
|
-
setMapLib(mod.default || mod);
|
|
62
|
-
setIsLoaded(true);
|
|
63
|
-
}
|
|
64
|
-
}).catch((err) => {
|
|
65
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0644\u0648\u062F \u0646\u0642\u0634\u0647 \u0646\u0634\u0627\u0646:", err);
|
|
118
|
+
setMapLib(mod.default || mod);
|
|
66
119
|
});
|
|
67
|
-
return () => {
|
|
68
|
-
canceled = true;
|
|
69
|
-
};
|
|
70
120
|
}, []);
|
|
71
121
|
(0, import_react.useEffect)(() => {
|
|
72
|
-
if (!mapLib || !mapContainerRef.current ||
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
map
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
markersRef.current.forEach((m) => m.remove());
|
|
84
|
-
markersRef.current = [];
|
|
85
|
-
if (mapInstanceRef.current) {
|
|
86
|
-
mapInstanceRef.current.remove();
|
|
87
|
-
mapInstanceRef.current = null;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
} catch (err) {
|
|
91
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0633\u0627\u062E\u062A \u0646\u0642\u0634\u0647:", err);
|
|
92
|
-
}
|
|
93
|
-
}, [mapLib, options, onMapLoad]);
|
|
122
|
+
if (!mapLib || !mapContainerRef.current || mapInstance) return;
|
|
123
|
+
const map = new mapLib.Map({
|
|
124
|
+
container: mapContainerRef.current,
|
|
125
|
+
...options
|
|
126
|
+
});
|
|
127
|
+
map.on("load", () => {
|
|
128
|
+
setMapInstance(map);
|
|
129
|
+
});
|
|
130
|
+
return () => {
|
|
131
|
+
};
|
|
132
|
+
}, [mapLib]);
|
|
94
133
|
(0, import_react.useEffect)(() => {
|
|
95
|
-
if (!
|
|
96
|
-
markersRef.current.forEach((m) => m.remove());
|
|
97
|
-
markersRef.current = [];
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
134
|
+
if (!mapInstance || !mapLib) return;
|
|
100
135
|
markersRef.current.forEach((m) => m.remove());
|
|
101
136
|
markersRef.current = [];
|
|
102
137
|
markers.forEach((markerData, index) => {
|
|
103
|
-
const
|
|
104
|
-
el
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"></div>
|
|
113
|
-
`;
|
|
114
|
-
el.style.cursor = "pointer";
|
|
115
|
-
el.style.transition = "transform 0.3s ease";
|
|
116
|
-
el.style.transform = markerData.id === selectedMarkerId ? "scale(1.4)" : "scale(1)";
|
|
117
|
-
const marker = new mapLib.Marker({ element: el }).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstanceRef.current);
|
|
138
|
+
const isSelected = markerData.id === selectedMarkerId;
|
|
139
|
+
const el = createCustomMarkerElement({
|
|
140
|
+
marker: markerData,
|
|
141
|
+
isSelected
|
|
142
|
+
});
|
|
143
|
+
const marker = new mapLib.Marker({
|
|
144
|
+
element: el,
|
|
145
|
+
anchor: "bottom"
|
|
146
|
+
}).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstance);
|
|
118
147
|
el.addEventListener("click", (e) => {
|
|
119
148
|
e.stopPropagation();
|
|
120
|
-
onMarkerClick?.(markerData, index,
|
|
149
|
+
onMarkerClick?.(markerData, index, mapInstance);
|
|
121
150
|
});
|
|
122
151
|
markersRef.current.push(marker);
|
|
123
152
|
});
|
|
124
|
-
}, [markers,
|
|
125
|
-
|
|
126
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", background: "#f3f4f6" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "\u062F\u0631 \u062D\u0627\u0644 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0646\u0642\u0634\u0647..." }) });
|
|
127
|
-
}
|
|
128
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: mapContainerRef, className, style, children });
|
|
153
|
+
}, [markers, mapInstance, selectedMarkerId]);
|
|
154
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "relative", ...style }, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: mapContainerRef, style: { width: "100%", height: "100%" } }) });
|
|
129
155
|
};
|
|
130
156
|
var Map_default = Map;
|
|
131
157
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.ts","../src/components/Map.tsx"],"sourcesContent":["// src/react.ts\r\n\r\n\"use client\";\r\n\r\nexport { default as NeshanMap } from './components/Map';\r\nexport type {\r\n MapProps,\r\n MapOptions,\r\n MarkerData,\r\n} from './types';","\
|
|
1
|
+
{"version":3,"sources":["../src/react.ts","../src/components/Map.tsx","../src/utils/createCustomMarkerElement.ts"],"sourcesContent":["// src/react.ts\r\n\r\n\"use client\";\r\n\r\nexport { default as NeshanMap } from './components/Map';\r\nexport type {\r\n MapProps,\r\n MapOptions,\r\n MarkerData,\r\n} from './types';","\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport type { MapboxMap, MarkerData, MapProps } from '../types';\r\nimport { createCustomMarkerElement } from '../utils/createCustomMarkerElement';\r\nimport '@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const [mapInstance, setMapInstance] = useState<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n\r\n \r\n useEffect(() => {\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n setMapLib(mod.default || mod);\r\n });\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstance) return;\r\n\r\n const map = new mapLib.Map({\r\n container: mapContainerRef.current,\r\n ...options,\r\n });\r\n\r\n map.on('load', () => {\r\n setMapInstance(map);\r\n });\r\n\r\n return () => {\r\n \r\n };\r\n }, [mapLib]); \r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstance || !mapLib) return;\r\n\r\n \r\n markersRef.current.forEach((m) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData, index) => {\r\n const isSelected = markerData.id === selectedMarkerId;\r\n const el = createCustomMarkerElement({\r\n marker: markerData,\r\n isSelected: isSelected,\r\n });\r\n\r\n \r\n const marker = new mapLib.Marker({ \r\n element: el,\r\n anchor: 'bottom' \r\n })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstance);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstance);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapInstance, selectedMarkerId]); \r\n\r\n return (\r\n <div style={{ position: 'relative', ...style }} className={className}>\r\n <div ref={mapContainerRef} style={{ width: '100%', height: '100%' }} />\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;","import type { MarkerData } from '../types';\r\n\r\ninterface CreateMarkerOptions {\r\n marker: MarkerData;\r\n isSelected: boolean;\r\n logoSrc?: string;\r\n showPrice?: boolean;\r\n}\r\n\r\nexport function createCustomMarkerElement({\r\n marker,\r\n isSelected,\r\n logoSrc = '',\r\n showPrice = true,\r\n}: CreateMarkerOptions): HTMLElement {\r\n const wrapper = document.createElement('div');\r\n \r\n // استایلهای پایه بصورت Inline برای اطمینان از نمایش\r\n Object.assign(wrapper.style, {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n cursor: 'pointer',\r\n transition: 'all 0.3s ease',\r\n transform: isSelected ? 'scale(1.2)' : 'scale(1)',\r\n zIndex: isSelected ? '10' : '1'\r\n });\r\n\r\n // بخش تصویر مارکر\r\n const iconTarget = document.createElement('div');\r\n Object.assign(iconTarget.style, {\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n backgroundColor: 'white',\r\n border: isSelected ? '3px solid #3b82f6' : '2px solid #ef4444',\r\n boxShadow: '0 4px 6px rgba(0,0,0,0.1)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n overflow: 'hidden'\r\n });\r\n\r\n if (logoSrc) {\r\n const img = document.createElement('img');\r\n img.src = logoSrc;\r\n img.style.width = '80%';\r\n img.style.height = '80%';\r\n img.style.objectFit = 'contain';\r\n iconTarget.appendChild(img);\r\n } else {\r\n // یک دایره رنگی ساده اگر لوگو نبود\r\n iconTarget.style.backgroundColor = '#ef4444';\r\n }\r\n\r\n wrapper.appendChild(iconTarget);\r\n\r\n // بخش برچسب قیمت\r\n if (showPrice && (marker.name || marker.price)) {\r\n const label = document.createElement('div');\r\n Object.assign(label.style, {\r\n backgroundColor: 'white',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n marginTop: '4px',\r\n fontSize: '11px',\r\n fontWeight: 'bold',\r\n whiteSpace: 'nowrap',\r\n boxShadow: '0 2px 4px rgba(0,0,0,0.2)',\r\n border: '1px solid #ddd'\r\n });\r\n const labelText = marker.price \r\n ? `${marker.price} ت` \r\n : marker.name;\r\n\r\nlabel.textContent = labelText || '';\r\n }\r\n\r\n return wrapper;\r\n}"],"mappings":"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","names":[]}
|
package/dist/react.js
CHANGED
|
@@ -2,95 +2,121 @@
|
|
|
2
2
|
|
|
3
3
|
// src/components/Map.tsx
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
|
|
6
|
+
// src/utils/createCustomMarkerElement.ts
|
|
7
|
+
function createCustomMarkerElement({
|
|
8
|
+
marker,
|
|
9
|
+
isSelected,
|
|
10
|
+
logoSrc = "",
|
|
11
|
+
showPrice = true
|
|
12
|
+
}) {
|
|
13
|
+
const wrapper = document.createElement("div");
|
|
14
|
+
Object.assign(wrapper.style, {
|
|
15
|
+
display: "flex",
|
|
16
|
+
flexDirection: "column",
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
cursor: "pointer",
|
|
19
|
+
transition: "all 0.3s ease",
|
|
20
|
+
transform: isSelected ? "scale(1.2)" : "scale(1)",
|
|
21
|
+
zIndex: isSelected ? "10" : "1"
|
|
22
|
+
});
|
|
23
|
+
const iconTarget = document.createElement("div");
|
|
24
|
+
Object.assign(iconTarget.style, {
|
|
25
|
+
width: "40px",
|
|
26
|
+
height: "40px",
|
|
27
|
+
borderRadius: "50%",
|
|
28
|
+
backgroundColor: "white",
|
|
29
|
+
border: isSelected ? "3px solid #3b82f6" : "2px solid #ef4444",
|
|
30
|
+
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
|
|
31
|
+
display: "flex",
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
overflow: "hidden"
|
|
35
|
+
});
|
|
36
|
+
if (logoSrc) {
|
|
37
|
+
const img = document.createElement("img");
|
|
38
|
+
img.src = logoSrc;
|
|
39
|
+
img.style.width = "80%";
|
|
40
|
+
img.style.height = "80%";
|
|
41
|
+
img.style.objectFit = "contain";
|
|
42
|
+
iconTarget.appendChild(img);
|
|
43
|
+
} else {
|
|
44
|
+
iconTarget.style.backgroundColor = "#ef4444";
|
|
45
|
+
}
|
|
46
|
+
wrapper.appendChild(iconTarget);
|
|
47
|
+
if (showPrice && (marker.name || marker.price)) {
|
|
48
|
+
const label = document.createElement("div");
|
|
49
|
+
Object.assign(label.style, {
|
|
50
|
+
backgroundColor: "white",
|
|
51
|
+
padding: "2px 8px",
|
|
52
|
+
borderRadius: "4px",
|
|
53
|
+
marginTop: "4px",
|
|
54
|
+
fontSize: "11px",
|
|
55
|
+
fontWeight: "bold",
|
|
56
|
+
whiteSpace: "nowrap",
|
|
57
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
58
|
+
border: "1px solid #ddd"
|
|
59
|
+
});
|
|
60
|
+
const labelText = marker.price ? `${marker.price} \u062A` : marker.name;
|
|
61
|
+
label.textContent = labelText || "";
|
|
62
|
+
}
|
|
63
|
+
return wrapper;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/components/Map.tsx
|
|
67
|
+
import "@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css";
|
|
5
68
|
import { jsx } from "react/jsx-runtime";
|
|
6
69
|
var Map = ({
|
|
7
70
|
options,
|
|
8
71
|
markers = [],
|
|
9
72
|
selectedMarkerId = null,
|
|
10
73
|
onMarkerClick,
|
|
11
|
-
onMapLoad,
|
|
12
|
-
children,
|
|
13
74
|
className = "",
|
|
14
75
|
style = { width: "100%", height: "100%" }
|
|
15
76
|
}) => {
|
|
16
77
|
const mapContainerRef = useRef(null);
|
|
17
|
-
const
|
|
78
|
+
const [mapInstance, setMapInstance] = useState(null);
|
|
18
79
|
const markersRef = useRef([]);
|
|
19
80
|
const [mapLib, setMapLib] = useState(null);
|
|
20
|
-
const [isLoaded, setIsLoaded] = useState(false);
|
|
21
81
|
useEffect(() => {
|
|
22
|
-
if (typeof window === "undefined") return;
|
|
23
|
-
let canceled = false;
|
|
24
82
|
import("@neshan-maps-platform/mapbox-gl").then((mod) => {
|
|
25
|
-
|
|
26
|
-
setMapLib(mod.default || mod);
|
|
27
|
-
setIsLoaded(true);
|
|
28
|
-
}
|
|
29
|
-
}).catch((err) => {
|
|
30
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0644\u0648\u062F \u0646\u0642\u0634\u0647 \u0646\u0634\u0627\u0646:", err);
|
|
83
|
+
setMapLib(mod.default || mod);
|
|
31
84
|
});
|
|
32
|
-
return () => {
|
|
33
|
-
canceled = true;
|
|
34
|
-
};
|
|
35
85
|
}, []);
|
|
36
86
|
useEffect(() => {
|
|
37
|
-
if (!mapLib || !mapContainerRef.current ||
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
map
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
markersRef.current.forEach((m) => m.remove());
|
|
49
|
-
markersRef.current = [];
|
|
50
|
-
if (mapInstanceRef.current) {
|
|
51
|
-
mapInstanceRef.current.remove();
|
|
52
|
-
mapInstanceRef.current = null;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
} catch (err) {
|
|
56
|
-
console.error("\u062E\u0637\u0627 \u062F\u0631 \u0633\u0627\u062E\u062A \u0646\u0642\u0634\u0647:", err);
|
|
57
|
-
}
|
|
58
|
-
}, [mapLib, options, onMapLoad]);
|
|
87
|
+
if (!mapLib || !mapContainerRef.current || mapInstance) return;
|
|
88
|
+
const map = new mapLib.Map({
|
|
89
|
+
container: mapContainerRef.current,
|
|
90
|
+
...options
|
|
91
|
+
});
|
|
92
|
+
map.on("load", () => {
|
|
93
|
+
setMapInstance(map);
|
|
94
|
+
});
|
|
95
|
+
return () => {
|
|
96
|
+
};
|
|
97
|
+
}, [mapLib]);
|
|
59
98
|
useEffect(() => {
|
|
60
|
-
if (!
|
|
61
|
-
markersRef.current.forEach((m) => m.remove());
|
|
62
|
-
markersRef.current = [];
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
99
|
+
if (!mapInstance || !mapLib) return;
|
|
65
100
|
markersRef.current.forEach((m) => m.remove());
|
|
66
101
|
markersRef.current = [];
|
|
67
102
|
markers.forEach((markerData, index) => {
|
|
68
|
-
const
|
|
69
|
-
el
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"></div>
|
|
78
|
-
`;
|
|
79
|
-
el.style.cursor = "pointer";
|
|
80
|
-
el.style.transition = "transform 0.3s ease";
|
|
81
|
-
el.style.transform = markerData.id === selectedMarkerId ? "scale(1.4)" : "scale(1)";
|
|
82
|
-
const marker = new mapLib.Marker({ element: el }).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstanceRef.current);
|
|
103
|
+
const isSelected = markerData.id === selectedMarkerId;
|
|
104
|
+
const el = createCustomMarkerElement({
|
|
105
|
+
marker: markerData,
|
|
106
|
+
isSelected
|
|
107
|
+
});
|
|
108
|
+
const marker = new mapLib.Marker({
|
|
109
|
+
element: el,
|
|
110
|
+
anchor: "bottom"
|
|
111
|
+
}).setLngLat([markerData.lng, markerData.lat]).addTo(mapInstance);
|
|
83
112
|
el.addEventListener("click", (e) => {
|
|
84
113
|
e.stopPropagation();
|
|
85
|
-
onMarkerClick?.(markerData, index,
|
|
114
|
+
onMarkerClick?.(markerData, index, mapInstance);
|
|
86
115
|
});
|
|
87
116
|
markersRef.current.push(marker);
|
|
88
117
|
});
|
|
89
|
-
}, [markers,
|
|
90
|
-
|
|
91
|
-
return /* @__PURE__ */ jsx("div", { style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", background: "#f3f4f6" }, children: /* @__PURE__ */ jsx("p", { children: "\u062F\u0631 \u062D\u0627\u0644 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0646\u0642\u0634\u0647..." }) });
|
|
92
|
-
}
|
|
93
|
-
return /* @__PURE__ */ jsx("div", { ref: mapContainerRef, className, style, children });
|
|
118
|
+
}, [markers, mapInstance, selectedMarkerId]);
|
|
119
|
+
return /* @__PURE__ */ jsx("div", { style: { position: "relative", ...style }, className, children: /* @__PURE__ */ jsx("div", { ref: mapContainerRef, style: { width: "100%", height: "100%" } }) });
|
|
94
120
|
};
|
|
95
121
|
var Map_default = Map;
|
|
96
122
|
export {
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Map.tsx"],"sourcesContent":["\
|
|
1
|
+
{"version":3,"sources":["../src/components/Map.tsx","../src/utils/createCustomMarkerElement.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport type { MapboxMap, MarkerData, MapProps } from '../types';\r\nimport { createCustomMarkerElement } from '../utils/createCustomMarkerElement';\r\nimport '@neshan-maps-platform/mapbox-gl/dist/NeshanMapboxGl.css';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const [mapInstance, setMapInstance] = useState<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n\r\n \r\n useEffect(() => {\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n setMapLib(mod.default || mod);\r\n });\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstance) return;\r\n\r\n const map = new mapLib.Map({\r\n container: mapContainerRef.current,\r\n ...options,\r\n });\r\n\r\n map.on('load', () => {\r\n setMapInstance(map);\r\n });\r\n\r\n return () => {\r\n \r\n };\r\n }, [mapLib]); \r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstance || !mapLib) return;\r\n\r\n \r\n markersRef.current.forEach((m) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData, index) => {\r\n const isSelected = markerData.id === selectedMarkerId;\r\n const el = createCustomMarkerElement({\r\n marker: markerData,\r\n isSelected: isSelected,\r\n });\r\n\r\n \r\n const marker = new mapLib.Marker({ \r\n element: el,\r\n anchor: 'bottom' \r\n })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstance);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstance);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapInstance, selectedMarkerId]); \r\n\r\n return (\r\n <div style={{ position: 'relative', ...style }} className={className}>\r\n <div ref={mapContainerRef} style={{ width: '100%', height: '100%' }} />\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;","import type { MarkerData } from '../types';\r\n\r\ninterface CreateMarkerOptions {\r\n marker: MarkerData;\r\n isSelected: boolean;\r\n logoSrc?: string;\r\n showPrice?: boolean;\r\n}\r\n\r\nexport function createCustomMarkerElement({\r\n marker,\r\n isSelected,\r\n logoSrc = '',\r\n showPrice = true,\r\n}: CreateMarkerOptions): HTMLElement {\r\n const wrapper = document.createElement('div');\r\n \r\n // استایلهای پایه بصورت Inline برای اطمینان از نمایش\r\n Object.assign(wrapper.style, {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n cursor: 'pointer',\r\n transition: 'all 0.3s ease',\r\n transform: isSelected ? 'scale(1.2)' : 'scale(1)',\r\n zIndex: isSelected ? '10' : '1'\r\n });\r\n\r\n // بخش تصویر مارکر\r\n const iconTarget = document.createElement('div');\r\n Object.assign(iconTarget.style, {\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n backgroundColor: 'white',\r\n border: isSelected ? '3px solid #3b82f6' : '2px solid #ef4444',\r\n boxShadow: '0 4px 6px rgba(0,0,0,0.1)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n overflow: 'hidden'\r\n });\r\n\r\n if (logoSrc) {\r\n const img = document.createElement('img');\r\n img.src = logoSrc;\r\n img.style.width = '80%';\r\n img.style.height = '80%';\r\n img.style.objectFit = 'contain';\r\n iconTarget.appendChild(img);\r\n } else {\r\n // یک دایره رنگی ساده اگر لوگو نبود\r\n iconTarget.style.backgroundColor = '#ef4444';\r\n }\r\n\r\n wrapper.appendChild(iconTarget);\r\n\r\n // بخش برچسب قیمت\r\n if (showPrice && (marker.name || marker.price)) {\r\n const label = document.createElement('div');\r\n Object.assign(label.style, {\r\n backgroundColor: 'white',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n marginTop: '4px',\r\n fontSize: '11px',\r\n fontWeight: 'bold',\r\n whiteSpace: 'nowrap',\r\n boxShadow: '0 2px 4px rgba(0,0,0,0.2)',\r\n border: '1px solid #ddd'\r\n });\r\n const labelText = marker.price \r\n ? `${marker.price} ت` \r\n : marker.name;\r\n\r\nlabel.textContent = labelText || '';\r\n }\r\n\r\n return wrapper;\r\n}"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCustomMarkerElement.d.ts","sourceRoot":"","sources":["../../src/utils/createCustomMarkerElement.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createCustomMarkerElement.d.ts","sourceRoot":"","sources":["../../src/utils/createCustomMarkerElement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,UAAU,mBAAmB;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,yBAAyB,CAAC,EACxC,MAAM,EACN,UAAU,EACV,OAAY,EACZ,SAAgB,GACjB,EAAE,mBAAmB,GAAG,WAAW,CAiEnC"}
|