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

@sechak.agency/moromap

v0.1.0

Published

Zero-dependency-fetch interactive Morocco map for JS/TS — regions & provinces/prefectures, labels, data markers, choropleths, themes, search, export (SVG/PNG). Ships with bundled geo-data and an optional React wrapper.

Readme

MoroMap

Interactive, dependency-light Morocco map for the browser — regions and provinces/prefectures, labels, data markers, choropleths, legends, search and SVG/PNG export. Works as vanilla TypeScript or as an optional React component. The geographic data (boundaries + city coordinates) is bundled in the package, so there is nothing to fetch at runtime.

npm install @sechak.agency/moromap
  • Vanilla TS/JS — a single MoroccoMap class, no framework required.
  • React — a thin <MoroccoMapView /> wrapper (@sechak.agency/moromap/react), React is an optional peer dependency.
  • Two levels — 12 regions or 75 provinces/prefectures.
  • Choropleths — colour zones by data, with automatic legends.
  • Data markers — points sized/coloured by value, with clustering.
  • 9 built-in themes + build-your-own from a single accent colour.
  • Trilingual names — French, Arabic, Amazigh (Tifinagh) where available.
  • Export — SVG, PNG (Retina), and print.
  • Search — built-in autocomplete over the current level's zones.
  • CSS is auto-injected; no separate stylesheet import required.

Quick start (vanilla)

import { MoroccoMap } from '@sechak.agency/moromap';

const map = new MoroccoMap(document.getElementById('map')!, {
  level: 'regions',
  labelMode: 'auto',
  onFeatureClick: (name) => console.log('clicked', name),
});

The container should have a width and a height — the map fills it responsively.

Quick start (React)

import { MoroccoMapView } from '@sechak.agency/moromap/react';

export function Map() {
  return (
    <div style={{ width: 480, height: 560 }}>
      <MoroccoMapView level="regions" labelMode="auto" searchable />
    </div>
  );
}

React is an optional peer dependency — install it only if you use @sechak.agency/moromap/react.


Choropleth (colour by data)

import { MoroccoMap, colorScaleFromData } from '@sechak.agency/moromap';

const values = {
  'Casablanca-Settat': 1200,
  'Rabat-Salé-Kénitra': 800,
  // ...
};

const scale = colorScaleFromData(Object.values(values));

new MoroccoMap(el, {
  level: 'regions',
  colorScale: (name) => scale.scale(values[name]),
  legend: { scale, title: 'Établissements' },
});

Data markers

import { MoroccoMap, CITIES, cityMarkers } from '@sechak.agency/moromap';

new MoroccoMap(el, {
  markers: cityMarkers(CITIES),      // 91 Moroccan cities, ready to use
  markerSizeRange: [4, 20],          // size by marker.value
  clusterMarkers: true,              // merge nearby points
});

Themes

import { MoroccoMap, DARK_THEME, themeFromAccent, THEME_PRESETS } from '@sechak.agency/moromap';

// A preset:
new MoroccoMap(el, { theme: DARK_THEME });

// Or derive a full, coherent theme from one brand colour:
new MoroccoMap(el, { theme: themeFromAccent('#6d28d9', 'dark') });

Presets: light, dark, ocean, sahara, royal, monochrome, sunset, emerald, slate (all available via THEME_PRESETS).

Export

map.exportSvg({ filename: 'maroc' });
await map.exportPng({ scale: 3, background: '#fff' });
map.print();

In React, drive the same actions through a ref:

const ref = useRef<MoroccoMapHandle>(null);
// ref.current?.exportPng({ scale: 2 })

API overview

new MoroccoMap(container, options)

Key options (see full JSDoc types in your editor via MoroccoMapOptions):

| Option | Type | Description | | --- | --- | --- | | level | 'regions' \| 'provinces' | Detail level (default 'regions'). | | labelMode | 'none' \| 'always' \| 'hover' \| 'auto' | Zone name display. | | labelPlacement | 'inline' \| 'callout' \| 'sidebar' \| 'tooltip-only' | Where values/labels render. | | renderStyle | 'solid' \| 'outline' \| 'dotted' | Fill style. | | theme | Partial<MoroccoMapTheme> | Merged with the default theme. | | colorScale | (name) => string | Choropleth colour per zone. | | zoneColors / zoneValues | Record<string, …> | Hand-set colours / values per zone. | | markers | MapMarker[] | Data points to overlay. | | markerSizeRange | [number, number] | Size markers by value. | | clusterMarkers | boolean | Merge nearby markers into clusters. | | legend | { scale, title?, position? } | Auto-rendered choropleth legend. | | zoomable | boolean | Mouse/trackpad zoom & pan. | | isolateOnClick | boolean | Zoom into a zone and dim the rest. | | attribution | boolean | Show the required "© OpenStreetMap contributors" credit (default true). | | attributionPosition | 'bottom-left' \| 'bottom-right' \| 'top-left' \| 'top-right' | Where the credit renders (default 'bottom-right'). | | onFeatureClick / onFeatureHover / onMarkerClick | callbacks | Interaction hooks. |

Named exports

  • Map: MoroccoMap
  • React: MoroccoMapView, MoroccoMapViewProps, MoroccoMapHandle (from @sechak.agency/moromap/react)
  • Themes: LIGHT_THEME, DARK_THEME, OCEAN_THEME, SAHARA_THEME, ROYAL_THEME, MONOCHROME_THEME, SUNSET_THEME, EMERALD_THEME, SLATE_THEME, THEME_PRESETS, resolveTheme, prefersDarkMode, themeFromAccent
  • Colour scales: sequentialScale, divergingScale, colorScaleFromData
  • Cities: CITIES, citiesOfRegion, citiesOfProvince, cityMarkers
  • Search: SearchIndex
  • Clustering: clusterMarkers
  • Export: exportPng, exportSvg, printMap
  • Plus TypeScript types for every option and data shape.

Styling

CSS is injected automatically the first time a map is created — you do not need to import a stylesheet. If your bundler or CSP requires an explicit stylesheet instead, one is shipped:

import '@sechak.agency/moromap/style.css';

Requirements

  • Node >= 18 (for building/tooling; the library itself runs in the browser).
  • A DOM environment — this is a browser library (SVG + Canvas for PNG export).
  • React >= 18 only if you use @sechak.agency/moromap/react.

Data & licence

The map boundaries and city coordinates are derived from OpenStreetMap and are licensed under the Open Database License (ODbL) v1.0, which requires crediting © OpenStreetMap contributors wherever the map is shown publicly.

This credit is displayed automatically in a corner of the map (see attribution / attributionPosition above) — you don't need to add it yourself. Only disable it (attribution: false) if you already display the same credit elsewhere on the page (e.g. in your site's footer); in that case, keeping the licence obligation satisfied is your responsibility.

The source code is released under the MIT License. See LICENSE for the full terms of both.