# react-google

React components and hooks for Google Maps with WebGL overlay support.

```typescript
import {
    GoogleApiProvider,
    GoogleMaps,
    WebGLOverlayView,
    useGapiLoader,
    useMap,
    useWebGLOverlayView,
} from '@yaoc1996/js-tools/react-google'
```

---

## Components

---

### `GoogleApiProvider`

Loads the Google Maps JavaScript API and provides a `Loader` instance to all descendants via `GoogleApiContext`.

#### Parameters

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `options` | `LoaderOptions` | — | Options passed to `@googlemaps/js-api-loader` (e.g. `apiKey`, `version`, `libraries`). |
| `children` | `ReactNode` | — | Descendant components that consume the loader context. |

#### Example

```typescript
<GoogleApiProvider options={{ apiKey: 'YOUR_API_KEY', version: 'weekly' }}>
    <GoogleMaps options={{ center: { lat: 22, lng: 114 }, zoom: 12 }} />
</GoogleApiProvider>
```

#### Notes

- The loader is created and the `core` library is imported on mount; the script is removed on unmount.
- `options` is deep-compared — the loader is only recreated when a value actually changes.

---

### `GoogleMaps`

Initialises a Google `Map` instance and provides it to all descendants via `GoogleMapsContext`. Renders a full-size `<div>` container.

#### Parameters

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `options` | `google.maps.MapOptions` | — | Google Maps `MapOptions` passed to the `Map` constructor. |
| `divRef` | `MutableRefObject<HTMLDivElement>` | — | Optional ref forwarded to the outer container `<div>`. |
| `children` | `ReactNode` | — | Components nested inside the map (e.g. `WebGLOverlayView`). |
| `...props` | `HTMLAttributes<HTMLDivElement>` | — | Any additional HTML attributes applied to the outer container. |

#### Example

```typescript
<GoogleApiProvider options={{ apiKey: 'YOUR_API_KEY' }}>
    <div style={{ width: 800, height: 600 }}>
        <GoogleMaps options={{ center: { lat: 22, lng: 114 }, zoom: 12 }}>
            {/* nested overlays here */}
        </GoogleMaps>
    </div>
</GoogleApiProvider>
```

#### Notes

- Must be rendered inside a `GoogleApiProvider`.
- `options` is deep-compared; the map is only recreated when a value actually changes.

---

### `WebGLOverlayView`

Creates a WebGL overlay anchored at a geographic coordinate and provides it to descendants via `WebGLOverlayViewContext`. Requires Three.js integration via `google-three`.

#### Parameters

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `anchor` | `google.maps.LatLngLiteral` | — | Geographic anchor for the WebGL overlay's coordinate origin. |
| `children` | `ReactNode` | — | Hook consumers for the overlay. |

#### Example

```typescript
<GoogleApiProvider options={{ apiKey: 'YOUR_API_KEY' }}>
    <GoogleMaps options={{ center: { lat: 22, lng: 114 }, zoom: 14 }}>
        <WebGLOverlayView anchor={{ lat: 22, lng: 114 }}>
            {/* use useWebGLOverlayView() here */}
        </WebGLOverlayView>
    </GoogleMaps>
</GoogleApiProvider>
```

#### Notes

- Must be rendered inside both `GoogleApiProvider` and `GoogleMaps`.
- The overlay is detached from the map and disposed on unmount.
- `anchor` is deep-compared; the overlay is only recreated when the value actually changes.

---

## Hooks

---

### `useGapiLoader()`

Returns the Google Maps `Loader` instance from the nearest `GoogleApiProvider`, or `null` if the API has not yet loaded.

#### Returns

`Loader | null` — `null` before the API loads; the `Loader` instance once available.

#### Example

```typescript
const loader = useGapiLoader()

useEffect(() => {
    if (loader) {
        loader.importLibrary('marker').then(({ AdvancedMarkerElement }) => {
            // use marker
        })
    }
}, [loader])
```

---

### `useMap()`

Returns the current Google `Map` instance from the nearest `GoogleMaps` context, or `null` if the map has not yet initialised.

#### Returns

`google.maps.Map | null | undefined` — `null` while the map is initialising; the `Map` instance once ready; `undefined` if called outside a `GoogleMaps` provider.

#### Example

```typescript
const map = useMap()

useEffect(() => {
    if (map) {
        map.panTo({ lat: 22, lng: 114 })
    }
}, [map])
```

---

### `useWebGLOverlayView()`

Returns the current `IWebGLOverlayView` instance from the nearest `WebGLOverlayView` context, or `null` if the overlay has not yet been created.

#### Returns

`IWebGLOverlayView | null | undefined` — `null` while the overlay is being set up; the instance once ready; `undefined` if called outside a `WebGLOverlayView` provider.

#### Example

```typescript
const overlayView = useWebGLOverlayView()

useEffect(() => {
    if (overlayView) {
        const mesh = new Mesh(geometry, material)
        overlayView.scene.add(mesh)
        return () => overlayView.scene.remove(mesh)
    }
}, [overlayView])
```
