{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "leaflet-store-locator-map",
  "title": "Leaflet Store Locator Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/leaflet-store-locator-map/LeafletStoreLocatorMap.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, LeafletPopup, type LeafletMapRef } from '@/components/ui/leaflet-map'\n\nexport interface RetailStore {\n  id: string\n  name: string\n  address: string\n  neighborhood: string\n  lat: number\n  lng: number\n  distanceMiles: number\n  hours: string\n  isOpen: boolean\n  amenities: string[]\n}\n\nexport interface LeafletStoreLocatorMapProps extends React.HTMLAttributes<HTMLDivElement> {\n  stores?: RetailStore[]\n}\n\nconst DEFAULT_STORES: RetailStore[] = [\n  {\n    id: 'nyc-herald',\n    name: 'Herald Square',\n    address: '151 W 34th St',\n    neighborhood: 'Midtown',\n    lat: 40.7484,\n    lng: -73.9879,\n    distanceMiles: 0.3,\n    hours: 'Open until 10 PM',\n    isOpen: true,\n    amenities: ['Pickup', 'Returns', 'Cafe'],\n  },\n  {\n    id: 'nyc-chelsea',\n    name: 'Chelsea Market',\n    address: '75 9th Ave',\n    neighborhood: 'Chelsea',\n    lat: 40.7424,\n    lng: -74.0061,\n    distanceMiles: 0.9,\n    hours: 'Open until 9 PM',\n    isOpen: true,\n    amenities: ['Parking', 'Cafe'],\n  },\n  {\n    id: 'nyc-soho',\n    name: 'SoHo Flagship',\n    address: '112 Greene St',\n    neighborhood: 'SoHo',\n    lat: 40.7248,\n    lng: -73.9984,\n    distanceMiles: 1.6,\n    hours: 'Open until 9 PM',\n    isOpen: true,\n    amenities: ['Parking', 'Pickup', 'Returns'],\n  },\n  {\n    id: 'nyc-ues',\n    name: 'Lexington & 78th',\n    address: '1120 Lexington Ave',\n    neighborhood: 'Upper East Side',\n    lat: 40.7736,\n    lng: -73.9614,\n    distanceMiles: 1.8,\n    hours: 'Open until 8 PM',\n    isOpen: true,\n    amenities: ['Pickup', 'Returns'],\n  },\n  {\n    id: 'nyc-tribeca',\n    name: 'Tribeca',\n    address: '60 Hudson St',\n    neighborhood: 'Tribeca',\n    lat: 40.7175,\n    lng: -74.0089,\n    distanceMiles: 2.1,\n    hours: 'Closed · Opens 10 AM',\n    isOpen: false,\n    amenities: ['Parking', 'Returns'],\n  },\n]\n\nexport function LeafletStoreLocatorMap({ className, stores = DEFAULT_STORES, ...props }: LeafletStoreLocatorMapProps) {\n  const [selectedId, setSelectedId] = React.useState(stores[0]?.id ?? '')\n  const mapRef = React.useRef<LeafletMapRef>(null)\n\n  const selectStore = (store: RetailStore) => {\n    setSelectedId(store.id)\n    mapRef.current?.flyTo?.({\n      center: [store.lng, store.lat],\n      zoom: 14,\n      duration: 900,\n    })\n  }\n\n  return (\n    <div\n      data-slot=\"leaflet-store-locator-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\">Stores</h2>\n        <p className=\"text-muted-foreground text-xs\">\n          {stores.filter((s) => s.isOpen).length} open · {stores.length} locations\n        </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\n              ref={mapRef}\n              variant=\"streets\"\n              center={[-73.985, 40.748]}\n              zoom={13}\n              className=\"absolute inset-0 size-full\"\n            >\n              {stores.map((store) => (\n                <LeafletMarker key={store.id} lngLat={[store.lng, store.lat]} anchor=\"center\">\n                  <button\n                    type=\"button\"\n                    className={\n                      selectedId === store.id\n                        ? 'border-primary bg-primary text-primary-foreground rounded-full border px-2 py-0.5 text-xs font-semibold shadow-xs'\n                        : 'border-border bg-card text-foreground rounded-full border px-2 py-0.5 text-xs font-semibold shadow-xs'\n                    }\n                    onClick={() => selectStore(store)}\n                  >\n                    {store.name}\n                  </button>\n                  <LeafletPopup offset={[0, -18]} className=\"space-y-1 text-xs\">\n                    <p className=\"text-foreground font-semibold\">{store.name}</p>\n                    <p className=\"text-muted-foreground\">\n                      {store.address}, {store.neighborhood}\n                    </p>\n                    <p className=\"text-muted-foreground\">\n                      {store.hours} · {store.distanceMiles} mi away\n                    </p>\n                  </LeafletPopup>\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\">Locations</CardTitle>\n          </CardHeader>\n          <CardContent className=\"divide-border min-h-0 flex-1 divide-y overflow-auto p-0\">\n            {stores.map((store) => (\n              <button\n                key={store.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 === store.id && 'bg-accent/60',\n                )}\n                onClick={() => selectStore(store)}\n              >\n                <div className=\"min-w-0 space-y-1\">\n                  <p className=\"text-foreground truncate text-sm font-medium\">{store.name}</p>\n                  <p className=\"text-muted-foreground truncate text-xs\">\n                    {store.address}, {store.neighborhood} · {store.hours}\n                  </p>\n                  <div className=\"flex flex-wrap gap-1\">\n                    {store.amenities.map((amenity) => (\n                      <Badge key={amenity} variant=\"secondary\" className=\"text-xs\">\n                        {amenity}\n                      </Badge>\n                    ))}\n                  </div>\n                </div>\n                <div className=\"flex shrink-0 flex-col items-end gap-1\">\n                  <span className=\"text-muted-foreground font-mono text-xs tabular-nums\">{store.distanceMiles} mi</span>\n                  <Badge variant={store.isOpen ? 'info' : 'secondary'} className=\"text-xs\">\n                    {store.isOpen ? 'Open' : 'Closed'}\n                  </Badge>\n                </div>\n              </button>\n            ))}\n          </CardContent>\n        </Card>\n      </div>\n    </div>\n  )\n}\n\nexport default LeafletStoreLocatorMap\n",
      "type": "registry:block",
      "target": "~/components/blocks/LeafletStoreLocatorMap.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": "Store locator on free OpenStreetMap tiles — no API key. Pins with bound popups, distance/hours/amenities list, fly-to on select.",
  "categories": [
    "dashboard",
    "app",
    "ecommerce"
  ]
}