File size: 2,161 Bytes
0e11366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import React from "react";
import { useMap } from "@vis.gl/react-google-maps";
import type { SelectMeta } from "../../../lib/types";

export default function SearchControl({
  onPlace,
}: {
  onPlace: (ll: [number, number], meta: SelectMeta) => void;
}) {
  const map = useMap();
  const onPlaceRef = React.useRef(onPlace);
  React.useEffect(() => {
    onPlaceRef.current = onPlace;
  }, [onPlace]);

  React.useEffect(() => {
    if (!map || !window.google) return;
    const container = document.createElement("div");
    Object.assign(container.style, {
      background: "#fff",
      borderRadius: "8px",
      boxShadow: "0 1px 4px rgba(0,0,0,.3)",
      margin: "10px",
      padding: "4px",
    });

    const input = document.createElement("input");
    input.type = "text";
    input.placeholder = "Search places…";
    input.setAttribute("aria-label", "Search places");
    Object.assign(input.style, {
      border: "0",
      outline: "0",
      padding: "10px 12px",
      width: "260px",
      borderRadius: "6px",
    } as CSSStyleDeclaration);

    container.appendChild(input);
    map.controls[google.maps.ControlPosition.TOP_LEFT].push(container);

    const ac = new google.maps.places.Autocomplete(input, {
      fields: ["geometry", "name", "formatted_address"],
      types: ["geocode"],
    });
    const listener = ac.addListener("place_changed", () => {
      const place = ac.getPlace();
      const loc = place?.geometry?.location;
      if (loc) {
        const ll: [number, number] = [loc.lat(), loc.lng()];
        map.setCenter({ lat: ll[0], lng: ll[1] });
        map.setZoom(12);
        onPlaceRef.current(ll, {
          kind: "search",
          title: place.name || "Search result",
          subtitle: place.formatted_address,
          raw: place,
        });
      }
    });

    return () => {
      google.maps.event.removeListener(listener);
      const arr = map.controls[google.maps.ControlPosition.TOP_LEFT];
      for (let i = 0; i < arr.getLength(); i++) {
        if (arr.getAt(i) === (container as any)) {
          arr.removeAt(i);
          break;
        }
      }
    };
  }, [map]);

  return null;
}