{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "delivery-tracking-map",
  "title": "Delivery Tracking Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/delivery-tracking-map/delivery-tracking-map.component.ts",
      "content": "// Live order delivery route on a Mapbox map: courier location, dropoff destination and\n// the merchant origin with a real-time ETA countdown side panel. Port of the React block\n// 1:1; markers follow the last-mile-courier-dispatch Angular pattern.\nimport {\n  type AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  type ElementRef,\n  Input,\n  type OnDestroy,\n  type QueryList,\n  ViewChildren,\n} from '@angular/core'\nimport type * as mapboxgl from 'mapbox-gl'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiMapComponent, type MapLayerInput, type MapSourceInput } from '@/ui/map/map.component'\n\nexport const DELIVERY_ORIGIN: [number, number] = [-122.4194, 37.7749]\nexport const DELIVERY_DESTINATION: [number, number] = [-122.392, 37.7915]\nexport const COURIER_POSITION: [number, number] = [-122.405, 37.783]\n\nexport const DELIVERY_ROUTE_COORDS: [number, number][] = [\n  [-122.4194, 37.7749],\n  [-122.414, 37.778],\n  [-122.405, 37.783],\n  [-122.399, 37.787],\n  [-122.392, 37.7915],\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-delivery-tracking-map, [ui-delivery-tracking-map]',\n  standalone: true,\n  host: {\n    '[attr.data-slot]': '\"delivery-tracking-map\"',\n    '[class]': 'hostClass',\n  },\n  imports: [\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiMapComponent,\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        <div\n          ui-map\n          variant=\"light\"\n          [accessToken]=\"accessToken ?? ''\"\n          [center]=\"courierPosition\"\n          [zoom]=\"13.5\"\n          class=\"h-full w-full\"\n          [sources]=\"routeSources\"\n          [layers]=\"routeLayers\"\n          (created)=\"onMapCreated($event)\"\n        >\n          <!-- Marker elements: handed to mapbox-gl Markers once the map exists, which moves each\n               inner #marker node onto the map; the outer node stays put for Angular's @for. -->\n          <div class=\"hidden\">\n            <div>\n              <!-- Restaurant / Merchant -->\n              <div #marker>\n                <div class=\"flex flex-col items-center\">\n                  <span class=\"bg-muted-foreground ring-muted size-3 rounded-full ring-4\"></span>\n                  <span class=\"border-border bg-background/90 mt-1 rounded border px-1.5 py-0.5 font-mono text-xs\"\n                    >Merchant</span\n                  >\n                </div>\n              </div>\n            </div>\n            <div>\n              <!-- Live Courier -->\n              <div #marker>\n                <div class=\"relative flex cursor-pointer items-center justify-center\" (click)=\"focusCourier()\">\n                  <span class=\"bg-primary/25 absolute size-7 animate-ping rounded-full\"></span>\n                  <div\n                    class=\"bg-primary text-primary-foreground ring-background flex size-7 items-center justify-center rounded-full shadow-md ring-2\"\n                  >\n                    🛵\n                  </div>\n                </div>\n              </div>\n            </div>\n            <div>\n              <!-- Destination -->\n              <div #marker>\n                <div class=\"flex cursor-pointer flex-col items-center\" (click)=\"focusDestination()\">\n                  <span class=\"bg-success ring-success/20 size-3 rounded-full ring-4\"></span>\n                  <span\n                    class=\"border-border bg-background/90 text-success mt-1 rounded border px-1.5 py-0.5 font-mono text-xs font-semibold\"\n                  >\n                    Delivery Dropoff\n                  </span>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Telemetry & Order Status -->\n      <div ui-card class=\"flex flex-col justify-between\">\n        <div ui-card-header>\n          <div class=\"flex items-center justify-between\">\n            <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">ORDER #8924</span>\n            <span ui-badge class=\"border-success/20 bg-success/10 text-success\">Approaching</span>\n          </div>\n          <h3 ui-card-title class=\"mt-2 text-lg\">Express Courier</h3>\n          <p ui-card-description>Estimated delivery in <strong class=\"text-foreground\">8 mins</strong> (0.8 mi away)</p>\n        </div>\n        <div ui-card-content class=\"space-y-4\">\n          <div class=\"border-border space-y-2 border-t pt-3\">\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground\">Driver</span>\n              <span class=\"text-foreground font-medium\">Carlos M. (★ 4.98)</span>\n            </div>\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground\">Vehicle</span>\n              <span class=\"text-foreground font-mono\">E-Scooter #412</span>\n            </div>\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground\">Destination</span>\n              <span class=\"text-foreground max-w-[170px] truncate font-medium\">Market St & 2nd Ave</span>\n            </div>\n          </div>\n\n          <div class=\"border-border space-y-1.5 border-t pt-3 font-mono text-xs\">\n            <div class=\"text-muted-foreground flex items-center gap-2\">\n              <span class=\"bg-success size-1.5 rounded-full\"></span>\n              <span>12:42 PM — Order picked up</span>\n            </div>\n            <div class=\"text-foreground flex items-center gap-2 font-medium\">\n              <span class=\"bg-primary size-1.5 rounded-full\"></span>\n              <span>12:51 PM — Approaching building</span>\n            </div>\n          </div>\n\n          <div class=\"flex gap-2 pt-2\">\n            <button ui-button variant=\"outline\" size=\"sm\" class=\"flex-1\" (click)=\"focusCourier()\">Track Courier</button>\n            <button ui-button variant=\"outline\" size=\"sm\" class=\"flex-1\" (click)=\"focusDestination()\">\n              Dropoff Point\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiDeliveryTrackingMapComponent implements AfterViewInit, OnDestroy {\n  @Input() accessToken?: string\n  @Input('class') className?: string\n\n  @ViewChildren('marker') private markerEls?: QueryList<ElementRef<HTMLDivElement>>\n\n  readonly origin: [number, number] = [...DELIVERY_ORIGIN] as [number, number]\n  readonly destination: [number, number] = [...DELIVERY_DESTINATION] as [number, number]\n  readonly courierPosition: [number, number] = [...COURIER_POSITION] as [number, number]\n\n  /** The delivery route polyline (the React block's MapSource). */\n  readonly routeSources: MapSourceInput[] = [\n    {\n      id: 'delivery-route',\n      type: 'geojson',\n      data: {\n        type: 'Feature',\n        properties: {},\n        geometry: { type: 'LineString', coordinates: DELIVERY_ROUTE_COORDS.map((c) => [...c]) },\n      },\n    },\n  ]\n\n  /** The blue route line (the React block's MapLayer). */\n  readonly routeLayers: MapLayerInput[] = [\n    {\n      id: 'delivery-route-line',\n      type: 'line',\n      source: 'delivery-route',\n      layout: { 'line-cap': 'round', 'line-join': 'round' },\n      paint: { 'line-color': '#2563eb', 'line-width': 4 },\n    },\n  ]\n\n  private map: mapboxgl.Map | null = null\n  private markers: mapboxgl.Marker[] = []\n  private destroyed = false\n\n  get hostClass(): string {\n    return cn('block w-full', this.className)\n  }\n\n  ngAfterViewInit(): void {\n    // A new marker list re-renders the marker elements; put the new set on the map.\n    this.markerEls?.changes.subscribe(() => void this.syncMarkers())\n  }\n\n  ngOnDestroy(): void {\n    this.destroyed = true\n    this.clearMarkers()\n    this.map = null\n  }\n\n  focusCourier(): void {\n    this.map?.flyTo?.({ center: this.courierPosition, zoom: 14.5 })\n  }\n\n  focusDestination(): void {\n    this.map?.flyTo?.({ center: this.destination, zoom: 15 })\n  }\n\n  onMapCreated(map: mapboxgl.Map): void {\n    this.map = map\n    void this.syncMarkers()\n  }\n\n  /** One mapbox-gl Marker per waypoint: merchant and dropoff anchored at the bottom\n      (the React MapMarkers), the courier centred (React anchor=\"center\"). */\n  private async syncMarkers(): Promise<void> {\n    const map = this.map\n    const els = this.markerEls?.toArray() ?? []\n    if (!map) return\n    const mod = await import('mapbox-gl')\n    const mapbox = mod.default ?? mod\n    if (this.destroyed || map !== this.map) return\n    this.clearMarkers()\n    const waypoints: { coords: [number, number]; anchor: 'bottom' | 'center' }[] = [\n      { coords: this.origin, anchor: 'bottom' },\n      { coords: this.courierPosition, anchor: 'center' },\n      { coords: this.destination, anchor: 'bottom' },\n    ]\n    this.markers = els.flatMap((el, i) => {\n      const waypoint = waypoints[i]\n      if (!waypoint) return []\n      return [\n        new mapbox.Marker({ element: el.nativeElement, anchor: waypoint.anchor }).setLngLat(waypoint.coords).addTo(map),\n      ]\n    })\n  }\n\n  private clearMarkers(): void {\n    for (const m of this.markers) m.remove()\n    this.markers = []\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/delivery-tracking-map/delivery-tracking-map.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/delivery-tracking-map/index.ts",
      "content": "export {\n  UiDeliveryTrackingMapComponent,\n  DELIVERY_ORIGIN,\n  DELIVERY_DESTINATION,\n  COURIER_POSITION,\n  DELIVERY_ROUTE_COORDS,\n} from './delivery-tracking-map.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/delivery-tracking-map/index.ts"
    }
  ],
  "dependencies": [
    "mapbox-gl"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/map.json"
  ],
  "description": "Live order delivery route showing courier location, dropoff destination, and real-time ETA countdown.",
  "categories": [
    "logistics",
    "delivery",
    "map"
  ]
}