npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@quantaroute/checkout

v1.3.0

Published

Embeddable DigiPin-powered smart address checkout widget — React (web), React Native & Expo (iOS/Android)

Downloads

149

Readme

@quantaroute/checkout

DigiPin-powered smart address checkout widget for Indian e-commerce. Two-step: Map pin → Auto-filled form. One package. Three platforms: React web · iOS · Android.

Made in India DigiPin Map License


What it does

Replaces broken Indian address forms with a precise two-step pin-drop flow:

Step 1 – Map Pin                    Step 2 – Auto-fill + Details
┌──────────────────────────┐        ┌──────────────────────────┐
│  [DigiPin: 39J-438-TJC7] │        │  📍 Auto-detected         │
│                           │        │  State:    Delhi          │
│    🗺  OSM vector map     │  ──►  │  District: New Delhi     │
│         📍 ← drag         │        │  Pincode:  110011         │
│                           │        │  ✓ Deliverable            │
│  [⊕ Locate Me]            │        │  🏠 Add details           │
│  [Confirm Location →]     │        │  Flat No:  [_________]    │
└──────────────────────────┘        │  [← Adjust] [Save ✓]    │
                                     └──────────────────────────┘

Key features:

  • DigiPin shown offline in real-time as the user drags the pin (~4 m × 4 m precision)
  • No Google Maps. Free vector basemap — choose from Carto Positron or OpenFreeMap styles (no API key for either)
  • Auto-fills State, District, Locality, Pincode, Delivery status from QuantaRoute API
  • Manual fields: Flat no., Floor, Building (OSM pre-filled), Street/Area (OSM pre-filled)
  • Mobile-first (full-screen on phones, card on desktop/tablet)
  • Dark mode, reduced-motion, keyboard navigation, ARIA labels
  • TypeScript — zero runtime deps beyond peer dependencies

Platform support

| Platform | Bundler | Map engine | Install | |---|---|---|---| | React / Next.js / Vite / Nuxt | Webpack / Vite | MapLibre GL JS | maplibre-gl | | iOS (Expo / React Native) | Metro | expo-osm-sdk (MapLibre GL Native) | expo-osm-sdk expo-location | | Android (Expo / React Native) | Metro | expo-osm-sdk (MapLibre GL Native) | expo-osm-sdk expo-location |

Same import on all platforms. Metro automatically resolves .native.tsx files on mobile; Vite/Webpack use the web .tsx files.


Quick start

0 · Get an API key

  1. Sign up at developers.quantaroute.com
  2. Create a project → copy your API key

Never hard-code or commit API keys to git.


Web (React / Next.js / Vite / Nuxt)

Install

npm install @quantaroute/checkout maplibre-gl

Import CSS

// In your app entry file (main.tsx / _app.tsx / layout.tsx / nuxt.config.ts)
import 'maplibre-gl/dist/maplibre-gl.css';
import '@quantaroute/checkout/style.css';

Use

import { CheckoutWidget } from '@quantaroute/checkout';

export default function CheckoutPage() {
  return (
    <CheckoutWidget
      apiKey={process.env.NEXT_PUBLIC_QUANTAROUTE_KEY!}
      onComplete={(address) => {
        console.log(address.digipin);           // "39J-438-TJC7"
        console.log(address.pincode);           // "110011"
        console.log(address.formattedAddress);  // "Flat 4B, Floor 3rd, ..."
        // → send to your backend / payment gateway
      }}
    />
  );
}

Next.js (App Router)

// app/checkout/page.tsx
'use client';

import dynamic from 'next/dynamic';

const CheckoutWidget = dynamic(
  () => import('@quantaroute/checkout').then((m) => m.CheckoutWidget),
  { ssr: false }
);

export default function CheckoutPage() {
  return (
    <main className="max-w-lg mx-auto p-4">
      <CheckoutWidget
        apiKey={process.env.NEXT_PUBLIC_QUANTAROUTE_KEY!}
        onComplete={(addr) => console.log(addr)}
      />
    </main>
  );
}

CSS in app/layout.tsx:

import 'maplibre-gl/dist/maplibre-gl.css';
import '@quantaroute/checkout/style.css';

Next.js (Pages Router)

import dynamic from 'next/dynamic';
const CheckoutWidget = dynamic(() => import('@quantaroute/checkout'), { ssr: false });

export default function CheckoutPage() {
  return (
    <CheckoutWidget
      apiKey={process.env.NEXT_PUBLIC_QUANTAROUTE_KEY!}
      onComplete={(a) => console.log(a)}
    />
  );
}

Nuxt 3

// nuxt.config.ts
export default defineNuxtConfig({
  css: ['maplibre-gl/dist/maplibre-gl.css', '@quantaroute/checkout/style.css'],
});
<!-- components/AddressWidget.client.vue  (.client = browser-only) -->
<script setup lang="ts">
import { CheckoutWidget } from '@quantaroute/checkout';
const { public: { qrApiKey } } = useRuntimeConfig();
</script>
<template>
  <CheckoutWidget :api-key="qrApiKey" map-height="360px" @complete="console.log" />
</template>

Vite + React

import 'maplibre-gl/dist/maplibre-gl.css';
import '@quantaroute/checkout/style.css';
import { CheckoutWidget } from '@quantaroute/checkout';

function App() {
  return (
    <CheckoutWidget
      apiKey={import.meta.env.VITE_QR_API_KEY}
      onComplete={(addr) => console.log('Saved:', addr)}
    />
  );
}

Vanilla JS (UMD / script tag)

<link rel="stylesheet" href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" />
<link rel="stylesheet" href="https://unpkg.com/@quantaroute/checkout/dist/style.css" />

<div id="checkout-root"></div>

<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@quantaroute/checkout/dist/lib/quantaroute-checkout.umd.js"></script>
<script>
  ReactDOM.createRoot(document.getElementById('checkout-root')).render(
    React.createElement(QuantaRouteCheckout.CheckoutWidget, {
      apiKey: 'YOUR_KEY',
      onComplete: (addr) => console.log('Done:', addr),
    })
  );
</script>

Native (Expo / React Native — iOS & Android)

Requires a development build. This does NOT work in Expo Go — expo-osm-sdk uses native modules.

1 · Install

npm install @quantaroute/checkout expo-osm-sdk expo-location

2 · Add the config plugin to app.json

{
  "expo": {
    "plugins": [
      ["@quantaroute/checkout/plugin", {
        "locationPermissionText": "Allow access to your location to place the delivery pin on the map."
      }]
    ]
  }
}

This single plugin automatically configures:

| What | iOS | Android | |---|---|---| | MapLibre native SDK | expo-osm-sdk/plugin | expo-osm-sdk/plugin | | Location permission | NSLocationWhenInUseUsageDescription | ACCESS_FINE_LOCATION | | Internet permission | – | INTERNET |

3 · Rebuild your dev client

npx expo run:ios
# or
npx expo run:android

4 · Use — identical import as web

import { CheckoutWidget } from '@quantaroute/checkout';
// No CSS import — styles are React Native StyleSheet objects

export default function CheckoutScreen() {
  return (
    <CheckoutWidget
      apiKey={process.env.EXPO_PUBLIC_QUANTAROUTE_KEY!}
      mapHeight={380}
      onComplete={(address) => {
        console.log(address.digipin);           // "39J-438-TJC7"
        console.log(address.formattedAddress);  // "Flat 4B, ..."
      }}
    />
  );
}

Demo native app

A working Expo demo is in demo-native/:

cd demo-native
npm install
# Set your API key in .env:  EXPO_PUBLIC_QUANTAROUTE_API_KEY=your_key
npx expo run:ios
npx expo run:android

Props

| Prop | Type | Default | Platform | |---|---|---|---| | apiKey | string | required | all | | onComplete | (addr: CompleteAddress) => void | required | all | | apiBaseUrl | string | https://api.quantaroute.com | all | | onError | (err: Error) => void | – | all | | defaultLat | number | India center | all | | defaultLng | number | India center | all | | theme | 'light' \| 'dark' | 'light' | all | | mapHeight | string \| number | '380px' / 380 | all | | title | string | 'Add Delivery Address' | all | | mapStyle | BuiltInMapStyle \| string | 'carto-positron' | all | | className | string | – | web only | | style | CSSProperties \| StyleProp<ViewStyle> | – | all | | indiaBoundaryUrl | string | – | web only |


CompleteAddress output

interface CompleteAddress {
  digipin: string;          // "39J-438-TJC7"
  lat: number;              // 28.61390
  lng: number;              // 77.20900

  // Auto-filled from QuantaRoute API
  state: string;            // "Delhi"
  district: string;         // "New Delhi"
  division: string;         // "New Delhi Central"
  locality: string;         // "Nirman Bhawan SO"
  pincode: string;          // "110011"
  delivery: string;         // "Delivery" | "Non Delivery"
  country: string;          // "India"

  // Manual entry by user
  flatNumber: string;       // "4B"
  floorNumber: string;      // "3rd"
  buildingName: string;     // "Sunshine Apartments"  (OSM pre-filled)
  streetName: string;       // "MG Road, Action Area" (OSM pre-filled)

  formattedAddress: string; // "4B, 3rd Floor, Sunshine Apartments, MG Road, ..."
}

Advanced usage

Use sub-components individually (web + native)

import { MapPinSelector, AddressForm, getDigiPin, isWithinIndia } from '@quantaroute/checkout';

// Offline DigiPin — no API call, ~0.1 ms
const dp = getDigiPin(28.6139, 77.2090); // "39J-438-TJC7"
const ok = isWithinIndia(28.6139, 77.2090); // true

// Custom two-step flow
function MyCheckout() {
  const [loc, setLoc] = useState<{ lat: number; lng: number; digipin: string } | null>(null);

  return loc == null
    ? <MapPinSelector onLocationConfirm={(lat, lng, digipin) => setLoc({ lat, lng, digipin })} />
    : <AddressForm
        lat={loc.lat}
        lng={loc.lng}
        digipin={loc.digipin}
        apiKey="..."
        onAddressComplete={(addr) => console.log(addr)}
        onBack={() => setLoc(null)}
      />;
}

Dark mode (web)

<CheckoutWidget apiKey="..." theme="dark" onComplete={...} />

Custom web theme via CSS variables

.qr-checkout {
  --qr-primary:      #6366f1;
  --qr-primary-dark: #4f46e5;
  --qr-radius:       8px;
  --qr-font:         'Poppins', sans-serif;
}

Choose a basemap style

Pass a built-in preset name or any MapLibre-compatible style URL:

// Built-in presets (no API key required for any of them)
<CheckoutWidget apiKey="..." mapStyle="carto-positron"       onComplete={...} />  {/* default */}
<CheckoutWidget apiKey="..." mapStyle="openfreemap-liberty"  onComplete={...} />  {/* colorful OSM */}
<CheckoutWidget apiKey="..." mapStyle="openfreemap-positron" onComplete={...} />  {/* clean light */}
<CheckoutWidget apiKey="..." mapStyle="openfreemap-bright"   onComplete={...} />  {/* vibrant */}

// Custom style URL (your own MapLibre server)
<CheckoutWidget apiKey="..." mapStyle="https://my-tiles.example.com/style.json" onComplete={...} />

Attribution is applied automatically for each built-in preset.

OpenFreeMap is a free, open-source tile hosting service. If you use the openfreemap-* presets in production, consider sponsoring the project to keep the public instance running.

India boundary overlay (web only)

<CheckoutWidget
  apiKey="..."
  indiaBoundaryUrl="/geojson/india.geojson"  {/* hosted in your public folder */}
  onComplete={...}
/>

Architecture

@quantaroute/checkout/
├── src/
│   ├── components/
│   │   ├── CheckoutWidget.tsx           ← web  (MapLibre GL JS)
│   │   ├── CheckoutWidget.native.tsx    ← native (SafeAreaView)
│   │   ├── MapPinSelector.tsx           ← web  (MapLibre marker)
│   │   ├── MapPinSelector.native.tsx    ← native (expo-osm-sdk OSMView)
│   │   ├── AddressForm.tsx              ← web  (HTML form)
│   │   └── AddressForm.native.tsx       ← native (TextInput / Modal)
│   ├── core/
│   │   ├── digipin.ts     ← offline DigiPin algorithm (shared, no DOM)
│   │   ├── api.ts         ← QuantaRoute API client (shared, fetch)
│   │   ├── mapStyles.ts   ← basemap preset registry + resolver (shared)
│   │   └── types.ts       ← TypeScript types (shared)
│   ├── hooks/
│   │   ├── useGeolocation.ts            ← web  (navigator.geolocation)
│   │   ├── useGeolocation.native.ts     ← native (expo-location)
│   │   └── useDigiPin.ts                ← shared (pure math)
│   └── styles/
│       ├── checkout.css                 ← web styles
│       └── checkout.native.ts           ← native StyleSheet.create()
├── expo-plugin.js   ← Expo config plugin
├── babel.config.js  ← Metro/Babel config
└── dist/            ← web build output (Vite)

Platform resolution:

Metro (Expo app)          → "react-native" export → src/index.ts
                            → MapPinSelector.native.tsx (expo-osm-sdk)
                            → useGeolocation.native.ts (expo-location)

Vite / Webpack / Next.js  → "import" export → dist/lib/quantaroute-checkout.es.js
                            → MapPinSelector.tsx (MapLibre GL JS)
                            → useGeolocation.ts (navigator.geolocation)

Map tile license

| Preset | Provider | Attribution | API key | |---|---|---|---| | carto-positron (default) | Carto | © OpenStreetMap contributors © CARTO | None | | openfreemap-liberty | OpenFreeMap | © OpenStreetMap contributors © OpenMapTiles · OpenFreeMap | None | | openfreemap-positron | OpenFreeMap | © OpenStreetMap contributors © OpenMapTiles · OpenFreeMap | None | | openfreemap-bright | OpenFreeMap | © OpenStreetMap contributors © OpenMapTiles · OpenFreeMap | None |

Attribution is injected automatically for all built-in presets. When using a custom style URL you are responsible for correct attribution per your tile provider's terms.

OpenFreeMap is fully open-source (MIT). If you use openfreemap-* presets in production, please consider sponsoring their public instance.


DigiPin license

The offline DigiPin algorithm is the official India Post implementation:


Development

git clone https://github.com/quantaroute/checkout.git
cd quantaroute-checkout
npm install

# Web dev server
npm run dev              # http://localhost:5173

# Type checks
npm run type-check       # web (Vite tsconfig)
npm run type-check:native # native (RN tsconfig)

# Build
npm run build:lib        # library → dist/lib/
npm run build            # library + demo

Native demo:

cd demo-native
npm install
npx expo run:ios         # requires Xcode
npx expo run:android     # requires Android Studio

Changelog

v1.3.0

  • mapStyle prop — choose a basemap preset or pass any MapLibre-compatible style URL
    • 'carto-positron' (default, unchanged — fully backward-compatible)
    • 'openfreemap-liberty' — colorful OSM-flavored style via OpenFreeMap
    • 'openfreemap-positron' — clean light style via OpenFreeMap
    • 'openfreemap-bright' — vibrant high-contrast style via OpenFreeMap
    • Custom URL string — pass any MapLibre style JSON endpoint
  • Attribution text is resolved automatically per provider (no manual setup needed)
  • New src/core/mapStyles.ts — shared preset registry used by both web and native components

v1.2.0

  • iOS & Android support via expo-osm-sdk (MapLibre GL Native)
  • MapPinSelector.native.tsx — draggable OSMView pin
  • AddressForm.native.tsxTextInput / ScrollView / Modal locality picker
  • CheckoutWidget.native.tsxSafeAreaView layout with identical flow logic
  • useGeolocation.native.ts — GPS via expo-location
  • checkout.native.ts — complete StyleSheet design system (light + dark)
  • expo-plugin.js — one-line app.json setup for iOS/Android
  • babel.config.js — Metro transpilation config
  • mapHeight prop now accepts number (native) or string (web, e.g. '380px')
  • All native peer dependencies marked optional (zero impact on web bundles)

v1.1.x

  • DigiPin badge overlay on map
  • Locality alternatives dropdown
  • OSM address pre-fill (building name, road, suburb)
  • India boundary GeoJSON overlay

v1.0.0

  • Initial release: MapLibre GL + Carto Positron
  • Offline DigiPin generation
  • QuantaRoute API integration
  • Mobile-first responsive design
  • Dark mode, reduced-motion, keyboard accessible

Made with ❤️ in India · Powered by QuantaRoute