@maptiler/geocoding-control 0.0.32 → 0.0.37

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.
@@ -5,11 +5,14 @@ import {
5
5
  type FlyToOptions,
6
6
  type FitBoundsOptions,
7
7
  Evented,
8
+ type FillLayerSpecification,
9
+ type LineLayerSpecification,
8
10
  } from "maplibre-gl";
9
11
  import type maplibregl from "maplibre-gl";
10
12
  import GeocodingControlComponent from "./GeocodingControl.svelte";
11
13
  import type { ControlOptions } from "./types";
12
- import { createMaplibreMapController } from "./maplibreMapController";
14
+ import { createMaplibreglMapController } from "./maplibreglMapController";
15
+ export { createMaplibreglMapController } from "./maplibreglMapController";
13
16
 
14
17
  type MapLibreGL = typeof maplibregl;
15
18
 
@@ -48,6 +51,14 @@ type MapLibreControlOptions = ControlOptions & {
48
51
  * @default true
49
52
  */
50
53
  flyTo?: boolean | (FlyToOptions & FitBoundsOptions);
54
+
55
+ /**
56
+ * Style for full feature geometry GeoJSON.
57
+ */
58
+ fullGeometryStyle?: {
59
+ fill: Pick<FillLayerSpecification, "layout" | "paint" | "filter">;
60
+ line: Pick<LineLayerSpecification, "layout" | "paint" | "filter">;
61
+ };
51
62
  };
52
63
 
53
64
  export class GeocodingControl extends Evented implements IControl {
@@ -67,18 +78,25 @@ export class GeocodingControl extends Evented implements IControl {
67
78
  div.className =
68
79
  "mapboxgl-ctrl-geocoder mapboxgl-ctrl maplibregl-ctrl-geocoder maplibregl-ctrl";
69
80
 
70
- const { maplibregl, marker, showResultMarkers, flyTo, ...restOptions } =
71
- this.#options;
81
+ const {
82
+ maplibregl,
83
+ marker,
84
+ showResultMarkers,
85
+ flyTo,
86
+ fullGeometryStyle,
87
+ ...restOptions
88
+ } = this.#options;
72
89
 
73
90
  const flyToOptions = typeof flyTo === "boolean" ? {} : flyTo;
74
91
 
75
- const mapController = createMaplibreMapController(
92
+ const mapController = createMaplibreglMapController(
76
93
  map,
77
94
  maplibregl,
78
95
  marker,
79
96
  showResultMarkers,
80
97
  flyToOptions,
81
- flyToOptions
98
+ flyToOptions,
99
+ fullGeometryStyle
82
100
  );
83
101
 
84
102
  this.#gc = new GeocodingControlComponent({
@@ -111,13 +129,19 @@ export class GeocodingControl extends Evented implements IControl {
111
129
  setOptions(options: MapLibreControlOptions) {
112
130
  this.#options = options;
113
131
 
114
- const { maplibregl, marker, showResultMarkers, flyTo, ...restOptions } =
115
- this.#options;
132
+ const {
133
+ maplibregl,
134
+ marker,
135
+ showResultMarkers,
136
+ flyTo,
137
+ fullGeometryStyle,
138
+ ...restOptions
139
+ } = this.#options;
116
140
 
117
141
  this.#gc?.$set(restOptions);
118
142
  }
119
143
 
120
- setQuery(value: string, submit = true) {
144
+ setQuery(value: string, submit: boolean | "always" = true) {
121
145
  (this.#gc as any)?.setQuery(value, submit);
122
146
  }
123
147
 
@@ -0,0 +1,12 @@
1
+ <svg viewBox="0 0 60.006 21.412" width="14" height="20">
2
+ <path
3
+ d="M30.003-26.765C13.46-26.765 0-14.158 0 1.337c0 23.286 24.535 42.952 28.39 46.04.24.192.402.316.471.376.323.282.732.424 1.142.424.41 0 .82-.142 1.142-.424.068-.06.231-.183.471-.376 3.856-3.09 28.39-22.754 28.39-46.04 0-15.495-13.46-28.102-30.003-28.102Zm1.757 12.469c4.38 0 7.858 1.052 10.431 3.158 2.595 2.105 3.89 4.913 3.89 8.422 0 2.34-.53 4.362-1.593 6.063-1.063 1.702-3.086 3.616-6.063 5.742-2.042 1.51-3.337 2.659-3.89 3.446-.532.787-.8 1.82-.8 3.096v1.914h-8.449V15.18c0-2.041.434-3.815 1.306-5.325.872-1.51 2.467-3.118 4.785-4.82 2.233-1.594 3.7-2.89 4.402-3.889a5.582 5.582 0 0 0 1.087-3.35c0-1.382-.51-2.435-1.531-3.158-1.02-.723-2.45-1.087-4.28-1.087-3.19 0-6.826 1.047-10.91 3.131l-3.472-6.986c4.742-2.659 9.77-3.992 15.087-3.992Zm-1.88 37.324c1.765 0 3.124.472 4.08 1.408.98.936 1.47 2.276 1.47 4.02 0 1.68-.49 3.007-1.47 3.985-.977.957-2.336 1.435-4.08 1.435-1.787 0-3.171-.465-4.15-1.4-.978-.958-1.47-2.298-1.47-4.02 0-1.787.48-3.14 1.436-4.054.957-.915 2.355-1.374 4.184-1.374Z"
4
+ />
5
+ </svg>
6
+
7
+ <style>
8
+ svg {
9
+ display: block;
10
+ fill: var(--color-icon-button);
11
+ }
12
+ </style>
@@ -1,13 +1,35 @@
1
1
  import * as L from "leaflet";
2
2
  import MarkerIcon from "./MarkerIcon.svelte";
3
3
  import type { Feature, MapController, Proximity } from "./types";
4
+ import type {
5
+ Polygon,
6
+ MultiPolygon,
7
+ LineString,
8
+ MultiLineString,
9
+ } from "@turf/helpers";
10
+ import mask from "@turf/mask";
11
+ import union from "@turf/union";
4
12
 
5
13
  export function createLeafletMapController(
6
14
  map: L.Map,
7
15
  marker: boolean | L.MarkerOptions = true,
8
16
  showResultMarkers: boolean | L.MarkerOptions = true,
9
17
  flyToOptions: L.ZoomPanOptions = {},
10
- flyToBounds: L.FitBoundsOptions = {}
18
+ flyToBounds: L.FitBoundsOptions = {},
19
+ fullGeometryStyle: L.PathOptions | L.StyleFunction = (feature) => {
20
+ const type = feature?.geometry?.type;
21
+
22
+ const weight = type === "LineString" || type === "MultiLineString" ? 3 : 2;
23
+
24
+ return {
25
+ color: "#3170fe",
26
+ fillColor: "#000",
27
+ fillOpacity: 0.1,
28
+ weight,
29
+ dashArray: [weight, weight],
30
+ lineCap: "butt",
31
+ };
32
+ }
11
33
  ) {
12
34
  let proximityChangeHandler: ((proximity: Proximity) => void) | undefined;
13
35
 
@@ -19,6 +41,10 @@ export function createLeafletMapController(
19
41
 
20
42
  let selectedMarker: L.Marker | undefined;
21
43
 
44
+ let resultLayer = L.geoJSON(undefined, {
45
+ style: fullGeometryStyle,
46
+ }).addTo(map);
47
+
22
48
  const handleMoveEnd = () => {
23
49
  if (!proximityChangeHandler) {
24
50
  prevProximity = undefined;
@@ -76,7 +102,7 @@ export function createLeafletMapController(
76
102
  },
77
103
 
78
104
  flyTo(center: [number, number], zoom: number) {
79
- map.flyTo(center, zoom, flyToOptions);
105
+ map.flyTo(center, zoom, { duration: 2, ...flyToOptions });
80
106
  },
81
107
 
82
108
  fitBounds(bbox: [number, number, number, number], padding: number): void {
@@ -85,7 +111,7 @@ export function createLeafletMapController(
85
111
  [bbox[1], bbox[0]],
86
112
  [bbox[3], bbox[2]],
87
113
  ],
88
- { ...flyToBounds, padding: [padding, padding] }
114
+ { padding: [padding, padding], duration: 2, ...flyToBounds }
89
115
  );
90
116
  },
91
117
 
@@ -97,37 +123,110 @@ export function createLeafletMapController(
97
123
  markedFeatures: Feature[] | undefined,
98
124
  picked: Feature | undefined
99
125
  ): void {
126
+ function setData(data?: GeoJSON.GeoJSON) {
127
+ resultLayer.clearLayers();
128
+
129
+ if (data) {
130
+ resultLayer.addData(data);
131
+ }
132
+ }
133
+
100
134
  for (const marker of markers) {
101
135
  marker.remove();
102
136
  }
103
137
 
104
138
  markers.length = 0;
105
139
 
106
- for (const feature of picked
107
- ? [...(markedFeatures ?? []), picked]
108
- : markedFeatures ?? []) {
109
- let m: L.Marker;
140
+ setData();
110
141
 
111
- const pos: L.LatLngExpression = [feature.center[1], feature.center[0]];
142
+ const createMarker = (pos: L.LatLngExpression) => {
143
+ const element = document.createElement("div");
144
+
145
+ new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
146
+
147
+ return new L.Marker(pos, {
148
+ icon: new L.DivIcon({ html: element, className: "" }),
149
+ });
150
+ };
151
+
152
+ if (picked) {
153
+ let handled = false;
154
+
155
+ if (picked.geometry.type === "GeometryCollection") {
156
+ const geoms = picked.geometry.geometries.filter(
157
+ (geometry) =>
158
+ geometry.type === "Polygon" || geometry.type === "MultiPolygon"
159
+ ) as (Polygon | MultiPolygon)[];
160
+
161
+ if (geoms.length > 0) {
162
+ let geometry = geoms.pop()!;
163
+
164
+ for (const geom of geoms) {
165
+ geometry = union(geometry, geom) as unknown as
166
+ | Polygon
167
+ | MultiPolygon; // union actually returns geometry
168
+ }
169
+
170
+ setData(mask({ ...picked, geometry }));
112
171
 
113
- if (feature === picked && typeof marker === "object") {
114
- m = new L.Marker(pos, marker);
172
+ handled = true;
173
+ } else {
174
+ const geometries = picked.geometry.geometries.filter(
175
+ (geometry) =>
176
+ geometry.type === "LineString" ||
177
+ geometry.type === "MultiLineString"
178
+ ) as (LineString | MultiLineString)[];
179
+
180
+ if (geometries.length > 0) {
181
+ setData({
182
+ ...picked,
183
+ geometry: { type: "GeometryCollection", geometries },
184
+ });
185
+
186
+ handled = true;
187
+ }
188
+ }
189
+ }
190
+
191
+ if (handled) {
192
+ // nothing
193
+ } else if (
194
+ picked.geometry.type === "Polygon" ||
195
+ picked.geometry.type === "MultiPolygon"
196
+ ) {
197
+ setData(mask(picked as any));
115
198
  } else if (
116
- feature !== picked &&
117
- typeof showResultMarkers === "object"
199
+ picked.geometry.type === "LineString" ||
200
+ picked.geometry.type === "MultiLineString"
118
201
  ) {
119
- m = new L.Marker(pos, showResultMarkers);
120
- } else {
121
- const element = document.createElement("div");
202
+ setData(picked as any);
122
203
 
123
- new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
204
+ return; // no pin for (multi)linestrings
205
+ }
206
+
207
+ const pos: L.LatLngExpression = [picked.center[1], picked.center[0]];
208
+
209
+ markers.push(
210
+ (typeof marker === "object"
211
+ ? new L.Marker(pos, marker)
212
+ : createMarker(pos)
213
+ ).addTo(map)
214
+ );
215
+ }
124
216
 
125
- m = new L.Marker(pos, {
126
- icon: new L.DivIcon({ html: element, className: "" }),
127
- });
217
+ for (const feature of markedFeatures ?? []) {
218
+ if (feature === picked) {
219
+ continue;
128
220
  }
129
221
 
130
- markers.push(m.addTo(map));
222
+ const pos: L.LatLngExpression = [feature.center[1], feature.center[0]];
223
+
224
+ markers.push(
225
+ (typeof showResultMarkers === "object"
226
+ ? new L.Marker(pos, showResultMarkers)
227
+ : createMarker(pos)
228
+ ).addTo(map)
229
+ );
131
230
  }
132
231
  },
133
232
 
@@ -0,0 +1,291 @@
1
+ import type MapLibreGL from "maplibre-gl";
2
+ import type {
3
+ FitBoundsOptions,
4
+ MapMouseEvent,
5
+ LngLat,
6
+ Map,
7
+ Marker,
8
+ FlyToOptions,
9
+ GeoJSONSource,
10
+ FillLayerSpecification,
11
+ LineLayerSpecification,
12
+ } from "maplibre-gl";
13
+ import MarkerIcon from "./MarkerIcon.svelte";
14
+ import type { Feature, MapController, Proximity } from "./types";
15
+ import mask from "@turf/mask";
16
+ import union from "@turf/union";
17
+ import type {
18
+ Polygon,
19
+ MultiPolygon,
20
+ LineString,
21
+ MultiLineString,
22
+ } from "@turf/helpers";
23
+
24
+ let emptyGeojson: GeoJSON.FeatureCollection = {
25
+ type: "FeatureCollection",
26
+ features: [],
27
+ };
28
+
29
+ export function createMaplibreglMapController(
30
+ map: Map,
31
+ maplibregl?: typeof MapLibreGL | undefined,
32
+ marker: boolean | maplibregl.MarkerOptions = true,
33
+ showResultMarkers: boolean | maplibregl.MarkerOptions = true,
34
+ flyToOptions: FlyToOptions = {},
35
+ fitBoundsOptions: FitBoundsOptions = {},
36
+ fullGeometryStyle: {
37
+ fill: Pick<FillLayerSpecification, "layout" | "paint" | "filter">;
38
+ line: Pick<LineLayerSpecification, "layout" | "paint" | "filter">;
39
+ } = {
40
+ fill: {
41
+ layout: {},
42
+ paint: {
43
+ "fill-color": "#000",
44
+ "fill-opacity": 0.1,
45
+ },
46
+ },
47
+ line: {
48
+ layout: {
49
+ "line-cap": "square",
50
+ },
51
+ paint: {
52
+ "line-width": ["case", ["==", ["geometry-type"], "Polygon"], 2, 3],
53
+ "line-dasharray": [1, 1],
54
+ "line-color": "#3170fe",
55
+ },
56
+ },
57
+ }
58
+ ) {
59
+ let proximityChangeHandler: ((proximity: Proximity) => void) | undefined;
60
+
61
+ let mapClickHandler: ((coordinates: [number, number]) => void) | undefined;
62
+
63
+ let prevProximity: Proximity = undefined;
64
+
65
+ let markers: Marker[] = [];
66
+
67
+ let selectedMarker: maplibregl.Marker | undefined;
68
+
69
+ function addFullGeometryLayer() {
70
+ map.addSource("full-geom", {
71
+ type: "geojson",
72
+ data: emptyGeojson,
73
+ });
74
+
75
+ map.addLayer({
76
+ ...fullGeometryStyle.fill,
77
+ id: "full-geom-fill",
78
+ type: "fill",
79
+ source: "full-geom",
80
+ filter: ["==", ["geometry-type"], "Polygon"],
81
+ });
82
+
83
+ map.addLayer({
84
+ ...fullGeometryStyle.line,
85
+ id: "full-geom-line",
86
+ type: "line",
87
+ source: "full-geom",
88
+ });
89
+ }
90
+
91
+ if (map.loaded()) {
92
+ addFullGeometryLayer();
93
+ } else {
94
+ map.once("load", () => {
95
+ addFullGeometryLayer();
96
+ });
97
+ }
98
+
99
+ const handleMapClick = (e: MapMouseEvent) => {
100
+ mapClickHandler?.([e.lngLat.lng, e.lngLat.lat]);
101
+ };
102
+
103
+ const handleMoveEnd = () => {
104
+ let c: LngLat;
105
+
106
+ const proximity =
107
+ map.getZoom() > 9
108
+ ? ([(c = map.getCenter().wrap()).lng, c.lat] as [number, number])
109
+ : undefined;
110
+
111
+ if (prevProximity !== proximity) {
112
+ prevProximity = proximity;
113
+
114
+ proximityChangeHandler?.(proximity);
115
+ }
116
+ };
117
+
118
+ const ctrl: MapController = {
119
+ setProximityChangeHandler(
120
+ _proximityChangeHandler: ((proximity: Proximity) => void) | undefined
121
+ ): void {
122
+ if (_proximityChangeHandler) {
123
+ proximityChangeHandler = _proximityChangeHandler;
124
+
125
+ map.on("moveend", handleMoveEnd);
126
+
127
+ handleMoveEnd();
128
+ } else {
129
+ map.off("moveend", handleMoveEnd);
130
+
131
+ proximityChangeHandler?.(undefined);
132
+
133
+ proximityChangeHandler = undefined;
134
+ }
135
+ },
136
+
137
+ setMapClickHandler(
138
+ _mapClickHandler: ((coordinates: [number, number]) => void) | undefined
139
+ ): void {
140
+ mapClickHandler = _mapClickHandler;
141
+
142
+ if (mapClickHandler) {
143
+ map.on("click", handleMapClick);
144
+ } else {
145
+ map.off("click", handleMapClick);
146
+ }
147
+ },
148
+
149
+ flyTo(center: [number, number], zoom: number): void {
150
+ map.flyTo({ center, zoom, ...flyToOptions });
151
+ },
152
+
153
+ fitBounds(bbox: [number, number, number, number], padding: number): void {
154
+ map.fitBounds(
155
+ [
156
+ [bbox[0], bbox[1]],
157
+ [bbox[2], bbox[3]],
158
+ ],
159
+ { padding, ...fitBoundsOptions }
160
+ );
161
+ },
162
+
163
+ indicateReverse(reverse: boolean): void {
164
+ map.getCanvas().style.cursor = reverse ? "crosshair" : "";
165
+ },
166
+
167
+ setMarkers(
168
+ markedFeatures: Feature[] | undefined,
169
+ picked: Feature | undefined
170
+ ): void {
171
+ function setData(data: GeoJSON.GeoJSON) {
172
+ (map.getSource("full-geom") as GeoJSONSource)?.setData(data);
173
+ }
174
+
175
+ for (const marker of markers) {
176
+ marker.remove();
177
+ }
178
+
179
+ markers.length = 0;
180
+
181
+ setData(emptyGeojson);
182
+
183
+ if (!maplibregl) {
184
+ return;
185
+ }
186
+
187
+ const createMarker = () => {
188
+ const element = document.createElement("div");
189
+
190
+ new MarkerIcon({
191
+ props: { displayIn: "maplibre" },
192
+ target: element,
193
+ });
194
+
195
+ return new maplibregl.Marker({ element });
196
+ };
197
+
198
+ if (picked) {
199
+ let handled = false;
200
+
201
+ if (picked.geometry.type === "GeometryCollection") {
202
+ const geoms = picked.geometry.geometries.filter(
203
+ (geometry) =>
204
+ geometry.type === "Polygon" || geometry.type === "MultiPolygon"
205
+ ) as (Polygon | MultiPolygon)[];
206
+
207
+ if (geoms.length > 0) {
208
+ let geometry = geoms.pop()!;
209
+
210
+ for (const geom of geoms) {
211
+ geometry = union(geometry, geom) as unknown as
212
+ | Polygon
213
+ | MultiPolygon; // union actually returns geometry
214
+ }
215
+
216
+ setData(mask({ ...picked, geometry }));
217
+
218
+ handled = true;
219
+ } else {
220
+ const geometries = picked.geometry.geometries.filter(
221
+ (geometry) =>
222
+ geometry.type === "LineString" ||
223
+ geometry.type === "MultiLineString"
224
+ ) as (LineString | MultiLineString)[];
225
+
226
+ if (geometries.length > 0) {
227
+ setData({
228
+ ...picked,
229
+ geometry: { type: "GeometryCollection", geometries },
230
+ });
231
+
232
+ handled = true;
233
+ }
234
+ }
235
+ }
236
+
237
+ if (handled) {
238
+ // nothing
239
+ } else if (
240
+ picked.geometry.type === "Polygon" ||
241
+ picked.geometry.type === "MultiPolygon"
242
+ ) {
243
+ setData(mask(picked as any));
244
+ } else if (
245
+ picked.geometry.type === "LineString" ||
246
+ picked.geometry.type === "MultiLineString"
247
+ ) {
248
+ setData(picked as any);
249
+
250
+ return; // no pin for (multi)linestrings
251
+ }
252
+
253
+ markers.push(
254
+ (typeof marker === "object"
255
+ ? new maplibregl.Marker(marker)
256
+ : createMarker()
257
+ )
258
+ .setLngLat(picked.center)
259
+ .addTo(map)
260
+ );
261
+ }
262
+
263
+ for (const feature of markedFeatures ?? []) {
264
+ if (feature === picked) {
265
+ continue;
266
+ }
267
+
268
+ markers.push(
269
+ (typeof showResultMarkers === "object"
270
+ ? new maplibregl.Marker(showResultMarkers)
271
+ : createMarker()
272
+ )
273
+ .setLngLat(feature.center)
274
+ .addTo(map)
275
+ );
276
+ }
277
+ },
278
+
279
+ setSelectedMarker(index: number): void {
280
+ if (selectedMarker) {
281
+ selectedMarker.getElement().classList.toggle("marker-selected", false);
282
+ }
283
+
284
+ selectedMarker = index > -1 ? markers[index] : undefined;
285
+
286
+ selectedMarker?.getElement().classList.toggle("marker-selected", true);
287
+ },
288
+ };
289
+
290
+ return ctrl;
291
+ }
package/src/lib/types.ts CHANGED
@@ -1,13 +1,15 @@
1
- export type Feature = {
1
+ export type Feature = GeoJSON.Feature & {
2
2
  id: string;
3
3
  text: string;
4
4
  place_name: string;
5
5
  place_type: string;
6
6
  center: [number, number];
7
7
  bbox: [number, number, number, number];
8
+ address?: string;
8
9
  };
9
10
 
10
11
  export type FeatureCollection = {
12
+ type: "FeatureCollection";
11
13
  features: Feature[];
12
14
  };
13
15
 
@@ -177,11 +179,25 @@ export type ControlOptions = {
177
179
  class?: string;
178
180
 
179
181
  /**
180
- * Set to `true` to enable reverse geocoding button with title _toggle reverse geocoding_ or set the button title directly.
182
+ * Set to `true` to enable reverse geocoding button with title. Set to `"always"` to reverse geocoding be always active.
181
183
  *
182
184
  * @default false
183
185
  */
184
- enableReverse?: boolean | string;
186
+ enableReverse?: boolean | "always";
187
+
188
+ /**
189
+ * Reverse toggle button title.
190
+ *
191
+ * @default "toggle reverse geocoding"
192
+ */
193
+ reverseButtonTitle?: string;
194
+
195
+ /**
196
+ * Clear button title.
197
+ *
198
+ * @default "clear"
199
+ */
200
+ clearButtonTitle?: string;
185
201
 
186
202
  /**
187
203
  * Set to `true` to show place type.
@@ -190,6 +206,13 @@ export type ControlOptions = {
190
206
  */
191
207
  showPlaceType?: boolean;
192
208
 
209
+ /**
210
+ * Set to `true` to show full feature geometry of the chosen result. Otherwise only marker will be shown.
211
+ *
212
+ * @default true
213
+ */
214
+ showFullGeometry?: boolean;
215
+
193
216
  // TODO - missing but useful from maplibre-gl-geocoder
194
217
  // popup // If true, a Popup will be added to the map when clicking on a marker using a default set of popup options. If the value is an object, the popup will be constructed using these options. If false, no popup will be added to the map. Requires that options.maplibregl also be set. (optional, default true)
195
218
  // render // A function that specifies how the results should be rendered in the dropdown menu. This function should accepts a single Carmen GeoJSON object as input and return a string. Any HTML in the returned string will be rendered.
@@ -1,4 +0,0 @@
1
- import type MapLibreGL from "maplibre-gl";
2
- import type { FitBoundsOptions, Map, FlyToOptions } from "maplibre-gl";
3
- import type { MapController } from "./types";
4
- export declare function createMaplibreMapController(map: Map, maplibregl?: typeof MapLibreGL | undefined, marker?: boolean | maplibregl.MarkerOptions, showResultMarkers?: boolean | maplibregl.MarkerOptions, flyToOptions?: FlyToOptions, fitBoundsOptions?: FitBoundsOptions): MapController;
@@ -1,12 +0,0 @@
1
- <svg viewBox="0 0 1000 1000" width="18px" height="18px">
2
- <path
3
- d="M500 115.1c212.2 0 384.9 172.6 384.9 384.9 0 212.2-172.7 384.9-384.9 384.9S115.1 712.2 115.1 500c0-212.4 172.5-384.9 384.9-384.9M500 10C229.4 10 10 229.4 10 500s219.4 490 490 490 490-219.4 490-490c-.2-270.6-219.5-490-490-490zm0 315c96.5 0 175 78.4 175 175 0 96.5-78.4 175-175 175-96.5 0-175-78.4-175-175 0-96.5 78.4-175 175-175m0-105c-154.7 0-279.9 125.4-279.9 279.9 0 154.7 125.4 279.9 279.9 279.9 154.5 0 279.9-125.4 279.9-279.9C779.9 345.3 654.5 220 500 220zm70 280c0 38.7-31.3 70-70 70s-70-31.3-70-70 31.3-70 70-70 70 31.3 70 70z"
4
- />
5
- </svg>
6
-
7
- <style>
8
- svg {
9
- display: block;
10
- fill: var(--color-icon-button);
11
- }
12
- </style>