17 Commits (f9c07a263d9d27b0874be3c3924e32ea80c1c0a7)

Author SHA1 Message Date
Buddy f9c07a263d refactor: split element classes from customElements.define
Every component is now two modules sharing a basename:

- src/elements/leaflet-foo.ts -- `export default class LeafletFooElement
  extends WithProps(...)`, the class only, no customElements.define, no
  side effects. src/elements/index.ts is an order-free barrel.
- src/components/leaflet-foo.ts -- three lines: import the class, define
  the tag, re-export. Importing this (or src/index.ts) registers the tag.

Plugin authors can now import a class without triggering the built-in
define, to subclass it or register it under a different tag name. Package
subpath exports `leaflet-components/elements`,
`leaflet-components/elements/leaflet-foo.js`, and
`leaflet-components/components/leaflet-foo.js` map onto dist/; jsr.json
gains an `./elements` entry.

The load-bearing ordering moves from the export statements in src/index.ts
to its `./components/*` side-effect imports (the elements barrel carries no
define, so its order is free). Classes are renamed LeafletFoo ->
LeafletFooElement, including in the HTMLElementTagNameMap augmentation.

Docs (CLAUDE.md, docs/, README.md) updated for the new layout.
2 weeks ago
Buddy 0419ab781d feat: type leaflet-* components and their leaflet: events
Two augmentations, so TypeScript actually knows about the custom elements:

- HTMLElementTagNameMap (src/index.ts): createElement/querySelector now
  infer the exact component class for all 24 tags instead of HTMLElement.
- Per-component addEventListener/removeEventListener overrides, typing
  `leaflet:<name>` events against the real Leaflet event payload
  (PopupEvent, DragEndEvent, LeafletMouseEvent, etc.) while still accepting
  ordinary DOM events normally, and rejecting event names that component
  doesn't fire.

src/core/event-types.ts holds reusable event-name -> payload-type
fragments (mirroring shared-props.ts's fragment reuse), composed per
family: MapEvents, MarkerEvents, PathEvents, TileLayerEvents,
DivOverlayLayerEvents, GroupEvents. LeafletAddEventListener<T>/
LeafletRemoveEventListener<T> in with-props.ts are type-only
intersection-of-overloads helpers applied via `declare addEventListener:
...`, the same pattern every component already uses for `declare readonly
leafletObject?: X` -- zero runtime cost. Deliberately no generic `string`
fallback overload: a fallback would silently accept unrecognized
`leaflet:*` names too, defeating the point.

Fixed a real bug found while building this: #forwardEvents was
dispatching the raw pre-merge `data` Leaflet passes to fire(), missing
type/target/sourceTarget that Leaflet's own fire() merges in before
notifying real .on() listeners. Typing `detail` against Leaflet's actual
event interfaces would have been dishonest otherwise, so the merge now
matches Leaflet's own Evented#fire.

Also added 'line-updated' to the existing internal-event HTMLElementEventMap
augmentation in register.ts (needed once addEventListener got overridden
on polygon/polyline, which use it internally) and cleaned up ~35 now-
redundant `as HTMLElement & {...}` casts across the test suite that the
tag name map makes unnecessary.
4 weeks ago
Buddy 14e35846d5 refactor: complete WithProps mixin, generic event forwarding, and full prop coverage
Finishes the WithProps(PROPS, options) mixin (src/core/with-props.ts): every
component gets reactive attributes, live-value property getters that read
through to the Leaflet object where possible, and every Leaflet event
re-emitted on the element as `leaflet:<type>` via a generic fire() patch (no
per-component or per-event registration needed).

Prop coverage:
- Centralized pathProps in shared-props.ts (stroke, lineCap, lineJoin,
  dashArray, dashOffset, fillRule, interactive, className,
  bubblingMouseEvents, pane), deduped leaflet-geojson against it.
- Added live getters backed by Leaflet's own accessors: radius (circle,
  circle-marker), bounds (rectangle, image/video/svg-overlay), url
  (image/video-overlay).
- Filled gaps: smoothFactor/noClip on polyline; a shared tileLayerProps
  fragment now used by both tile-layer and tile-layer-wms (WMS previously
  exposed none of its base tile options); crs on WMS; zIndex/className/
  keepAspectRatio/errorOverlayUrl on video-overlay; fixed tile-layer's
  zIndex default and div-icon's className default to match Leaflet.

Tooling:
- Removed dead src/core/events.ts (broken, unused, superseded by the
  generic event forwarding above) and src/core/attributes.ts (emptied by
  an earlier rename, nothing imported it).
- Swapped ESLint + @typescript-eslint for oxlint: no released
  @typescript-eslint version supports the pinned typescript@7, even for
  parsing alone. oxlint has its own parser and lints clean.
- Dropped the Rollup CJS/UMD bundle step; dist/ is ESM-only from tsc now.
  Updated package.json's main/module/exports/unpkg accordingly.
- Updated CLAUDE.md to match: build/lint commands, ESM-only output, the
  event-forwarding mechanism, and layer-group/feature-group now going
  through WithProps({}) instead of raw HTMLElement.
4 weeks ago
Buddy e2382f1117 refactor: enforce strict TypeScript linting rules
Upgrade ESLint config to use flat config with @typescript-eslint/strict-type-checked and stylistic-type-checked presets.

- Use defineConfig helper, scope to .ts files only
- Replace || with ??, convert type to interface, remove redundant type assertions and non-null assertions
- Annotate intentional violations (unbound-method, non-null-assertion) with eslint-disable
- Use querySelectorAll<T> for typed selection, Map over globalThis.Map
- Add @eslint/js dev dependency
3 months ago
Buddy f85e67547d refactor: use events for control-layers layer add/remove instead of DOM traversal
Replace the #map getter (which used closest("leaflet-map") + leafletObject)
with two new custom events: leaflet-add-layer and leaflet-remove-layer.
The map listens for them and delegates to map.addLayer/removeLayer.

This removes the coupling between leaflet-control-layers and the map
element, aligning with the existing leaflet-register event protocol.
3 months ago
Buddy c283632262 feat: add leafletObject escape hatch + move event wiring
Every component now exposes a uniform get leafletObject() returning
the underlying Leaflet instance (undefined before connected).

Event wiring:
- Marker: listen for 'dragend move' via onChange, syncing lat/lng
  back to attributes. Converted from arrow property to regular
  method using Leaflet's 3rd context arg pattern.
- Circle, CircleMarker: listen for 'move' via onMove with syncing
  guard (same pattern).
- Popup, Tooltip: listen for 'move' via onChange with syncing
  guard and null-check on getLatLng().

Also:
- Update README with escape hatch section
- Change map getter from get map() to get leafletObject() for
  consistency
- index.html: add importmap for leaflet
- All component exports changed from default to named
- index.ts re-exports updated accordingly
3 months ago
Buddy 11cae8c89f style: replace Number/String/parseInt/parseFloat with shorter equivalents
Replace Number(x) with +x, String(x) with template literal,
parseInt(x, 10) with +, and parseFloat(x || "0") with +(x ?? 0).
Fix operator precedence with parentheses around ?? expressions.
3 months ago
Buddy 7ae092ac98 refactor: consolidate core modules into utils.ts
Merge path-style.ts and with-props.ts into utils.ts to reduce the
number of core files from 5 to 3 (utils.ts, props.ts, register.ts).
Unify duplicate ../core/utils.ts imports in all component files.
Remove stale re-exports from src/index.ts.
3 months ago
Buddy d8bdc2dcfa refactor: replace any with generics in NumProp and BoolOffProp
Make NumProp and BoolOffProp generic (NumProp<T>, BoolOffProp<T>)
instead of using any, with T inferred from callback parameters at
call sites via the num<T>() and off<T>() factory helpers. Remove
unused num import from leaflet-tile-layer-wms. Fix prettier
formatting issues.
3 months ago
Buddy f95cc3b1f6 refactor: switch leaflet-map to defineProps with factory helpers
Extend num() factory to accept optional extra fields (mapGet, mapSet,
viewState, event). Add off() factory and BoolOffPropInput type. Update
defineProps to derive disable- prefix for bool-off attrs. Remove
~40 lines of local type definitions from leaflet-map.ts.
3 months ago
Buddy 96037f22b6 refactor: switch component exports from named to default
All 21 component files export exactly one class. Change to
export default so consumers can import them without named braces.
Update src/index.ts re-exports from "export *" to
"export { default as LeafletXxx }". Fix the two type-only
imports of LeafletLine to use default import syntax.
3 months ago
Buddy 85f0fbe216 refactor: use .ts extension for relative imports in source
Change all import specifiers from ".js" to ".ts" in TypeScript source
files. Add allowImportingTsExtensions and rewriteRelativeImportExtensions
to tsconfig so tsc strips them to ".js" in the dist output — no build
pipeline changes needed. Update CLAUDE.md to reflect the new extension policy.
3 months ago
Buddy 4d27c8eaac core: rename prettier config and run prettier 3 months ago
Buddy 2c2e83b7d0 feat: auto-invalidate map size on element resize via ResizeObserver
Replace the height-attribute approach with a ResizeObserver on the host
element so the map re-renders whenever its container size changes from
any source — CSS class, inline style, parent layout, etc.
4 months ago
Buddy 41acdc9bb7 feat: load Leaflet CSS via CDN <link> instead of bundling
Replace inline CSS import with a configurable CDN <link> to fix 404s on
marker icon PNG files (relative paths now resolve against the CDN URL).

- Remove leaflet/dist/leaflet.css import and --loader:.css=text from build
- Add css-url, css-integrity, css-crossorigin attributes on <leaflet-map>
- Derive Icon.Default.imagePath from CSS URL for JS-loaded marker icons
- Move shadow DOM setup into connectedCallback with reconnection guard
- Use CSS_ATTRS constant for observedAttributes and attributeChangedCallback

CSS attrs default to https://unpkg.com/leaflet@1.9.4/dist/leaflet.css with
SRI integrity and crossorigin='anonymous'. Custom CSS URLs drop the
default integrity; set css-integrity explicitly to re-enable SRI.
4 months ago
Buddy 5f3fd5f61a refactor: replace inheritance hierarchy with composable PROPS-table pattern
Remove LeafletElement and LeafletControl base classes. Every component
now self-describes its attributes via a PROPS table, derives observed-
Attributes from it, and generates prototype getters/setters in static {}.

Registration lifecycle is extracted into standalone helpers
(registerWithParent, createChildRegisterHandler). Common update
patterns (path style) are shared via imported helpers instead of
duplicated across 5+ components.

Components manage their own #obj private field instead of a shared
protected leafletObject. Leaflet-map-style declarative patterns are
now consistent across all 20 components.
4 months ago
Buddy 6b448ba092 feat: Initial implementation of leaflet-components
Wraps Leaflet.js as native Web Components. Each element maps 1:1 to a
Leaflet object with reactive attribute binding and proper lifecycle cleanup.

Key design decisions:
- LeafletElement base class handles attribute→option mapping, the
  leaflet-register bubble event for parent/child wiring, and
  disconnectedCallback cleanup tracking parent bindings.
- LeafletControl base class for map controls (zoom, attribution, scale).
- leaflet-map uses a PROPS table to drive observedAttributes, getters/setters,
  attributeChangedCallback, and map event listeners from a single source of
  truth. Property types are derived via a mapped type over the table; the
  mixin-base pattern (TypedBase) makes them visible to TypeScript without an
  interface merge.
- Boolean map options that default to true use disable-* attributes.
- Leaflet and its CSS are bundled into dist/index.js via esbuild.
- JSR config included for @buddy/leaflet-components.
4 months ago