You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
leaflet-components/CLAUDE.md

3.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

npm run build      # tsc emits individual ESM modules, then Rollup bundles ESM/CJS/UMD
npm run typecheck  # tsc --noEmit
npm run lint       # ESLint over src/**/*.{ts,js}
npm run format     # Prettier formatting

There are no tests in this project. To preview components locally, open index.html in a browser with any static-file server.

Architecture

This library wraps Leaflet.js as native Web Components (Custom Elements). Each HTML element maps 1:1 to a Leaflet object.

WithProps mixin: src/core/with-props.ts

The WithProps(Base, PROPS) mixin factory replaces the old LeafletElement base class. Each component defines a PROPS table (a const record mapping kebab-case attribute names to PropDef descriptors), then extends WithProps(HTMLElement, PROPS). The mixin handles:

  • observedAttributes getter derived from the PROPS table keys.
  • definePropAccessors — property getters/setters on the prototype that sync attributes.
  • parseAttributeValue for boolean, number, and JSON coersion in attributeChangedCallback.
  • On connect, initOptions() builds a Leaflet options object from current attributes + PROPS defaults, then calls createLeafletObject().
  • On attribute change, updateLeafletObject() by default dispatches to the matching Leaflet setter (e.g. setOpacity, setRadius). Components override this for custom attribute handling (e.g. lat/lng pairs).

leaflet-map: src/components/leaflet-map.ts

LeafletMap extends HTMLElement directly and uses Shadow DOM. It is the root of the component tree and terminates all bubbling leaflet-register events by calling layer.addTo(this.map). Uses a ResizeObserver on the host element to call map.invalidateSize() automatically.

Child component pattern

All non-map components extend WithProps(HTMLElement, PROPS). To add a new component:

  1. Define a PROPS = {...} const table mapping kebab-case attributes to PropDef entries.
  2. Declare class LeafletFoo extends WithProps(HTMLElement, PROPS) implementing createLeafletObject(): L.Layer.
  3. Override updateLeafletObject(name, val) only if the default setter-based update won't work (common for coordinate pairs).
  4. Call customElements.define('leaflet-foo', LeafletFoo) at the bottom.
  5. Export from src/index.ts.

For components that accept children (layers, popups, tooltips), use the registerChildren/unregisterChildren/getChildren WeakMap-backed helpers from src/core/register.ts in connectedCallback/disconnectedCallback instead of maintaining private fields.

Special cases

  • leaflet-polygon uses <leaflet-line> children for vertices. The polygon collects lat/lng from child leaflet-line elements rather than having them as direct attributes.
  • leaflet-popup / leaflet-tooltip: content comes from innerHTML, not attributes. leaflet-popup watches for DOM mutations to keep Leaflet in sync.
  • leaflet-layer-group / leaflet-feature-group: passthrough containers extending HTMLElement directly (not via WithProps). Children register themselves into them via the standard bubble mechanism.

Output

tsc compiles src/dist/ as individual ESM modules (.js + .d.ts + .d.ts.map), then rollup -c bundles dist/index.js (ESM), dist/index.cjs (CJS), and dist/index.umd.js (UMD) — each with minified variants. Leaflet is always external (never bundled). Imports within source use .ts extensions; rewriteRelativeImportExtensions in tsconfig strips them to .js in the tsc output (tsconfig.json:16).