@symfony/ux-google-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,19 +1,18 @@
1
- import type { LoaderOptions } from '@googlemaps/js-api-loader';
2
- import AbstractMapController from '@symfony/ux-map';
3
- import type { Icon, InfoWindowWithoutPositionDefinition, MarkerDefinition, Point, PolygonDefinition, PolylineDefinition } from '@symfony/ux-map';
1
+ import { LoaderOptions } from '@googlemaps/js-api-loader';
2
+ import AbstractMapController, { MapDefinition, MarkerDefinition, PolygonDefinition, PolylineDefinition, CircleDefinition, RectangleDefinition, InfoWindowDefinition, Icon } from '@symfony/ux-map';
3
+
4
4
  type MapOptions = Pick<google.maps.MapOptions, 'mapId' | 'gestureHandling' | 'backgroundColor' | 'disableDoubleClickZoom' | 'zoomControl' | 'zoomControlOptions' | 'mapTypeControl' | 'mapTypeControlOptions' | 'streetViewControl' | 'streetViewControlOptions' | 'fullscreenControl' | 'fullscreenControlOptions'>;
5
- export default class extends AbstractMapController<MapOptions, google.maps.Map, google.maps.marker.AdvancedMarkerElementOptions, google.maps.marker.AdvancedMarkerElement, google.maps.InfoWindowOptions, google.maps.InfoWindow, google.maps.PolygonOptions, google.maps.Polygon, google.maps.PolylineOptions, google.maps.Polyline> {
5
+ declare class export_default extends AbstractMapController<MapOptions, google.maps.MapOptions, google.maps.Map, google.maps.marker.AdvancedMarkerElementOptions, google.maps.marker.AdvancedMarkerElement, google.maps.InfoWindowOptions, google.maps.InfoWindow, google.maps.PolygonOptions, google.maps.Polygon, google.maps.PolylineOptions, google.maps.Polyline, google.maps.CircleOptions, google.maps.Circle, google.maps.RectangleOptions, google.maps.Rectangle> {
6
6
  providerOptionsValue: Pick<LoaderOptions, 'apiKey' | 'id' | 'language' | 'region' | 'nonce' | 'retries' | 'url' | 'version' | 'libraries'>;
7
7
  map: google.maps.Map;
8
- parser: DOMParser;
9
8
  connect(): Promise<void>;
10
9
  centerValueChanged(): void;
11
10
  zoomValueChanged(): void;
11
+ minZoomValueChanged(): void;
12
+ maxZoomValueChanged(): void;
12
13
  protected dispatchEvent(name: string, payload?: Record<string, unknown>): void;
13
- protected doCreateMap({ center, zoom, options, }: {
14
- center: Point | null;
15
- zoom: number | null;
16
- options: MapOptions;
14
+ protected doCreateMap({ definition }: {
15
+ definition: MapDefinition<MapOptions, google.maps.MapOptions>;
17
16
  }): google.maps.Map;
18
17
  protected doCreateMarker({ definition, }: {
19
18
  definition: MarkerDefinition<google.maps.marker.AdvancedMarkerElementOptions, google.maps.InfoWindowOptions>;
@@ -27,16 +26,25 @@ export default class extends AbstractMapController<MapOptions, google.maps.Map,
27
26
  definition: PolylineDefinition<google.maps.PolylineOptions, google.maps.InfoWindowOptions>;
28
27
  }): google.maps.Polyline;
29
28
  protected doRemovePolyline(polyline: google.maps.Polyline): void;
29
+ protected doCreateCircle({ definition }: {
30
+ definition: CircleDefinition<google.maps.CircleOptions, google.maps.InfoWindowOptions>;
31
+ }): google.maps.Circle;
32
+ protected doRemoveCircle(circle: google.maps.Circle): void;
33
+ protected doCreateRectangle({ definition, }: {
34
+ definition: RectangleDefinition<google.maps.RectangleOptions, google.maps.InfoWindowOptions>;
35
+ }): google.maps.Rectangle;
36
+ protected doRemoveRectangle(rectangle: google.maps.Rectangle): void;
30
37
  protected doCreateInfoWindow({ definition, element, }: {
31
- definition: InfoWindowWithoutPositionDefinition<google.maps.InfoWindowOptions>;
32
- element: google.maps.marker.AdvancedMarkerElement | google.maps.Polygon | google.maps.Polyline;
38
+ definition: Omit<InfoWindowDefinition<google.maps.InfoWindowOptions>, 'position'>;
39
+ element: google.maps.marker.AdvancedMarkerElement | google.maps.Polygon | google.maps.Polyline | google.maps.Circle | google.maps.Rectangle;
33
40
  }): google.maps.InfoWindow;
34
41
  protected doFitBoundsToMarkers(): void;
35
42
  private createTextOrElement;
36
- protected doCreateIcon({ definition, element, }: {
43
+ protected doCreateIcon({ definition, element }: {
37
44
  definition: Icon;
38
45
  element: google.maps.marker.AdvancedMarkerElement;
39
46
  }): void;
40
47
  private closeInfoWindowsExcept;
41
48
  }
42
- export {};
49
+
50
+ export { export_default as default };
@@ -1,313 +1,428 @@
1
- import { Loader } from '@googlemaps/js-api-loader';
2
- import { Controller } from '@hotwired/stimulus';
1
+ // src/map_controller.ts
2
+ import { Loader } from "@googlemaps/js-api-loader";
3
3
 
4
- const IconTypes = {
5
- Url: 'url',
6
- Svg: 'svg',
7
- UxIcon: 'ux-icon',
4
+ // ../../../../assets/dist/abstract_map_controller.js
5
+ import { Controller } from "@hotwired/stimulus";
6
+ var IconTypes = {
7
+ Url: "url",
8
+ Svg: "svg",
9
+ UxIcon: "ux-icon"
8
10
  };
9
- class default_1 extends Controller {
10
- constructor() {
11
- super(...arguments);
12
- this.markers = new Map();
13
- this.polygons = new Map();
14
- this.polylines = new Map();
15
- this.infoWindows = [];
16
- this.isConnected = false;
11
+ var abstract_map_controller_default = class extends Controller {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.markers = /* @__PURE__ */ new Map();
15
+ this.polygons = /* @__PURE__ */ new Map();
16
+ this.polylines = /* @__PURE__ */ new Map();
17
+ this.circles = /* @__PURE__ */ new Map();
18
+ this.rectangles = /* @__PURE__ */ new Map();
19
+ this.infoWindows = [];
20
+ this.isConnected = false;
21
+ }
22
+ connect() {
23
+ const extra = this.hasExtraValue ? this.extraValue : {};
24
+ const mapDefinition = {
25
+ center: this.hasCenterValue ? this.centerValue : null,
26
+ zoom: this.hasZoomValue ? this.zoomValue : null,
27
+ minZoom: this.hasMinZoomValue ? this.minZoomValue : null,
28
+ maxZoom: this.hasMaxZoomValue ? this.maxZoomValue : null,
29
+ options: this.optionsValue,
30
+ extra
31
+ };
32
+ this.dispatchEvent("pre-connect", mapDefinition);
33
+ this.createMarker = this.createDrawingFactory("marker", this.markers, this.doCreateMarker.bind(this));
34
+ this.createPolygon = this.createDrawingFactory("polygon", this.polygons, this.doCreatePolygon.bind(this));
35
+ this.createPolyline = this.createDrawingFactory("polyline", this.polylines, this.doCreatePolyline.bind(this));
36
+ this.createCircle = this.createDrawingFactory("circle", this.circles, this.doCreateCircle.bind(this));
37
+ this.createRectangle = this.createDrawingFactory("rectangle", this.rectangles, this.doCreateRectangle.bind(this));
38
+ this.map = this.doCreateMap({ definition: mapDefinition });
39
+ this.markersValue.forEach((definition) => this.createMarker({ definition }));
40
+ this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
41
+ this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
42
+ this.circlesValue.forEach((definition) => this.createCircle({ definition }));
43
+ this.rectanglesValue.forEach((definition) => this.createRectangle({ definition }));
44
+ if (this.fitBoundsToMarkersValue) {
45
+ this.doFitBoundsToMarkers();
17
46
  }
18
- connect() {
19
- const options = this.optionsValue;
20
- this.dispatchEvent('pre-connect', { options });
21
- this.createMarker = this.createDrawingFactory('marker', this.markers, this.doCreateMarker.bind(this));
22
- this.createPolygon = this.createDrawingFactory('polygon', this.polygons, this.doCreatePolygon.bind(this));
23
- this.createPolyline = this.createDrawingFactory('polyline', this.polylines, this.doCreatePolyline.bind(this));
24
- this.map = this.doCreateMap({
25
- center: this.hasCenterValue ? this.centerValue : null,
26
- zoom: this.hasZoomValue ? this.zoomValue : null,
27
- options,
28
- });
29
- this.markersValue.forEach((definition) => this.createMarker({ definition }));
30
- this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
31
- this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
32
- if (this.fitBoundsToMarkersValue) {
33
- this.doFitBoundsToMarkers();
34
- }
35
- this.dispatchEvent('connect', {
36
- map: this.map,
37
- markers: [...this.markers.values()],
38
- polygons: [...this.polygons.values()],
39
- polylines: [...this.polylines.values()],
40
- infoWindows: this.infoWindows,
41
- });
42
- this.isConnected = true;
47
+ this.dispatchEvent("connect", {
48
+ map: this.map,
49
+ markers: [...this.markers.values()],
50
+ polygons: [...this.polygons.values()],
51
+ polylines: [...this.polylines.values()],
52
+ circles: [...this.circles.values()],
53
+ rectangles: [...this.rectangles.values()],
54
+ infoWindows: this.infoWindows,
55
+ extra
56
+ });
57
+ this.isConnected = true;
58
+ }
59
+ //region Public API
60
+ createInfoWindow({
61
+ definition,
62
+ element
63
+ }) {
64
+ this.dispatchEvent("info-window:before-create", { definition, element });
65
+ const infoWindow = this.doCreateInfoWindow({ definition, element });
66
+ this.dispatchEvent("info-window:after-create", { infoWindow, definition, element });
67
+ this.infoWindows.push(infoWindow);
68
+ return infoWindow;
69
+ }
70
+ markersValueChanged() {
71
+ if (!this.isConnected) {
72
+ return;
43
73
  }
44
- createInfoWindow({ definition, element, }) {
45
- this.dispatchEvent('info-window:before-create', { definition, element });
46
- const infoWindow = this.doCreateInfoWindow({ definition, element });
47
- this.dispatchEvent('info-window:after-create', { infoWindow, definition, element });
48
- this.infoWindows.push(infoWindow);
49
- return infoWindow;
74
+ this.onDrawChanged(this.markers, this.markersValue, this.createMarker, this.doRemoveMarker);
75
+ if (this.fitBoundsToMarkersValue) {
76
+ this.doFitBoundsToMarkers();
50
77
  }
51
- markersValueChanged() {
52
- if (!this.isConnected) {
53
- return;
54
- }
55
- this.onDrawChanged(this.markers, this.markersValue, this.createMarker, this.doRemoveMarker);
56
- if (this.fitBoundsToMarkersValue) {
57
- this.doFitBoundsToMarkers();
58
- }
78
+ }
79
+ polygonsValueChanged() {
80
+ if (!this.isConnected) {
81
+ return;
59
82
  }
60
- polygonsValueChanged() {
61
- if (!this.isConnected) {
62
- return;
63
- }
64
- this.onDrawChanged(this.polygons, this.polygonsValue, this.createPolygon, this.doRemovePolygon);
83
+ this.onDrawChanged(this.polygons, this.polygonsValue, this.createPolygon, this.doRemovePolygon);
84
+ }
85
+ polylinesValueChanged() {
86
+ if (!this.isConnected) {
87
+ return;
65
88
  }
66
- polylinesValueChanged() {
67
- if (!this.isConnected) {
68
- return;
69
- }
70
- this.onDrawChanged(this.polylines, this.polylinesValue, this.createPolyline, this.doRemovePolyline);
89
+ this.onDrawChanged(this.polylines, this.polylinesValue, this.createPolyline, this.doRemovePolyline);
90
+ }
91
+ circlesValueChanged() {
92
+ if (!this.isConnected) {
93
+ return;
71
94
  }
72
- createDrawingFactory(type, draws, factory) {
73
- const eventBefore = `${type}:before-create`;
74
- const eventAfter = `${type}:after-create`;
75
- return ({ definition }) => {
76
- this.dispatchEvent(eventBefore, { definition });
77
- const drawing = factory({ definition });
78
- this.dispatchEvent(eventAfter, { [type]: drawing, definition });
79
- draws.set(definition['@id'], drawing);
80
- return drawing;
81
- };
95
+ this.onDrawChanged(this.circles, this.circlesValue, this.createCircle, this.doRemoveCircle);
96
+ }
97
+ rectanglesValueChanged() {
98
+ if (!this.isConnected) {
99
+ return;
82
100
  }
83
- onDrawChanged(draws, newDrawDefinitions, factory, remover) {
84
- const idsToRemove = new Set(draws.keys());
85
- newDrawDefinitions.forEach((definition) => {
86
- idsToRemove.delete(definition['@id']);
87
- });
88
- idsToRemove.forEach((id) => {
89
- const draw = draws.get(id);
90
- remover(draw);
91
- draws.delete(id);
92
- });
93
- newDrawDefinitions.forEach((definition) => {
94
- if (!draws.has(definition['@id'])) {
95
- factory({ definition });
96
- }
97
- });
98
- }
99
- }
100
- default_1.values = {
101
- providerOptions: Object,
102
- center: Object,
103
- zoom: Number,
104
- fitBoundsToMarkers: Boolean,
105
- markers: Array,
106
- polygons: Array,
107
- polylines: Array,
108
- options: Object,
101
+ this.onDrawChanged(this.rectangles, this.rectanglesValue, this.createRectangle, this.doRemoveRectangle);
102
+ }
103
+ createDrawingFactory(type, draws, factory) {
104
+ const eventBefore = `${type}:before-create`;
105
+ const eventAfter = `${type}:after-create`;
106
+ return ({ definition }) => {
107
+ this.dispatchEvent(eventBefore, { definition });
108
+ if (typeof definition.rawOptions !== "undefined") {
109
+ console.warn(
110
+ `[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.`,
111
+ definition
112
+ );
113
+ }
114
+ const drawing = factory({ definition });
115
+ this.dispatchEvent(eventAfter, { [type]: drawing, definition });
116
+ draws.set(definition["@id"], drawing);
117
+ return drawing;
118
+ };
119
+ }
120
+ onDrawChanged(draws, newDrawDefinitions, factory, remover) {
121
+ const idsToRemove = new Set(draws.keys());
122
+ newDrawDefinitions.forEach((definition) => {
123
+ idsToRemove.delete(definition["@id"]);
124
+ });
125
+ idsToRemove.forEach((id) => {
126
+ const draw = draws.get(id);
127
+ remover(draw);
128
+ draws.delete(id);
129
+ });
130
+ newDrawDefinitions.forEach((definition) => {
131
+ if (!draws.has(definition["@id"])) {
132
+ factory({ definition });
133
+ }
134
+ });
135
+ }
136
+ //endregion
137
+ };
138
+ abstract_map_controller_default.values = {
139
+ providerOptions: Object,
140
+ center: Object,
141
+ zoom: Number,
142
+ minZoom: Number,
143
+ maxZoom: Number,
144
+ fitBoundsToMarkers: Boolean,
145
+ markers: Array,
146
+ polygons: Array,
147
+ polylines: Array,
148
+ circles: Array,
149
+ rectangles: Array,
150
+ options: Object,
151
+ extra: Object
109
152
  };
110
153
 
111
- let _google;
112
- const parser = new DOMParser();
113
- class map_controller extends default_1 {
114
- async connect() {
115
- if (!_google) {
116
- _google = { maps: {} };
117
- let { libraries = [], ...loaderOptions } = this.providerOptionsValue;
118
- const loader = new Loader(loaderOptions);
119
- libraries = ['core', ...libraries.filter((library) => library !== 'core')];
120
- const librariesImplementations = await Promise.all(libraries.map((library) => loader.importLibrary(library)));
121
- librariesImplementations.map((libraryImplementation, index) => {
122
- if (typeof libraryImplementation !== 'object' || libraryImplementation === null) {
123
- return;
124
- }
125
- const library = libraries[index];
126
- if (['marker', 'places', 'geometry', 'journeySharing', 'drawing', 'visualization'].includes(library)) {
127
- _google.maps[library] = libraryImplementation;
128
- }
129
- else {
130
- _google.maps = { ..._google.maps, ...libraryImplementation };
131
- }
132
- });
133
- }
134
- super.connect();
135
- this.parser = new DOMParser();
154
+ // src/map_controller.ts
155
+ var _google;
156
+ var _loading = false;
157
+ var _loaded = false;
158
+ var _onLoadedCallbacks = [];
159
+ var parser = new DOMParser();
160
+ var map_controller_default = class extends abstract_map_controller_default {
161
+ async connect() {
162
+ const onLoaded = () => super.connect();
163
+ if (_loaded) {
164
+ onLoaded();
165
+ return;
136
166
  }
137
- centerValueChanged() {
138
- if (this.map && this.hasCenterValue && this.centerValue) {
139
- this.map.setCenter(this.centerValue);
140
- }
167
+ if (_loading) {
168
+ _onLoadedCallbacks.push(onLoaded);
169
+ return;
141
170
  }
142
- zoomValueChanged() {
143
- if (this.map && this.hasZoomValue && this.zoomValue) {
144
- this.map.setZoom(this.zoomValue);
145
- }
171
+ _loading = true;
172
+ _google = { maps: {} };
173
+ let { libraries = [], ...loaderOptions } = this.providerOptionsValue;
174
+ const loader = new Loader(loaderOptions);
175
+ libraries = ["core", ...libraries.filter((library) => library !== "core")];
176
+ const librariesImplementations = await Promise.all(libraries.map((library) => loader.importLibrary(library)));
177
+ librariesImplementations.map((libraryImplementation, index) => {
178
+ if (typeof libraryImplementation !== "object" || libraryImplementation === null) {
179
+ return;
180
+ }
181
+ const library = libraries[index];
182
+ if (["marker", "places", "geometry", "journeySharing", "drawing", "visualization"].includes(library)) {
183
+ _google.maps[library] = libraryImplementation;
184
+ } else {
185
+ _google.maps = { ..._google.maps, ...libraryImplementation };
186
+ }
187
+ });
188
+ _loading = false;
189
+ _loaded = true;
190
+ onLoaded();
191
+ _onLoadedCallbacks.forEach((callback) => callback());
192
+ _onLoadedCallbacks = [];
193
+ }
194
+ centerValueChanged() {
195
+ if (this.map && this.hasCenterValue && this.centerValue) {
196
+ this.map.setCenter(this.centerValue);
146
197
  }
147
- dispatchEvent(name, payload = {}) {
148
- this.dispatch(name, {
149
- prefix: 'ux:map',
150
- detail: {
151
- ...payload,
152
- google: _google,
153
- },
154
- });
198
+ }
199
+ zoomValueChanged() {
200
+ if (this.map && this.hasZoomValue && this.zoomValue) {
201
+ this.map.setZoom(this.zoomValue);
155
202
  }
156
- doCreateMap({ center, zoom, options, }) {
157
- options.zoomControl = typeof options.zoomControlOptions !== 'undefined';
158
- options.mapTypeControl = typeof options.mapTypeControlOptions !== 'undefined';
159
- options.streetViewControl = typeof options.streetViewControlOptions !== 'undefined';
160
- options.fullscreenControl = typeof options.fullscreenControlOptions !== 'undefined';
161
- return new _google.maps.Map(this.element, {
162
- ...options,
163
- center,
164
- zoom,
165
- });
203
+ }
204
+ minZoomValueChanged() {
205
+ if (this.map && this.hasMinZoomValue && this.minZoomValue) {
206
+ this.map.setOptions({ minZoom: this.minZoomValue });
166
207
  }
167
- doCreateMarker({ definition, }) {
168
- const { '@id': _id, position, title, infoWindow, icon, extra, rawOptions = {}, ...otherOptions } = definition;
169
- const marker = new _google.maps.marker.AdvancedMarkerElement({
170
- position,
171
- title,
172
- ...otherOptions,
173
- ...rawOptions,
174
- map: this.map,
175
- });
176
- if (infoWindow) {
177
- this.createInfoWindow({ definition: infoWindow, element: marker });
178
- }
179
- if (icon) {
180
- this.doCreateIcon({ definition: icon, element: marker });
181
- }
182
- return marker;
208
+ }
209
+ maxZoomValueChanged() {
210
+ if (this.map && this.hasMaxZoomValue && this.maxZoomValue) {
211
+ this.map.setOptions({ maxZoom: this.maxZoomValue });
183
212
  }
184
- doRemoveMarker(marker) {
185
- marker.map = null;
213
+ }
214
+ dispatchEvent(name, payload = {}) {
215
+ payload.google = _google;
216
+ this.dispatch(name, {
217
+ prefix: "ux:map",
218
+ detail: payload
219
+ });
220
+ }
221
+ doCreateMap({ definition }) {
222
+ const { center, zoom, minZoom, maxZoom, options, bridgeOptions = {} } = definition;
223
+ options.zoomControl = typeof options.zoomControlOptions !== "undefined";
224
+ options.mapTypeControl = typeof options.mapTypeControlOptions !== "undefined";
225
+ options.streetViewControl = typeof options.streetViewControlOptions !== "undefined";
226
+ options.fullscreenControl = typeof options.fullscreenControlOptions !== "undefined";
227
+ return new _google.maps.Map(this.element, {
228
+ center,
229
+ zoom,
230
+ minZoom,
231
+ maxZoom,
232
+ ...options,
233
+ ...bridgeOptions
234
+ });
235
+ }
236
+ doCreateMarker({
237
+ definition
238
+ }) {
239
+ const { "@id": _id, position, title, infoWindow, icon, rawOptions = {}, bridgeOptions = {} } = definition;
240
+ const marker = new _google.maps.marker.AdvancedMarkerElement({
241
+ position,
242
+ title,
243
+ map: this.map,
244
+ ...rawOptions,
245
+ ...bridgeOptions
246
+ });
247
+ if (infoWindow) {
248
+ this.createInfoWindow({ definition: infoWindow, element: marker });
186
249
  }
187
- doCreatePolygon({ definition, }) {
188
- const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition;
189
- const polygon = new _google.maps.Polygon({
190
- ...rawOptions,
191
- paths: points,
192
- map: this.map,
193
- });
194
- if (title) {
195
- polygon.set('title', title);
196
- }
197
- if (infoWindow) {
198
- this.createInfoWindow({ definition: infoWindow, element: polygon });
199
- }
200
- return polygon;
250
+ if (icon) {
251
+ this.doCreateIcon({ definition: icon, element: marker });
201
252
  }
202
- doRemovePolygon(polygon) {
203
- polygon.setMap(null);
253
+ return marker;
254
+ }
255
+ doRemoveMarker(marker) {
256
+ marker.map = null;
257
+ }
258
+ doCreatePolygon({
259
+ definition
260
+ }) {
261
+ const { "@id": _id, points, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
262
+ const polygon = new _google.maps.Polygon({
263
+ paths: points,
264
+ map: this.map,
265
+ ...rawOptions,
266
+ ...bridgeOptions
267
+ });
268
+ if (title) {
269
+ polygon.set("title", title);
204
270
  }
205
- doCreatePolyline({ definition, }) {
206
- const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition;
207
- const polyline = new _google.maps.Polyline({
208
- ...rawOptions,
209
- path: points,
210
- map: this.map,
211
- });
212
- if (title) {
213
- polyline.set('title', title);
214
- }
215
- if (infoWindow) {
216
- this.createInfoWindow({ definition: infoWindow, element: polyline });
217
- }
218
- return polyline;
271
+ if (infoWindow) {
272
+ this.createInfoWindow({ definition: infoWindow, element: polygon });
219
273
  }
220
- doRemovePolyline(polyline) {
221
- polyline.setMap(null);
274
+ return polygon;
275
+ }
276
+ doRemovePolygon(polygon) {
277
+ polygon.setMap(null);
278
+ }
279
+ doCreatePolyline({
280
+ definition
281
+ }) {
282
+ const { "@id": _id, points, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
283
+ const polyline = new _google.maps.Polyline({
284
+ path: points,
285
+ map: this.map,
286
+ ...rawOptions,
287
+ ...bridgeOptions
288
+ });
289
+ if (title) {
290
+ polyline.set("title", title);
222
291
  }
223
- doCreateInfoWindow({ definition, element, }) {
224
- const { headerContent, content, extra, rawOptions = {}, ...otherOptions } = definition;
225
- const infoWindow = new _google.maps.InfoWindow({
226
- headerContent: this.createTextOrElement(headerContent),
227
- content: this.createTextOrElement(content),
228
- ...otherOptions,
229
- ...rawOptions,
230
- });
231
- if (element instanceof google.maps.marker.AdvancedMarkerElement) {
232
- element.addListener('click', () => {
233
- if (definition.autoClose) {
234
- this.closeInfoWindowsExcept(infoWindow);
235
- }
236
- infoWindow.open({ map: this.map, anchor: element });
237
- });
238
- if (definition.opened) {
239
- infoWindow.open({ map: this.map, anchor: element });
240
- }
241
- }
242
- else if (element instanceof google.maps.Polygon) {
243
- element.addListener('click', (event) => {
244
- if (definition.autoClose) {
245
- this.closeInfoWindowsExcept(infoWindow);
246
- }
247
- infoWindow.setPosition(event.latLng);
248
- infoWindow.open(this.map);
249
- });
250
- if (definition.opened) {
251
- const bounds = new google.maps.LatLngBounds();
252
- element.getPath().forEach((point) => {
253
- bounds.extend(point);
254
- });
255
- infoWindow.setPosition(bounds.getCenter());
256
- infoWindow.open({ map: this.map, anchor: element });
257
- }
258
- }
259
- return infoWindow;
292
+ if (infoWindow) {
293
+ this.createInfoWindow({ definition: infoWindow, element: polyline });
260
294
  }
261
- doFitBoundsToMarkers() {
262
- if (this.markers.size === 0) {
263
- return;
264
- }
265
- const bounds = new google.maps.LatLngBounds();
266
- this.markers.forEach((marker) => {
267
- if (!marker.position) {
268
- return;
269
- }
270
- bounds.extend(marker.position);
271
- });
272
- this.map.fitBounds(bounds);
295
+ return polyline;
296
+ }
297
+ doRemovePolyline(polyline) {
298
+ polyline.setMap(null);
299
+ }
300
+ doCreateCircle({ definition }) {
301
+ const { "@id": _id, center, radius, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
302
+ const circle = new _google.maps.Circle({
303
+ center,
304
+ radius,
305
+ map: this.map,
306
+ ...rawOptions,
307
+ ...bridgeOptions
308
+ });
309
+ if (title) {
310
+ circle.set("title", title);
273
311
  }
274
- createTextOrElement(content) {
275
- if (!content) {
276
- return null;
277
- }
278
- if (content.includes('<')) {
279
- const div = document.createElement('div');
280
- div.innerHTML = content;
281
- return div;
282
- }
283
- return content;
312
+ if (infoWindow) {
313
+ this.createInfoWindow({ definition: infoWindow, element: circle });
284
314
  }
285
- doCreateIcon({ definition, element, }) {
286
- const { type, width, height } = definition;
287
- if (type === IconTypes.Svg) {
288
- element.content = parser.parseFromString(definition.html, 'image/svg+xml').documentElement;
289
- }
290
- else if (type === IconTypes.UxIcon) {
291
- element.content = parser.parseFromString(definition._generated_html, 'image/svg+xml').documentElement;
292
- }
293
- else if (type === IconTypes.Url) {
294
- const icon = document.createElement('img');
295
- icon.width = width;
296
- icon.height = height;
297
- icon.src = definition.url;
298
- element.content = icon;
299
- }
300
- else {
301
- throw new Error(`Unsupported icon type: ${type}.`);
302
- }
315
+ return circle;
316
+ }
317
+ doRemoveCircle(circle) {
318
+ circle.setMap(null);
319
+ }
320
+ doCreateRectangle({
321
+ definition
322
+ }) {
323
+ const { northEast, southWest, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition;
324
+ const rectangle = new _google.maps.Rectangle({
325
+ bounds: new _google.maps.LatLngBounds(southWest, northEast),
326
+ map: this.map,
327
+ ...rawOptions,
328
+ ...bridgeOptions
329
+ });
330
+ if (title) {
331
+ rectangle.set("title", title);
303
332
  }
304
- closeInfoWindowsExcept(infoWindow) {
305
- this.infoWindows.forEach((otherInfoWindow) => {
306
- if (otherInfoWindow !== infoWindow) {
307
- otherInfoWindow.close();
308
- }
309
- });
333
+ if (infoWindow) {
334
+ this.createInfoWindow({ definition: infoWindow, element: rectangle });
310
335
  }
311
- }
312
-
313
- export { map_controller as default };
336
+ return rectangle;
337
+ }
338
+ doRemoveRectangle(rectangle) {
339
+ rectangle.setMap(null);
340
+ }
341
+ doCreateInfoWindow({
342
+ definition,
343
+ element
344
+ }) {
345
+ const { headerContent, content, opened, autoClose, rawOptions = {}, bridgeOptions = {} } = definition;
346
+ let position = null;
347
+ if (element instanceof google.maps.Circle) {
348
+ position = element.getCenter();
349
+ } else if (element instanceof google.maps.Rectangle) {
350
+ position = element.getBounds()?.getCenter() || null;
351
+ } else if (element instanceof google.maps.Polygon || element instanceof google.maps.Polyline) {
352
+ }
353
+ const infoWindowOptions = {
354
+ headerContent: this.createTextOrElement(headerContent),
355
+ content: this.createTextOrElement(content),
356
+ position,
357
+ ...rawOptions,
358
+ ...bridgeOptions
359
+ };
360
+ const infoWindow = new _google.maps.InfoWindow(infoWindowOptions);
361
+ element.addListener("click", (event) => {
362
+ if (autoClose) {
363
+ this.closeInfoWindowsExcept(infoWindow);
364
+ }
365
+ if (infoWindowOptions.position === null) {
366
+ infoWindow.setPosition(event.latLng);
367
+ }
368
+ infoWindow.open({ map: this.map, anchor: element });
369
+ });
370
+ if (opened) {
371
+ if (autoClose) {
372
+ this.closeInfoWindowsExcept(infoWindow);
373
+ }
374
+ infoWindow.open({ map: this.map, anchor: element });
375
+ }
376
+ return infoWindow;
377
+ }
378
+ doFitBoundsToMarkers() {
379
+ if (this.markers.size === 0) {
380
+ return;
381
+ }
382
+ const bounds = new google.maps.LatLngBounds();
383
+ this.markers.forEach((marker) => {
384
+ if (!marker.position) {
385
+ return;
386
+ }
387
+ bounds.extend(marker.position);
388
+ });
389
+ this.map.fitBounds(bounds);
390
+ }
391
+ createTextOrElement(content) {
392
+ if (!content) {
393
+ return null;
394
+ }
395
+ if (content.includes("<")) {
396
+ const div = document.createElement("div");
397
+ div.innerHTML = content;
398
+ return div;
399
+ }
400
+ return content;
401
+ }
402
+ doCreateIcon({ definition, element }) {
403
+ const { type, width, height } = definition;
404
+ if (type === IconTypes.Svg) {
405
+ element.content = parser.parseFromString(definition.html, "image/svg+xml").documentElement;
406
+ } else if (type === IconTypes.UxIcon) {
407
+ element.content = parser.parseFromString(definition._generated_html, "image/svg+xml").documentElement;
408
+ } else if (type === IconTypes.Url) {
409
+ const icon = document.createElement("img");
410
+ icon.width = width;
411
+ icon.height = height;
412
+ icon.src = definition.url;
413
+ element.content = icon;
414
+ } else {
415
+ throw new Error(`Unsupported icon type: ${type}.`);
416
+ }
417
+ }
418
+ closeInfoWindowsExcept(infoWindow) {
419
+ this.infoWindows.forEach((otherInfoWindow) => {
420
+ if (otherInfoWindow !== infoWindow) {
421
+ otherInfoWindow.close();
422
+ }
423
+ });
424
+ }
425
+ };
426
+ export {
427
+ map_controller_default as default
428
+ };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@symfony/ux-google-map",
3
3
  "description": "GoogleMaps 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
  "google-maps",
@@ -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": {
@@ -50,7 +43,23 @@
50
43
  "devDependencies": {
51
44
  "@googlemaps/js-api-loader": "^1.16.6",
52
45
  "@hotwired/stimulus": "^3.0.0",
53
- "@symfony/ux-map": "2.26.1",
54
- "@types/google.maps": "^3.55.9"
46
+ "@testing-library/dom": "^10.4.0",
47
+ "@testing-library/jest-dom": "^6.6.3",
48
+ "@testing-library/user-event": "^14.6.1",
49
+ "@types/google.maps": "^3.55.9",
50
+ "@vitest/browser": "^3.2.4",
51
+ "jsdom": "^26.1.0",
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
  }