{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "leaflet-disaster-response-map",
  "title": "Leaflet Disaster Response Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/leaflet-disaster-response-map/LeafletDisasterResponseMap.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { LeafletMap, LeafletMarker, LeafletCircle, type LeafletMapRef } from '@/components/ui/leaflet-map'\n\nexport type FacilityType = 'Shelter' | 'Medical Staging' | 'Command Post'\nexport type FacilityStatus = 'Open' | 'Near Capacity' | 'Closed'\n\nexport interface Facility {\n  id: string\n  name: string\n  type: FacilityType\n  /** [lng, lat] — Mapbox order. */\n  coords: [number, number]\n  capacity: number\n  occupied: number\n  status: FacilityStatus\n}\n\nexport interface LeafletDisasterResponseMapProps extends React.HTMLAttributes<HTMLDivElement> {\n  facilities?: Facility[]\n}\n\n// Module-level constants: stable references keep LeafletMap's center effect\n// from re-firing setView on every render and cancelling flyTo animations.\nconst MAP_CENTER: [number, number] = [-122.2711, 37.8044]\n\n// Wildfire incident origin in the Oakland Hills + a secondary spot fire.\nconst INCIDENT: [number, number] = [-122.165, 37.845]\nconst SPOT_FIRE: [number, number] = [-122.145, 37.856]\n\n// Evacuation perimeter rings (meter radii): hard exclusion + warning zone.\nconst EVAC_RADIUS_M = 1800\nconst WARNING_RADIUS_M = 3600\n\nconst DEFAULT_FACILITIES: Facility[] = [\n  {\n    id: 's-1',\n    name: 'Oakland Civic Shelter',\n    type: 'Shelter',\n    coords: [-122.265, 37.795],\n    capacity: 500,\n    occupied: 340,\n    status: 'Open',\n  },\n  {\n    id: 's-2',\n    name: 'Eastmont Medical Staging',\n    type: 'Medical Staging',\n    coords: [-122.19, 37.77],\n    capacity: 120,\n    occupied: 98,\n    status: 'Near Capacity',\n  },\n  {\n    id: 's-3',\n    name: 'Unified Incident Command Post',\n    type: 'Command Post',\n    coords: [-122.225, 37.852],\n    capacity: 80,\n    occupied: 45,\n    status: 'Open',\n  },\n]\n\nexport function LeafletDisasterResponseMap({\n  className,\n  facilities = DEFAULT_FACILITIES,\n  ...props\n}: LeafletDisasterResponseMapProps) {\n  const [activeId, setActiveId] = React.useState(facilities[0]?.id ?? '')\n  const mapRef = React.useRef<LeafletMapRef>(null)\n  const activeFacility = facilities.find((f) => f.id === activeId) ?? facilities[0]\n\n  const focusFacility = (f: Facility) => {\n    setActiveId(f.id)\n    mapRef.current?.flyTo?.({ center: f.coords, zoom: 12.5, duration: 800 })\n  }\n\n  const focusHazard = () => {\n    mapRef.current?.flyTo?.({ center: INCIDENT, zoom: 12, duration: 800 })\n  }\n\n  return (\n    <div\n      data-slot=\"leaflet-disaster-response-map\"\n      className={cn('grid gap-4 lg:grid-cols-[1fr_320px]', className)}\n      {...props}\n    >\n      <div className=\"border-border bg-card relative h-[480px] overflow-hidden rounded-xl border\">\n        <LeafletMap ref={mapRef} variant=\"light\" center={MAP_CENTER} zoom={11} className=\"h-full w-full\">\n          {/* Evacuation perimeter rings (radii in meters) */}\n          <LeafletCircle\n            center={INCIDENT}\n            radius={EVAC_RADIUS_M}\n            color=\"#dc2626\"\n            weight={2}\n            opacity={0.9}\n            dashArray=\"6 4\"\n            fillColor=\"#ef4444\"\n            fillOpacity={0.15}\n            onClick={focusHazard}\n          />\n          <LeafletCircle\n            center={INCIDENT}\n            radius={WARNING_RADIUS_M}\n            color=\"#d97706\"\n            weight={1.5}\n            opacity={0.7}\n            dashArray=\"4 6\"\n            fillColor=\"#f59e0b\"\n            fillOpacity={0.05}\n          />\n\n          {/* Active fire origin */}\n          <LeafletMarker lngLat={INCIDENT} anchor=\"center\" onClick={focusHazard}>\n            <div className=\"relative flex cursor-pointer items-center justify-center\">\n              <span className=\"bg-destructive/30 absolute size-9 animate-ping rounded-full\" />\n              <div className=\"bg-destructive flex size-7 items-center justify-center rounded-full font-mono text-xs font-bold text-white shadow-lg ring-2 ring-white\">\n                🔥\n              </div>\n            </div>\n          </LeafletMarker>\n\n          {/* Secondary spot fire */}\n          <LeafletMarker lngLat={SPOT_FIRE} anchor=\"center\" onClick={focusHazard}>\n            <div className=\"relative flex cursor-pointer items-center justify-center\">\n              <span className=\"bg-warning/30 absolute size-6 animate-ping rounded-full\" />\n              <div className=\"bg-warning flex size-6 items-center justify-center rounded-full font-mono text-xs font-bold text-white shadow-md ring-2 ring-white\">\n                🔥\n              </div>\n            </div>\n          </LeafletMarker>\n\n          {/* Shelters and Medical Staging */}\n          {facilities.map((f) => (\n            <LeafletMarker key={f.id} lngLat={f.coords} anchor=\"bottom\" onClick={() => focusFacility(f)}>\n              <div className=\"group flex cursor-pointer flex-col items-center\">\n                <div\n                  className={cn(\n                    'flex size-7 items-center justify-center rounded-full shadow-md ring-2',\n                    f.type === 'Shelter'\n                      ? 'bg-success text-white ring-emerald-400/40'\n                      : f.type === 'Medical Staging'\n                        ? 'bg-info text-white ring-blue-400/40'\n                        : 'bg-primary text-primary-foreground ring-primary/40',\n                  )}\n                >\n                  {f.type === 'Shelter' ? '🏠' : f.type === 'Medical Staging' ? '✚' : '★'}\n                </div>\n                <span className=\"border-border bg-background/90 mt-1 rounded border px-1 py-0.5 font-mono text-xs font-bold whitespace-nowrap shadow-xs\">\n                  {f.name.split(' ')[0]}\n                </span>\n              </div>\n            </LeafletMarker>\n          ))}\n        </LeafletMap>\n      </div>\n\n      {/* Incident Control Dashboard */}\n      <Card className=\"flex flex-col justify-between\">\n        <CardHeader>\n          <div className=\"flex items-center justify-between\">\n            <Badge\n              variant=\"outline\"\n              className=\"border-destructive/30 bg-destructive/10 text-destructive font-mono text-xs\"\n            >\n              LEVEL 3 EVACUATION\n            </Badge>\n            <Badge className=\"border-success/20 bg-success/10 text-success\">{activeFacility.status}</Badge>\n          </div>\n          <CardTitle className=\"mt-2 text-lg\">{activeFacility.name}</CardTitle>\n          <CardDescription className=\"text-xs\">\n            Capacity: {activeFacility.occupied} / {activeFacility.capacity} beds occupied\n          </CardDescription>\n        </CardHeader>\n        <CardContent className=\"space-y-4\">\n          {/* Capacity Bar */}\n          <div className=\"border-border space-y-1.5 border-t pt-3\">\n            <div className=\"flex items-center justify-between font-mono text-xs\">\n              <span className=\"text-muted-foreground\">Occupancy Rate</span>\n              <span className=\"text-foreground font-bold\">\n                {Math.round((activeFacility.occupied / activeFacility.capacity) * 100)}%\n              </span>\n            </div>\n            <div className=\"bg-muted h-2 w-full overflow-hidden rounded-full\">\n              <div\n                className={cn(\n                  'h-full rounded-full transition-[width,background-color]',\n                  activeFacility.occupied / activeFacility.capacity > 0.8 ? 'bg-warning' : 'bg-success',\n                )}\n                style={{ width: `${(activeFacility.occupied / activeFacility.capacity) * 100}%` }}\n              />\n            </div>\n          </div>\n\n          <div className=\"border-border space-y-1 border-t pt-3\">\n            <div className=\"text-muted-foreground mb-1 font-mono text-xs tracking-wider uppercase\">\n              Staged Relief Sites\n            </div>\n            {facilities.map((f) => (\n              <button\n                key={f.id}\n                type=\"button\"\n                className={cn(\n                  'flex w-full items-center justify-between rounded-md px-2 py-1 text-xs transition-colors',\n                  activeId === f.id\n                    ? 'bg-accent text-accent-foreground font-semibold'\n                    : 'hover:bg-muted text-muted-foreground',\n                )}\n                onClick={() => focusFacility(f)}\n              >\n                <span className=\"max-w-[170px] truncate\">{f.name}</span>\n                <span className=\"font-mono text-xs opacity-75\">\n                  {f.occupied}/{f.capacity}\n                </span>\n              </button>\n            ))}\n          </div>\n\n          <div className=\"flex gap-2 pt-2\">\n            <Button variant=\"outline\" size=\"sm\" className=\"flex-1 font-mono text-xs\" onClick={focusHazard}>\n              Exclusion Zone\n            </Button>\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              className=\"flex-1 font-mono text-xs\"\n              onClick={() => focusFacility(activeFacility)}\n            >\n              Focus Site\n            </Button>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n  )\n}\n\nexport default LeafletDisasterResponseMap\n",
      "type": "registry:block",
      "target": "~/components/blocks/LeafletDisasterResponseMap.tsx"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/leaflet-map.json"
  ],
  "description": "Incident management map on free OpenStreetMap/Esri tiles — no API key. Evacuation perimeter rings, shelter capacities, and emergency staging points.",
  "categories": [
    "logistics",
    "emergency",
    "map"
  ]
}