{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "property-boundary-map",
  "title": "Property Boundary Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/property-boundary-map/PropertyBoundaryMap.vue",
      "content": "<script setup lang=\"ts\">\nimport { nextTick, ref } from 'vue'\nimport { Map, MapMarker, MapSource, MapLayer, type MapRef } from '@/components/ui/map'\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\n\ndefineProps<{ accessToken?: string }>()\n\ninterface Parcel {\n  apn: string\n  address: string\n  zoning: string\n  lotSqFt: string\n  acres: number\n  assessedValue: string\n  taxYear: number\n  coords: [number, number]\n  polygon: [number, number][]\n}\n\nconst mapRef = ref<MapRef | null>(null)\n\nconst parcels: Parcel[] = [\n  {\n    apn: '0482-104-012',\n    address: '450 Mountain View Rd, Austin, TX',\n    zoning: 'SF-3 (Single Family)',\n    lotSqFt: '14,280 sq ft',\n    acres: 0.33,\n    assessedValue: '$1,280,000',\n    taxYear: 2025,\n    coords: [-97.7431, 30.2672],\n    polygon: [\n      [-97.7438, 30.2678],\n      [-97.7424, 30.2678],\n      [-97.7424, 30.2666],\n      [-97.7438, 30.2666],\n      [-97.7438, 30.2678],\n    ],\n  },\n  {\n    apn: '0482-104-013',\n    address: '460 Mountain View Rd, Austin, TX',\n    zoning: 'SF-3 (Single Family)',\n    lotSqFt: '16,500 sq ft',\n    acres: 0.38,\n    assessedValue: '$1,410,000',\n    taxYear: 2025,\n    coords: [-97.741, 30.2672],\n    polygon: [\n      [-97.7424, 30.2678],\n      [-97.741, 30.2678],\n      [-97.741, 30.2666],\n      [-97.7424, 30.2666],\n      [-97.7424, 30.2678],\n    ],\n  },\n]\n\nconst activeParcel = ref<Parcel>(parcels[0])\n\nasync function selectParcel(p: Parcel) {\n  activeParcel.value = p\n  // `:center` is reactive, so Vue re-applies it on the next tick and would\n  // otherwise cancel this flight and strand the camera at the default zoom.\n  await nextTick()\n  mapRef.value?.flyTo({ center: p.coords, zoom: 17 })\n}\n</script>\n\n<template>\n  <div class=\"grid gap-4 lg:grid-cols-[1fr_320px]\">\n    <div class=\"border-border bg-card relative h-[480px] overflow-hidden rounded-xl border\">\n      <Map\n        ref=\"mapRef\"\n        :access-token=\"accessToken\"\n        variant=\"satellite-streets\"\n        :center=\"activeParcel.coords\"\n        :zoom=\"16.5\"\n        class=\"h-full w-full\"\n      >\n        <!-- Parcel Boundary Polygons -->\n        <MapSource\n          id=\"parcel-primary\"\n          :options=\"{\n            type: 'geojson',\n            data: {\n              type: 'Feature',\n              properties: {},\n              geometry: { type: 'Polygon', coordinates: [activeParcel.polygon] },\n            },\n          }\"\n        />\n        <MapLayer\n          id=\"parcel-primary-fill\"\n          :options=\"{\n            type: 'fill',\n            source: 'parcel-primary',\n            paint: { 'fill-color': '#eab308', 'fill-opacity': 0.28 },\n          }\"\n        />\n        <MapLayer\n          id=\"parcel-primary-line\"\n          :options=\"{\n            type: 'line',\n            source: 'parcel-primary',\n            paint: { 'line-color': '#facc15', 'line-width': 2.5 },\n          }\"\n        />\n\n        <MapMarker v-for=\"p in parcels\" :key=\"p.apn\" :lng-lat=\"p.coords\" anchor=\"center\" @click=\"selectParcel(p)\">\n          <div class=\"group flex cursor-pointer flex-col items-center\">\n            <span\n              class=\"border-border bg-background/90 rounded border px-1.5 py-0.5 font-mono text-xs font-bold shadow-md\"\n              :class=\"activeParcel.apn === p.apn ? 'border-warning text-warning' : 'text-foreground'\"\n            >\n              {{ p.apn }}\n            </span>\n          </div>\n        </MapMarker>\n      </Map>\n    </div>\n\n    <!-- Cadastral Parcel Valuation Card -->\n    <Card class=\"flex flex-col justify-between\">\n      <CardHeader>\n        <div class=\"flex items-center justify-between\">\n          <Badge variant=\"outline\" class=\"font-mono text-xs\">APN {{ activeParcel.apn }}</Badge>\n          <Badge class=\"border-warning/20 bg-warning/10 text-warning\">{{ activeParcel.zoning }}</Badge>\n        </div>\n        <CardTitle class=\"mt-2 text-base font-medium\">{{ activeParcel.address }}</CardTitle>\n        <CardDescription class=\"font-mono text-xs\"\n          >{{ activeParcel.lotSqFt }} • {{ activeParcel.acres }} Acres</CardDescription\n        >\n      </CardHeader>\n      <CardContent class=\"space-y-4\">\n        <div class=\"border-border space-y-2 border-t pt-3 font-mono text-xs\">\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground\">Assessed Valuation</span>\n            <span class=\"text-foreground text-base font-bold\">{{ activeParcel.assessedValue }}</span>\n          </div>\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground\">Zoning Code</span>\n            <span class=\"text-foreground\">{{ activeParcel.zoning }}</span>\n          </div>\n          <div class=\"flex items-center justify-between\">\n            <span class=\"text-muted-foreground\">Assessment Roll Year</span>\n            <span class=\"text-foreground\">{{ activeParcel.taxYear }}</span>\n          </div>\n        </div>\n\n        <div class=\"border-border space-y-1 border-t pt-3\">\n          <div class=\"text-muted-foreground mb-1 font-mono text-xs tracking-wider uppercase\">\n            Adjacent Cadastral Lots\n          </div>\n          <button\n            v-for=\"p in parcels\"\n            :key=\"p.apn\"\n            type=\"button\"\n            class=\"flex w-full items-center justify-between rounded-md px-2 py-1 text-xs transition-colors\"\n            :class=\"\n              activeParcel.apn === p.apn\n                ? 'bg-accent text-accent-foreground font-semibold'\n                : 'hover:bg-muted text-muted-foreground'\n            \"\n            @click=\"selectParcel(p)\"\n          >\n            <span class=\"font-mono\">{{ p.apn }}</span>\n            <span class=\"font-mono text-xs opacity-75\">{{ p.lotSqFt }}</span>\n          </button>\n        </div>\n\n        <Button variant=\"outline\" size=\"sm\" class=\"w-full font-mono text-xs\" @click=\"selectParcel(activeParcel)\">\n          Center Cadastral Lot\n        </Button>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/PropertyBoundaryMap.vue"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/map.json"
  ],
  "description": "Cadastral parcel boundaries with zoning classifications, lot acreage, and tax assessment valuation.",
  "categories": [
    "real-estate",
    "places",
    "map"
  ]
}