@amir83nasr/map 1.1.0 → 1.1.2
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/README.md +16 -16
- package/dist/engine/picker.d.ts +3 -0
- package/dist/index.cjs +53 -42
- package/dist/index.js +282 -243
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ import { LocationPickerView } from '@amir83nasr/map';
|
|
|
31
31
|
/>;
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
52 Qom neighborhood suggestions ship as the package default — no `search.suggestions` needed. Pass your own array to replace them, or `suggestions: []` to disable.
|
|
35
35
|
|
|
36
36
|
The component calls `destroy()` in its own `useEffect` cleanup — no manual init/destroy. Give it a height (default `480px` via `style`); without one the map renders empty.
|
|
37
37
|
|
|
@@ -52,19 +52,19 @@ Public surface: one component (`LocationPickerView`), its props type (`QomPickPr
|
|
|
52
52
|
|
|
53
53
|
Props of `LocationPickerView` (`QomPickProps` = engine options minus `container`, plus `className`/`style`; callbacks are props):
|
|
54
54
|
|
|
55
|
-
| Key | Type | Default
|
|
56
|
-
| ---------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
57
|
-
| `map.center/zoom/minZoom/maxZoom/bounds` | — | Qom`34.6416,50.8764`, z14
|
|
58
|
-
| `map.style` | URL\| StyleSpecification | Snapp-like OpenFreeMap
|
|
59
|
-
| `map.glyphs` | string | jsDelivr CDN (bundled IRANYekanX PBFs)
|
|
60
|
-
| `controls` | `{gps, confirmButton, searchTrigger, developers}` | all true except developers
|
|
61
|
-
| `search` | `{enabled, placeholder, suggestions, minLength, debounceMs, limit}` |
|
|
62
|
-
| `sheet` | `{enabled}` | true
|
|
63
|
-
| `behavior` | `{snapToRoad, resolveOnMove, resolveDelayMs, settleDelayMs, snapDelayMs, pickZoom, locateZoom}` | `400/250/900/15/18`
|
|
64
|
-
| `markers` | `Venue[]` | `[]` (off)
|
|
65
|
-
| `i18n` | `{labels}` | Persian (`fa`), always RTL
|
|
66
|
-
| callbacks | `onLocationChange/onAddressResolved/onSearchResults/onPick/onConfirm/onLocate/onError` | —
|
|
67
|
-
| `className/style` | — | height`480`
|
|
55
|
+
| Key | Type | Default | Notes |
|
|
56
|
+
| ---------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------- |
|
|
57
|
+
| `map.center/zoom/minZoom/maxZoom/bounds` | — | Qom`34.6416,50.8764`, z14 | — |
|
|
58
|
+
| `map.style` | URL\| StyleSpecification | Snapp-like OpenFreeMap | vector style only (never raster) |
|
|
59
|
+
| `map.glyphs` | string | jsDelivr CDN (bundled IRANYekanX PBFs) | relative paths resolve against page base; self-host by copying`fonts/` |
|
|
60
|
+
| `controls` | `{gps, confirmButton, searchTrigger, developers}` | all true except developers | `developers` opens the in-map developer docs |
|
|
61
|
+
| `search` | `{enabled, placeholder, suggestions, minLength, debounceMs, limit}` | 52 Qom neighborhoods (all shown);`3 / 350ms / 5` | Nominatim, Qom viewbox; custom array replaces,`[]` disables; `limit` caps remote results only |
|
|
62
|
+
| `sheet` | `{enabled}` | true | — |
|
|
63
|
+
| `behavior` | `{snapToRoad, resolveOnMove, resolveDelayMs, settleDelayMs, snapDelayMs, pickZoom, locateZoom}` | `400/250/900/15/18` | snap waits longer than settle; pinch-zoom never snaps |
|
|
64
|
+
| `markers` | `Venue[]` | `[]` (off) | generic pins, demo enables Qom data |
|
|
65
|
+
| `i18n` | `{labels}` | Persian (`fa`), always RTL | full label override |
|
|
66
|
+
| callbacks | `onLocationChange/onAddressResolved/onSearchResults/onPick/onConfirm/onLocate/onError` | — | props |
|
|
67
|
+
| `className/style` | — | height`480` | pass a height, otherwise the map is empty |
|
|
68
68
|
|
|
69
69
|
Types (`PickerLocation`, `Venue`, `SearchSuggestion`, `QomPickProps`, …) are re-exported from `@amir83nasr/map`.
|
|
70
70
|
|
|
@@ -99,7 +99,7 @@ Default basemap is vector (OpenFreeMap + OpenMapTiles); raster styles are not su
|
|
|
99
99
|
|
|
100
100
|
## In-map developer docs
|
|
101
101
|
|
|
102
|
-
Pass `controls={{ developers: true }}` to show a «توسعهدهندگان» button on the map. It opens Persian docs inside the map (`.qp-docs`)
|
|
102
|
+
Pass `controls={{ developers: true }}` to show a «توسعهدهندگان» button on the map. It opens numbered Persian docs inside the map (`.qp-docs`) with a section nav: 2-line quick start, mandatory worker setup (Vite / Next.js), props with defaults, callbacks table, theming vars, mount-only `key` rule, FAQ, and two copyable LLM prompts. Every code block has its own copy button (`.qp-code` + `.qp-code-copy`).
|
|
103
103
|
|
|
104
104
|
## Project structure
|
|
105
105
|
|
|
@@ -133,7 +133,7 @@ cd package && pnpm build && pnpm pack --dry-run # inspect tarball
|
|
|
133
133
|
pnpm publish --filter @amir83nasr/map --access public
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
Versioning: semver, currently `1.1.
|
|
136
|
+
Versioning: semver, currently `1.1.1`.
|
|
137
137
|
|
|
138
138
|
## Limitations
|
|
139
139
|
|
package/dist/engine/picker.d.ts
CHANGED
|
@@ -54,7 +54,10 @@ export declare class LocationPicker {
|
|
|
54
54
|
private devDocsHtml;
|
|
55
55
|
private openDocs;
|
|
56
56
|
private closeDocs;
|
|
57
|
+
private copyDone;
|
|
58
|
+
private copyText;
|
|
57
59
|
private copyPrompt;
|
|
60
|
+
private copyCode;
|
|
58
61
|
private fallbackCopy;
|
|
59
62
|
private openSearch;
|
|
60
63
|
private closeSearch;
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var le=Object.defineProperty;var ce=(s,e,t)=>e in s?le(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var d=(s,e,t)=>ce(s,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const de=require("react/jsx-runtime"),P=require("react"),z=require("maplibre-gl"),pe={searchPlaceholder:"جستوجوی موقعیت...",searchTitle:"جستجوی موقعیت",suggestedPlaces:"مکانهای پیشنهادی",searching:"در حال جستجو...",noResults:"نتیجهای پیدا نشد؛ عبارت دیگری امتحان کنید",searchError:"خطا در جستجو؛ اتصال را بررسی کنید",confirmLocation:"تایید موقعیت",confirm:"تایید",editOnMap:"ویرایش روی نقشه",chosenAddress:"آدرس انتخابی",coordsToServer:"مختصات ارسالی به سرور",close:"بستن",clearSearch:"پاک کردن جستجو",currentLocation:"موقعیت فعلی",locating:"در حال پیدا کردن آدرس...",resolving:"در حال پیدا کردن آدرس...",registered:"موقعیت ثبت شد",gpsUnsupported:"GPS در این مرورگر پشتیبانی نمیشود",locateTimeout:"دریافت موقعیت طول کشید؛ دستی انتخاب کنید",locateUnavailable:"موقعیت در دسترس نیست؛ دستی انتخاب کنید",geoTitle:"دسترسی به موقعیت مکانی",geoText:"برای انتخاب موقعیت فعلی شما، لازم است دسترسی موقعیت مکانی را فعال کنید.",geoBlocked:"مرورگر قبلاً دسترسی را بسته است. از تنظیمات سایت مرورگر، دسترسی Location را مجاز کنید.",enableAccess:"فعال کردن دسترسی",developers:"توسعهدهندگان",backToMap:"بازگشت به نقشه",copy:"کپی",copied:"کپی شد",submitting:"در حال ثبت..."},ie=[{name:"۱۹ دی، قم",addr:"محله ۱۹ دی، شهر قم",lat:34.6558,lng:50.9055},{name:"آذر، قم",addr:"محله آذر، شهر قم",lat:34.6492,lng:50.8965},{name:"امام حسین، قم",addr:"میدان امام حسین، شهر قم",lat:34.6512,lng:50.8932},{name:"انسجام، قم",addr:"محله انسجام، شهر قم",lat:34.6058,lng:50.8752},{name:"انقلاب، قم",addr:"خیابان انقلاب، شهر قم",lat:34.6462,lng:50.8915},{name:"باجک، قم",addr:"محله باجک، شهر قم",lat:34.6601,lng:50.8823},{name:"بلوار امین، قم",addr:"محله بلوار امین، شهر قم",lat:34.6248,lng:50.8792},{name:"بنیاد، قم",addr:"محله بنیاد، شهر قم",lat:34.6475,lng:50.8985},{name:"پردیسان، قم",addr:"شهرک پردیسان، شهر قم",lat:34.6021,lng:50.8412},{name:"توحید، قم",addr:"محله توحید، شهر قم",lat:34.6685,lng:50.8748},{name:"جمکران، قم",addr:"محله جمکران، شهر قم",lat:34.5853,lng:50.9068},{name:"چهارمردان، قم",addr:"محله چهارمردان، شهر قم",lat:34.6401,lng:50.8873},{name:"حافظ، قم",addr:"خیابان حافظ، شهر قم",lat:34.6368,lng:50.8785},{name:"حرم، قم",addr:"محله حرم، شهر قم",lat:34.6448,lng:50.8791},{name:"خاکفرج، قم",addr:"محله خاکفرج، شهر قم",lat:34.6798,lng:50.9012},{name:"دروازه ری، قم",addr:"محله دروازه ری، شهر قم",lat:34.6352,lng:50.8958},{name:"دورشهر، قم",addr:"محله دورشهر، شهر قم",lat:34.6442,lng:50.8744},{name:"زاویه، قم",addr:"محله زاویه، شهر قم",lat:34.6385,lng:50.8682},{name:"زنبیلآباد، قم",addr:"محله زنبیلآباد، شهر قم",lat:34.6221,lng:50.8912},{name:"سالاریه، قم",addr:"محله سالاریه، شهر قم",lat:34.6289,lng:50.8624},{name:"سمیه، قم",addr:"خیابان سمیه، شهر قم",lat:34.6521,lng:50.8842},{name:"شهدا، قم",addr:"خیابان شهدا، شهر قم",lat:34.6425,lng:50.8831},{name:"شهرقائم، قم",addr:"شهرک قائم، شهر قم",lat:34.6158,lng:50.8505},{name:"شهرک امام حسن، قم",addr:"شهرک امام حسن، شهر قم",lat:34.6358,lng:50.8521},{name:"شهرک مهدیه، قم",addr:"شهرک مهدیه، شهر قم",lat:34.6258,lng:50.8452},{name:"شهرک ولیعصر، قم",addr:"شهرک ولیعصر، شهر قم",lat:34.6125,lng:50.8585},{name:"شیخآباد، قم",addr:"محله شیخآباد، شهر قم",lat:34.6582,lng:50.8718},{name:"صدوق، قم",addr:"خیابان صدوق، شهر قم",lat:34.6198,lng:50.8725},{name:"صفائیه، قم",addr:"محله صفائیه، شهر قم",lat:34.6327,lng:50.8713},{name:"عسگریه، قم",addr:"محله عسگریه، شهر قم",lat:34.6305,lng:50.9018},{name:"عطاران، قم",addr:"محله عطاران، شهر قم",lat:34.6548,lng:50.8895},{name:"فرهنگیان، قم",addr:"محله فرهنگیان، شهر قم",lat:34.6105,lng:50.8702},{name:"کشاورز، قم",addr:"محله کشاورز، شهر قم",lat:34.6642,lng:50.8885},{name:"کلهری، قم",addr:"منطقه کلهری، شهر قم",lat:34.6211,lng:50.9055},{name:"کیوانفر، قم",addr:"محله کیوانفر، شهر قم",lat:34.6172,lng:50.8856},{name:"مطهری، قم",addr:"خیابان مطهری، شهر قم",lat:34.6485,lng:50.8878},{name:"معلم، قم",addr:"میدان معلم، شهر قم",lat:34.6275,lng:50.8942},{name:"نوبهار، قم",addr:"محله نوبهار، شهر قم",lat:34.6623,lng:50.8952},{name:"نیروگاه، قم",addr:"محله نیروگاه، شهر قم",lat:34.6712,lng:50.8851},{name:"هفتتیر، قم",addr:"خیابان هفتتیر، شهر قم",lat:34.6442,lng:50.8995},{name:"یزدانشهر، قم",addr:"محله یزدانشهر، شهر قم",lat:34.6012,lng:50.8628}],$={lat:34.6416,lng:50.8764},ue=14;function he(s){return{...pe,...(s==null?void 0:s.labels)??{}}}function me(){return"rtl"}function ge(s){const e=s??{};return{container:e.container,map:{center:{...$},zoom:ue,minZoom:11,maxZoom:19,bounds:[[34.15,50.35],[35.05,51.45]],...e.map??{}},controls:{gps:!0,confirmButton:!0,searchTrigger:!0,developers:!1,...e.controls??{}},search:{enabled:!0,suggestions:ie,minLength:3,debounceMs:350,limit:5,...e.search??{}},sheet:{enabled:!0,...e.sheet??{}},behavior:{snapToRoad:!0,resolveOnMove:!0,resolveDelayMs:400,settleDelayMs:250,snapDelayMs:900,pickZoom:15,locateZoom:18,...e.behavior??{}},i18n:{labels:he(e.i18n)},markers:e.markers??[]}}const ye="#e9ebee",fe="#e9ebee",G="#a9e29b",be="#9ed894",ve="#b5e8a6",we="#d3ddd0",qe="#e9dfc0",xe="#b9d9f2",ke="#cfe4f7",N="#a9cdf0",V="#4e6e94",U="#dfe3e9",Se="#e9ebee",O="#ffffff",Le="#d9dde2",x="#ffffff",A="#d5dae0",Ee="#cdbfa8",Te="#e9ebee",H="#c6ccd4",F="#b9bdc4",Q="#a7aab3",Y="#5b6067",_="#2f3338",f="#f7f8f9",j="#565b62",Me=["coalesce",["get","name:fa"],["get","name:nonlatin"],["get","name"],["get","name:latin"]],Re=["0","۰","1","۱","2","۲","3","۳","4","۴","5","۵","6","۶","7","۷","8","۸","9","۹","٠","۰","١","۱","٢","۲","٣","۳","٤","۴","٥","۵","٦","۶","٧","۷","٨","۸","٩","۹"];function Ae(s,e=40){const t=["coalesce",s,""],o=["split",["to-string",t],""],r=["length",o],i=[];for(let a=0;a<e;a++){const n=["at",a,o];i.push(["case",[">",r,a],["match",n,...Re,n],""])}return i.push(["slice",["to-string",t],e]),["format",["concat",...i],{}]}const b=Ae(Me),k=["IRANYekanX"],D=["IRANYekanX"],q=["LineString","MultiLineString"],_e=["MultiPoint","Point"];function y(s){return["interpolate",["exponential",1.2],["zoom"],...s]}const X=["interpolate",["exponential",1.2],["zoom"],12.5,0,13,1.5,14,2.5,20,11.5],Ce=["interpolate",["exponential",1.2],["zoom"],12,.5,13,1,14,4,20,15],ze=[{id:"background",type:"background",paint:{"background-color":ye}},{id:"landuse-residential",type:"fill",source:"openmaptiles","source-layer":"landuse",filter:["match",["get","class"],["neighbourhood","residential"],!0,!1],paint:{"fill-color":fe}},{id:"landuse-cemetery",type:"fill",source:"openmaptiles","source-layer":"landuse",filter:["==",["get","class"],"cemetery"],paint:{"fill-color":we}},{id:"landcover-wood",type:"fill",source:"openmaptiles","source-layer":"landcover",filter:["==",["get","class"],"wood"],paint:{"fill-color":be}},{id:"landcover-grass",type:"fill",source:"openmaptiles","source-layer":"landcover",filter:["==",["get","class"],"grass"],paint:{"fill-color":ve}},{id:"landcover-grass-park",type:"fill",source:"openmaptiles","source-layer":"park",paint:{"fill-color":G}},{id:"park",type:"fill",source:"openmaptiles","source-layer":"park",filter:["match",["geometry-type"],["MultiPolygon","Polygon"],!0,!1],paint:{"fill-color":G}},{id:"landcover-sand",type:"fill",source:"openmaptiles","source-layer":"landcover",filter:["==",["get","class"],"sand"],paint:{"fill-color":qe}},{id:"water",type:"fill",source:"openmaptiles","source-layer":"water",filter:["all",["!=",["get","intermittent"],1],["!=",["get","brunnel"],"tunnel"]],paint:{"fill-color":xe}},{id:"water-intermittent",type:"fill",source:"openmaptiles","source-layer":"water",filter:["all",["==",["get","intermittent"],1],["!=",["get","brunnel"],"tunnel"]],paint:{"fill-color":ke,"fill-opacity":.8}},{id:"waterway-other",type:"line",source:"openmaptiles","source-layer":"waterway",filter:["all",["match",["get","class"],["canal","river","stream"],!1,!0],["==",["get","intermittent"],0]],paint:{"line-color":N,"line-width":["interpolate",["exponential",1.3],["zoom"],13,.5,20,2]}},{id:"waterway-stream-canal",type:"line",source:"openmaptiles","source-layer":"waterway",filter:["all",["match",["get","class"],["canal","stream"],!0,!1],["!=",["get","brunnel"],"tunnel"],["==",["get","intermittent"],0]],paint:{"line-color":N,"line-width":["interpolate",["exponential",1.3],["zoom"],13,.5,20,6]}},{id:"waterway-river",type:"line",source:"openmaptiles","source-layer":"waterway",filter:["all",["==",["get","class"],"river"],["!=",["get","brunnel"],"tunnel"],["!=",["get","intermittent"],1]],paint:{"line-color":N,"line-width":["interpolate",["exponential",1.2],["zoom"],10,.8,20,6]}},{id:"building",type:"fill",source:"openmaptiles","source-layer":"building",paint:{"fill-antialias":!0,"fill-color":U}},{id:"building-top",type:"fill",source:"openmaptiles","source-layer":"building",paint:{"fill-color":Se,"fill-opacity":["interpolate",["linear"],["zoom"],13,0,16,1],"fill-outline-color":U,"fill-translate":["interpolate",["linear"],["zoom"],14,["literal",[0,0]],16,["literal",[-2,-2]]]}},{id:"aeroway-area",type:"fill",source:"openmaptiles","source-layer":"aeroway",paint:{"fill-color":Te,"fill-opacity":["interpolate",["linear"],["zoom"],13,0,14,1]}},{id:"aeroway-taxiway-casing",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"taxiway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":H,"line-width":["interpolate",["exponential",1.5],["zoom"],11,2,17,12]}},{id:"aeroway-taxiway",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"taxiway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":["interpolate",["exponential",1.5],["zoom"],11,1,17,10]}},{id:"aeroway-runway-casing",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"runway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":H,"line-width":["interpolate",["exponential",1.5],["zoom"],11,5,17,55]}},{id:"aeroway-runway",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"runway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":["interpolate",["exponential",1.5],["zoom"],11,4,17,50]}},{id:"highway-minor-casing",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["!=",["get","brunnel"],"tunnel"],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":Le,"line-opacity":["interpolate",["linear"],["zoom"],12,0,12.5,1],"line-width":Ce}},{id:"highway-link-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:13,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary","secondary","tertiary","trunk"],!0,!1],["==",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-width":y([12,1,13,3,14,4,20,15])}},{id:"highway-secondary-tertiary-casing",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["secondary","tertiary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-width":y([8,1.5,20,17])}},{id:"highway-primary-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-opacity":["interpolate",["linear"],["zoom"],7,0,8,1],"line-width":y([7,0,8,.6,9,1.5,20,22])}},{id:"highway-trunk-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["trunk"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-opacity":["interpolate",["linear"],["zoom"],5,0,6,1],"line-width":y([5,0,6,.6,7,1.5,20,22])}},{id:"highway-motorway-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:4,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"motorway"],["!=",["get","ramp"],1]],layout:{"line-cap":"butt","line-join":"round"},paint:{"line-color":A,"line-opacity":["interpolate",["linear"],["zoom"],4,0,5,1],"line-width":y([4,0,5,.4,6,.6,7,1.5,20,22])}},{id:"highway-path",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"path"]],paint:{"line-color":Ee,"line-dasharray":[1.5,.75],"line-width":y([15,1.2,20,4])}},{id:"highway-link",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:13,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary","secondary","tertiary","trunk"],!0,!1],["==",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([12.5,0,13,1.5,14,2.5,20,11.5])}},{id:"highway-minor",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["!=",["get","brunnel"],"tunnel"],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":X}},{id:"highway-secondary-tertiary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["secondary","tertiary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([6.5,0,8,.5,20,13])}},{id:"highway-primary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([8.5,0,9,.5,20,18])}},{id:"highway-trunk",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["trunk"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([6.5,0,7,.5,20,18])}},{id:"highway-motorway",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"motorway"],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([6.5,0,7,.5,20,18])}},{id:"bridge-link",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:13,filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["primary","secondary","tertiary","trunk"],!0,!1],["==",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([12.5,0,13,1.5,14,2.5,20,11.5])}},{id:"bridge-minor",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":X}},{id:"bridge-secondary-tertiary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["secondary","tertiary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([6.5,0,8,.5,20,13])}},{id:"bridge-trunk-primary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["primary","trunk"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([6.5,0,7,.5,20,18])}},{id:"bridge-motorway",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["==",["get","brunnel"],"bridge"],["==",["get","class"],"motorway"],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":x,"line-width":y([6.5,0,7,.5,20,18])}},{id:"railway-transit",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["==",["get","class"],"transit"],["match",["get","brunnel"],["tunnel"],!1,!0]],paint:{"line-color":F,"line-width":["interpolate",["exponential",1.4],["zoom"],14,.4,20,1]}},{id:"railway-service",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["has","service"],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"rail"]],paint:{"line-color":F,"line-width":["interpolate",["exponential",1.4],["zoom"],14,.4,20,1]}},{id:"railway",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["!",["has","service"]],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"rail"]],paint:{"line-color":F,"line-width":["interpolate",["exponential",1.4],["zoom"],14,.4,15,.75,20,2]}},{id:"boundary_3",type:"line",source:"openmaptiles","source-layer":"boundary",filter:["all",["==",["get","admin_level"],3],["!=",["get","maritime"],1]],paint:{"line-color":Q,"line-dasharray":[1,1],"line-width":["interpolate",["linear"],["zoom"],7,1,11,2]}},{id:"boundary_2",type:"line",source:"openmaptiles","source-layer":"boundary",filter:["all",["==",["get","admin_level"],2],["!=",["get","maritime"],1],["!=",["get","disputed"],1],["!",["has","claimed_by"]]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":Q,"line-opacity":["interpolate",["linear"],["zoom"],0,.4,4,1],"line-width":["interpolate",["linear"],["zoom"],3,1,5,1.2,12,3]}},{id:"waterway_line_label",type:"symbol",source:"openmaptiles","source-layer":"waterway",layout:{"symbol-placement":"line","symbol-spacing":350,"text-field":b,"text-font":k,"text-size":13},paint:{"text-color":V,"text-halo-color":f,"text-halo-width":1.5}},{id:"water_name_label",type:"symbol",source:"openmaptiles","source-layer":"water_name",layout:{"text-field":b,"text-font":k,"text-max-width":8,"text-size":12},paint:{"text-color":V,"text-halo-color":f,"text-halo-width":1.5}},{id:"poi_worship_school",type:"symbol",source:"openmaptiles","source-layer":"poi",minzoom:14,filter:["match",["get","class"],["place_of_worship","school","college","library","hospital","park"],!0,!1],layout:{"icon-image":["match",["get","class"],["place_of_worship"],"place_of_worship",["school"],"school",["college"],"school",["library"],"school",["hospital"],"hospital",["park"],"park",""],"icon-size":1.1,"text-anchor":"top","text-field":b,"text-font":k,"text-max-width":8,"text-offset":[0,1],"text-size":12},paint:{"text-color":j,"text-halo-color":f,"text-halo-width":1.5}},{id:"poi_shops",type:"symbol",source:"openmaptiles","source-layer":"poi",minzoom:15.5,filter:["match",["get","class"],["shop","grocery","restaurant","cafe","fast_food","pharmacy","bank","fuel"],!0,!1],layout:{"icon-image":["match",["get","class"],["grocery"],"grocery",["restaurant"],"restaurant",["cafe"],"cafe",["fast_food"],"restaurant",["pharmacy"],"pharmacy",["bank"],"bank",["fuel"],"fuel","shop"],"icon-size":1,"text-anchor":"top","text-field":b,"text-font":k,"text-max-width":8,"text-offset":[0,1],"text-size":12},paint:{"text-color":j,"text-halo-color":f,"text-halo-width":1.5}},{id:"poi_r1",type:"symbol",source:"openmaptiles","source-layer":"poi",minzoom:16,filter:["all",["match",["geometry-type"],_e,!0,!1],[">=",["get","rank"],1],["<",["get","rank"],7]],layout:{"icon-image":["match",["get","subclass"],["florist","furniture"],["get","subclass"],["get","class"]],"icon-size":.8,"text-anchor":"top","text-field":b,"text-font":k,"text-max-width":8,"text-offset":[0,.8],"text-size":12},paint:{"text-color":j,"text-halo-color":f,"text-halo-width":1.5}},{id:"airport",type:"symbol",source:"openmaptiles","source-layer":"aerodrome_label",minzoom:10,filter:["all",["has","iata"]],layout:{"icon-image":"airport_11","icon-size":1,"text-anchor":"top","text-field":b,"text-font":k,"text-max-width":8,"text-offset":[0,.8],"text-size":12},paint:{"text-color":j,"text-halo-color":f,"text-halo-width":1.5}},{id:"highway-name-minor",type:"symbol",source:"openmaptiles","source-layer":"transportation_name",minzoom:14,filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"symbol-placement":"line","text-field":b,"text-font":k,"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],14,11,17,12]},paint:{"text-color":Y,"text-halo-color":f,"text-halo-width":1.5}},{id:"highway-name-major",type:"symbol",source:"openmaptiles","source-layer":"transportation_name",minzoom:11,filter:["match",["get","class"],["primary","secondary","tertiary","trunk","motorway"],!0,!1],layout:{"symbol-placement":"line","text-field":b,"text-font":D,"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],11,11,15,13]},paint:{"text-color":Y,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_village",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:9,filter:["==",["get","class"],"village"],layout:{"text-field":b,"text-font":k,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],9,11,12,13]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_town",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:6,filter:["==",["get","class"],"town"],layout:{"text-field":b,"text-font":D,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],7,12,11,14]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_other",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:8,filter:["match",["get","class"],["city","continent","country","state","town","village"],!1,!0],layout:{"text-field":b,"text-font":k,"text-max-width":8,"text-size":["interpolate",["linear"],["zoom"],8,10,12,12]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_city",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:3,filter:["all",["==",["get","class"],"city"],["!=",["get","capital"],2]],layout:{"text-field":b,"text-font":D,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],4,11,7,13,11,16]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_city_capital",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:3,filter:["all",["==",["get","class"],"city"],["==",["get","capital"],2]],layout:{"text-field":b,"text-font":D,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],4,12,7,14,11,18]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}}],$e="https://tiles.openfreemap.org/planet",Pe={version:8,name:"snapp-like",glyphs:"https://cdn.jsdelivr.net/npm/@amir83nasr/map@1/fonts/{fontstack}/{range}.pbf",sprite:"https://tiles.openfreemap.org/sprites/ofm_f384/ofm",sources:{openmaptiles:{type:"vector",url:$e}},layers:ze};class Oe{constructor(){d(this,"map",new Map)}on(e,t){let o=this.map.get(e);return o||this.map.set(e,o=new Set),o.add(t),()=>this.off(e,t)}off(e,t){var o;(o=this.map.get(e))==null||o.delete(t)}emit(e,t){for(const o of this.map.get(e)??[])try{o(t)}catch{}}}function C(s){return`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${s}</svg>`}const v={locate:C('<line x1="2" x2="5" y1="12" y2="12"/><line x1="19" x2="22" y1="12" y2="12"/><line x1="12" x2="12" y1="2" y2="5"/><line x1="12" x2="12" y1="19" y2="22"/><circle cx="12" cy="12" r="7"/><circle cx="12" cy="12" r="3"/>'),pin:C('<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>'),search:C('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),star:C('<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" fill="currentColor" stroke="none"/>'),x:C('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>')},K="۰۱۲۳۴۵۶۷۸۹";function S(s){return String(s).replace(/\d/g,e=>K[Number(e)]).replace(/[٠-٩]/g,e=>K["٠١٢٣٤٥٦٧٨٩".indexOf(e)])}function J(s,e=5){return S(Number(s).toFixed(e))}function M(s){return String(s).replace(/[۰-۹]/g,e=>String("۰۱۲۳۴۵۶۷۸۹".indexOf(e))).replace(/[٠-٩]/g,e=>String("٠١٢٣٤٥٦٧٨٩".indexOf(e)))}function ee(s){if(!s)return"";const e=String(s).split(",").map(o=>o.trim()).filter(Boolean),t=o=>!!(/^(ایران|Iran)$/i.test(o)||/^استان\b/.test(o)||/^شهرستان\b/.test(o)||/^بخش\b/.test(o)||/^[\d\s\-–—]+$/.test(M(o)));return e.filter(o=>!t(o)).slice(0,4).reverse().join(", ")}function je(s,e){return Number.isFinite(s)&&Number.isFinite(e)&&s>=-90&&s<=90&&e>=-180&&e<=180}const De="50.35,35.05,51.45,34.15",W=new Map,Z=new Map;function se(s,e){s.size>e&&s.delete(s.keys().next().value)}async function Ie(s,e,t){const o=`${s.toFixed(4)},${e.toFixed(4)}`,r=W.get(o);if(r)return r;const i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${s}&lon=${e}&accept-language=fa`,{headers:{Accept:"application/json"},signal:t==null?void 0:t.signal});if(!i.ok)throw new Error(`http ${i.status}`);const a=await i.json();if(!a.display_name)throw new Error("empty result");return W.set(o,a.display_name),se(W,200),a.display_name}async function Ne(s,e=5,t){const o=`${M(s).trim().toLowerCase()}|${e}`,r=Z.get(o);if(r)return r;const i=await fetch(`https://nominatim.openstreetmap.org/search?format=jsonv2&accept-language=fa&limit=${e}&viewbox=${De}&bounded=1&q=${encodeURIComponent(M(s))}`,{headers:{Accept:"application/json"},signal:t==null?void 0:t.signal});if(!i.ok)throw new Error(`http ${i.status}`);const a=await i.json();return Z.set(o,a),se(Z,50),a}const Fe=["highway-minor","highway-link","highway-secondary-tertiary","highway-primary","highway-trunk","highway-motorway","bridge-minor","bridge-link","bridge-secondary-tertiary","bridge-trunk-primary","bridge-motorway"],T=64,We=15,te=2;function Ze(s,e,t,o,r,i){const a=r-t,n=i-o,l=a*a+n*n,g=l===0?0:((s-t)*a+(e-o)*n)/l,m=Math.max(0,Math.min(1,g)),p=t+m*a,u=o+m*n;return{x:p,y:u,d2:(s-p)*(s-p)+(e-u)*(e-u)}}function Be(s,e,t){if(s.getZoom()<We)return null;const o=s.project([t,e]);let r;try{const l=[[o.x-T,o.y-T],[o.x+T,o.y+T]];r=s.queryRenderedFeatures(l,{layers:Fe})}catch{return null}let i=null,a=T*T;for(const l of r){const g=l.geometry,m=g.type==="LineString"?[g.coordinates]:g.type==="MultiLineString"?g.coordinates:[];for(const p of m){let u=null;for(const L of p){const c=s.project(L);if(u){const h=Ze(o.x,o.y,u.x,u.y,c.x,c.y);h.d2<a&&(a=h.d2,i={x:h.x,y:h.y})}u={x:c.x,y:c.y}}}}if(!i||a<te*te)return null;const n=s.unproject([i.x,i.y]);return{lat:n.lat,lng:n.lng}}const oe=3,Ge="Vite: import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url'; سپس setupQomPickWorker(workerUrl) را قبل از mount صدا بزنید. Next.js/webpack: هر دو فایل worker و shared را کپی کنید.",Ve="qompick: MapLibre worker failed to load. Call setupQomPickWorker(workerUrl) from @amir83nasr/map before mounting LocationPickerView. Vite: use maplibre-gl-worker.mjs?worker&url. Next.js/webpack: copy maplibre-gl-worker.mjs and maplibre-gl-shared.mjs.";let B=!1;function Ue(s){const e=globalThis.Worker;if(typeof e!="function")return()=>{};class t extends e{constructor(r,i){super(r,i),B=!1,this.addEventListener("error",()=>{B=!0,s()})}}return globalThis.Worker=t,()=>{globalThis.Worker=e}}function He(s){const e=s,t=[e==null?void 0:e.message,e==null?void 0:e.filename,e==null?void 0:e.url,s].filter(o=>typeof o=="string").join(" ").toLowerCase();return/maplibre-gl-(worker|shared)(?:-dev)?\.mjs/.test(t)||/failed to fetch worker script/.test(t)||/worker/.test(t)&&/failed to load|cannot load|dynamically imported module/.test(t)}const I="من میخواهم با پکیج قمپیک (@amir83nasr/map) یک نقشه انتخاب موقعیت (LocationPickerView) از صفر در پروژه React/Next.js بسازم. این پکیج کاملاً متنباز و رایگان است و روی MapLibre GL ساخته شده و فقط نسخه React دارد. لطفاً قدمبهقدم و به ترتیب راهنماییام کن: ۱) نصب — دستور نصب @amir83nasr/map و maplibre-gl نسخه ۶ (که peer dependency است و باید جدا نصب شود)؛ ۲) راهاندازی پایه — ایمپورت @amir83nasr/map/styles.css (شامل CSS مپلایبر، فقط یک import CSS) و رندر کامپوننت LocationPickerView با ارتفاع مشخص (مثلاً 480px، چون بدون ارتفاع نقشه خالی دیده میشود) و center و zoom اولیه؛ ۳) جستجو — استفاده از پیشنهادهای پیشفرض محلههای قم، یا جایگزینی آنها با search.suggestions شامل name و addr و lat و lng؛۴) مارکرها — نمایش مارکر مکانها با markers؛ ۵) دریافت نتیجه — گرفتن مختصات و آدرس تاییدشده کاربر با onConfirm؛ ۶) پاکسازی — کامپوننت LocationPickerView خودش destroy را در cleanup صدا میزند. کد کامل و قابل اجرا بده شامل همه importها و cssها، بگو هر بخش چه میکند، و در پایان خروجی مورد انتظار را توصیف کن: نقشه فارسی راستچین (RTL) و موبایلفرست با پین وسط، دکمه GPS، جستجو و دکمه تایید موقعیت. اگر چیزی از پروژه من لازم داری (نسخه React/Next.js، نسخه پکیجها) اول بپرس.",ae="پروژه React/Next.js من از قبل وجود دارد و میخواهم نقشه انتخاب موقعیت قمپیک (@amir83nasr/map) را به آن اضافه کنم بدون اینکه چیز دیگری خراب شود. این پکیج کاملاً متنباز و رایگان است و روی MapLibre GL ساخته شده و فقط نسخه React دارد. لطفاً قدمبهقدم و به ترتیب راهنماییام کن: ۱) نصب — دستور نصب @amir83nasr/map و maplibre-gl نسخه ۶ (که peer dependency است و باید جدا نصب شود)، با توجه به اینکه بقیه dependencyهای پروژه نباید بههم بخورد؛ ۲) ایمپورت css — اضافه کردن @amir83nasr/map/styles.css (شامل CSS مپلایبر؛ فقط یک import CSS) طوری که با استایلهای فعلی پروژه تداخل نکند (همه کلاسها و متغیرهای قمپیک با qp- شروع میشوند)؛ ۳) کانتینر — رندر LocationPickerView با ارتفاع مشخص (مثلاً 480px، چون بدون ارتفاع نقشه خالی دیده میشود) در جای مناسب صفحه فعلی؛ ۴) اتصال — دادن center و zoom، استفاده یا جایگزینی پیشنهادهای پیشفرض search، نمایش markers، و گرفتن مختصات و آدرس تاییدشده با onConfirm؛۵) پاکسازی — کامپوننت LocationPickerView خودش destroy را در cleanup صدا میزند. کد کامل و قابل اجرا بده شامل همه importها، بگو هر بخش چه میکند، و در پایان خروجی مورد انتظار را توصیف کن: نقشه فارسی راستچین (RTL) و موبایلفرست با پین وسط، دکمه GPS، جستجو و دکمه تایید موقعیت. اگر چیزی از پروژه من لازم داری (نسخه React/Next.js، نسخه پکیجها، ساختار فایلها) اول بپرس.",re={zero:I,existing:ae};function w(s){const e=document.createElement("template");return e.innerHTML=s.trim(),e.content.firstElementChild}class Qe{constructor(e){d(this,"opts");d(this,"emitter",new Oe);d(this,"root");d(this,"map");d(this,"myMarker",null);d(this,"venueMarkers",[]);d(this,"labelEl");d(this,"toastEl");d(this,"overlay");d(this,"resolveT",0);d(this,"searchT",0);d(this,"toastT",0);d(this,"settleT",0);d(this,"confirmT",0);d(this,"venueT",[]);d(this,"revSeq",0);d(this,"searchSeq",0);d(this,"revAbort",null);d(this,"searchAbort",null);d(this,"destroyed",!1);d(this,"workerFailed",!1);d(this,"boundsSaved",null);d(this,"lat",$.lat);d(this,"lng",$.lng);d(this,"address","");d(this,"resolving",!1);d(this,"onKey",e=>{e.key==="Escape"&&(this.overlay.hidden?this.isHidden(".qp-docs")?this.isHidden(".qp-confirm")?this.isHidden(".qp-geo")||this.closeModal("qp-geo"):this.closeModal("qp-confirm"):this.closeDocs():this.closeSearch())});var o,r;const t=typeof e.container=="string"?document.querySelector(e.container):e.container;if(!t)throw new Error("qompick: container not found");this.opts=ge(e);for(const[i,a]of[["onLocationChange","locationChange"],["onAddressResolved","addressResolved"],["onSearchResults","searchResults"],["onPick","pick"],["onConfirm","confirm"],["onLocate","locate"],["onError","error"]]){const n=e[i];typeof n=="function"&&this.emitter.on(a,n)}this.build(t),this.initMap(),this.opts.markers.length&&this.addVenues(this.opts.markers),this.setLocation(((o=this.opts.map.center)==null?void 0:o.lat)??$.lat,((r=this.opts.map.center)==null?void 0:r.lng)??$.lng,{resolve:!0}),this.emitter.emit("ready",this.getLocation())}isHidden(e){var t;return((t=this.root.querySelector(e))==null?void 0:t.hidden)??!0}on(e,t){return this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}getLocation(){return{lat:this.lat,lng:this.lng,address:this.address}}setLocation(e,t,o={}){if(!je(e,t)){this.fail(new Error("invalid coordinates"));return}this.lat=e,this.lng=t;const r=this.getLocation();if(this.emitter.emit("locationChange",r),o.moveMap&&this.map){const i=o.zoom??Math.max(this.map.getZoom(),this.opts.behavior.pickZoom??15);this.map.flyTo({center:[t,e],zoom:i,duration:450})}o.resolve!==!1&&this.opts.behavior.resolveOnMove!==!1?this.scheduleResolve(e,t):this.renderLabel()}locate(){if(!navigator.geolocation){this.toast(this.t("gpsUnsupported")),this.fail(new Error("geolocate: unsupported"));return}const e=this.root.querySelector(".qp-gps");if(!window.isSecureContext){this.openModal("qp-geo"),this.fail(new Error("geolocate: insecure-context"));return}e==null||e.classList.add("is-locating"),navigator.geolocation.getCurrentPosition(t=>{if(e==null||e.classList.remove("is-locating"),!this.boundsSaved){const o=this.map.getMaxBounds();o&&(this.boundsSaved={sw:o.getSouthWest().toArray(),ne:o.getNorthEast().toArray()})}this.map.setMaxBounds(null),this.showMyPos(t.coords.latitude,t.coords.longitude),this.setLocation(t.coords.latitude,t.coords.longitude,{moveMap:!0,zoom:this.opts.behavior.locateZoom??18}),this.boundsSaved&&(this.map.setMaxBounds([this.boundsSaved.sw,this.boundsSaved.ne]),this.boundsSaved=null),this.emitter.emit("locate",this.getLocation())},t=>{e==null||e.classList.remove("is-locating"),(t==null?void 0:t.code)===t.PERMISSION_DENIED?this.openModal("qp-geo"):(this.toast((t==null?void 0:t.code)===t.TIMEOUT?this.t("locateTimeout"):this.t("locateUnavailable")),this.scheduleResolve(this.lat,this.lng,100)),this.fail(new Error(`geolocate: ${t==null?void 0:t.code}`))},{timeout:1e4})}confirm(e){const t={lat:this.lat,lng:this.lng,address:e??this.address};return this.emitter.emit("confirm",t),t}destroy(){var e,t,o,r;this.destroyed=!0,document.removeEventListener("keydown",this.onKey),window.clearTimeout(this.resolveT),window.clearTimeout(this.searchT),window.clearTimeout(this.toastT),window.clearTimeout(this.settleT),window.clearTimeout(this.confirmT),this.venueT.forEach(i=>window.clearTimeout(i)),(e=this.revAbort)==null||e.abort(),(t=this.searchAbort)==null||t.abort(),this.venueMarkers.forEach(i=>i.remove()),(o=this.myMarker)==null||o.remove(),(r=this.map)==null||r.remove(),this.root.remove()}t(e){return this.opts.i18n.labels[e]}build(e){const t=this.opts,o=me(),r=(t.search.placeholder??this.t("searchPlaceholder")).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">");this.root=w(`<div class="qp qp-app" dir="${o}"></div>`);const i='<div class="qp-pin" aria-hidden="true"><div class="qp-pin-body"><div class="qp-pin-head"><div class="qp-pin-hole"></div></div><div class="qp-pin-stem"></div><div class="qp-pin-foot"></div></div><div class="qp-pin-shadow"></div></div>';this.root.innerHTML=`
|
|
1
|
+
"use strict";var ne=Object.defineProperty;var le=(a,e,t)=>e in a?ne(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var d=(a,e,t)=>le(a,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ce=require("react/jsx-runtime"),P=require("react"),z=require("maplibre-gl"),de={searchPlaceholder:"جستوجوی موقعیت...",searchTitle:"جستجوی موقعیت",suggestedPlaces:"مکانهای پیشنهادی",searching:"در حال جستجو...",noResults:"نتیجهای پیدا نشد؛ عبارت دیگری امتحان کنید",searchError:"خطا در جستجو؛ اتصال را بررسی کنید",confirmLocation:"تایید موقعیت",confirm:"تایید",editOnMap:"ویرایش روی نقشه",chosenAddress:"آدرس انتخابی",coordsToServer:"مختصات ارسالی به سرور",close:"بستن",clearSearch:"پاک کردن جستجو",currentLocation:"موقعیت فعلی",locating:"در حال پیدا کردن آدرس...",resolving:"در حال پیدا کردن آدرس...",registered:"موقعیت ثبت شد",gpsUnsupported:"GPS در این مرورگر پشتیبانی نمیشود",locateTimeout:"دریافت موقعیت طول کشید؛ دستی انتخاب کنید",locateUnavailable:"موقعیت در دسترس نیست؛ دستی انتخاب کنید",geoTitle:"دسترسی به موقعیت مکانی",geoText:"برای انتخاب موقعیت فعلی شما، لازم است دسترسی موقعیت مکانی را فعال کنید.",geoBlocked:"مرورگر قبلاً دسترسی را بسته است. از تنظیمات سایت مرورگر، دسترسی Location را مجاز کنید.",enableAccess:"فعال کردن دسترسی",developers:"توسعهدهندگان",backToMap:"بازگشت به نقشه",copy:"کپی",copied:"کپی شد",submitting:"در حال ثبت..."},re=[{name:"۱۹ دی",addr:"شهر قم، خیابان ۱۹ دی",lat:34.6457,lng:50.8851},{name:"۷۲ تن",addr:"شهر قم، میدان ۷۲ تن",lat:34.6753,lng:50.8922},{name:"آبشار",addr:"شهر قم، بوستان آبشار",lat:34.6869,lng:50.8899},{name:"آذر",addr:"شهر قم، بوستان شهدای آذر",lat:34.6341,lng:50.906},{name:"ارم",addr:"شهر قم، محله ارم",lat:34.6424,lng:50.8804},{name:"امام حسین",addr:"شهر قم، میدان امام حسین",lat:34.6426,lng:50.8491},{name:"امام خمینی",addr:"شهر قم، خیابان امام خمینی",lat:34.6633,lng:50.8759},{name:"انسجام",addr:"شهر قم، محله انسجام",lat:34.6081,lng:50.8783},{name:"انقلاب",addr:"شهر قم، خیابان انقلاب",lat:34.6354,lng:50.8906},{name:"باجک",addr:"شهر قم، محله باجک",lat:34.6496,lng:50.8906},{name:"بلوار امین",addr:"شهر قم، بلوار امین",lat:34.6335,lng:50.8676},{name:"بلوار الغدیر",addr:"شهر قم، بلوار الغدیر",lat:34.5956,lng:50.8209},{name:"بلوار جمهوری اسلامی",addr:"شهر قم، بلوار جمهوری اسلامی",lat:34.6056,lng:50.8866},{name:"بلوار پیامبر اعظم",addr:"شهر قم، بلوار پیامبر اعظم",lat:34.6113,lng:50.8973},{name:"بنیاد",addr:"شهر قم، محله بنیاد",lat:34.5944,lng:50.8768},{name:"پردیسان",addr:"شهر قم، شهرک پردیسان",lat:34.5588,lng:50.8331},{name:"توحید",addr:"شهر قم، میدان توحید",lat:34.6436,lng:50.8628},{name:"جمکران",addr:"شهر قم، مسجد مقدس جمکران",lat:34.5841,lng:50.9146},{name:"چهارمردان",addr:"شهر قم، محله چهارمردان",lat:34.6335,lng:50.889},{name:"حافظ",addr:"شهر قم، خیابان حافظ",lat:34.6494,lng:50.8611},{name:"حرم",addr:"شهر قم، حرم حضرت معصومه",lat:34.6419,lng:50.8787},{name:"خاکفرج",addr:"شهر قم، محله خاکفرج",lat:34.6517,lng:50.8853},{name:"دروازه ری",addr:"شهر قم، محله دروازه ری",lat:34.6446,lng:50.9023},{name:"دورشهر",addr:"شهر قم، محله دورشهر",lat:34.6296,lng:50.8705},{name:"زاویه",addr:"شهر قم، محله زاویه",lat:34.6214,lng:50.9078},{name:"زنبیلآباد",addr:"شهر قم، محله زنبیلآباد",lat:34.6075,lng:50.862},{name:"سالاریه",addr:"شهر قم، محله سالاریه",lat:34.6116,lng:50.8471},{name:"سعیدی",addr:"شهر قم، میدان سعیدی",lat:34.65,lng:50.878},{name:"سمیه",addr:"شهر قم، خیابان سمیه",lat:34.632,lng:50.8826},{name:"شهدا",addr:"شهر قم، خیابان شهدا",lat:34.6362,lng:50.872},{name:"شهرک امام حسن",addr:"شهر قم، شهرک امام حسن",lat:34.6782,lng:50.88},{name:"شهرک صنعتی شکوهیه",addr:"شهر قم، شهرک صنعتی شکوهیه",lat:34.7956,lng:50.8177},{name:"شهرک فاطمیه",addr:"شهر قم، شهرک فاطمیه",lat:34.6746,lng:50.8521},{name:"شهرک قدس",addr:"شهر قم، شهرک قدس",lat:34.5969,lng:50.8426},{name:"شهرک مهدیه",addr:"شهر قم، شهرک مهدیه",lat:34.5823,lng:50.8238},{name:"شیخآباد",addr:"شهر قم، محله شیخآباد",lat:34.6474,lng:50.8344},{name:"صدوق",addr:"شهر قم، محله صدوق",lat:34.6313,lng:50.8743},{name:"صفائیه",addr:"شهر قم، محله صفائیه",lat:34.6362,lng:50.8721},{name:"طالقانی",addr:"شهر قم، خیابان طالقانی",lat:34.6734,lng:50.8704},{name:"عطاران",addr:"شهر قم، محله عطاران",lat:34.624,lng:50.8714},{name:"علیبنجعفر",addr:"شهر قم، آستان علیبنجعفر",lat:34.6313,lng:50.8973},{name:"فرهنگیان",addr:"شهر قم، محله فرهنگیان",lat:34.6682,lng:50.8984},{name:"کشاورز",addr:"شهر قم، خیابان کشاورز",lat:34.656,lng:50.8446},{name:"کلهری",addr:"شهر قم، منطقه کلهری",lat:34.6257,lng:50.9034},{name:"کیوانفر",addr:"شهر قم، بلوار شهید کیوانفر",lat:34.6582,lng:50.8821},{name:"مطهری",addr:"شهر قم، خیابان مطهری",lat:34.646,lng:50.8486},{name:"معلم",addr:"شهر قم، میدان معلم",lat:34.6328,lng:50.8848},{name:"نوبهار",addr:"شهر قم، محله نوبهار",lat:34.6409,lng:50.9053},{name:"نیروگاه",addr:"شهر قم، محله نیروگاه",lat:34.6487,lng:50.8587},{name:"هفتتیر",addr:"شهر قم، خیابان هفتتیر",lat:34.6571,lng:50.8848},{name:"هنرستان",addr:"شهر قم، محله هنرستان",lat:34.628,lng:50.8878},{name:"یزدانشهر",addr:"شهر قم، محله یزدانشهر",lat:34.6154,lng:50.8824}],$={lat:34.6416,lng:50.8764},pe=14;function he(a){return{...de,...(a==null?void 0:a.labels)??{}}}function ue(){return"rtl"}function me(a){const e=a??{};return{container:e.container,map:{center:{...$},zoom:pe,minZoom:11,maxZoom:19,bounds:[[34.15,50.35],[35.05,51.45]],...e.map??{}},controls:{gps:!0,confirmButton:!0,searchTrigger:!0,developers:!1,...e.controls??{}},search:{enabled:!0,suggestions:re,minLength:3,debounceMs:350,limit:5,...e.search??{}},sheet:{enabled:!0,...e.sheet??{}},behavior:{snapToRoad:!0,resolveOnMove:!0,resolveDelayMs:400,settleDelayMs:250,snapDelayMs:900,pickZoom:15,locateZoom:18,...e.behavior??{}},i18n:{labels:he(e.i18n)},markers:e.markers??[]}}const ge="#e9ebee",ye="#e9ebee",G="#a9e29b",fe="#9ed894",be="#b5e8a6",ve="#d3ddd0",we="#e9dfc0",qe="#b9d9f2",ke="#cfe4f7",j="#a9cdf0",U="#4e6e94",V="#dfe3e9",xe="#e9ebee",O="#ffffff",Se="#d9dde2",k="#ffffff",A="#d5dae0",Le="#cdbfa8",Ee="#e9ebee",H="#c6ccd4",N="#b9bdc4",Q="#a7aab3",Y="#5b6067",_="#2f3338",f="#f7f8f9",D="#565b62",Te=["coalesce",["get","name:fa"],["get","name:nonlatin"],["get","name"],["get","name:latin"]],Me=["0","۰","1","۱","2","۲","3","۳","4","۴","5","۵","6","۶","7","۷","8","۸","9","۹","٠","۰","١","۱","٢","۲","٣","۳","٤","۴","٥","۵","٦","۶","٧","۷","٨","۸","٩","۹"];function Re(a,e=40){const t=["coalesce",a,""],o=["split",["to-string",t],""],r=["length",o],i=[];for(let s=0;s<e;s++){const n=["at",s,o];i.push(["case",[">",r,s],["match",n,...Me,n],""])}return i.push(["slice",["to-string",t],e]),["format",["concat",...i],{}]}const b=Re(Te),x=["IRANYekanX"],I=["IRANYekanX"],q=["LineString","MultiLineString"],Ae=["MultiPoint","Point"];function y(a){return["interpolate",["exponential",1.2],["zoom"],...a]}const X=["interpolate",["exponential",1.2],["zoom"],12.5,0,13,1.5,14,2.5,20,11.5],_e=["interpolate",["exponential",1.2],["zoom"],12,.5,13,1,14,4,20,15],Ce=[{id:"background",type:"background",paint:{"background-color":ge}},{id:"landuse-residential",type:"fill",source:"openmaptiles","source-layer":"landuse",filter:["match",["get","class"],["neighbourhood","residential"],!0,!1],paint:{"fill-color":ye}},{id:"landuse-cemetery",type:"fill",source:"openmaptiles","source-layer":"landuse",filter:["==",["get","class"],"cemetery"],paint:{"fill-color":ve}},{id:"landcover-wood",type:"fill",source:"openmaptiles","source-layer":"landcover",filter:["==",["get","class"],"wood"],paint:{"fill-color":fe}},{id:"landcover-grass",type:"fill",source:"openmaptiles","source-layer":"landcover",filter:["==",["get","class"],"grass"],paint:{"fill-color":be}},{id:"landcover-grass-park",type:"fill",source:"openmaptiles","source-layer":"park",paint:{"fill-color":G}},{id:"park",type:"fill",source:"openmaptiles","source-layer":"park",filter:["match",["geometry-type"],["MultiPolygon","Polygon"],!0,!1],paint:{"fill-color":G}},{id:"landcover-sand",type:"fill",source:"openmaptiles","source-layer":"landcover",filter:["==",["get","class"],"sand"],paint:{"fill-color":we}},{id:"water",type:"fill",source:"openmaptiles","source-layer":"water",filter:["all",["!=",["get","intermittent"],1],["!=",["get","brunnel"],"tunnel"]],paint:{"fill-color":qe}},{id:"water-intermittent",type:"fill",source:"openmaptiles","source-layer":"water",filter:["all",["==",["get","intermittent"],1],["!=",["get","brunnel"],"tunnel"]],paint:{"fill-color":ke,"fill-opacity":.8}},{id:"waterway-other",type:"line",source:"openmaptiles","source-layer":"waterway",filter:["all",["match",["get","class"],["canal","river","stream"],!1,!0],["==",["get","intermittent"],0]],paint:{"line-color":j,"line-width":["interpolate",["exponential",1.3],["zoom"],13,.5,20,2]}},{id:"waterway-stream-canal",type:"line",source:"openmaptiles","source-layer":"waterway",filter:["all",["match",["get","class"],["canal","stream"],!0,!1],["!=",["get","brunnel"],"tunnel"],["==",["get","intermittent"],0]],paint:{"line-color":j,"line-width":["interpolate",["exponential",1.3],["zoom"],13,.5,20,6]}},{id:"waterway-river",type:"line",source:"openmaptiles","source-layer":"waterway",filter:["all",["==",["get","class"],"river"],["!=",["get","brunnel"],"tunnel"],["!=",["get","intermittent"],1]],paint:{"line-color":j,"line-width":["interpolate",["exponential",1.2],["zoom"],10,.8,20,6]}},{id:"building",type:"fill",source:"openmaptiles","source-layer":"building",paint:{"fill-antialias":!0,"fill-color":V}},{id:"building-top",type:"fill",source:"openmaptiles","source-layer":"building",paint:{"fill-color":xe,"fill-opacity":["interpolate",["linear"],["zoom"],13,0,16,1],"fill-outline-color":V,"fill-translate":["interpolate",["linear"],["zoom"],14,["literal",[0,0]],16,["literal",[-2,-2]]]}},{id:"aeroway-area",type:"fill",source:"openmaptiles","source-layer":"aeroway",paint:{"fill-color":Ee,"fill-opacity":["interpolate",["linear"],["zoom"],13,0,14,1]}},{id:"aeroway-taxiway-casing",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"taxiway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":H,"line-width":["interpolate",["exponential",1.5],["zoom"],11,2,17,12]}},{id:"aeroway-taxiway",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"taxiway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":["interpolate",["exponential",1.5],["zoom"],11,1,17,10]}},{id:"aeroway-runway-casing",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"runway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":H,"line-width":["interpolate",["exponential",1.5],["zoom"],11,5,17,55]}},{id:"aeroway-runway",type:"line",source:"openmaptiles","source-layer":"aeroway",filter:["==",["get","class"],"runway"],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":["interpolate",["exponential",1.5],["zoom"],11,4,17,50]}},{id:"highway-minor-casing",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["!=",["get","brunnel"],"tunnel"],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":Se,"line-opacity":["interpolate",["linear"],["zoom"],12,0,12.5,1],"line-width":_e}},{id:"highway-link-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:13,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary","secondary","tertiary","trunk"],!0,!1],["==",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-width":y([12,1,13,3,14,4,20,15])}},{id:"highway-secondary-tertiary-casing",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["secondary","tertiary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-width":y([8,1.5,20,17])}},{id:"highway-primary-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-opacity":["interpolate",["linear"],["zoom"],7,0,8,1],"line-width":y([7,0,8,.6,9,1.5,20,22])}},{id:"highway-trunk-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["trunk"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":A,"line-opacity":["interpolate",["linear"],["zoom"],5,0,6,1],"line-width":y([5,0,6,.6,7,1.5,20,22])}},{id:"highway-motorway-casing",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:4,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"motorway"],["!=",["get","ramp"],1]],layout:{"line-cap":"butt","line-join":"round"},paint:{"line-color":A,"line-opacity":["interpolate",["linear"],["zoom"],4,0,5,1],"line-width":y([4,0,5,.4,6,.6,7,1.5,20,22])}},{id:"highway-path",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"path"]],paint:{"line-color":Le,"line-dasharray":[1.5,.75],"line-width":y([15,1.2,20,4])}},{id:"highway-link",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:13,filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary","secondary","tertiary","trunk"],!0,!1],["==",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([12.5,0,13,1.5,14,2.5,20,11.5])}},{id:"highway-minor",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["!=",["get","brunnel"],"tunnel"],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":X}},{id:"highway-secondary-tertiary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["secondary","tertiary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([6.5,0,8,.5,20,13])}},{id:"highway-primary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["primary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([8.5,0,9,.5,20,18])}},{id:"highway-trunk",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["match",["get","class"],["trunk"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([6.5,0,7,.5,20,18])}},{id:"highway-motorway",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"motorway"],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([6.5,0,7,.5,20,18])}},{id:"bridge-link",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:13,filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["primary","secondary","tertiary","trunk"],!0,!1],["==",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([12.5,0,13,1.5,14,2.5,20,11.5])}},{id:"bridge-minor",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":O,"line-width":X}},{id:"bridge-secondary-tertiary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["secondary","tertiary"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([6.5,0,8,.5,20,13])}},{id:"bridge-trunk-primary",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["==",["get","brunnel"],"bridge"],["match",["get","class"],["primary","trunk"],!0,!1],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([6.5,0,7,.5,20,18])}},{id:"bridge-motorway",type:"line",source:"openmaptiles","source-layer":"transportation",minzoom:5,filter:["all",["==",["get","brunnel"],"bridge"],["==",["get","class"],"motorway"],["!=",["get","ramp"],1]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":k,"line-width":y([6.5,0,7,.5,20,18])}},{id:"railway-transit",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["==",["get","class"],"transit"],["match",["get","brunnel"],["tunnel"],!1,!0]],paint:{"line-color":N,"line-width":["interpolate",["exponential",1.4],["zoom"],14,.4,20,1]}},{id:"railway-service",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["has","service"],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"rail"]],paint:{"line-color":N,"line-width":["interpolate",["exponential",1.4],["zoom"],14,.4,20,1]}},{id:"railway",type:"line",source:"openmaptiles","source-layer":"transportation",filter:["all",["match",["geometry-type"],q,!0,!1],["!",["has","service"]],["match",["get","brunnel"],["bridge","tunnel"],!1,!0],["==",["get","class"],"rail"]],paint:{"line-color":N,"line-width":["interpolate",["exponential",1.4],["zoom"],14,.4,15,.75,20,2]}},{id:"boundary_3",type:"line",source:"openmaptiles","source-layer":"boundary",filter:["all",["==",["get","admin_level"],3],["!=",["get","maritime"],1]],paint:{"line-color":Q,"line-dasharray":[1,1],"line-width":["interpolate",["linear"],["zoom"],7,1,11,2]}},{id:"boundary_2",type:"line",source:"openmaptiles","source-layer":"boundary",filter:["all",["==",["get","admin_level"],2],["!=",["get","maritime"],1],["!=",["get","disputed"],1],["!",["has","claimed_by"]]],layout:{"line-cap":"round","line-join":"round"},paint:{"line-color":Q,"line-opacity":["interpolate",["linear"],["zoom"],0,.4,4,1],"line-width":["interpolate",["linear"],["zoom"],3,1,5,1.2,12,3]}},{id:"waterway_line_label",type:"symbol",source:"openmaptiles","source-layer":"waterway",layout:{"symbol-placement":"line","symbol-spacing":350,"text-field":b,"text-font":x,"text-size":13},paint:{"text-color":U,"text-halo-color":f,"text-halo-width":1.5}},{id:"water_name_label",type:"symbol",source:"openmaptiles","source-layer":"water_name",layout:{"text-field":b,"text-font":x,"text-max-width":8,"text-size":12},paint:{"text-color":U,"text-halo-color":f,"text-halo-width":1.5}},{id:"poi_worship_school",type:"symbol",source:"openmaptiles","source-layer":"poi",minzoom:14,filter:["match",["get","class"],["place_of_worship","school","college","library","hospital","park"],!0,!1],layout:{"icon-image":["match",["get","class"],["place_of_worship"],"place_of_worship",["school"],"school",["college"],"school",["library"],"school",["hospital"],"hospital",["park"],"park",""],"icon-size":1.1,"text-anchor":"top","text-field":b,"text-font":x,"text-max-width":8,"text-offset":[0,1],"text-size":12},paint:{"text-color":D,"text-halo-color":f,"text-halo-width":1.5}},{id:"poi_shops",type:"symbol",source:"openmaptiles","source-layer":"poi",minzoom:15.5,filter:["match",["get","class"],["shop","grocery","restaurant","cafe","fast_food","pharmacy","bank","fuel"],!0,!1],layout:{"icon-image":["match",["get","class"],["grocery"],"grocery",["restaurant"],"restaurant",["cafe"],"cafe",["fast_food"],"restaurant",["pharmacy"],"pharmacy",["bank"],"bank",["fuel"],"fuel","shop"],"icon-size":1,"text-anchor":"top","text-field":b,"text-font":x,"text-max-width":8,"text-offset":[0,1],"text-size":12},paint:{"text-color":D,"text-halo-color":f,"text-halo-width":1.5}},{id:"poi_r1",type:"symbol",source:"openmaptiles","source-layer":"poi",minzoom:16,filter:["all",["match",["geometry-type"],Ae,!0,!1],[">=",["get","rank"],1],["<",["get","rank"],7]],layout:{"icon-image":["match",["get","subclass"],["florist","furniture"],["get","subclass"],["get","class"]],"icon-size":.8,"text-anchor":"top","text-field":b,"text-font":x,"text-max-width":8,"text-offset":[0,.8],"text-size":12},paint:{"text-color":D,"text-halo-color":f,"text-halo-width":1.5}},{id:"airport",type:"symbol",source:"openmaptiles","source-layer":"aerodrome_label",minzoom:10,filter:["all",["has","iata"]],layout:{"icon-image":"airport_11","icon-size":1,"text-anchor":"top","text-field":b,"text-font":x,"text-max-width":8,"text-offset":[0,.8],"text-size":12},paint:{"text-color":D,"text-halo-color":f,"text-halo-width":1.5}},{id:"highway-name-minor",type:"symbol",source:"openmaptiles","source-layer":"transportation_name",minzoom:14,filter:["all",["match",["geometry-type"],q,!0,!1],["match",["get","class"],["minor","service","track"],!0,!1]],layout:{"symbol-placement":"line","text-field":b,"text-font":x,"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],14,11,17,12]},paint:{"text-color":Y,"text-halo-color":f,"text-halo-width":1.5}},{id:"highway-name-major",type:"symbol",source:"openmaptiles","source-layer":"transportation_name",minzoom:11,filter:["match",["get","class"],["primary","secondary","tertiary","trunk","motorway"],!0,!1],layout:{"symbol-placement":"line","text-field":b,"text-font":I,"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],11,11,15,13]},paint:{"text-color":Y,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_village",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:9,filter:["==",["get","class"],"village"],layout:{"text-field":b,"text-font":x,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],9,11,12,13]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_town",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:6,filter:["==",["get","class"],"town"],layout:{"text-field":b,"text-font":I,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],7,12,11,14]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_other",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:8,filter:["match",["get","class"],["city","continent","country","state","town","village"],!1,!0],layout:{"text-field":b,"text-font":x,"text-max-width":8,"text-size":["interpolate",["linear"],["zoom"],8,10,12,12]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_city",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:3,filter:["all",["==",["get","class"],"city"],["!=",["get","capital"],2]],layout:{"text-field":b,"text-font":I,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],4,11,7,13,11,16]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}},{id:"label_city_capital",type:"symbol",source:"openmaptiles","source-layer":"place",minzoom:3,filter:["all",["==",["get","class"],"city"],["==",["get","capital"],2]],layout:{"text-field":b,"text-font":I,"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],4,12,7,14,11,18]},paint:{"text-color":_,"text-halo-color":f,"text-halo-width":1.5}}],ze="https://tiles.openfreemap.org/planet",$e={version:8,name:"snapp-like",glyphs:"https://cdn.jsdelivr.net/npm/@amir83nasr/map@1/fonts/{fontstack}/{range}.pbf",sprite:"https://tiles.openfreemap.org/sprites/ofm_f384/ofm",sources:{openmaptiles:{type:"vector",url:ze}},layers:Ce};class Pe{constructor(){d(this,"map",new Map)}on(e,t){let o=this.map.get(e);return o||this.map.set(e,o=new Set),o.add(t),()=>this.off(e,t)}off(e,t){var o;(o=this.map.get(e))==null||o.delete(t)}emit(e,t){for(const o of this.map.get(e)??[])try{o(t)}catch{}}}function C(a){return`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${a}</svg>`}const v={locate:C('<line x1="2" x2="5" y1="12" y2="12"/><line x1="19" x2="22" y1="12" y2="12"/><line x1="12" x2="12" y1="2" y2="5"/><line x1="12" x2="12" y1="19" y2="22"/><circle cx="12" cy="12" r="7"/><circle cx="12" cy="12" r="3"/>'),pin:C('<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>'),search:C('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),star:C('<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" fill="currentColor" stroke="none"/>'),x:C('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>')},K="۰۱۲۳۴۵۶۷۸۹";function S(a){return String(a).replace(/\d/g,e=>K[Number(e)]).replace(/[٠-٩]/g,e=>K["٠١٢٣٤٥٦٧٨٩".indexOf(e)])}function J(a,e=5){return S(Number(a).toFixed(e))}function M(a){return String(a).replace(/[۰-۹]/g,e=>String("۰۱۲۳۴۵۶۷۸۹".indexOf(e))).replace(/[٠-٩]/g,e=>String("٠١٢٣٤٥٦٧٨٩".indexOf(e)))}function ee(a){if(!a)return"";const e=String(a).split(",").map(o=>o.trim()).filter(Boolean),t=o=>!!(/^(ایران|Iran)$/i.test(o)||/^استان\b/.test(o)||/^شهرستان\b/.test(o)||/^بخش\b/.test(o)||/^[\d\s\-–—]+$/.test(M(o)));return e.filter(o=>!t(o)).slice(0,4).reverse().join(", ")}function Oe(a,e){return Number.isFinite(a)&&Number.isFinite(e)&&a>=-90&&a<=90&&e>=-180&&e<=180}const De="50.35,35.05,51.45,34.15",W=new Map,F=new Map;function ie(a,e){a.size>e&&a.delete(a.keys().next().value)}async function Ie(a,e,t){const o=`${a.toFixed(4)},${e.toFixed(4)}`,r=W.get(o);if(r)return r;const i=await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${a}&lon=${e}&accept-language=fa`,{headers:{Accept:"application/json"},signal:t==null?void 0:t.signal});if(!i.ok)throw new Error(`http ${i.status}`);const s=await i.json();if(!s.display_name)throw new Error("empty result");return W.set(o,s.display_name),ie(W,200),s.display_name}async function je(a,e=5,t){const o=`${M(a).trim().toLowerCase()}|${e}`,r=F.get(o);if(r)return r;const i=await fetch(`https://nominatim.openstreetmap.org/search?format=jsonv2&accept-language=fa&limit=${e}&viewbox=${De}&bounded=1&q=${encodeURIComponent(M(a))}`,{headers:{Accept:"application/json"},signal:t==null?void 0:t.signal});if(!i.ok)throw new Error(`http ${i.status}`);const s=await i.json();return F.set(o,s),ie(F,50),s}const Ne=["highway-minor","highway-link","highway-secondary-tertiary","highway-primary","highway-trunk","highway-motorway","bridge-minor","bridge-link","bridge-secondary-tertiary","bridge-trunk-primary","bridge-motorway"],T=64,We=15,te=2;function Fe(a,e,t,o,r,i){const s=r-t,n=i-o,l=s*s+n*n,g=l===0?0:((a-t)*s+(e-o)*n)/l,m=Math.max(0,Math.min(1,g)),p=t+m*s,h=o+m*n;return{x:p,y:h,d2:(a-p)*(a-p)+(e-h)*(e-h)}}function Ze(a,e,t){if(a.getZoom()<We)return null;const o=a.project([t,e]);let r;try{const l=[[o.x-T,o.y-T],[o.x+T,o.y+T]];r=a.queryRenderedFeatures(l,{layers:Ne})}catch{return null}let i=null,s=T*T;for(const l of r){const g=l.geometry,m=g.type==="LineString"?[g.coordinates]:g.type==="MultiLineString"?g.coordinates:[];for(const p of m){let h=null;for(const L of p){const c=a.project(L);if(h){const u=Fe(o.x,o.y,h.x,h.y,c.x,c.y);u.d2<s&&(s=u.d2,i={x:u.x,y:u.y})}h={x:c.x,y:c.y}}}}if(!i||s<te*te)return null;const n=a.unproject([i.x,i.y]);return{lat:n.lat,lng:n.lng}}const oe=3,Be="Vite: import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url'; سپس setupQomPickWorker(workerUrl) را قبل از mount صدا بزنید. Next.js/webpack: هر دو فایل worker و shared را کپی کنید.",Ge="qompick: MapLibre worker failed to load. Call setupQomPickWorker(workerUrl) from @amir83nasr/map before mounting LocationPickerView. Vite: use maplibre-gl-worker.mjs?worker&url. Next.js/webpack: copy maplibre-gl-worker.mjs and maplibre-gl-shared.mjs.";let Z=!1;function Ue(a){const e=globalThis.Worker;if(typeof e!="function")return()=>{};class t extends e{constructor(r,i){super(r,i),Z=!1,this.addEventListener("error",()=>{Z=!0,a()})}}return globalThis.Worker=t,()=>{globalThis.Worker=e}}function Ve(a){const e=a,t=[e==null?void 0:e.message,e==null?void 0:e.filename,e==null?void 0:e.url,a].filter(o=>typeof o=="string").join(" ").toLowerCase();return/maplibre-gl-(worker|shared)(?:-dev)?\.mjs/.test(t)||/failed to fetch worker script/.test(t)||/worker/.test(t)&&/failed to load|cannot load|dynamically imported module/.test(t)}const B="من میخواهم با پکیج قمپیک (@amir83nasr/map) یک نقشه انتخاب موقعیت (LocationPickerView) از صفر در پروژه React/Next.js بسازم. این پکیج کاملاً متنباز و رایگان است و روی MapLibre GL ساخته شده و فقط نسخه React دارد. لطفاً قدمبهقدم و به ترتیب راهنماییام کن: ۱) نصب — دستور نصب @amir83nasr/map و maplibre-gl نسخه ۶ (که peer dependency است و باید جدا نصب شود)؛ ۲) راهاندازی پایه — ایمپورت @amir83nasr/map/styles.css (شامل CSS مپلایبر، فقط یک import CSS) و رندر کامپوننت LocationPickerView با ارتفاع مشخص (مثلاً 480px، چون بدون ارتفاع نقشه خالی دیده میشود) و center و zoom اولیه؛ ۳) جستجو — استفاده از پیشنهادهای پیشفرض محلههای قم، یا جایگزینی آنها با search.suggestions شامل name و addr و lat و lng؛۴) مارکرها — نمایش مارکر مکانها با markers؛ ۵) دریافت نتیجه — گرفتن مختصات و آدرس تاییدشده کاربر با onConfirm؛ ۶) پاکسازی — کامپوننت LocationPickerView خودش destroy را در cleanup صدا میزند. کد کامل و قابل اجرا بده شامل همه importها و cssها، بگو هر بخش چه میکند، و در پایان خروجی مورد انتظار را توصیف کن: نقشه فارسی راستچین (RTL) و موبایلفرست با پین وسط، دکمه GPS، جستجو و دکمه تایید موقعیت. اگر چیزی از پروژه من لازم داری (نسخه React/Next.js، نسخه پکیجها) اول بپرس.",ae="پروژه React/Next.js من از قبل وجود دارد و میخواهم نقشه انتخاب موقعیت قمپیک (@amir83nasr/map) را به آن اضافه کنم بدون اینکه چیز دیگری خراب شود. این پکیج کاملاً متنباز و رایگان است و روی MapLibre GL ساخته شده و فقط نسخه React دارد. لطفاً قدمبهقدم و به ترتیب راهنماییام کن: ۱) نصب — دستور نصب @amir83nasr/map و maplibre-gl نسخه ۶ (که peer dependency است و باید جدا نصب شود)، با توجه به اینکه بقیه dependencyهای پروژه نباید بههم بخورد؛ ۲) ایمپورت css — اضافه کردن @amir83nasr/map/styles.css (شامل CSS مپلایبر؛ فقط یک import CSS) طوری که با استایلهای فعلی پروژه تداخل نکند (همه کلاسها و متغیرهای قمپیک با qp- شروع میشوند)؛ ۳) کانتینر — رندر LocationPickerView با ارتفاع مشخص (مثلاً 480px، چون بدون ارتفاع نقشه خالی دیده میشود) در جای مناسب صفحه فعلی؛ ۴) اتصال — دادن center و zoom، استفاده یا جایگزینی پیشنهادهای پیشفرض search، نمایش markers، و گرفتن مختصات و آدرس تاییدشده با onConfirm؛۵) پاکسازی — کامپوننت LocationPickerView خودش destroy را در cleanup صدا میزند. کد کامل و قابل اجرا بده شامل همه importها، بگو هر بخش چه میکند، و در پایان خروجی مورد انتظار را توصیف کن: نقشه فارسی راستچین (RTL) و موبایلفرست با پین وسط، دکمه GPS، جستجو و دکمه تایید موقعیت. اگر چیزی از پروژه من لازم داری (نسخه React/Next.js، نسخه پکیجها، ساختار فایلها) اول بپرس.",He={zero:B,existing:ae};function w(a){const e=document.createElement("template");return e.innerHTML=a.trim(),e.content.firstElementChild}class Qe{constructor(e){d(this,"opts");d(this,"emitter",new Pe);d(this,"root");d(this,"map");d(this,"myMarker",null);d(this,"venueMarkers",[]);d(this,"labelEl");d(this,"toastEl");d(this,"overlay");d(this,"resolveT",0);d(this,"searchT",0);d(this,"toastT",0);d(this,"settleT",0);d(this,"confirmT",0);d(this,"venueT",[]);d(this,"revSeq",0);d(this,"searchSeq",0);d(this,"revAbort",null);d(this,"searchAbort",null);d(this,"destroyed",!1);d(this,"workerFailed",!1);d(this,"boundsSaved",null);d(this,"lat",$.lat);d(this,"lng",$.lng);d(this,"address","");d(this,"resolving",!1);d(this,"onKey",e=>{e.key==="Escape"&&(this.overlay.hidden?this.isHidden(".qp-docs")?this.isHidden(".qp-confirm")?this.isHidden(".qp-geo")||this.closeModal("qp-geo"):this.closeModal("qp-confirm"):this.closeDocs():this.closeSearch())});var o,r;const t=typeof e.container=="string"?document.querySelector(e.container):e.container;if(!t)throw new Error("qompick: container not found");this.opts=me(e);for(const[i,s]of[["onLocationChange","locationChange"],["onAddressResolved","addressResolved"],["onSearchResults","searchResults"],["onPick","pick"],["onConfirm","confirm"],["onLocate","locate"],["onError","error"]]){const n=e[i];typeof n=="function"&&this.emitter.on(s,n)}this.build(t),this.initMap(),this.opts.markers.length&&this.addVenues(this.opts.markers),this.setLocation(((o=this.opts.map.center)==null?void 0:o.lat)??$.lat,((r=this.opts.map.center)==null?void 0:r.lng)??$.lng,{resolve:!0}),this.emitter.emit("ready",this.getLocation())}isHidden(e){var t;return((t=this.root.querySelector(e))==null?void 0:t.hidden)??!0}on(e,t){return this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}getLocation(){return{lat:this.lat,lng:this.lng,address:this.address}}setLocation(e,t,o={}){if(!Oe(e,t)){this.fail(new Error("invalid coordinates"));return}this.lat=e,this.lng=t;const r=this.getLocation();if(this.emitter.emit("locationChange",r),o.moveMap&&this.map){const i=o.zoom??Math.max(this.map.getZoom(),this.opts.behavior.pickZoom??15);this.map.flyTo({center:[t,e],zoom:i,duration:450})}o.resolve!==!1&&this.opts.behavior.resolveOnMove!==!1?this.scheduleResolve(e,t):this.renderLabel()}locate(){if(!navigator.geolocation){this.toast(this.t("gpsUnsupported")),this.fail(new Error("geolocate: unsupported"));return}const e=this.root.querySelector(".qp-gps");if(!window.isSecureContext){this.openModal("qp-geo"),this.fail(new Error("geolocate: insecure-context"));return}e==null||e.classList.add("is-locating"),navigator.geolocation.getCurrentPosition(t=>{if(e==null||e.classList.remove("is-locating"),!this.boundsSaved){const o=this.map.getMaxBounds();o&&(this.boundsSaved={sw:o.getSouthWest().toArray(),ne:o.getNorthEast().toArray()})}this.map.setMaxBounds(null),this.showMyPos(t.coords.latitude,t.coords.longitude),this.setLocation(t.coords.latitude,t.coords.longitude,{moveMap:!0,zoom:this.opts.behavior.locateZoom??18}),this.boundsSaved&&(this.map.setMaxBounds([this.boundsSaved.sw,this.boundsSaved.ne]),this.boundsSaved=null),this.emitter.emit("locate",this.getLocation())},t=>{e==null||e.classList.remove("is-locating"),(t==null?void 0:t.code)===t.PERMISSION_DENIED?this.openModal("qp-geo"):(this.toast((t==null?void 0:t.code)===t.TIMEOUT?this.t("locateTimeout"):this.t("locateUnavailable")),this.scheduleResolve(this.lat,this.lng,100)),this.fail(new Error(`geolocate: ${t==null?void 0:t.code}`))},{timeout:1e4})}confirm(e){const t={lat:this.lat,lng:this.lng,address:e??this.address};return this.emitter.emit("confirm",t),t}destroy(){var e,t,o,r;this.destroyed=!0,document.removeEventListener("keydown",this.onKey),window.clearTimeout(this.resolveT),window.clearTimeout(this.searchT),window.clearTimeout(this.toastT),window.clearTimeout(this.settleT),window.clearTimeout(this.confirmT),this.venueT.forEach(i=>window.clearTimeout(i)),(e=this.revAbort)==null||e.abort(),(t=this.searchAbort)==null||t.abort(),this.venueMarkers.forEach(i=>i.remove()),(o=this.myMarker)==null||o.remove(),(r=this.map)==null||r.remove(),this.root.remove()}t(e){return this.opts.i18n.labels[e]}build(e){const t=this.opts,o=ue(),r=(t.search.placeholder??this.t("searchPlaceholder")).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">");this.root=w(`<div class="qp qp-app" dir="${o}"></div>`);const i='<div class="qp-pin" aria-hidden="true"><div class="qp-pin-body"><div class="qp-pin-head"><div class="qp-pin-hole"></div></div><div class="qp-pin-stem"></div><div class="qp-pin-foot"></div></div><div class="qp-pin-shadow"></div></div>';this.root.innerHTML=`
|
|
2
2
|
<div class="qp-layout">
|
|
3
3
|
<main class="qp-map-wrap"><div class="qp-map"></div>${i}
|
|
4
4
|
${t.controls.gps?`<button class="qp-gps" type="button" aria-label="${this.t("currentLocation")}">${v.locate}</button>`:""}
|
|
@@ -20,58 +20,69 @@
|
|
|
20
20
|
<div class="qp-modal qp-geo" hidden><div class="qp-modal-card"><div class="qp-modal-head"><h2>${this.t("geoTitle")}</h2><button class="qp-x" type="button" aria-label="${this.t("close")}">${v.x}</button></div><p>${this.t("geoText")}</p><p class="qp-modal-sub">${this.t("geoBlocked")}</p><div class="qp-modal-row"><button class="qp-cta qp-geo-retry" type="button">${this.t("enableAccess")}</button></div></div></div>
|
|
21
21
|
<div class="qp-modal qp-confirm" hidden><div class="qp-modal-card"><div class="qp-modal-head"><h2>${this.t("confirmLocation")}</h2><button class="qp-x" type="button" aria-label="${this.t("close")}">${v.x}</button></div><label>${this.t("chosenAddress")}</label><textarea class="qp-addr" rows="3"></textarea><div>${this.t("coordsToServer")}</div><div class="qp-coords" dir="ltr"></div><div class="qp-modal-row"><button class="qp-cta qp-final" type="button">${this.t("confirm")}</button><button class="qp-ghost qp-edit" type="button">${this.t("editOnMap")}</button></div></div></div>
|
|
22
22
|
${t.controls.developers?this.devDocsHtml():""}
|
|
23
|
-
<div class="qp-toast" role="status"></div>`,e.appendChild(this.root),this.labelEl=this.root.querySelector(".qp-search-label")??w("<span></span>"),this.toastEl=this.root.querySelector(".qp-toast"),this.overlay=this.root.querySelector(".qp-overlay")??w("<div></div>"),this.wire(),requestAnimationFrame(()=>this.root.classList.add("is-ready"))}wire(){var o,r,i,
|
|
23
|
+
<div class="qp-toast" role="status"></div>`,e.appendChild(this.root),this.labelEl=this.root.querySelector(".qp-search-label")??w("<span></span>"),this.toastEl=this.root.querySelector(".qp-toast"),this.overlay=this.root.querySelector(".qp-overlay")??w("<div></div>"),this.wire(),requestAnimationFrame(()=>this.root.classList.add("is-ready"))}wire(){var o,r,i,s,n,l,g,m,p,h,L;(o=this.root.querySelector(".qp-gps"))==null||o.addEventListener("click",()=>this.locate()),(r=this.root.querySelector(".qp-search-trigger"))==null||r.addEventListener("click",()=>this.openSearch()),(i=this.root.querySelector(".qp-ov-close"))==null||i.addEventListener("click",()=>this.closeSearch()),(s=this.root.querySelector(".qp-cta"))==null||s.addEventListener("click",()=>this.openConfirm()),(n=this.root.querySelector(".qp-final"))==null||n.addEventListener("click",()=>this.finishConfirm()),(l=this.root.querySelector(".qp-edit"))==null||l.addEventListener("click",()=>this.closeModal("qp-confirm")),(g=this.root.querySelector(".qp-geo-retry"))==null||g.addEventListener("click",()=>{this.closeModal("qp-geo"),this.locate()}),this.root.querySelectorAll(".qp-modal").forEach(c=>c.addEventListener("click",u=>{u.target===c&&(c.hidden=!0)})),this.root.querySelectorAll(".qp-modal .qp-x").forEach(c=>c.addEventListener("click",()=>{var u;(u=c.closest(".qp-modal"))==null||u.setAttribute("hidden","")})),(m=this.root.querySelector(".qp-docs .qp-x"))==null||m.addEventListener("click",()=>this.closeDocs()),document.addEventListener("keydown",this.onKey),(p=this.root.querySelector(".qp-dev"))==null||p.addEventListener("click",()=>this.openDocs()),(h=this.root.querySelector(".qp-back"))==null||h.addEventListener("click",()=>this.closeDocs()),(L=this.root.querySelector(".qp-docs"))==null||L.addEventListener("click",c=>{c.target===this.root.querySelector(".qp-docs")&&this.closeDocs()}),this.root.querySelectorAll(".qp-copy").forEach(c=>c.addEventListener("click",u=>{this.copyPrompt(u.currentTarget)})),this.root.querySelectorAll(".qp-code-copy").forEach(c=>c.addEventListener("click",u=>{this.copyCode(u.currentTarget)}));const e=this.root.querySelector(".qp-overlay .qp-field input");if(e){const c=this.root.querySelector(".qp-overlay .qp-clear"),u=()=>{c&&(c.hidden=e.value.length===0)};e.addEventListener("input",()=>{u(),this.onQuery(e.value)}),e.addEventListener("keydown",R=>{R.key==="Enter"&&this.runSearch(e.value.trim())}),c==null||c.addEventListener("click",()=>{e.value="",u(),this.renderSuggest(""),e.focus()}),this.renderSuggest("")}const t=this.root.querySelector(".qp-desk-input");if(t){const c=this.root.querySelector(".qp-desk-clear"),u=()=>{c&&(c.hidden=t.value.length===0)};t.addEventListener("input",()=>{u(),this.onDeskQuery(t.value)}),t.addEventListener("keydown",R=>{R.key==="Enter"&&this.runRemoteSearch(t.value.trim(),".qp-results-desk",".qp-desk-home")}),c==null||c.addEventListener("click",()=>{t.value="",u(),this.renderDeskSuggest(""),t.focus()}),this.renderDeskSuggest("")}}initMap(){const e=this.opts,t=this.root.querySelector(".qp-map"),o=typeof e.map.style=="object"&&e.map.style!==null?{...e.map.style}:{...$e},r=e.map.glyphs?{...o,glyphs:e.map.glyphs}:o;if(typeof r.glyphs=="string"&&!/^(https?:|data:|blob:|\/)/.test(r.glyphs)){const p=document.baseURI,h=p.endsWith("/")?p:p.slice(0,p.lastIndexOf("/")+1);r.glyphs=h+r.glyphs}const i=e.map.bounds,s=Ue(()=>this.showWorkerError());try{this.map=new z.Map({container:t,style:r,center:[e.map.center.lng,e.map.center.lat],zoom:e.map.zoom,minZoom:e.map.minZoom,maxZoom:e.map.maxZoom,attributionControl:!1,renderWorldCopies:!1,fadeDuration:100,crossSourceCollisions:!1,scrollZoom:{around:"center"},dragRotate:!1,touchPitch:!1,clickTolerance:5,maxCanvasSize:[8192,8192],maxBounds:[[i[0][1],i[0][0]],[i[1][1],i[1][0]]]})}finally{s()}Z&&this.showWorkerError(),this.map.on("error",p=>{if(Ve(p.error)){this.showWorkerError();return}console.error(p.error),this.fail(p.error)}),requestAnimationFrame(()=>this.map.resize());const n=this.root.querySelector(".qp-map-wrap");let l=null,g=this.map.getZoom(),m=this.map.getCenter();this.map.on("movestart",()=>{n.classList.add("is-moving"),window.clearTimeout(this.settleT),g=this.map.getZoom(),m=this.map.getCenter()}),this.map.on("move",()=>{const p=this.map.getCenter();this.lat=p.lat,this.lng=p.lng}),this.map.on("moveend",p=>{n.classList.remove("is-moving");const h=this.map.getCenter();if(window.clearTimeout(this.settleT),l&&Math.abs(h.lat-l.lat)<1e-7&&Math.abs(h.lng-l.lng)<1e-7){l=null;return}if(!p.originalEvent){this.setLocation(h.lat,h.lng);return}const L=Math.hypot(h.lat-m.lat,h.lng-m.lng)*111320,c=this.map.getZoom(),u=Math.abs(c-g)>1&&L<10,R=u?0:this.opts.behavior.snapDelayMs??this.opts.behavior.settleDelayMs;this.settleT=window.setTimeout(()=>{if(!this.destroyed){if(this.opts.behavior.snapToRoad&&!u)try{const E=Ze(this.map,h.lat,h.lng);if(E){l=E,this.map.easeTo({center:[E.lng,E.lat],duration:400}),this.setLocation(E.lat,E.lng);return}}catch{}this.setLocation(h.lat,h.lng)}},R)})}showWorkerError(){var s;if(this.destroyed||this.workerFailed)return;this.workerFailed=!0;const e=new Error(Ge);console.warn(e.message),this.fail(e);const t=w('<div class="qp-err qp-map-err" role="alert"></div>'),o=w("<strong></strong>");o.textContent="ورکر MapLibre بارگذاری نشد؛ نقشه قابل استفاده نیست.";const r=w("<span></span>");r.textContent="راهحل: ";const i=w('<code dir="ltr"></code>');i.textContent=Be,r.appendChild(i),t.append(o,r),(s=this.root.querySelector(".qp-map-wrap"))==null||s.appendChild(t)}showMyPos(e,t){if(this.myMarker){this.myMarker.setLngLat([t,e]);return}const o=w('<div class="qp-my-wrap"><div class="qp-my-dot"></div></div>');this.myMarker=new z.Marker({element:o}).setLngLat([t,e]).addTo(this.map)}addVenues(e){for(const t of e){const o=document.createElement("button");o.type="button",o.className="qp-venue",o.setAttribute("aria-label",t.name),o.innerHTML=v.star,o.addEventListener("click",()=>{this.setLocation(t.lat,t.lng,{moveMap:!0,zoom:this.opts.behavior.pickZoom}),this.emitter.emit("pick",this.getLocation())});const r=w('<div class="qp-venue-pop"><span class="qp-venue-dot"></span><span></span></div>');r.lastElementChild.textContent=t.name;const i=new z.Popup({offset:26,anchor:"top",closeButton:!1,className:"qp-venue-pop-wrap"}).setDOMContent(r),s=new z.Marker({element:o}).setLngLat([t.lng,t.lat]).setPopup(i).addTo(this.map);let n=0;i.on("open",()=>{window.clearTimeout(n),n=window.setTimeout(()=>i.remove(),4e3),this.venueT.push(n)}),i.on("close",()=>window.clearTimeout(n)),this.venueMarkers.push(s)}}scheduleResolve(e,t,o){window.clearTimeout(this.resolveT);const r=o??this.opts.behavior.resolveDelayMs??600;this.resolveT=window.setTimeout(()=>void this.resolveAddress(e,t),r)}async resolveAddress(e,t){var r;(r=this.revAbort)==null||r.abort(),this.revAbort=new AbortController;const o=++this.revSeq;this.resolving=!0,this.labelEl.textContent=this.t("resolving");try{const i=await Ie(e,t,{signal:this.revAbort.signal});if(o!==this.revSeq||this.destroyed)return;this.address=ee(i),this.emitter.emit("addressResolved",this.getLocation())}catch(i){if(i instanceof DOMException&&i.name==="AbortError"||o!==this.revSeq)return;this.address="",this.fail(i)}finally{if(o!==this.revSeq)return;this.resolving=!1,this.renderLabel()}}renderLabel(){this.labelEl.textContent=this.address?S(this.address):this.t("searchTitle")}devDocsHtml(){const e=this.t("copy"),t=o=>`<div class="qp-code" dir="ltr"><pre>${o}</pre><button class="qp-ghost qp-code-copy" type="button">${e}</button></div>`;return`<div class="qp-docs" hidden><div class="qp-docs-card">
|
|
24
24
|
<div class="qp-modal-head"><h2>${this.t("developers")}</h2><button class="qp-x" type="button" aria-label="${this.t("close")}">${v.x}</button></div>
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
onConfirm={(loc) => console.log(loc)}
|
|
35
|
-
/>
|
|
36
|
-
<p class="qp-note">نکته: CSS مپلایبر
|
|
37
|
-
<p class="qp-note">نکته: فونت فارسی IRANYekanX داخل خود پکیج است (با همین import CSS لود میشود) و لیبلهای فارسی نقشه هم از PBFهای داخل پکیج میآیند — بدون تنظیم اضافه.</p>
|
|
38
|
-
<p class="qp-note">نکته: کامپوننت خودش init و destroy را در lifecycle (useEffect) انجام میدهد — بدون init/destroy دستی. تنظیمات engine فقط موقع mount اعمال میشوند؛ برای تنظیمات جدید با <code dir="ltr">key</code> ریمانت کنید (فقط callbackها زنده میمانند).</p>
|
|
39
|
-
<p class="qp-note">ورکر MapLibre را قبل از mount تنظیم کنید: در Vite فایل <code dir="ltr">maplibre-gl-worker.mjs?worker&url</code> را import و به <code dir="ltr">setupQomPickWorker()</code> بدهید؛ در Next.js/webpack هر دو فایل worker و shared را کپی کنید. خطای ورکر در <code dir="ltr">onError</code>، کنسول و <code dir="ltr">.qp-err</code> نمایش داده میشود.</p>
|
|
25
|
+
<p class="qp-note">قمپیک (@amir83nasr/map) — نقشه انتخاب موقعیت روی MapLibre، فقط React، کاملاً متنباز و رایگان. نقشه همیشه VECTOR است (نه raster)؛ فارسی راستچین (RTL) و موبایلفرست.</p>
|
|
26
|
+
<nav class="qp-docs-nav">
|
|
27
|
+
<a href="#qp-d-install">نصب</a><a href="#qp-d-quick">شروع سریع</a><a href="#qp-d-worker">ورکر</a><a href="#qp-d-props">تنظیمات</a><a href="#qp-d-cb">کالبکها</a><a href="#qp-d-style">ظاهر</a><a href="#qp-d-faq">خطاها</a><a href="#qp-d-prompts">پرامپتها</a>
|
|
28
|
+
</nav>
|
|
29
|
+
<section id="qp-d-install"><h3>۱) نصب</h3>${t("pnpm add @amir83nasr/map maplibre-gl")}
|
|
30
|
+
<p class="qp-note">نکته: maplibre-gl نسخه ۶ و react/react-dom peer dependency هستند و باید جدا نصب شوند.</p></section>
|
|
31
|
+
<section id="qp-d-quick"><h3>۲) شروع سریع — ۲ خط</h3>${t(`import '@amir83nasr/map/styles.css';
|
|
32
|
+
import { LocationPickerView } from '@amir83nasr/map';`)}${t(`<LocationPickerView
|
|
33
|
+
style={{ height: 480 }}
|
|
34
|
+
onConfirm={(loc) => console.log(loc.lat, loc.lng, loc.address)}
|
|
35
|
+
/>;`)}
|
|
36
|
+
<p class="qp-note">نکته: همین یک import کافی است (CSS مپلایبر + فونت IRANYekanX داخلش است). بدون <code dir="ltr">height</code> نقشه خالی دیده میشود (پیشفرض <code dir="ltr">480px</code>). کامپوننت خودش init/destroy میکند — دستی صدا نزنید.</p>
|
|
40
37
|
<p class="qp-note">نکته Next.js App Router: کامپوننت client است؛ با <code dir="ltr">dynamic(..., { ssr: false })</code> لود کنید.</p></section>
|
|
41
|
-
<section
|
|
42
|
-
<
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
<li>
|
|
49
|
-
<
|
|
38
|
+
<section id="qp-d-worker"><h3>۳) ورکر MapLibre — قبل از mount (اجباری)</h3>
|
|
39
|
+
<p class="qp-note">پکیج نمیتواند ورکر را برای شما باندل کند. علامت خرابی: نقشه خاکستری + باکس <code dir="ltr">.qp-map-err</code> + یک <code dir="ltr">console.warn</code> + کال <code dir="ltr">onError</code>.</p>
|
|
40
|
+
<p class="qp-note">Vite:</p>${t(`import { setupQomPickWorker } from '@amir83nasr/map';
|
|
41
|
+
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
|
|
42
|
+
setupQomPickWorker(workerUrl);`)}
|
|
43
|
+
<p class="qp-note">Next.js/webpack: هر دو فایل <code dir="ltr">maplibre-gl-worker.mjs</code> و <code dir="ltr">maplibre-gl-shared.mjs</code> را در خروجی public کپی کنید و URL عمومی ورکر را به <code dir="ltr">setupQomPickWorker()</code> بدهید (الیاس <code dir="ltr">setupMapWorker</code> یکسان است).</p></section>
|
|
44
|
+
<section id="qp-d-props"><h3>۴) تنظیمات مهم</h3><ul class="qp-list">
|
|
45
|
+
<li><code dir="ltr">map</code> — مرکز/زوم/محدوده (<code dir="ltr">center / zoom / minZoom / maxZoom / bounds</code>)؛ پیشفرض قم <code dir="ltr">34.6416,50.8764</code> زوم ۱۴. استایل سفارشی فقط برداری (<code dir="ltr">style</code>)؛ <code dir="ltr">glyphs</code> برای self-host فونت نقشه.</li>
|
|
46
|
+
<li><code dir="ltr">search</code> — پیشفرض ۵۲ محله قم (همه نمایش، بدون سقف): <code dir="ltr">enabled / placeholder / suggestions / minLength(3) / debounceMs(350) / limit(5)</code>. آرایه سفارشی جایگزین میشود؛ <code dir="ltr">[]</code> غیرفعال میکند. <code dir="ltr">limit</code> فقط نتایج ریموت (Nominatim) است.</li>
|
|
47
|
+
<li><code dir="ltr">markers</code> — پینها با <code dir="ltr">name / lat / lng</code>؛ کلیک → پرواز تا <code dir="ltr">pickZoom</code> + کال <code dir="ltr">onPick</code>.</li>
|
|
48
|
+
<li><code dir="ltr">controls</code> — <code dir="ltr">gps / confirmButton / searchTrigger / developers</code>.</li>
|
|
49
|
+
<li><code dir="ltr">behavior</code> — <code dir="ltr">snapToRoad / resolveOnMove / resolveDelayMs(400) / settleDelayMs(250) / snapDelayMs(900) / pickZoom(15) / locateZoom(18)</code>. اسنپ فقط حرکت دستی، زوم ≥ ۱۵؛ پینچزوم و حرکات کد هرگز اسنپ نمیشوند.</li>
|
|
50
|
+
<li><code dir="ltr">i18n.labels</code> — بازنویسی متنها؛ چیدمان همیشه RTL است.</li></ul>
|
|
51
|
+
${t(`<LocationPickerView
|
|
50
52
|
map={{ center: { lat: 34.64, lng: 50.87 }, zoom: 15 }}
|
|
51
53
|
search={{ minLength: 3, limit: 5 }}
|
|
54
|
+
markers={[{ name: 'فروشگاه', lat: 34.63, lng: 50.87 }]}
|
|
52
55
|
controls={{ gps: true, developers: true }}
|
|
53
56
|
onConfirm={(loc) => console.log(loc)}
|
|
54
|
-
/>
|
|
55
|
-
<
|
|
57
|
+
/>;`)}
|
|
58
|
+
<p class="qp-note">تنظیمات engine فقط موقع mount اعمال میشوند؛ برای اعمال جدید با <code dir="ltr">key</code> ریمانت کنید — فقط کالبکها زنده میمانند: <code dir="ltr"><LocationPickerView key={cityId} ... /></code>.</p></section>
|
|
59
|
+
<section id="qp-d-cb"><h3>۵) کالبکها — کدام برای چه</h3><ul class="qp-list">
|
|
60
|
+
<li><code dir="ltr">onConfirm</code> — دکمه تایید در مودال → <b>ذخیره نتیجه</b> (فرم/سرور).</li>
|
|
61
|
+
<li><code dir="ltr">onPick</code> — کلیک پین/پیشنهاد → واکنش، نه ذخیره.</li>
|
|
62
|
+
<li><code dir="ltr">onLocationChange</code> — هر حرکت مرکز (پرتکرار).</li>
|
|
63
|
+
<li><code dir="ltr">onAddressResolved</code> — پایان ژئوکد معکوس.</li>
|
|
64
|
+
<li><code dir="ltr">onSearchResults</code> — پایان جستجوی ریموت.</li>
|
|
65
|
+
<li><code dir="ltr">onLocate</code> — موفقیت GPS. <code dir="ltr">onError</code> — هر خطا از جمله ورکر.</li></ul></section>
|
|
66
|
+
<section id="qp-d-style"><h3>۶) سفارشیسازی ظاهر</h3><p class="qp-note">prop تم نیست؛ همه کلاسها/متغیرها با <code dir="ltr">qp-</code> شروع میشوند و با پروژه تداخل نمیکنند:</p>
|
|
67
|
+
${t(".qp { --qp-brand: #16a34a; --qp-ink: #111; --qp-radius: 16px; }")}
|
|
68
|
+
<p class="qp-note">متغیرها: <code dir="ltr">--qp-brand --qp-brand-dark --qp-bg --qp-card --qp-ink --qp-muted --qp-line --qp-radius --qp-shadow --qp-font</code>.</p></section>
|
|
69
|
+
<section><h3>۷) ساختار پروژه</h3><ul class="qp-list">
|
|
56
70
|
<li><code dir="ltr">package/src/index.tsx</code> — API عمومی (re-export از <code dir="ltr">react/ + core/</code>).</li>
|
|
57
71
|
<li><code dir="ltr">package/src/react/</code> — کامپوننت <code dir="ltr">LocationPickerView</code> + هلپر <code dir="ltr">setupQomPickWorker</code>.</li>
|
|
58
72
|
<li><code dir="ltr">package/src/engine/</code> — engine داخلی (<code dir="ltr">picker</code>، در exports عمومی نیست).</li>
|
|
59
73
|
<li><code dir="ltr">package/src/core/ + style/</code> — تایپها و helperها + استایل و basemap.</li>
|
|
60
|
-
<li><code dir="ltr">
|
|
61
|
-
<li><code dir="ltr">package/fonts/</code> — فونت IRANYekanX (woff2) و PBFهای glyph نقشه؛ داخل tarball منتشر میشود.</li>
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
<
|
|
65
|
-
<
|
|
74
|
+
<li><code dir="ltr">dist/styles.css</code> — ایمپورت: <code dir="ltr">@amir83nasr/map/styles.css</code>.</li>
|
|
75
|
+
<li><code dir="ltr">package/fonts/</code> — فونت IRANYekanX (woff2) و PBFهای glyph نقشه؛ داخل tarball منتشر میشود.</li></ul></section>
|
|
76
|
+
<section id="qp-d-faq"><h3>۸) سوالات پرتکرار</h3><ul class="qp-list">
|
|
77
|
+
<li>نقشه خالی/خاکستری بدون خطا؟ ارتفاع بدهید (<code dir="ltr">style={{ height: 480 }}</code>).</li>
|
|
78
|
+
<li>باکس قرمز ورکر؟ بخش ۳ (ورکر) — نه چیز دیگر.</li>
|
|
79
|
+
<li>لیبل فارسی نقشه نیست؟ CDN glyph مسدود است؛ <code dir="ltr">map.glyphs</code> را به کپی محلی <code dir="ltr">fonts/</code> بدهید.</li>
|
|
80
|
+
<li>پراپ جدید اثر ندارد؟ mount-only است؛ <code dir="ltr">key</code> بدهید.</li>
|
|
81
|
+
<li>کرش Next.js (<code dir="ltr">window/document</code>)؟ <code dir="ltr">'use client' + ssr: false</code>.</li>
|
|
82
|
+
<li>کدام نسخه maplibre؟ ۶ (peer). رایگان؟ بله، متنباز.</li></ul></section>
|
|
83
|
+
<section id="qp-d-prompts"><h3>پرامپت شروع از صفر</h3><div class="qp-prompt">${B}</div>
|
|
66
84
|
<div class="qp-modal-row"><button class="qp-ghost qp-copy" type="button" data-prompt="zero">${this.t("copy")}</button></div></section>
|
|
67
85
|
<section><h3>پرامپت افزودن به پروژه موجود</h3><div class="qp-prompt">${ae}</div>
|
|
68
86
|
<div class="qp-modal-row"><button class="qp-ghost qp-copy" type="button" data-prompt="existing">${this.t("copy")}</button></div></section>
|
|
69
|
-
<section><h3>سوالات پرتکرار</h3><ul class="qp-list">
|
|
70
|
-
<li>نقشه خالی است؟ به کامپوننت ارتفاع بدهید (مثلاً <code dir="ltr">style={{ height: 480 }}</code>)؛ بدون ارتفاع نقشه دیده نمیشود.</li>
|
|
71
|
-
<li>لیبلهای فارسی نقشه نمایش داده نمیشود؟ glyphهای پیشفرض از CDN پکیج میآیند؛ برای self-host کردن، <code dir="ltr">map.glyphs</code> را به مسیر فونتهای پکیج (مثلاً <code dir="ltr">/fonts/{fontstack}/{range}.pbf</code> بعد از کپی <code dir="ltr">node_modules/@amir83nasr/map/fonts</code>) تنظیم کنید.</li>
|
|
72
|
-
<li>پیام خطای ورکر روی نقشه میبینید؟ در Vite، <code dir="ltr">maplibre-gl-worker.mjs?worker&url</code> را import و قبل از mount به <code dir="ltr">setupQomPickWorker()</code> بدهید؛ در Next.js/webpack هر دو فایل <code dir="ltr">maplibre-gl-worker.mjs</code> و <code dir="ltr">maplibre-gl-shared.mjs</code> را کپی کنید. پکیج همین خطا را یکبار به <code dir="ltr">onError</code> و کنسول هم میفرستد.</li>
|
|
73
|
-
<li>کدام نسخه maplibre؟ نسخه ۶؛ چون peer dependency است باید جدا نصب شود.</li>
|
|
74
|
-
<li>در Next.js App Router؟ کامپوننت client است؛ با <code dir="ltr">dynamic(..., { ssr: false })</code> لود کنید.</li>
|
|
75
|
-
<li>رایگان است؟ بله، قمپیک کاملاً متنباز و رایگان است.</li></ul></section>
|
|
76
87
|
<div class="qp-modal-row"><button class="qp-cta qp-back" type="button">${this.t("backToMap")}</button></div>
|
|
77
|
-
</div></div>`}openDocs(){var e;(e=this.root.querySelector(".qp-docs"))==null||e.removeAttribute("hidden")}closeDocs(){const e=this.root.querySelector(".qp-docs");e&&(e.hidden=!0)}
|
|
88
|
+
</div></div>`}openDocs(){var e;(e=this.root.querySelector(".qp-docs"))==null||e.removeAttribute("hidden")}closeDocs(){const e=this.root.querySelector(".qp-docs");e&&(e.hidden=!0)}copyDone(e){const t=e.textContent??"";e.textContent=this.t("copied"),window.setTimeout(()=>{e.textContent=t},1500)}copyText(e,t){var r;const o=()=>this.copyDone(t);if((r=navigator.clipboard)!=null&&r.writeText){navigator.clipboard.writeText(e).then(o,()=>this.fallbackCopy(e,o));return}this.fallbackCopy(e,o)}copyPrompt(e){const t=e.dataset.prompt??"zero";this.copyText(He[t]??B,e)}copyCode(e){var o;const t=(o=e.closest(".qp-code"))==null?void 0:o.querySelector("pre");t&&this.copyText(t.textContent??"",e)}fallbackCopy(e,t){const o=document.createElement("textarea");o.value=e,o.style.position="fixed",o.style.opacity="0",document.body.appendChild(o),o.select();try{document.execCommand("copy")}catch{}o.remove(),t()}openSearch(){this.overlay.hidden=!1;const e=this.root.querySelector(".qp-overlay .qp-field input");e&&(e.value="",this.renderSuggest(""),window.setTimeout(()=>e.focus(),50))}closeSearch(){this.overlay.hidden=!0;const e=this.root.querySelector(".qp-overlay .qp-field input");e&&e.blur()}pickSuggestion(e){this.setLocation(e.lat,e.lng,{moveMap:!0,zoom:this.opts.behavior.pickZoom}),this.emitter.emit("pick",this.getLocation()),this.closeSearch()}pickResult(e,t){this.searchSeq++,this.setLocation(parseFloat(e),parseFloat(t),{moveMap:!0,zoom:this.opts.behavior.pickZoom});const o=this.getLocation();this.emitter.emit("pick",o),this.closeSearch()}suggestionRow(e){const t=w(`<button class="qp-row" type="button"><span class="qp-ric">${v.pin}</span><span class="qp-t"><b></b><small></small></span></button>`);return t.querySelector("b").textContent=S(e.name),t.querySelector("small").textContent=S(e.addr),t.addEventListener("click",()=>this.pickSuggestion(e)),t}resultRow(e,t,o){const r=w(`<button class="qp-card" type="button"><span class="qp-ric">${v.pin}</span><span><b></b><small></small></span></button>`);return r.querySelector("b").textContent=S(String(e).split(",")[0]),r.querySelector("small").textContent=S(ee(e)),r.addEventListener("click",()=>this.pickResult(t,o)),r}filteredSuggestions(e){const t=M(e).trim();return this.suggestions().filter(o=>!t||M(o.name).includes(t)||M(o.addr).includes(t)).sort((o,r)=>o.name.localeCompare(r.name,"fa"))}suggestions(){return this.opts.search.suggestions??[]}renderSuggest(e){const t=this.root.querySelector(".qp-suggest"),o=this.root.querySelector(".qp-home"),r=this.root.querySelector(".qp-results");if(t){t.innerHTML="";for(const i of this.filteredSuggestions(e))t.appendChild(this.suggestionRow(i));o&&(o.hidden=!1),r&&(r.innerHTML="")}}renderDeskSuggest(e){const t=this.root.querySelector(".qp-suggest-desk"),o=this.root.querySelector(".qp-desk-home"),r=this.root.querySelector(".qp-results-desk");if(t){t.innerHTML="";for(const i of this.filteredSuggestions(e))t.appendChild(this.suggestionRow(i));o&&(o.hidden=!1),r&&(r.innerHTML="")}}onQuery(e){this.onQueryShared(e,t=>this.renderSuggest(t),t=>void this.runSearch(t))}onQueryShared(e,t,o){this.searchSeq++;const r=this.searchSeq;window.clearTimeout(this.searchT);const i=e.trim(),s=this.opts.search.minLength??oe;if(i.length<1){t("");return}if(i.length<s){t(i);return}this.searchT=window.setTimeout(()=>{r===this.searchSeq&&o(i)},this.opts.search.debounceMs??350)}async runSearch(e){await this.runRemoteSearch(e,".qp-results",".qp-home")}onDeskQuery(e){this.onQueryShared(e,t=>this.renderDeskSuggest(t),t=>void this.runRemoteSearch(t,".qp-results-desk",".qp-desk-home"))}async runRemoteSearch(e,t,o){var g;const r=e.trim(),i=this.root.querySelector(t),s=this.root.querySelector(o);if(!i)return;if(!r){t.includes("desk")?this.renderDeskSuggest(""):this.renderSuggest("");return}const n=this.opts.search.minLength??oe;if(r.length<n){t.includes("desk")?this.renderDeskSuggest(r):this.renderSuggest(r);return}const l=++this.searchSeq;(g=this.searchAbort)==null||g.abort(),this.searchAbort=new AbortController,s&&(s.hidden=!0),i.innerHTML=`<div class="qp-err">${this.t("searching")}</div>`;try{const m=await je(r,this.opts.search.limit??5,{signal:this.searchAbort.signal});if(l!==this.searchSeq)return;if(this.emitter.emit("searchResults",m),!m.length){i.innerHTML=`<div class="qp-err">${this.t("noResults")}</div>`;return}i.innerHTML="";for(const p of m)i.appendChild(this.resultRow(p.display_name,p.lat,p.lon))}catch(m){if(m instanceof DOMException&&m.name==="AbortError"||l!==this.searchSeq)return;i.innerHTML=`<div class="qp-err">${this.t("searchError")}</div>`,this.fail(m)}}openModal(e){var t;(t=this.root.querySelector(`.${e}`))==null||t.removeAttribute("hidden")}closeModal(e){const t=this.root.querySelector(`.${e}`);t&&(t.hidden=!0)}openConfirm(){!this.address&&!this.resolving&&this.scheduleResolve(this.lat,this.lng,100),this.root.querySelector(".qp-addr").value=this.address?S(this.address):"",this.root.querySelector(".qp-coords").textContent=`${Number(this.lat).toFixed(6)}, ${Number(this.lng).toFixed(6)}`,this.openModal("qp-confirm")}finishConfirm(){const e=this.root.querySelector(".qp-final"),t=this.root.querySelector(".qp-addr").value;e.disabled=!0;const o=e.textContent??"";e.textContent=this.t("submitting"),window.clearTimeout(this.confirmT),this.confirmT=window.setTimeout(()=>{if(this.destroyed)return;e.disabled=!1,e.textContent=o;const r=this.confirm(t);this.closeModal("qp-confirm"),this.toast(`${this.t("registered")} (${J(Number(r.lat))}, ${J(Number(r.lng))})`)},800)}toast(e){this.toastEl.textContent=e,this.toastEl.classList.add("show"),window.clearTimeout(this.toastT),this.toastT=window.setTimeout(()=>this.toastEl.classList.remove("show"),2600)}fail(e){const t=e instanceof Error?e:new Error(String(e));this.emitter.emit("error",t)}}function se(a){z.setWorkerUrl(a)}const Ye=se;function Xe({className:a,style:e,...t}){const o=P.useRef(null),r=P.useRef(t);return P.useEffect(()=>{r.current=t}),P.useEffect(()=>{if(!o.current)return;const i=new Qe({...r.current,container:o.current,onLocationChange:s=>{var n,l;return(l=(n=r.current).onLocationChange)==null?void 0:l.call(n,s)},onAddressResolved:s=>{var n,l;return(l=(n=r.current).onAddressResolved)==null?void 0:l.call(n,s)},onSearchResults:s=>{var n,l;return(l=(n=r.current).onSearchResults)==null?void 0:l.call(n,s)},onPick:s=>{var n,l;return(l=(n=r.current).onPick)==null?void 0:l.call(n,s)},onConfirm:s=>{var n,l;return(l=(n=r.current).onConfirm)==null?void 0:l.call(n,s)},onLocate:s=>{var n,l;return(l=(n=r.current).onLocate)==null?void 0:l.call(n,s)},onError:s=>{var n,l;return(l=(n=r.current).onError)==null?void 0:l.call(n,s)}});return()=>i.destroy()},[]),ce.jsx("div",{ref:o,className:a,style:{height:480,...e}})}exports.LocationPickerView=Xe;exports.QOM_SUGGESTIONS=re;exports.setupMapWorker=Ye;exports.setupQomPickWorker=se;
|