Map
mapcn/mapFreeComponent
A MapLibre-powered map component with markers, popups, tooltips, routes, and controls.
Install it
npx shadcn@latest add https://mapcn.dev/r/map.jsonSource
1"use client";23import MapLibreGL, { type PopupOptions, type MarkerOptions } from "maplibre-gl";4import "maplibre-gl/dist/maplibre-gl.css";5import type * as GeoJSON from "geojson";6import {7 createContext,8 forwardRef,9 useCallback,10 useContext,11 useEffect,12 useId,13 useImperativeHandle,14 useMemo,15 useRef,16 useState,17 type ReactNode,18} from "react";19import { createPortal } from "react-dom";20import { X, Minus, Plus, Locate, Maximize, Loader2 } from "lucide-react";2122import { cn } from "@/lib/utils";2324const defaultStyles = {25 dark: "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",26 light: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",27};2829// A tile-less, dependency-free style with a transparent background. Use it for30// data visualizations (choropleths, world arcs, dot maps) where you draw your31// own layers and don't need a street basemap. The easiest way to opt in is the32// `blank` prop:33// <Map blank>...</Map>34// The transparent background lets the themed container show through.35const blankMapStyle: MapLibreGL.StyleSpecification = {36 version: 8,37 sources: {},38 layers: [39 {40 id: "background",41 type: "background",42 paint: { "background-color": "rgba(0, 0, 0, 0)" },43 },44 ],45};4647// Prevent equivalent inline style objects from triggering a full map style reload.48function useStableValue<T>(value: T): T {49 const key = useMemo(() => JSON.stringify(value) ?? "", [value]);50 // eslint-disable-next-line react-hooks/exhaustive-deps51 return useMemo(() => value, [key]);52}5354function mergeHoverPaint<T extends Record<string, unknown>>(55 paint: T,56 hoverPaint: T | undefined,57): T {58 if (!hoverPaint) return paint;59 const merged: Record<string, unknown> = { ...paint };60 for (const [key, hoverValue] of Object.entries(hoverPaint)) {61 if (hoverValue === undefined) continue;62 const baseValue = merged[key];63 merged[key] =64 baseValue === undefined65 ? hoverValue66 : [67 "case",68 ["boolean", ["feature-state", "hover"], false],69 hoverValue,70 baseValue,71 ];72 }73 return merged as T;74}7576type Theme = "light" | "dark";7778// Check the document for an explicit theme (works with next-themes, etc.).79// Covers both `attribute="class"` (the default) and `attribute="data-theme"`.80function getDocumentTheme(): Theme | null {81 if (typeof document === "undefined") return null;82 const root = document.documentElement;83// … truncated
What it pulls in
npm packages
