@symfony/ux-leaflet-map 2.26.1 → 2.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,46 +1,66 @@
1
- import AbstractMapController from '@symfony/ux-map';
2
- import type { Icon, InfoWindowWithoutPositionDefinition, MarkerDefinition, Point, PolygonDefinition, PolylineDefinition } from '@symfony/ux-map';
3
- import 'leaflet/dist/leaflet.min.css';
1
+ import AbstractMapController, { MapDefinition, MarkerDefinition, PolygonDefinition, PolylineDefinition, CircleDefinition, RectangleDefinition, InfoWindowDefinition, Icon } from '@symfony/ux-map';
4
2
  import * as L from 'leaflet';
5
- import type { MapOptions as LeafletMapOptions, MarkerOptions, PolylineOptions as PolygonOptions, PolylineOptions, PopupOptions } from 'leaflet';
6
- type MapOptions = Pick<LeafletMapOptions, 'center' | 'zoom'> & {
3
+ import { MapOptions as MapOptions$1, ControlPosition, MarkerOptions, PopupOptions, PolylineOptions, CircleOptions } from 'leaflet';
4
+
5
+ type MapOptions = Pick<MapOptions$1, 'attributionControl' | 'zoomControl'> & {
6
+ attributionControlOptions?: {
7
+ position: ControlPosition;
8
+ prefix: string | false;
9
+ };
10
+ zoomControlOptions?: {
11
+ position: ControlPosition;
12
+ zoomInText: string;
13
+ zoomInTitle: string;
14
+ zoomOutText: string;
15
+ zoomOutTitle: string;
16
+ };
7
17
  tileLayer: {
8
18
  url: string;
9
19
  attribution: string;
10
20
  options: Record<string, unknown>;
11
21
  } | false;
12
22
  };
13
- export default class extends AbstractMapController<MapOptions, L.Map, MarkerOptions, L.Marker, PopupOptions, L.Popup, PolygonOptions, L.Polygon, PolylineOptions, L.Polyline> {
23
+ declare class export_default extends AbstractMapController<MapOptions, MapOptions$1, L.Map, MarkerOptions, L.Marker, PopupOptions, L.Popup, PolylineOptions, L.Polygon, PolylineOptions, L.Polyline, CircleOptions, L.Circle, PolylineOptions, L.Rectangle> {
14
24
  map: L.Map;
15
25
  connect(): void;
16
26
  centerValueChanged(): void;
17
27
  zoomValueChanged(): void;
28
+ minZoomValueChanged(): void;
29
+ maxZoomValueChanged(): void;
18
30
  protected dispatchEvent(name: string, payload?: Record<string, unknown>): void;
19
- protected doCreateMap({ center, zoom, options, }: {
20
- center: Point | null;
21
- zoom: number | null;
22
- options: MapOptions;
31
+ protected doCreateMap({ definition }: {
32
+ definition: MapDefinition<MapOptions, MapOptions$1>;
23
33
  }): L.Map;
24
34
  protected doCreateMarker({ definition }: {
25
35
  definition: MarkerDefinition<MarkerOptions, PopupOptions>;
26
36
  }): L.Marker;
27
37
  protected doRemoveMarker(marker: L.Marker): void;
28
- protected doCreatePolygon({ definition, }: {
29
- definition: PolygonDefinition<PolygonOptions, PopupOptions>;
38
+ protected doCreatePolygon({ definition }: {
39
+ definition: PolygonDefinition<PolylineOptions, PopupOptions>;
30
40
  }): L.Polygon;
31
41
  protected doRemovePolygon(polygon: L.Polygon): void;
32
- protected doCreatePolyline({ definition, }: {
42
+ protected doCreatePolyline({ definition }: {
33
43
  definition: PolylineDefinition<PolylineOptions, PopupOptions>;
34
44
  }): L.Polyline;
35
45
  protected doRemovePolyline(polyline: L.Polyline): void;
46
+ protected doCreateCircle({ definition }: {
47
+ definition: CircleDefinition<CircleOptions, PopupOptions>;
48
+ }): L.Circle;
49
+ protected doRemoveCircle(circle: L.Circle): void;
50
+ protected doCreateRectangle({ definition }: {
51
+ definition: RectangleDefinition<PolylineOptions, PopupOptions>;
52
+ }): L.Rectangle;
53
+ protected doRemoveRectangle(rectangle: L.Rectangle): void;
36
54
  protected doCreateInfoWindow({ definition, element, }: {
37
- definition: InfoWindowWithoutPositionDefinition<PopupOptions>;
38
- element: L.Marker | L.Polygon | L.Polyline;
55
+ definition: Omit<InfoWindowDefinition<PopupOptions>, 'position'>;
56
+ element: L.Marker | L.Polygon | L.Polyline | L.Circle | L.Rectangle;
39
57
  }): L.Popup;
40
- protected doCreateIcon({ definition, element, }: {
58
+ protected doCreateIcon({ definition, element }: {
41
59
  definition: Icon;
42
60
  element: L.Marker;
43
61
  }): void;
44
62
  protected doFitBoundsToMarkers(): void;
63
+ private closePopups;
45
64
  }
46
- export {};
65
+
66
+ export { export_default as default };
@@ -1,252 +1,374 @@
1
- import { Controller } from '@hotwired/stimulus';
2
- import 'leaflet/dist/leaflet.min.css';
3
- import * as L from 'leaflet';
4
-
5
- const IconTypes = {
6
- Url: 'url',
7
- Svg: 'svg',
8
- UxIcon: 'ux-icon',
1
+ // ../../../../assets/dist/abstract_map_controller.js
2
+ import { Controller } from "@hotwired/stimulus";
3
+ var IconTypes = {
4
+ Url: "url",
5
+ Svg: "svg",
6
+ UxIcon: "ux-icon"
9
7
  };
10
- class default_1 extends Controller {
11
- constructor() {
12
- super(...arguments);
13
- this.markers = new Map();
14
- this.polygons = new Map();
15
- this.polylines = new Map();
16
- this.infoWindows = [];
17
- this.isConnected = false;
18
- }
19
- connect() {
20
- const options = this.optionsValue;
21
- this.dispatchEvent('pre-connect', { options });
22
- this.createMarker = this.createDrawingFactory('marker', this.markers, this.doCreateMarker.bind(this));
23
- this.createPolygon = this.createDrawingFactory('polygon', this.polygons, this.doCreatePolygon.bind(this));
24
- this.createPolyline = this.createDrawingFactory('polyline', this.polylines, this.doCreatePolyline.bind(this));
25
- this.map = this.doCreateMap({
26
- center: this.hasCenterValue ? this.centerValue : null,
27
- zoom: this.hasZoomValue ? this.zoomValue : null,
28
- options,
29
- });
30
- this.markersValue.forEach((definition) => this.createMarker({ definition }));
31
- this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
32
- this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
33
- if (this.fitBoundsToMarkersValue) {
34
- this.doFitBoundsToMarkers();
35
- }
36
- this.dispatchEvent('connect', {
37
- map: this.map,
38
- markers: [...this.markers.values()],
39
- polygons: [...this.polygons.values()],
40
- polylines: [...this.polylines.values()],
41
- infoWindows: this.infoWindows,
42
- });
43
- this.isConnected = true;
44
- }
45
- createInfoWindow({ definition, element, }) {
46
- this.dispatchEvent('info-window:before-create', { definition, element });
47
- const infoWindow = this.doCreateInfoWindow({ definition, element });
48
- this.dispatchEvent('info-window:after-create', { infoWindow, definition, element });
49
- this.infoWindows.push(infoWindow);
50
- return infoWindow;
51
- }
52
- markersValueChanged() {
53
- if (!this.isConnected) {
54
- return;
55
- }
56
- this.onDrawChanged(this.markers, this.markersValue, this.createMarker, this.doRemoveMarker);
57
- if (this.fitBoundsToMarkersValue) {
58
- this.doFitBoundsToMarkers();
59
- }
60
- }
61
- polygonsValueChanged() {
62
- if (!this.isConnected) {
63
- return;
64
- }
65
- this.onDrawChanged(this.polygons, this.polygonsValue, this.createPolygon, this.doRemovePolygon);
66
- }
67
- polylinesValueChanged() {
68
- if (!this.isConnected) {
69
- return;
70
- }
71
- this.onDrawChanged(this.polylines, this.polylinesValue, this.createPolyline, this.doRemovePolyline);
72
- }
73
- createDrawingFactory(type, draws, factory) {
74
- const eventBefore = `${type}:before-create`;
75
- const eventAfter = `${type}:after-create`;
76
- return ({ definition }) => {
77
- this.dispatchEvent(eventBefore, { definition });
78
- const drawing = factory({ definition });
79
- this.dispatchEvent(eventAfter, { [type]: drawing, definition });
80
- draws.set(definition['@id'], drawing);
81
- return drawing;
82
- };
83
- }
84
- onDrawChanged(draws, newDrawDefinitions, factory, remover) {
85
- const idsToRemove = new Set(draws.keys());
86
- newDrawDefinitions.forEach((definition) => {
87
- idsToRemove.delete(definition['@id']);
88
- });
89
- idsToRemove.forEach((id) => {
90
- const draw = draws.get(id);
91
- remover(draw);
92
- draws.delete(id);
93
- });
94
- newDrawDefinitions.forEach((definition) => {
95
- if (!draws.has(definition['@id'])) {
96
- factory({ definition });
97
- }
98
- });
99
- }
100
- }
101
- default_1.values = {
102
- providerOptions: Object,
103
- center: Object,
104
- zoom: Number,
105
- fitBoundsToMarkers: Boolean,
106
- markers: Array,
107
- polygons: Array,
108
- polylines: Array,
109
- options: Object,
8
+ var abstract_map_controller_default = class extends Controller {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.markers = /* @__PURE__ */ new Map();
12
+ this.polygons = /* @__PURE__ */ new Map();
13
+ this.polylines = /* @__PURE__ */ new Map();
14
+ this.circles = /* @__PURE__ */ new Map();
15
+ this.rectangles = /* @__PURE__ */ new Map();
16
+ this.infoWindows = [];
17
+ this.isConnected = false;
18
+ }
19
+ connect() {
20
+ const extra = this.hasExtraValue ? this.extraValue : {};
21
+ const mapDefinition = {
22
+ center: this.hasCenterValue ? this.centerValue : null,
23
+ zoom: this.hasZoomValue ? this.zoomValue : null,
24
+ minZoom: this.hasMinZoomValue ? this.minZoomValue : null,
25
+ maxZoom: this.hasMaxZoomValue ? this.maxZoomValue : null,
26
+ options: this.optionsValue,
27
+ extra
28
+ };
29
+ this.dispatchEvent("pre-connect", mapDefinition);
30
+ this.createMarker = this.createDrawingFactory("marker", this.markers, this.doCreateMarker.bind(this));
31
+ this.createPolygon = this.createDrawingFactory("polygon", this.polygons, this.doCreatePolygon.bind(this));
32
+ this.createPolyline = this.createDrawingFactory("polyline", this.polylines, this.doCreatePolyline.bind(this));
33
+ this.createCircle = this.createDrawingFactory("circle", this.circles, this.doCreateCircle.bind(this));
34
+ this.createRectangle = this.createDrawingFactory("rectangle", this.rectangles, this.doCreateRectangle.bind(this));
35
+ this.map = this.doCreateMap({ definition: mapDefinition });
36
+ this.markersValue.forEach((definition) => this.createMarker({ definition }));
37
+ this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
38
+ this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
39
+ this.circlesValue.forEach((definition) => this.createCircle({ definition }));
40
+ this.rectanglesValue.forEach((definition) => this.createRectangle({ definition }));
41
+ if (this.fitBoundsToMarkersValue) {
42
+ this.doFitBoundsToMarkers();
43
+ }
44
+ this.dispatchEvent("connect", {
45
+ map: this.map,
46
+ markers: [...this.markers.values()],
47
+ polygons: [...this.polygons.values()],
48
+ polylines: [...this.polylines.values()],
49
+ circles: [...this.circles.values()],
50
+ rectangles: [...this.rectangles.values()],
51
+ infoWindows: this.infoWindows,
52
+ extra
53
+ });
54
+ this.isConnected = true;
55
+ }
56
+ //region Public API
57
+ createInfoWindow({
58
+ definition,
59
+ element
60
+ }) {
61
+ this.dispatchEvent("info-window:before-create", { definition, element });
62
+ const infoWindow = this.doCreateInfoWindow({ definition, element });
63
+ this.dispatchEvent("info-window:after-create", { infoWindow, definition, element });
64
+ this.infoWindows.push(infoWindow);
65
+ return infoWindow;
66
+ }
67
+ markersValueChanged() {
68
+ if (!this.isConnected) {
69
+ return;
70
+ }
71
+ this.onDrawChanged(this.markers, this.markersValue, this.createMarker, this.doRemoveMarker);
72
+ if (this.fitBoundsToMarkersValue) {
73
+ this.doFitBoundsToMarkers();
74
+ }
75
+ }
76
+ polygonsValueChanged() {
77
+ if (!this.isConnected) {
78
+ return;
79
+ }
80
+ this.onDrawChanged(this.polygons, this.polygonsValue, this.createPolygon, this.doRemovePolygon);
81
+ }
82
+ polylinesValueChanged() {
83
+ if (!this.isConnected) {
84
+ return;
85
+ }
86
+ this.onDrawChanged(this.polylines, this.polylinesValue, this.createPolyline, this.doRemovePolyline);
87
+ }
88
+ circlesValueChanged() {
89
+ if (!this.isConnected) {
90
+ return;
91
+ }
92
+ this.onDrawChanged(this.circles, this.circlesValue, this.createCircle, this.doRemoveCircle);
93
+ }
94
+ rectanglesValueChanged() {
95
+ if (!this.isConnected) {
96
+ return;
97
+ }
98
+ this.onDrawChanged(this.rectangles, this.rectanglesValue, this.createRectangle, this.doRemoveRectangle);
99
+ }
100
+ createDrawingFactory(type, draws, factory) {
101
+ const eventBefore = `${type}:before-create`;
102
+ const eventAfter = `${type}:after-create`;
103
+ return ({ definition }) => {
104
+ this.dispatchEvent(eventBefore, { definition });
105
+ if (typeof definition.rawOptions !== "undefined") {
106
+ console.warn(
107
+ `[Symfony UX Map] The event "${eventBefore}" added a deprecated "rawOptions" property to the definition, it will be removed in a next major version, replace it with "bridgeOptions" instead.`,
108
+ definition
109
+ );
110
+ }
111
+ const drawing = factory({ definition });
112
+ this.dispatchEvent(eventAfter, { [type]: drawing, definition });
113
+ draws.set(definition["@id"], drawing);
114
+ return drawing;
115
+ };
116
+ }
117
+ onDrawChanged(draws, newDrawDefinitions, factory, remover) {
118
+ const idsToRemove = new Set(draws.keys());
119
+ newDrawDefinitions.forEach((definition) => {
120
+ idsToRemove.delete(definition["@id"]);
121
+ });
122
+ idsToRemove.forEach((id) => {
123
+ const draw = draws.get(id);
124
+ remover(draw);
125
+ draws.delete(id);
126
+ });
127
+ newDrawDefinitions.forEach((definition) => {
128
+ if (!draws.has(definition["@id"])) {
129
+ factory({ definition });
130
+ }
131
+ });
132
+ }
133
+ //endregion
134
+ };
135
+ abstract_map_controller_default.values = {
136
+ providerOptions: Object,
137
+ center: Object,
138
+ zoom: Number,
139
+ minZoom: Number,
140
+ maxZoom: Number,
141
+ fitBoundsToMarkers: Boolean,
142
+ markers: Array,
143
+ polygons: Array,
144
+ polylines: Array,
145
+ circles: Array,
146
+ rectangles: Array,
147
+ options: Object,
148
+ extra: Object
110
149
  };
111
150
 
112
- class map_controller extends default_1 {
113
- connect() {
114
- L.Marker.prototype.options.icon = L.divIcon({
115
- html: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill-rule="evenodd" stroke-linecap="round" clip-rule="evenodd" viewBox="0 0 500 820"><defs><linearGradient id="__sf_ux_map_gradient_marker_fill" x1="0" x2="1" y1="0" y2="0" gradientTransform="matrix(0 -37.57 37.57 0 416.45 541)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#126FC6"/><stop offset="1" stop-color="#4C9CD1"/></linearGradient><linearGradient id="__sf_ux_map_gradient_marker_border" x1="0" x2="1" y1="0" y2="0" gradientTransform="matrix(0 -19.05 19.05 0 414.48 522.49)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2E6C97"/><stop offset="1" stop-color="#3883B7"/></linearGradient></defs><circle cx="252.31" cy="266.24" r="83.99" fill="#fff"/><path fill="url(#__sf_ux_map_gradient_marker_fill)" stroke="url(#__sf_ux_map_gradient_marker_border)" stroke-width="1.1" d="M416.54 503.61c-6.57 0-12.04 5.7-12.04 11.87 0 2.78 1.56 6.3 2.7 8.74l9.3 17.88 9.26-17.88c1.13-2.43 2.74-5.79 2.74-8.74 0-6.18-5.38-11.87-11.96-11.87Zm0 7.16a4.69 4.69 0 1 1-.02 9.4 4.69 4.69 0 0 1 .02-9.4Z" transform="translate(-7889.1 -9807.44) scale(19.54)"/></svg>',
116
- iconSize: [25, 41],
117
- iconAnchor: [12.5, 41],
118
- popupAnchor: [0, -41],
119
- className: '',
120
- });
121
- super.connect();
122
- }
123
- centerValueChanged() {
124
- if (this.map && this.hasCenterValue && this.centerValue && this.hasZoomValue && this.zoomValue) {
125
- this.map.setView(this.centerValue, this.zoomValue);
126
- }
127
- }
128
- zoomValueChanged() {
129
- if (this.map && this.hasZoomValue && this.zoomValue) {
130
- this.map.setZoom(this.zoomValue);
131
- }
132
- }
133
- dispatchEvent(name, payload = {}) {
134
- this.dispatch(name, {
135
- prefix: 'ux:map',
136
- detail: {
137
- ...payload,
138
- L,
139
- },
140
- });
141
- }
142
- doCreateMap({ center, zoom, options, }) {
143
- const map = L.map(this.element, {
144
- ...options,
145
- center: center === null ? undefined : center,
146
- zoom: zoom === null ? undefined : zoom,
147
- });
148
- if (options.tileLayer) {
149
- L.tileLayer(options.tileLayer.url, {
150
- attribution: options.tileLayer.attribution,
151
- ...options.tileLayer.options,
152
- }).addTo(map);
153
- }
154
- return map;
155
- }
156
- doCreateMarker({ definition }) {
157
- const { '@id': _id, position, title, infoWindow, icon, extra, rawOptions = {}, ...otherOptions } = definition;
158
- const marker = L.marker(position, { title: title || undefined, ...otherOptions, ...rawOptions }).addTo(this.map);
159
- if (infoWindow) {
160
- this.createInfoWindow({ definition: infoWindow, element: marker });
161
- }
162
- if (icon) {
163
- this.doCreateIcon({ definition: icon, element: marker });
164
- }
165
- return marker;
166
- }
167
- doRemoveMarker(marker) {
168
- marker.remove();
169
- }
170
- doCreatePolygon({ definition, }) {
171
- const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition;
172
- const polygon = L.polygon(points, { ...rawOptions }).addTo(this.map);
173
- if (title) {
174
- polygon.bindPopup(title);
175
- }
176
- if (infoWindow) {
177
- this.createInfoWindow({ definition: infoWindow, element: polygon });
178
- }
179
- return polygon;
180
- }
181
- doRemovePolygon(polygon) {
182
- polygon.remove();
183
- }
184
- doCreatePolyline({ definition, }) {
185
- const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition;
186
- const polyline = L.polyline(points, { ...rawOptions }).addTo(this.map);
187
- if (title) {
188
- polyline.bindPopup(title);
189
- }
190
- if (infoWindow) {
191
- this.createInfoWindow({ definition: infoWindow, element: polyline });
192
- }
193
- return polyline;
194
- }
195
- doRemovePolyline(polyline) {
196
- polyline.remove();
197
- }
198
- doCreateInfoWindow({ definition, element, }) {
199
- const { headerContent, content, rawOptions = {}, ...otherOptions } = definition;
200
- element.bindPopup([headerContent, content].filter((x) => x).join('<br>'), { ...otherOptions, ...rawOptions });
201
- if (definition.opened) {
202
- element.openPopup();
203
- }
204
- const popup = element.getPopup();
205
- if (!popup) {
206
- throw new Error('Unable to get the Popup associated with the element.');
207
- }
208
- return popup;
209
- }
210
- doCreateIcon({ definition, element, }) {
211
- const { type, width, height } = definition;
212
- let icon;
213
- if (type === IconTypes.Svg) {
214
- icon = L.divIcon({
215
- html: definition.html,
216
- iconSize: [width, height],
217
- className: '',
218
- });
219
- }
220
- else if (type === IconTypes.UxIcon) {
221
- icon = L.divIcon({
222
- html: definition._generated_html,
223
- iconSize: [width, height],
224
- className: '',
225
- });
226
- }
227
- else if (type === IconTypes.Url) {
228
- icon = L.icon({
229
- iconUrl: definition.url,
230
- iconSize: [width, height],
231
- className: '',
232
- });
233
- }
234
- else {
235
- throw new Error(`Unsupported icon type: ${type}.`);
236
- }
237
- element.setIcon(icon);
238
- }
239
- doFitBoundsToMarkers() {
240
- if (this.markers.size === 0) {
241
- return;
242
- }
243
- const bounds = [];
244
- this.markers.forEach((marker) => {
245
- const position = marker.getLatLng();
246
- bounds.push([position.lat, position.lng]);
247
- });
248
- this.map.fitBounds(bounds);
249
- }
250
- }
251
-
252
- export { map_controller as default };
151
+ // src/map_controller.ts
152
+ import "leaflet/dist/leaflet.min.css";
153
+ import * as L from "leaflet";
154
+ var map_controller_default = class extends abstract_map_controller_default {
155
+ connect() {
156
+ L.Marker.prototype.options.icon = L.divIcon({
157
+ html: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill-rule="evenodd" stroke-linecap="round" clip-rule="evenodd" viewBox="0 0 500 820"><defs><linearGradient id="__sf_ux_map_gradient_marker_fill" x1="0" x2="1" y1="0" y2="0" gradientTransform="matrix(0 -37.57 37.57 0 416.45 541)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#126FC6"/><stop offset="1" stop-color="#4C9CD1"/></linearGradient><linearGradient id="__sf_ux_map_gradient_marker_border" x1="0" x2="1" y1="0" y2="0" gradientTransform="matrix(0 -19.05 19.05 0 414.48 522.49)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2E6C97"/><stop offset="1" stop-color="#3883B7"/></linearGradient></defs><circle cx="252.31" cy="266.24" r="83.99" fill="#fff"/><path fill="url(#__sf_ux_map_gradient_marker_fill)" stroke="url(#__sf_ux_map_gradient_marker_border)" stroke-width="1.1" d="M416.54 503.61c-6.57 0-12.04 5.7-12.04 11.87 0 2.78 1.56 6.3 2.7 8.74l9.3 17.88 9.26-17.88c1.13-2.43 2.74-5.79 2.74-8.74 0-6.18-5.38-11.87-11.96-11.87Zm0 7.16a4.69 4.69 0 1 1-.02 9.4 4.69 4.69 0 0 1 .02-9.4Z" transform="translate(-7889.1 -9807.44) scale(19.54)"/></svg>',
158
+ iconSize: [25, 41],
159
+ iconAnchor: [12.5, 41],
160
+ popupAnchor: [0, -41],
161
+ className: ""
162
+ // Adding an empty class to the icon to avoid the default Leaflet styles
163
+ });
164
+ super.connect();
165
+ }
166
+ centerValueChanged() {
167
+ if (this.map && this.hasCenterValue && this.centerValue && this.hasZoomValue && this.zoomValue) {
168
+ this.map.setView(this.centerValue, this.zoomValue);
169
+ }
170
+ }
171
+ zoomValueChanged() {
172
+ if (this.map && this.hasZoomValue && this.zoomValue) {
173
+ this.map.setZoom(this.zoomValue);
174
+ }
175
+ }
176
+ minZoomValueChanged() {
177
+ if (this.map && this.hasMinZoomValue && this.minZoomValue) {
178
+ this.map.setMinZoom(this.minZoomValue);
179
+ }
180
+ }
181
+ maxZoomValueChanged() {
182
+ if (this.map && this.hasMaxZoomValue && this.maxZoomValue) {
183
+ this.map.setMaxZoom(this.maxZoomValue);
184
+ }
185
+ }
186
+ dispatchEvent(name, payload = {}) {
187
+ payload.L = L;
188
+ this.dispatch(name, {
189
+ prefix: "ux:map",
190
+ detail: payload
191
+ });
192
+ }
193
+ doCreateMap({ definition }) {
194
+ const { center, zoom, minZoom, maxZoom, options, bridgeOptions = {} } = definition;
195
+ const map2 = L.map(this.element, {
196
+ center: center === null ? void 0 : center,
197
+ zoom: zoom === null ? void 0 : zoom,
198
+ minZoom: minZoom === null ? void 0 : minZoom,
199
+ maxZoom: maxZoom === null ? void 0 : maxZoom,
200
+ attributionControl: false,
201
+ zoomControl: false,
202
+ ...options,
203
+ ...bridgeOptions
204
+ });
205
+ if (options.tileLayer) {
206
+ L.tileLayer(options.tileLayer.url, {
207
+ attribution: options.tileLayer.attribution,
208
+ ...options.tileLayer.options
209
+ }).addTo(map2);
210
+ }
211
+ if (typeof options.attributionControlOptions !== "undefined") {
212
+ L.control.attribution({ ...options.attributionControlOptions }).addTo(map2);
213
+ }
214
+ if (typeof options.zoomControlOptions !== "undefined") {
215
+ L.control.zoom({ ...options.zoomControlOptions }).addTo(map2);
216
+ }
217
+ return map2;
218
+ }
219
+ doCreateMarker({ definition }) {
220
+ const { "@id": _id, position, title, infoWindow, icon: icon2, rawOptions = {}, bridgeOptions = {} } = definition;
221
+ const marker2 = L.marker(position, {
222
+ title: title || void 0,
223
+ ...rawOptions,
224
+ ...bridgeOptions,
225
+ riseOnHover: true
226
+ }).addTo(this.map);
227
+ if (infoWindow) {
228
+ this.createInfoWindow({ definition: infoWindow, element: marker2 });
229
+ }
230
+ if (icon2) {
231
+ this.doCreateIcon({ definition: icon2, element: marker2 });
232
+ }
233
+ return marker2;
234
+ }
235
+ doRemoveMarker(marker2) {
236
+ marker2.remove();
237
+ }
238
+ doCreatePolygon({ definition }) {
239
+ const { "@id": _id, points, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
240
+ const polygon2 = L.polygon(points, { ...rawOptions, ...bridgeOptions }).addTo(this.map);
241
+ if (title) {
242
+ polygon2.bindPopup(title);
243
+ }
244
+ if (infoWindow) {
245
+ this.createInfoWindow({ definition: infoWindow, element: polygon2 });
246
+ }
247
+ return polygon2;
248
+ }
249
+ doRemovePolygon(polygon2) {
250
+ polygon2.remove();
251
+ }
252
+ doCreatePolyline({ definition }) {
253
+ const { "@id": _id, points, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
254
+ const polyline2 = L.polyline(points, { ...rawOptions, ...bridgeOptions }).addTo(this.map);
255
+ if (title) {
256
+ polyline2.bindPopup(title);
257
+ }
258
+ if (infoWindow) {
259
+ this.createInfoWindow({ definition: infoWindow, element: polyline2 });
260
+ }
261
+ return polyline2;
262
+ }
263
+ doRemovePolyline(polyline2) {
264
+ polyline2.remove();
265
+ }
266
+ doCreateCircle({ definition }) {
267
+ const { "@id": _id, center, radius, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
268
+ const circle2 = L.circle(center, { radius, ...rawOptions, ...bridgeOptions }).addTo(this.map);
269
+ if (title) {
270
+ circle2.bindPopup(title);
271
+ }
272
+ if (infoWindow) {
273
+ this.createInfoWindow({ definition: infoWindow, element: circle2 });
274
+ }
275
+ return circle2;
276
+ }
277
+ doRemoveCircle(circle2) {
278
+ circle2.remove();
279
+ }
280
+ doCreateRectangle({ definition }) {
281
+ const { "@id": _id, southWest, northEast, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
282
+ const rectangle2 = L.rectangle(
283
+ [
284
+ [southWest.lat, southWest.lng],
285
+ [northEast.lat, northEast.lng]
286
+ ],
287
+ { ...rawOptions, ...bridgeOptions }
288
+ ).addTo(this.map);
289
+ if (title) {
290
+ rectangle2.bindPopup(title);
291
+ }
292
+ if (infoWindow) {
293
+ this.createInfoWindow({ definition: infoWindow, element: rectangle2 });
294
+ }
295
+ return rectangle2;
296
+ }
297
+ doRemoveRectangle(rectangle2) {
298
+ rectangle2.remove();
299
+ }
300
+ doCreateInfoWindow({
301
+ definition,
302
+ element
303
+ }) {
304
+ const { headerContent, content, opened, autoClose, rawOptions = {}, bridgeOptions = {} } = definition;
305
+ element.bindPopup([headerContent, content].filter((x) => x).join("<br>"), { ...rawOptions, ...bridgeOptions });
306
+ if (opened) {
307
+ if (autoClose) {
308
+ this.closePopups();
309
+ }
310
+ element.openPopup();
311
+ }
312
+ const popup = element.getPopup();
313
+ if (!popup) {
314
+ throw new Error("Unable to get the Popup associated with the element.");
315
+ }
316
+ popup.on("click", () => {
317
+ if (autoClose) {
318
+ this.closePopups({ except: popup });
319
+ }
320
+ });
321
+ return popup;
322
+ }
323
+ doCreateIcon({ definition, element }) {
324
+ const { type, width, height } = definition;
325
+ let icon2;
326
+ if (type === IconTypes.Svg) {
327
+ icon2 = L.divIcon({
328
+ html: definition.html,
329
+ iconSize: [width, height],
330
+ className: ""
331
+ // Adding an empty class to the icon to avoid the default Leaflet styles
332
+ });
333
+ } else if (type === IconTypes.UxIcon) {
334
+ icon2 = L.divIcon({
335
+ html: definition._generated_html,
336
+ iconSize: [width, height],
337
+ className: ""
338
+ // Adding an empty class to the icon to avoid the default Leaflet styles
339
+ });
340
+ } else if (type === IconTypes.Url) {
341
+ icon2 = L.icon({
342
+ iconUrl: definition.url,
343
+ iconSize: [width, height],
344
+ className: ""
345
+ // Adding an empty class to the icon to avoid the default Leaflet styles
346
+ });
347
+ } else {
348
+ throw new Error(`Unsupported icon type: ${type}.`);
349
+ }
350
+ element.setIcon(icon2);
351
+ }
352
+ doFitBoundsToMarkers() {
353
+ if (this.markers.size === 0) {
354
+ return;
355
+ }
356
+ const bounds = [];
357
+ this.markers.forEach((marker2) => {
358
+ const position = marker2.getLatLng();
359
+ bounds.push([position.lat, position.lng]);
360
+ });
361
+ this.map.fitBounds(bounds);
362
+ }
363
+ closePopups(options = {}) {
364
+ this.infoWindows.forEach((popup) => {
365
+ if (options.except && popup === options.except) {
366
+ return;
367
+ }
368
+ popup.close();
369
+ });
370
+ }
371
+ };
372
+ export {
373
+ map_controller_default as default
374
+ };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@symfony/ux-leaflet-map",
3
3
  "description": "Leaflet bridge for Symfony UX Map, integrate interactive maps in your Symfony applications",
4
4
  "license": "MIT",
5
- "version": "2.26.1",
5
+ "version": "2.28.1",
6
6
  "keywords": [
7
7
  "symfony-ux",
8
8
  "leaflet",
@@ -16,13 +16,6 @@
16
16
  ],
17
17
  "main": "dist/map_controller.js",
18
18
  "types": "dist/map_controller.d.ts",
19
- "scripts": {
20
- "build": "node ../../../../../../bin/build_package.js .",
21
- "watch": "node ../../../../../../bin/build_package.js . --watch",
22
- "test": "../../../../../../bin/test_package.sh .",
23
- "check": "biome check",
24
- "ci": "biome ci"
25
- },
26
19
  "symfony": {
27
20
  "controllers": {
28
21
  "map": {
@@ -49,8 +42,24 @@
49
42
  },
50
43
  "devDependencies": {
51
44
  "@hotwired/stimulus": "^3.0.0",
52
- "@symfony/ux-map": "2.26.1",
45
+ "@testing-library/dom": "^10.4.0",
46
+ "@testing-library/jest-dom": "^6.6.3",
47
+ "@testing-library/user-event": "^14.6.1",
53
48
  "@types/leaflet": "^1.9.12",
54
- "leaflet": "^1.9.4"
49
+ "@vitest/browser": "^3.2.4",
50
+ "jsdom": "^26.1.0",
51
+ "leaflet": "^1.9.4",
52
+ "tslib": "^2.8.1",
53
+ "tsx": "^4.20.3",
54
+ "typescript": "^5.8.3",
55
+ "vitest": "^3.2.4",
56
+ "@symfony/ux-map": "2.28.1"
57
+ },
58
+ "scripts": {
59
+ "build": "tsx ../../../../../../bin/build_package.ts .",
60
+ "watch": "tsx ../../../../../../bin/build_package.ts . --watch",
61
+ "test": "../../../../../../bin/test_package.sh .",
62
+ "check": "biome check",
63
+ "ci": "biome ci"
55
64
  }
56
65
  }