{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "leaflet-sales-territory-map",
  "title": "Leaflet Sales Territory Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/leaflet-sales-territory-map/LeafletSalesTerritoryMap.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { LeafletMap, LeafletMarker, LeafletPolygon, type LeafletMapRef } from '@/components/ui/leaflet-map'\n\nexport type TerritoryStatus = 'attained' | 'ontrack' | 'attention'\n\nexport interface SalesTerritory {\n  id: string\n  name: string\n  code: string\n  rep: string\n  arr: string\n  attainment: number\n  status: TerritoryStatus\n  /** Territory centroid as [lng, lat]. */\n  centerLngLat: [number, number]\n  /** Territory boundary ring as [lng, lat][]. */\n  polygon: [number, number][]\n}\n\n// Hand-drawn plausible US region boundaries — four rep territories tiling CONUS.\nexport const DEFAULT_TERRITORIES: SalesTerritory[] = [\n  {\n    id: 'pacific-west',\n    name: 'Pacific West',\n    code: 'PAC',\n    rep: 'Sierra Delgado',\n    arr: '$2.8M',\n    attainment: 112,\n    status: 'attained',\n    centerLngLat: [-119.8, 39.5],\n    polygon: [\n      [-124.4, 32.5],\n      [-114.0, 32.5],\n      [-114.0, 35.0],\n      [-114.6, 39.0],\n      [-120.0, 42.0],\n      [-117.0, 45.9],\n      [-117.0, 49.0],\n      [-124.7, 48.4],\n      [-124.2, 40.0],\n      [-124.4, 32.5],\n    ],\n  },\n  {\n    id: 'mountain-central',\n    name: 'Mountain Central',\n    code: 'MTN',\n    rep: 'Colt Brannigan',\n    arr: '$2.2M',\n    attainment: 97,\n    status: 'ontrack',\n    centerLngLat: [-104.8, 39.9],\n    polygon: [\n      [-117.0, 49.0],\n      [-95.0, 49.0],\n      [-95.0, 43.5],\n      [-97.5, 40.0],\n      [-95.5, 36.5],\n      [-100.0, 34.5],\n      [-103.0, 32.0],\n      [-106.5, 31.8],\n      [-108.2, 31.3],\n      [-111.0, 31.3],\n      [-114.0, 32.5],\n      [-114.0, 35.0],\n      [-114.6, 39.0],\n      [-120.0, 42.0],\n      [-117.0, 45.9],\n      [-117.0, 49.0],\n    ],\n  },\n  {\n    id: 'southeast',\n    name: 'Southeast',\n    code: 'SE',\n    rep: 'Harper Quinn',\n    arr: '$1.9M',\n    attainment: 84,\n    status: 'attention',\n    centerLngLat: [-83.0, 33.5],\n    polygon: [\n      [-95.5, 36.5],\n      [-94.0, 33.0],\n      [-93.0, 30.0],\n      [-89.0, 29.0],\n      [-84.0, 29.9],\n      [-82.6, 28.0],\n      [-81.0, 25.8],\n      [-80.1, 25.1],\n      [-80.5, 26.8],\n      [-81.4, 30.4],\n      [-80.8, 32.2],\n      [-77.5, 34.0],\n      [-75.5, 35.5],\n      [-76.0, 36.9],\n      [-77.5, 39.0],\n      [-80.5, 40.8],\n      [-83.0, 39.5],\n      [-84.8, 38.0],\n      [-88.0, 37.0],\n      [-90.5, 36.0],\n      [-95.5, 36.5],\n    ],\n  },\n  {\n    id: 'northeast',\n    name: 'Northeast',\n    code: 'NE',\n    rep: 'Devon Whitaker',\n    arr: '$3.4M',\n    attainment: 121,\n    status: 'attained',\n    centerLngLat: [-74.5, 41.8],\n    polygon: [\n      [-95.0, 49.0],\n      [-95.0, 45.9],\n      [-92.5, 44.5],\n      [-89.5, 43.0],\n      [-87.0, 41.5],\n      [-83.5, 41.7],\n      [-79.8, 42.3],\n      [-76.8, 43.5],\n      [-74.0, 45.0],\n      [-71.0, 45.0],\n      [-70.0, 43.6],\n      [-70.9, 42.9],\n      [-74.0, 40.5],\n      [-75.0, 38.5],\n      [-77.5, 39.0],\n      [-80.5, 40.8],\n      [-83.0, 39.5],\n      [-84.8, 38.0],\n      [-88.0, 37.0],\n      [-90.5, 36.0],\n      [-95.5, 36.5],\n      [-97.5, 40.0],\n      [-95.0, 43.5],\n      [-95.0, 49.0],\n    ],\n  },\n]\n\n/** Plain-hex fills — Leaflet renders paths to SVG/canvas, so CSS vars do not resolve there. */\nexport const TERRITORY_STATUS_STYLES: Record<TerritoryStatus, { fill: string; stroke: string }> = {\n  attained: { fill: '#22c55e', stroke: '#4ade80' },\n  ontrack: { fill: '#38bdf8', stroke: '#7dd3fc' },\n  attention: { fill: '#f59e0b', stroke: '#fbbf24' },\n}\n\nexport interface LeafletSalesTerritoryMapProps extends React.HTMLAttributes<HTMLDivElement> {\n  territories?: SalesTerritory[]\n}\n\n// Geographic center of CONUS — stable reference so the map's center effect never re-fires.\nconst US_CENTER: [number, number] = [-98.5795, 39.8283]\n\nfunction statusVariant(status: TerritoryStatus) {\n  if (status === 'attained') return 'info' as const\n  if (status === 'ontrack') return 'secondary' as const\n  return 'warning' as const\n}\n\nexport function LeafletSalesTerritoryMap({\n  className,\n  territories = DEFAULT_TERRITORIES,\n  ...props\n}: LeafletSalesTerritoryMapProps) {\n  const [selectedId, setSelectedId] = React.useState(territories[0]?.id ?? '')\n  const mapRef = React.useRef<LeafletMapRef>(null)\n\n  const selectTerritory = (territory: SalesTerritory) => {\n    setSelectedId(territory.id)\n    mapRef.current?.flyTo?.({\n      center: territory.centerLngLat,\n      zoom: 5,\n      duration: 800,\n    })\n  }\n\n  return (\n    <div\n      data-slot=\"leaflet-sales-territory-map\"\n      className={cn('flex h-full min-h-0 flex-col gap-4', className)}\n      {...props}\n    >\n      <div className=\"flex flex-wrap items-center justify-between gap-3\">\n        <h2 className=\"text-foreground text-lg font-semibold tracking-tight\">Territories</h2>\n        <p className=\"text-muted-foreground text-xs\">{territories.length} regions</p>\n      </div>\n\n      <div className=\"grid min-h-0 flex-1 grid-cols-1 gap-4 lg:grid-cols-12\">\n        <Card className=\"border-border flex min-h-0 flex-col overflow-hidden shadow-xs lg:col-span-8\">\n          <div className=\"relative min-h-[360px] flex-1 overflow-hidden\">\n            <LeafletMap ref={mapRef} variant=\"dark\" center={US_CENTER} zoom={4} className=\"absolute inset-0 size-full\">\n              {territories.map((t) => (\n                <LeafletPolygon\n                  key={`boundary-${t.id}`}\n                  lngLatPath={t.polygon}\n                  color={TERRITORY_STATUS_STYLES[t.status].stroke}\n                  weight={selectedId === t.id ? 2.5 : 1.5}\n                  opacity={0.9}\n                  fill\n                  fillColor={TERRITORY_STATUS_STYLES[t.status].fill}\n                  fillOpacity={selectedId === t.id ? 0.3 : 0.14}\n                  onClick={() => selectTerritory(t)}\n                />\n              ))}\n              {territories.map((t) => (\n                <LeafletMarker key={t.id} lngLat={t.centerLngLat} anchor=\"center\">\n                  <button\n                    type=\"button\"\n                    className={\n                      selectedId === t.id\n                        ? 'border-primary bg-primary text-primary-foreground rounded-full border px-2 py-0.5 font-mono text-xs font-semibold shadow-xs'\n                        : 'border-border bg-card text-foreground rounded-full border px-2 py-0.5 font-mono text-xs font-semibold shadow-xs'\n                    }\n                    onClick={() => selectTerritory(t)}\n                  >\n                    {t.code} {t.attainment}%\n                  </button>\n                </LeafletMarker>\n              ))}\n            </LeafletMap>\n          </div>\n        </Card>\n\n        <Card className=\"border-border flex min-h-0 flex-col overflow-hidden shadow-xs lg:col-span-4\">\n          <CardHeader className=\"border-border border-b p-4\">\n            <CardTitle className=\"text-sm font-semibold\">Quota</CardTitle>\n          </CardHeader>\n          <CardContent className=\"divide-border min-h-0 flex-1 divide-y overflow-auto p-0\">\n            {territories.map((t) => (\n              <button\n                key={t.id}\n                type=\"button\"\n                className={cn(\n                  'hover:bg-accent/50 flex w-full items-center justify-between gap-3 px-4 py-3 text-left transition-colors',\n                  selectedId === t.id && 'bg-accent/60',\n                )}\n                onClick={() => selectTerritory(t)}\n              >\n                <div className=\"min-w-0\">\n                  <p className=\"text-foreground truncate text-sm font-medium\">\n                    {t.code} · {t.name}\n                  </p>\n                  <p className=\"text-muted-foreground truncate font-mono text-xs tabular-nums\">\n                    {t.rep} · {t.arr}\n                  </p>\n                </div>\n                <Badge variant={statusVariant(t.status)} className=\"shrink-0 text-xs tabular-nums\">\n                  {t.attainment}%\n                </Badge>\n              </button>\n            ))}\n          </CardContent>\n        </Card>\n      </div>\n    </div>\n  )\n}\n\nexport default LeafletSalesTerritoryMap\n",
      "type": "registry:block",
      "target": "~/components/blocks/LeafletSalesTerritoryMap.tsx"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/leaflet-map.json"
  ],
  "description": "Sales territory map on free OpenStreetMap/Esri tiles — no API key. Region boundary polygons and rep pins with quota attainment; select a territory to fly the camera.",
  "categories": [
    "analytics",
    "dashboard"
  ]
}