Skip to content

Overlay components

These items work with the catalog overlays a map composes: the energy set through profile="energy" and the treaties through overlays={["treaties"]}. The overlays themselves are documented under Overlays.

npx shadcn@latest registry add @unmap=https://registry.unmap.dev/r/{name}.json
npx shadcn@latest add @unmap/energy-map

The React line registers the registry once per project, so later items can be named @unmap/<item>; shadcn-vue has no registry add and takes the item URL directly. Files land in components/ui/ beside your own; nothing is overwritten without asking.

Browse every item on registry.unmap.dev
ItemWhat it is
energy-layer-controlThe energy overlay set as a layer-legend preset, for a map that already used profile="energy".
energy-map<Map> already composed with profile="energy" (muted by default). Map composition only, not a style.
well-searchSearch box labelled for UWIs. Sends the query string only; the gateway detects UWI vs civic.
legal-land-searchSearch box labelled for LSD. Same rule: query string only.
energy-popupIdentify wells, pipelines, and facilities on click. onLookup(at) fires as a click starts a lookup, then one of onIdentify(hit, at), onMiss(at) or onError(error, at) (Vue: @lookup, @identify, @miss, @error). Only the latest click answers: a lookup overtaken by a newer click gets none of the three.
treaty-contextHistoric and modern treaty switches, a coordinate lookup, and a details panel that lists every treaty record at a point, in English and French. Pair with overlays={["treaties"]}. onSelect (Vue: @select) receives each answer: the context, the record ids drawn under the point, and the hidden categories. onError (Vue: @error) receives a failed lookup and the point it was for.

Energy

energy-map is a map already composed with profile="energy" on muted cartography, and the other energy items work inside it: well-search finds a well by its UWI, energy-layer-control switches the overlays on and off, and energy-popup identifies what is under a click. A key without the energy add-on still gets the basemap; the overlay tiles and UWI search answer 403 addon_required. Every search and every click that identifies is one request. The layer control renders a bare fieldset, so the example floats it in your Card. See Energy profile.

"use client";
 
import { Card, CardContent } from "@/components/ui/card";
import { EnergyMap } from "@/components/ui/energy-map";
import { EnergyLayerControl } from "@/components/ui/energy-layer-control";
import { WellSearch } from "@/components/ui/well-search";
import { EnergyPopup } from "@/components/ui/energy-popup";
 
export function WellsMap() {
  const apiKey = process.env.NEXT_PUBLIC_UNMAP_KEY!;
  return (
    <div className="h-[560px]">
      <EnergyMap apiKey={apiKey} center={[-114.07, 51.05]} zoom={7}>
        <div className="absolute top-3 left-3 z-10 w-72">
          <WellSearch apiKey={apiKey} />
        </div>
        <Card className="absolute right-3 bottom-10 z-10 w-60">
          <CardContent>
            <EnergyLayerControl />
          </CardContent>
        </Card>
        <EnergyPopup apiKey={apiKey} onIdentify={(hit) => console.log(hit.uwi ?? hit.name)} />
      </EnergyMap>
    </div>
  );
}
<script setup lang="ts">
import type { IdentifyResult } from "@unmap/geocoding";
import { Card, CardContent } from "@/components/ui/card";
import { UnmapEnergyMap } from "@/components/ui/energy-map";
import { UnmapEnergyLayerControl } from "@/components/ui/energy-layer-control";
import { UnmapWellSearch } from "@/components/ui/well-search";
import { UnmapEnergyPopup } from "@/components/ui/energy-popup";
 
const apiKey = import.meta.env.VITE_UNMAP_KEY!;
function onIdentify(hit: IdentifyResult) {
  console.log(hit.uwi ?? hit.name);
}
</script>
 
<template>
  <div class="h-[560px]">
    <UnmapEnergyMap :api-key="apiKey" :center="[-114.07, 51.05]" :zoom="7">
      <div class="absolute top-3 left-3 z-10 w-72">
        <UnmapWellSearch :api-key="apiKey" />
      </div>
      <Card class="absolute right-3 bottom-10 z-10 w-60">
        <CardContent>
          <UnmapEnergyLayerControl />
        </CardContent>
      </Card>
      <UnmapEnergyPopup :api-key="apiKey" @identify="onIdentify" />
    </UnmapEnergyMap>
  </div>
</template>

legal-land-search is the LSD twin of well-search: the same search box, labelled for legal land descriptions such as NW-25-24-1-W5, and it sends the query string only. It works on any map; the search needs an add-on that includes legal land (Legal Land, Energy or Agriculture). See Legal land.

"use client";
 
import { Map } from "@/components/ui/map";
import { LegalLandSearch } from "@/components/ui/legal-land-search";
 
export function LandFinder() {
  const apiKey = process.env.NEXT_PUBLIC_UNMAP_KEY!;
  return (
    <div className="h-[480px]">
      <Map apiKey={apiKey} style="muted" center={[-113.49, 53.55]} zoom={8}>
        <div className="absolute top-3 left-3 z-10 w-72">
          <LegalLandSearch apiKey={apiKey} onSelect={(result) => console.log(result.name)} />
        </div>
      </Map>
    </div>
  );
}
<script setup lang="ts">
import type { GeocodeResult } from "@unmap/geocoding";
import { UnmapMap } from "@/components/ui/map";
import { UnmapLegalLandSearch } from "@/components/ui/legal-land-search";
 
const apiKey = import.meta.env.VITE_UNMAP_KEY!;
function onSelect(result: GeocodeResult) {
  console.log(result.name);
}
</script>
 
<template>
  <div class="h-[480px]">
    <UnmapMap :api-key="apiKey" map-style="muted" :center="[-113.49, 53.55]" :zoom="8">
      <div class="absolute top-3 left-3 z-10 w-72">
        <UnmapLegalLandSearch :api-key="apiKey" @select="onSelect" />
      </div>
    </UnmapMap>
  </div>
</template>

Treaties

treaty-context pairs with overlays={["treaties"]}: switches for historic and modern treaties, a coordinate lookup, and a panel that lists every treaty record at a point, in English and French. Each lookup, from a click on the map, typed coordinates or the point prop, is one request. The treaties overlay is core, with no add-on. See Treaty overlay.

"use client";
 
import { Card, CardContent } from "@/components/ui/card";
import { Map } from "@/components/ui/map";
import { TreatyContext } from "@/components/ui/treaty-context";
 
export function TreatyMap() {
  const apiKey = process.env.NEXT_PUBLIC_UNMAP_KEY!;
  return (
    <div className="h-[560px]">
      <Map apiKey={apiKey} style="muted" center={[-106.67, 52.13]} zoom={5} overlays={["treaties"]}>
        <Card className="absolute top-3 left-3 z-10 max-h-[calc(100%-1.5rem)] w-80 overflow-y-auto">
          <CardContent>
            <TreatyContext apiKey={apiKey} onSelect={({ context }) => console.log(context.matches.map((match) => match.name))} />
          </CardContent>
        </Card>
      </Map>
    </div>
  );
}
<script setup lang="ts">
import type { TreatySelection } from "@unmap/geocoding";
import { Card, CardContent } from "@/components/ui/card";
import { UnmapMap } from "@/components/ui/map";
import { UnmapTreatyContext } from "@/components/ui/treaty-context";
 
const apiKey = import.meta.env.VITE_UNMAP_KEY!;
function onSelect({ context }: TreatySelection) {
  console.log(context.matches.map((match) => match.name));
}
</script>
 
<template>
  <div class="h-[560px]">
    <UnmapMap :api-key="apiKey" map-style="muted" :center="[-106.67, 52.13]" :zoom="5" :overlays="['treaties']">
      <Card class="absolute top-3 left-3 z-10 max-h-[calc(100%-1.5rem)] w-80 overflow-y-auto">
        <CardContent>
          <UnmapTreatyContext :api-key="apiKey" @select="onSelect" />
        </CardContent>
      </Card>
    </UnmapMap>
  </div>
</template>