{"id":23152456,"url":"https://github.com/1amageek/mapkit","last_synced_at":"2025-04-04T15:40:38.544Z","repository":{"id":240777675,"uuid":"768521878","full_name":"1amageek/mapkit","owner":"1amageek","description":"A React wrapper for Apple's MapKit JS, providing a seamless way to integrate Apple Maps into your React applications.","archived":false,"fork":false,"pushed_at":"2025-02-26T05:45:19.000Z","size":168,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-26T06:27:54.247Z","etag":null,"topics":["applemaps","mapkit","mapkit-js"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/1amageek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-07T08:38:04.000Z","updated_at":"2025-02-26T05:45:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"cf7cc3aa-5b86-4e47-8867-89252b52c3e3","html_url":"https://github.com/1amageek/mapkit","commit_stats":null,"previous_names":["1amageek/mapkit"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1amageek%2Fmapkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1amageek%2Fmapkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1amageek%2Fmapkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1amageek%2Fmapkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/1amageek","download_url":"https://codeload.github.com/1amageek/mapkit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247207006,"owners_count":20901555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["applemaps","mapkit","mapkit-js"],"created_at":"2024-12-17T19:14:47.400Z","updated_at":"2025-04-04T15:40:38.514Z","avatar_url":"https://github.com/1amageek.png","language":"TypeScript","readme":"# @1amageek/mapkit\n\nA React wrapper for Apple's MapKit JS, providing a seamless way to integrate Apple Maps into your React applications.\n\n## Features\n\n- 🗺️ Full TypeScript support\n- 🔄 React component lifecycle integration\n- 📍 Support for markers, custom annotations, and overlays\n- 🎨 Customizable map styling and controls\n- 🔒 Automatic token management and refresh\n- 🎯 Built-in error handling\n- 💫 Smooth animations and transitions\n- 🖱️ Comprehensive event handling for map interactions, annotations, and user location\n\n## Installation\n\n```bash\nnpm install @1amageek/mapkit\n```\n\n## Prerequisites\n\nYou'll need:\n1. An Apple Developer account\n2. A Maps ID from the Apple Developer portal\n3. A token generation endpoint in your backend\n\n## Basic Usage\n\nFirst, wrap your application with the `MapKitProvider`:\n\n```tsx\nimport { MapKitProvider } from '@1amageek/mapkit';\n\nconst App = () =\u003e {\n  const fetchToken = async () =\u003e {\n    // Fetch your MapKit JS token from your server\n    const response = await fetch('your-token-endpoint');\n    const data = await response.json();\n    return {\n      token: data.token,\n      expiresAt: data.expiresAt // Unix timestamp in seconds\n    };\n  };\n\n  return (\n    \u003cMapKitProvider \n      fetchToken={fetchToken}\n      options={{\n        language: 'en'\n      }}\n    \u003e\n      \u003cYourApp /\u003e\n    \u003c/MapKitProvider\u003e\n  );\n};\n```\n\nThen use the Map component:\n\n```tsx\nimport { Map, MarkerAnnotation } from '@1amageek/mapkit';\n```\n\n## Event Handling\n\nThe library supports a wide range of events for the map, annotations, and user location:\n\n### Map Events\nThe `Map` component emits various events related to map display and interaction:\n- `onRegionChangeStart`: Triggered when the map region starts changing.\n- `onRegionChangeEnd`: Triggered when the map region finishes changing.\n- `onRotationStart`: Triggered when the map starts rotating.\n- `onRotationEnd`: Triggered when the map finishes rotating.\n- `onScrollStart`: Triggered when the map starts scrolling.\n- `onScrollEnd`: Triggered when the map finishes scrolling.\n- `onZoomStart`: Triggered when the map starts zooming.\n- `onZoomEnd`: Triggered when the map finishes zooming.\n- `onMapTypeChange`: Triggered when the map type changes (e.g., from satellite to standard).\n- `onSingleTap`: Triggered when the map is tapped once.\n- `onDoubleTap`: Triggered when the map is double-tapped.\n- `onLongPress`: Triggered when the map is long-pressed.\n\n### Annotation Events\n\n- `onSelect`: Triggered when an annotation is selected\n- `onDeselect`: Triggered when an annotation is deselected\n- `onDrag`: Triggered while an annotation is being dragged, providing real-time updates.\n- `onDragStart`: Triggered when starting to drag an annotation\n- `onDragEnd`: Triggered when finishing dragging an annotation\n\n### User Location Events\n- `onUserLocationChange`: Triggered when the user's location changes. Provides the new coordinate and timestamp.\n- `onUserLocationError`: Triggered when an error occurs while trying to retrieve the user's location.\n\nExample usage with events:\n\n```tsx\nimport { Map, MarkerAnnotation } from '@1amageek/mapkit';\n\nconst MapComponent = () =\u003e {\n\n  return (\n    \u003cMap\n      id=\"my-map\"\n      options={{\n        showsUserLocation: true,\n        showsCompass: \"Adaptive\",\n      }}\n      onRegionChangeStart={(event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e {\n        console.log(\"Region change start\", event);\n      }}\n      onRegionChangeEnd={(event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e {\n        console.log(\"Region change end\", event);\n      }}\n      region={{\n        center: {\n          latitude: 35.6812,\n          longitude: 139.7671\n        },\n        span: {\n          latitudeDelta: 0.1,\n          longitudeDelta: 0.1\n        }\n      }}\n    \u003e\n      \u003cMarkerAnnotation\n        coordinate={{\n          latitude: 35.6812,\n          longitude: 139.7671\n        }}\n        title=\"Tokyo Tower\"\n        subtitle=\"Tourist Attraction\"\n      /\u003e\n    \u003c/Map\u003e\n  );\n};\n```\n\n## Event Types\n\n```typescript\ninterface AnnotationEventHandlers {\n  onSelect?: (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void;\n  onDeselect?: (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void;\n  onDrag?: (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void;\n  onDragStart?: (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void;\n  onDragEnd?: (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void;\n}\n```\n\n## Usage Examples\n\n### Basic Marker Annotation with Events\n\n```tsx\n\u003cMap\u003e\n  \u003cMarkerAnnotation\n    coordinate={{\n      latitude: 35.6812,\n      longitude: 139.7671\n    }}\n    title=\"Tokyo Tower\"\n    subtitle=\"Tourist Attraction\"\n    draggable={true}\n    onSelect={(event) =\u003e {\n      // Event when user clicks/taps the annotation\n      const annotation = event.target;\n      console.log('Selected:', annotation.title);\n      console.log('At coordinate:', annotation.coordinate);\n    }}\n    onDrag={(event) =\u003e {\n      // Real-time coordinate updates during drag\n      console.log('Current position:', event.coordinate);\n    }}\n    onDragEnd={(event) =\u003e {\n      // Final location after drag ends\n      const { latitude, longitude } = event.coordinate;\n      console.log('Final position:', { latitude, longitude });\n    }}\n  /\u003e\n\u003c/Map\u003e\n```\n\n### Custom Annotation with Complex Interaction\n\n```tsx\n\u003cMap\u003e\n  \u003cCustomAnnotation\n    coordinate={{\n      latitude: 35.6812,\n      longitude: 139.7671\n    }}\n    draggable={true}\n    onSelect={(event) =\u003e {\n      // Access to DOM event and screen coordinates\n      console.log('Click position:', event.pointOnPage);\n      console.log('DOM event:', event.domEvent);\n    }}\n    callout={{\n      calloutContentForAnnotation: (annotation) =\u003e (\n        \u003cdiv className=\"custom-callout\"\u003e\n          \u003ch3\u003e{annotation.title}\u003c/h3\u003e\n          \u003cbutton onClick={() =\u003e handleCalloutAction(annotation)}\u003e\n            Details\n          \u003c/button\u003e\n        \u003c/div\u003e\n      )\n    }}\n  \u003e\n    \u003cdiv className=\"custom-marker\"\u003e\n      {/* Your custom marker content */}\n    \u003c/div\u003e\n  \u003c/CustomAnnotation\u003e\n\u003c/Map\u003e\n```\n\n### Multiple Annotations with Shared Event Handler\n\n```tsx\nconst MapWithAnnotations = () =\u003e {\n  const handleAnnotationSelect = (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e {\n    // Common handler for all annotations\n    const { title, data } = event.target;\n    console.log('Selected location:', title);\n    console.log('Custom data:', data);\n  };\n\n  return (\n    \u003cMap\u003e\n      {locations.map((location) =\u003e (\n        \u003cMarkerAnnotation\n          key={location.id}\n          coordinate={location.coordinate}\n          title={location.name}\n          data={location.customData}\n          onSelect={handleAnnotationSelect}\n        /\u003e\n      ))}\n    \u003c/Map\u003e\n  );\n};\n```\n\n### Image Annotation with Clustering\n\n```tsx\n\u003cMap\u003e\n  \u003cImageAnnotation\n    coordinate={{\n      latitude: 35.6812,\n      longitude: 139.7671\n    }}\n    url={{\n      1: \"path/to/image.png\",\n      2: \"path/to/image@2x.png\",\n      3: \"path/to/image@3x.png\"\n    }}\n    clusteringIdentifier=\"landmarks\"\n    onSelect={(event) =\u003e {\n      if (event.target.memberAnnotations) {\n        // This is a cluster\n        console.log('Cluster size:', event.target.memberAnnotations.length);\n      } else {\n        // Single annotation\n        console.log('Selected image annotation');\n      }\n    }}\n  /\u003e\n\u003c/Map\u003e\n```\n\nThese event handlers are available for all annotation types (`MarkerAnnotation`, `ImageAnnotation`, `CustomAnnotation`).\n\n# Advanced Features\n\n### Custom Annotations\n\nCreate custom annotations with your own React components:\n\n```tsx\nimport { CustomAnnotation } from '@1amageek/mapkit';\n\nconst CustomPin = () =\u003e (\n  \u003cCustomAnnotation\n    coordinate={{\n      latitude: 35.6812,\n      longitude: 139.7671\n    }}\n  \u003e\n    \u003cdiv className=\"custom-pin\"\u003e\n      \u003cimg src=\"pin-icon.png\" alt=\"Custom Pin\" /\u003e\n    \u003c/div\u003e\n  \u003c/CustomAnnotation\u003e\n);\n```\n\n### Overlays\n\nAdd various types of overlays to your map:\n\n```tsx\nimport { CircleOverlay, PolylineOverlay, PolygonOverlay } from '@1amageek/mapkit';\n\nconst MapWithOverlays = () =\u003e (\n  \u003cMap\u003e\n    \u003cCircleOverlay\n      coordinate={{ latitude: 35.6812, longitude: 139.7671 }}\n      radius={1000}\n      options={{\n        strokeColor: \"#FF0000\",\n        lineWidth: 2,\n        fillColor: \"#FF000033\"\n      }}\n    /\u003e\n    \u003cPolylineOverlay\n      points={[\n        { latitude: 35.6812, longitude: 139.7671 },\n        { latitude: 35.6813, longitude: 139.7672 }\n      ]}\n      options={{\n        strokeColor: \"#0000FF\",\n        lineWidth: 3\n      }}\n    /\u003e\n  \u003c/Map\u003e\n);\n```\n\n### Error Handling\n\nThe library provides built-in error handling:\n\n```tsx\nconst MapComponent = () =\u003e (\n  \u003cMap\n    onMapError={(error) =\u003e {\n      console.error('Map error:', error);\n    }}\n    errorComponent={\u003cdiv\u003eFailed to load map\u003c/div\u003e}\n    loadingComponent={\u003cdiv\u003eLoading map...\u003c/div\u003e}\n  /\u003e\n);\n```\n\n## API Reference\n\n### MapKitProvider Props\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| fetchToken | () =\u003e Promise\u003cMapKitTokenResponse\u003e | Yes | Function to fetch MapKit JS token |\n| options | MapKitInitOptions | No | Initialization options |\n| onError | (error: MapKitError) =\u003e void | No | Error handler |\n\n### Map Props\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| id | string | No | Map container ID |\n| options | mapkit.MapConstructorOptions | No | Map configuration options |\n| location | Coordinate | No | Center Coordinate |\n| region | Region | No | Map region with center and span |\n| onMapError | (error: Error \\| MapKitError) =\u003e void | No | Error handler |\n| onAppear | (map: mapkit.Map) =\u003e void | No | Called when map is ready |\n| onChange | (map: mapkit.Map, newAnnotations: mapkit.Annotation[]) =\u003e void | No | Called when annotations/overlays change |\n| className | string | No | Additional CSS classes |\n| loadingComponent | ReactNode | No | Custom loading component |\n| errorComponent | ReactNode | No | Custom error component |\n| onRegionChangeStart | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map region starts changing. |\n| onRegionChangeEnd | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map region finishes changing. |\n| onRotationStart | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map starts rotating. |\n| onRotationEnd | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map finishes rotating. |\n| onScrollStart | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map starts scrolling. |\n| onScrollEnd | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map finishes scrolling. |\n| onZoomStart | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map starts zooming. |\n| onZoomEnd | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map finishes zooming. |\n| onMapTypeChange | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map type changes. |\n| onUserLocationChange | (event: mapkit.EventBase\u003cmapkit.Map\u003e \u0026 { coordinate: mapkit.Coordinate; timestamp: Date }) =\u003e void | No | Triggered when the user's location changes. |\n| onUserLocationError | (event: mapkit.EventBase\u003cmapkit.Map\u003e \u0026 { code: number; message: string }) =\u003e void | No | Triggered when an error occurs while trying to retrieve the user's location. |\n| onSingleTap | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map is tapped once. |\n| onDoubleTap | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map is double-tapped. |\n| onLongPress | (event: mapkit.EventBase\u003cmapkit.Map\u003e) =\u003e void | No | Triggered when the map is long-pressed. |\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.","funding_links":[],"categories":["UI Components"],"sub_categories":["Map"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1amageek%2Fmapkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F1amageek%2Fmapkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1amageek%2Fmapkit/lists"}