15 Commits (08558515043f6e82673ed0d3129fadd6c3fa9ceb)

Author SHA1 Message Date
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 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 10027c9fe7 refactor: rename withProps to WithProps
Capitalize the mixin factory name since it's used in the extends
position (class Foo extends WithProps(...)). Update CLAUDE.md to
match.
3 months ago
Buddy f615dceea3 refactor: replace PROPS literal tables with factory helpers
Add num(), str(), on() factory functions and defineProps() wrapper
to core/props.ts. Each helper returns a PropDef fragment without
'attr'; defineProps fills it in via camelToKebab(key), with an
optional override for edge cases like playsInline->playsinline.

Input types are derived from their canonical counterparts via
OptionalAttr<T> = Omit<T, 'attr'> & { attr?: string }, keeping
definitions in sync automatically.

Net effect: ~3800 chars removed across 18 component files, no
behavior change, full type inference preserved.
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 5d0d15fba1 refactor: move props.ts from src/types/ to src/core/
The types/ directory now only had a single file. The PropDef and
PropTypesFromTable types are foundational to the module infrastructure
(used by utils.ts, with-props.ts, and every component), so core/ is a
better home. Deleted the empty types/ directory.
3 months ago
Buddy e2752aa7e0 refactor: extract child-registration boilerplate into WeakMap helpers
Adds registerChildren / unregisterChildren / getChildren to
register.ts using module-scoped WeakMaps, removing the duplicated
#children / #childHandler fields + lifecycle wiring from 15
components.

registerChildren(el, layer) creates the children Map + handler,
stores both in WeakMaps, wires the event listener, and calls
registerWithParent — all in one call. unregisterChildren(el)
tears it down. getChildren(el) gives access to the map for
components that need custom child iteration in disconnectedCallback
(geojson, layer-group, feature-group).

Net: -101 lines, 15 components lose 2-4 fields + 4-8 lifecycle
lines each. Components with extra lifecycle work (marker -> dragend,
polygon/polyline -> observer + syncCoords) keep their custom
additions inline, just the register boilerplate is replaced.
3 months ago
Buddy c18829a0e3 refactor: extract duplicate #num helper into standalone numAttr()
Removes the identical private #num method from 5 components
(leaflet-circle, leaflet-circle-marker, leaflet-marker,
leaflet-popup, leaflet-tooltip). Replaces with numAttr(this, PROPS, name)
call to the new helper in utils.ts.
3 months ago
Buddy 80c87468b6 refactor: extract withProps mixin to eliminate TypedBase/observedAttributes boilerplate
18 components now use withProps(HTMLElement, PROPS) instead of
repeating TypedBase cast, static get observedAttributes(), and
static { definePropAccessors(...) } in each file.

Adds src/core/with-props.ts — a mixin factory that derives
PropTypesFromTable, defines property accessors, and sets up
observedAttributes from a PROPS table in a single expression.
3 months ago
Buddy a7b0df2616 fix: register custom event in HTMLElementEventMap to eliminate casts
Augment HTMLElementEventMap with 'leaflet-register' so that
addEventListener('leaflet-register', handler) natively accepts
(e: LeafletRegisterEvent) => void, removing the need for
as EventListener casts in all 14 consumer components.
3 months ago
Buddy 4e1abdcc3d refactor: extract static PROP accessor blocks into definePropAccessors helper
All 17 TypedBase components now share a single definePropAccessors(proto, PROPS)
call in their static block instead of duplicating the getter/setter loop.

Also includes pre-existing cleanup:
- Refine LeafletRegisterEvent type (interface -> generic CustomEvent)
- Drop unused attrToPropName helper
- Fix createChildRegisterHandler return type in layer-group/feature-group
3 months ago
Buddy 1e7ea22342 fix: prevent tooltip crash from empty-string pane option
buildOptions was passing default values for absent attributes,
including empty-string defaults like pane:'', which caused Leaflet to
look up this._panes[''] and return undefined, crashing in appendChild.

- Skip empty-string defaults in buildOptions so Leaflet uses its own
- Broaden createChildRegisterHandler param from LayerGroup to Layer so
  non-container layers (marker, circle, etc.) can intercept popup/tooltip
  children and call bindPopup/bindTooltip instead of bubbling to the map
- Add child-registration handler to every layer component (all 12)
- Fix disconnectedCallback in container components to unbind popups and
  tooltips and remove child layers properly
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