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.
@@ -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":"AAIA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAyB,MAAM,UAAU,CAAC;AAE3D,QAAA,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAwH3B,CAAC;AAEF,eAAe,GAAG,CAAC"}
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 mapInstanceRef = (0, import_react.useRef)(null);
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
- if (!canceled) {
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 || mapInstanceRef.current) return;
72
- try {
73
- const map = new mapLib.Map({
74
- container: mapContainerRef.current,
75
- ...options
76
- });
77
- map.on("load", () => {
78
- mapInstanceRef.current = map;
79
- onMapLoad?.(map);
80
- });
81
- return () => {
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 (!mapInstanceRef.current || !mapLib || markers.length === 0) {
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 el = document.createElement("div");
103
- el.innerHTML = `
104
- <div style="
105
- background: #ef4444;
106
- width: 32px;
107
- height: 32px;
108
- border-radius: 50%;
109
- border: 4px solid white;
110
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
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, mapInstanceRef.current);
148
+ onMarkerClick?.(markerData, index, mapInstance);
120
149
  });
121
150
  markersRef.current.push(marker);
122
151
  });
123
- }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);
124
- if (!isLoaded) {
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:
@@ -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';","\r\n\r\n\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport { MapProps, MapboxMap, MarkerData } from '../types';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n onMapLoad,\r\n children,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const mapInstanceRef = useRef<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n const [isLoaded, setIsLoaded] = useState(false); \r\n\r\n \r\n useEffect(() => {\r\n if (typeof window === 'undefined') return;\r\n\r\n let canceled = false;\r\n\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n if (!canceled) {\r\n setMapLib(mod.default || mod);\r\n setIsLoaded(true);\r\n }\r\n }).catch((err) => {\r\n console.error(\"خطا در لود نقشه نشان:\", err);\r\n });\r\n\r\n return () => {\r\n canceled = true;\r\n };\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstanceRef.current) return;\r\n\r\n try {\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 mapInstanceRef.current = map;\r\n onMapLoad?.(map);\r\n });\r\n\r\n return () => {\r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n if (mapInstanceRef.current) {\r\n mapInstanceRef.current.remove();\r\n mapInstanceRef.current = null;\r\n }\r\n };\r\n } catch (err) {\r\n console.error(\"خطا در ساخت نقشه:\", err);\r\n }\r\n }, [mapLib, options, onMapLoad]);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstanceRef.current || !mapLib || markers.length === 0) {\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n return;\r\n }\r\n\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData: MarkerData, index: number) => {\r\n const el = document.createElement('div');\r\n el.innerHTML = `\r\n <div style=\"\r\n background: #ef4444;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n border: 4px solid white;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n \"></div>\r\n `;\r\n el.style.cursor = 'pointer';\r\n el.style.transition = 'transform 0.3s ease';\r\n el.style.transform = markerData.id === selectedMarkerId ? 'scale(1.4)' : 'scale(1)';\r\n\r\n const marker = new mapLib.Marker({ element: el })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstanceRef.current!);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstanceRef.current!);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);\r\n\r\n \r\n if (!isLoaded) {\r\n return (\r\n <div style={{ ...style, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f3f4f6' }}>\r\n <p>در حال بارگذاری نقشه...</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div ref={mapContainerRef} className={className} style={style}>\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIA,mBAAmD;AAiH3C;AA9GR,IAAM,MAA0B,CAAC;AAAA,EAC/B;AAAA,EACA,UAAU,CAAC;AAAA,EACX,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ,EAAE,OAAO,QAAQ,QAAQ,OAAO;AAC1C,MAAM;AACJ,QAAM,sBAAkB,qBAAuB,IAAI;AACnD,QAAM,qBAAiB,qBAAyB,IAAI;AACpD,QAAM,iBAAa,qBAAc,CAAC,CAAC;AACnC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAc,IAAI;AAC9C,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAG9C,8BAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AAEnC,QAAI,WAAW;AAEf,WAAO,iCAAiC,EAAE,KAAK,CAAC,QAAQ;AACtD,UAAI,CAAC,UAAU;AACb,kBAAU,IAAI,WAAW,GAAG;AAC5B,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,cAAQ,MAAM,yGAAyB,GAAG;AAAA,IAC5C,CAAC;AAED,WAAO,MAAM;AACX,iBAAW;AAAA,IACb;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,8BAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,gBAAgB,WAAW,eAAe,QAAS;AAEnE,QAAI;AACF,YAAM,MAAM,IAAI,OAAO,IAAI;AAAA,QACzB,WAAW,gBAAgB;AAAA,QAC3B,GAAG;AAAA,MACL,CAAC;AAED,UAAI,GAAG,QAAQ,MAAM;AACnB,uBAAe,UAAU;AACzB,oBAAY,GAAG;AAAA,MACjB,CAAC;AAED,aAAO,MAAM;AACX,mBAAW,QAAQ,QAAQ,CAAC,MAAW,EAAE,OAAO,CAAC;AACjD,mBAAW,UAAU,CAAC;AACtB,YAAI,eAAe,SAAS;AAC1B,yBAAe,QAAQ,OAAO;AAC9B,yBAAe,UAAU;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,sFAAqB,GAAG;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,SAAS,CAAC;AAG/B,8BAAU,MAAM;AACd,QAAI,CAAC,eAAe,WAAW,CAAC,UAAU,QAAQ,WAAW,GAAG;AAE9D,iBAAW,QAAQ,QAAQ,CAAC,MAAW,EAAE,OAAO,CAAC;AACjD,iBAAW,UAAU,CAAC;AACtB;AAAA,IACF;AAGA,eAAW,QAAQ,QAAQ,CAAC,MAAW,EAAE,OAAO,CAAC;AACjD,eAAW,UAAU,CAAC;AAEtB,YAAQ,QAAQ,CAAC,YAAwB,UAAkB;AACzD,YAAM,KAAK,SAAS,cAAc,KAAK;AACvC,SAAG,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUf,SAAG,MAAM,SAAS;AAClB,SAAG,MAAM,aAAa;AACtB,SAAG,MAAM,YAAY,WAAW,OAAO,mBAAmB,eAAe;AAEzE,YAAM,SAAS,IAAI,OAAO,OAAO,EAAE,SAAS,GAAG,CAAC,EAC7C,UAAU,CAAC,WAAW,KAAK,WAAW,GAAG,CAAC,EAC1C,MAAM,eAAe,OAAQ;AAEhC,SAAG,iBAAiB,SAAS,CAAC,MAAM;AAClC,UAAE,gBAAgB;AAClB,wBAAgB,YAAY,OAAO,eAAe,OAAQ;AAAA,MAC5D,CAAC;AAED,iBAAW,QAAQ,KAAK,MAAM;AAAA,IAChC,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,QAAQ,eAAe,SAAS,eAAe,gBAAgB,CAAC;AAG7E,MAAI,CAAC,UAAU;AACb,WACE,4CAAC,SAAI,OAAO,EAAE,GAAG,OAAO,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,YAAY,UAAU,GAC7G,sDAAC,OAAE,0HAAuB,GAC5B;AAAA,EAEJ;AAEA,SACE,4CAAC,SAAI,KAAK,iBAAiB,WAAsB,OAC9C,UACH;AAEJ;AAEA,IAAO,cAAQ;","names":[]}
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 mapInstanceRef = useRef(null);
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
- if (!canceled) {
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 || mapInstanceRef.current) return;
36
- try {
37
- const map = new mapLib.Map({
38
- container: mapContainerRef.current,
39
- ...options
40
- });
41
- map.on("load", () => {
42
- mapInstanceRef.current = map;
43
- onMapLoad?.(map);
44
- });
45
- return () => {
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 (!mapInstanceRef.current || !mapLib || markers.length === 0) {
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 el = document.createElement("div");
67
- el.innerHTML = `
68
- <div style="
69
- background: #ef4444;
70
- width: 32px;
71
- height: 32px;
72
- border-radius: 50%;
73
- border: 4px solid white;
74
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
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, mapInstanceRef.current);
112
+ onMarkerClick?.(markerData, index, mapInstance);
84
113
  });
85
114
  markersRef.current.push(marker);
86
115
  });
87
- }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);
88
- if (!isLoaded) {
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":["\r\n\r\n\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport { MapProps, MapboxMap, MarkerData } from '../types';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n onMapLoad,\r\n children,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const mapInstanceRef = useRef<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n const [isLoaded, setIsLoaded] = useState(false); \r\n\r\n \r\n useEffect(() => {\r\n if (typeof window === 'undefined') return;\r\n\r\n let canceled = false;\r\n\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n if (!canceled) {\r\n setMapLib(mod.default || mod);\r\n setIsLoaded(true);\r\n }\r\n }).catch((err) => {\r\n console.error(\"خطا در لود نقشه نشان:\", err);\r\n });\r\n\r\n return () => {\r\n canceled = true;\r\n };\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstanceRef.current) return;\r\n\r\n try {\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 mapInstanceRef.current = map;\r\n onMapLoad?.(map);\r\n });\r\n\r\n return () => {\r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n if (mapInstanceRef.current) {\r\n mapInstanceRef.current.remove();\r\n mapInstanceRef.current = null;\r\n }\r\n };\r\n } catch (err) {\r\n console.error(\"خطا در ساخت نقشه:\", err);\r\n }\r\n }, [mapLib, options, onMapLoad]);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstanceRef.current || !mapLib || markers.length === 0) {\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n return;\r\n }\r\n\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData: MarkerData, index: number) => {\r\n const el = document.createElement('div');\r\n el.innerHTML = `\r\n <div style=\"\r\n background: #ef4444;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n border: 4px solid white;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n \"></div>\r\n `;\r\n el.style.cursor = 'pointer';\r\n el.style.transition = 'transform 0.3s ease';\r\n el.style.transform = markerData.id === selectedMarkerId ? 'scale(1.4)' : 'scale(1)';\r\n\r\n const marker = new mapLib.Marker({ element: el })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstanceRef.current!);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstanceRef.current!);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);\r\n\r\n \r\n if (!isLoaded) {\r\n return (\r\n <div style={{ ...style, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f3f4f6' }}>\r\n <p>در حال بارگذاری نقشه...</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div ref={mapContainerRef} className={className} style={style}>\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;"],"mappings":";AAIA,SAAgB,WAAW,QAAQ,gBAAgB;AAiH3C;AA9GR,IAAM,MAA0B,CAAC;AAAA,EAC/B;AAAA,EACA,UAAU,CAAC;AAAA,EACX,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ,EAAE,OAAO,QAAQ,QAAQ,OAAO;AAC1C,MAAM;AACJ,QAAM,kBAAkB,OAAuB,IAAI;AACnD,QAAM,iBAAiB,OAAyB,IAAI;AACpD,QAAM,aAAa,OAAc,CAAC,CAAC;AACnC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAc,IAAI;AAC9C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAG9C,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AAEnC,QAAI,WAAW;AAEf,WAAO,iCAAiC,EAAE,KAAK,CAAC,QAAQ;AACtD,UAAI,CAAC,UAAU;AACb,kBAAU,IAAI,WAAW,GAAG;AAC5B,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,cAAQ,MAAM,yGAAyB,GAAG;AAAA,IAC5C,CAAC;AAED,WAAO,MAAM;AACX,iBAAW;AAAA,IACb;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,gBAAgB,WAAW,eAAe,QAAS;AAEnE,QAAI;AACF,YAAM,MAAM,IAAI,OAAO,IAAI;AAAA,QACzB,WAAW,gBAAgB;AAAA,QAC3B,GAAG;AAAA,MACL,CAAC;AAED,UAAI,GAAG,QAAQ,MAAM;AACnB,uBAAe,UAAU;AACzB,oBAAY,GAAG;AAAA,MACjB,CAAC;AAED,aAAO,MAAM;AACX,mBAAW,QAAQ,QAAQ,CAAC,MAAW,EAAE,OAAO,CAAC;AACjD,mBAAW,UAAU,CAAC;AACtB,YAAI,eAAe,SAAS;AAC1B,yBAAe,QAAQ,OAAO;AAC9B,yBAAe,UAAU;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,sFAAqB,GAAG;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,SAAS,CAAC;AAG/B,YAAU,MAAM;AACd,QAAI,CAAC,eAAe,WAAW,CAAC,UAAU,QAAQ,WAAW,GAAG;AAE9D,iBAAW,QAAQ,QAAQ,CAAC,MAAW,EAAE,OAAO,CAAC;AACjD,iBAAW,UAAU,CAAC;AACtB;AAAA,IACF;AAGA,eAAW,QAAQ,QAAQ,CAAC,MAAW,EAAE,OAAO,CAAC;AACjD,eAAW,UAAU,CAAC;AAEtB,YAAQ,QAAQ,CAAC,YAAwB,UAAkB;AACzD,YAAM,KAAK,SAAS,cAAc,KAAK;AACvC,SAAG,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUf,SAAG,MAAM,SAAS;AAClB,SAAG,MAAM,aAAa;AACtB,SAAG,MAAM,YAAY,WAAW,OAAO,mBAAmB,eAAe;AAEzE,YAAM,SAAS,IAAI,OAAO,OAAO,EAAE,SAAS,GAAG,CAAC,EAC7C,UAAU,CAAC,WAAW,KAAK,WAAW,GAAG,CAAC,EAC1C,MAAM,eAAe,OAAQ;AAEhC,SAAG,iBAAiB,SAAS,CAAC,MAAM;AAClC,UAAE,gBAAgB;AAClB,wBAAgB,YAAY,OAAO,eAAe,OAAQ;AAAA,MAC5D,CAAC;AAED,iBAAW,QAAQ,KAAK,MAAM;AAAA,IAChC,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,QAAQ,eAAe,SAAS,eAAe,gBAAgB,CAAC;AAG7E,MAAI,CAAC,UAAU;AACb,WACE,oBAAC,SAAI,OAAO,EAAE,GAAG,OAAO,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,YAAY,UAAU,GAC7G,8BAAC,OAAE,0HAAuB,GAC5B;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,KAAK,iBAAiB,WAAsB,OAC9C,UACH;AAEJ;AAEA,IAAO,cAAQ;","names":[]}
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 mapInstanceRef = (0, import_react.useRef)(null);
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
- if (!canceled) {
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 || mapInstanceRef.current) return;
73
- try {
74
- const map = new mapLib.Map({
75
- container: mapContainerRef.current,
76
- ...options
77
- });
78
- map.on("load", () => {
79
- mapInstanceRef.current = map;
80
- onMapLoad?.(map);
81
- });
82
- return () => {
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 (!mapInstanceRef.current || !mapLib || markers.length === 0) {
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 el = document.createElement("div");
104
- el.innerHTML = `
105
- <div style="
106
- background: #ef4444;
107
- width: 32px;
108
- height: 32px;
109
- border-radius: 50%;
110
- border: 4px solid white;
111
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
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, mapInstanceRef.current);
149
+ onMarkerClick?.(markerData, index, mapInstance);
121
150
  });
122
151
  markersRef.current.push(marker);
123
152
  });
124
- }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);
125
- if (!isLoaded) {
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:
@@ -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';","\r\n\r\n\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport { MapProps, MapboxMap, MarkerData } from '../types';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n onMapLoad,\r\n children,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const mapInstanceRef = useRef<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n const [isLoaded, setIsLoaded] = useState(false); \r\n\r\n \r\n useEffect(() => {\r\n if (typeof window === 'undefined') return;\r\n\r\n let canceled = false;\r\n\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n if (!canceled) {\r\n setMapLib(mod.default || mod);\r\n setIsLoaded(true);\r\n }\r\n }).catch((err) => {\r\n console.error(\"خطا در لود نقشه نشان:\", err);\r\n });\r\n\r\n return () => {\r\n canceled = true;\r\n };\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstanceRef.current) return;\r\n\r\n try {\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 mapInstanceRef.current = map;\r\n onMapLoad?.(map);\r\n });\r\n\r\n return () => {\r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n if (mapInstanceRef.current) {\r\n mapInstanceRef.current.remove();\r\n mapInstanceRef.current = null;\r\n }\r\n };\r\n } catch (err) {\r\n console.error(\"خطا در ساخت نقشه:\", err);\r\n }\r\n }, [mapLib, options, onMapLoad]);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstanceRef.current || !mapLib || markers.length === 0) {\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n return;\r\n }\r\n\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData: MarkerData, index: number) => {\r\n const el = document.createElement('div');\r\n el.innerHTML = `\r\n <div style=\"\r\n background: #ef4444;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n border: 4px solid white;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n \"></div>\r\n `;\r\n el.style.cursor = 'pointer';\r\n el.style.transition = 'transform 0.3s ease';\r\n el.style.transform = markerData.id === selectedMarkerId ? 'scale(1.4)' : 'scale(1)';\r\n\r\n const marker = new mapLib.Marker({ element: el })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstanceRef.current!);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstanceRef.current!);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);\r\n\r\n \r\n if (!isLoaded) {\r\n return (\r\n <div style={{ ...style, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f3f4f6' }}>\r\n <p>در حال بارگذاری نقشه...</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div ref={mapContainerRef} className={className} style={style}>\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;"],"mappings":"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","names":[]}
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 mapInstanceRef = useRef(null);
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
- if (!canceled) {
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 || mapInstanceRef.current) return;
38
- try {
39
- const map = new mapLib.Map({
40
- container: mapContainerRef.current,
41
- ...options
42
- });
43
- map.on("load", () => {
44
- mapInstanceRef.current = map;
45
- onMapLoad?.(map);
46
- });
47
- return () => {
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 (!mapInstanceRef.current || !mapLib || markers.length === 0) {
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 el = document.createElement("div");
69
- el.innerHTML = `
70
- <div style="
71
- background: #ef4444;
72
- width: 32px;
73
- height: 32px;
74
- border-radius: 50%;
75
- border: 4px solid white;
76
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
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, mapInstanceRef.current);
114
+ onMarkerClick?.(markerData, index, mapInstance);
86
115
  });
87
116
  markersRef.current.push(marker);
88
117
  });
89
- }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);
90
- if (!isLoaded) {
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":["\r\n\r\n\"use client\";\r\n\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport { MapProps, MapboxMap, MarkerData } from '../types';\r\n\r\nconst Map: React.FC<MapProps> = ({\r\n options,\r\n markers = [],\r\n selectedMarkerId = null,\r\n onMarkerClick,\r\n onMapLoad,\r\n children,\r\n className = '',\r\n style = { width: '100%', height: '100%' },\r\n}) => {\r\n const mapContainerRef = useRef<HTMLDivElement>(null);\r\n const mapInstanceRef = useRef<MapboxMap | null>(null);\r\n const markersRef = useRef<any[]>([]);\r\n const [mapLib, setMapLib] = useState<any>(null);\r\n const [isLoaded, setIsLoaded] = useState(false); \r\n\r\n \r\n useEffect(() => {\r\n if (typeof window === 'undefined') return;\r\n\r\n let canceled = false;\r\n\r\n import('@neshan-maps-platform/mapbox-gl').then((mod) => {\r\n if (!canceled) {\r\n setMapLib(mod.default || mod);\r\n setIsLoaded(true);\r\n }\r\n }).catch((err) => {\r\n console.error(\"خطا در لود نقشه نشان:\", err);\r\n });\r\n\r\n return () => {\r\n canceled = true;\r\n };\r\n }, []);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapLib || !mapContainerRef.current || mapInstanceRef.current) return;\r\n\r\n try {\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 mapInstanceRef.current = map;\r\n onMapLoad?.(map);\r\n });\r\n\r\n return () => {\r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n if (mapInstanceRef.current) {\r\n mapInstanceRef.current.remove();\r\n mapInstanceRef.current = null;\r\n }\r\n };\r\n } catch (err) {\r\n console.error(\"خطا در ساخت نقشه:\", err);\r\n }\r\n }, [mapLib, options, onMapLoad]);\r\n\r\n \r\n useEffect(() => {\r\n if (!mapInstanceRef.current || !mapLib || markers.length === 0) {\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n return;\r\n }\r\n\r\n \r\n markersRef.current.forEach((m: any) => m.remove());\r\n markersRef.current = [];\r\n\r\n markers.forEach((markerData: MarkerData, index: number) => {\r\n const el = document.createElement('div');\r\n el.innerHTML = `\r\n <div style=\"\r\n background: #ef4444;\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n border: 4px solid white;\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n \"></div>\r\n `;\r\n el.style.cursor = 'pointer';\r\n el.style.transition = 'transform 0.3s ease';\r\n el.style.transform = markerData.id === selectedMarkerId ? 'scale(1.4)' : 'scale(1)';\r\n\r\n const marker = new mapLib.Marker({ element: el })\r\n .setLngLat([markerData.lng, markerData.lat])\r\n .addTo(mapInstanceRef.current!);\r\n\r\n el.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n onMarkerClick?.(markerData, index, mapInstanceRef.current!);\r\n });\r\n\r\n markersRef.current.push(marker);\r\n });\r\n }, [markers, mapLib, mapInstanceRef.current, onMarkerClick, selectedMarkerId]);\r\n\r\n \r\n if (!isLoaded) {\r\n return (\r\n <div style={{ ...style, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f3f4f6' }}>\r\n <p>در حال بارگذاری نقشه...</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div ref={mapContainerRef} className={className} style={style}>\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\nexport default Map;"],"mappings":"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","names":[]}
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":"AAEA,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,CAiCnC"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mehdi-akbari-map",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "A professional Map",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",