main
v0.2.0
v0.1.0
v0.1.1
${ noResults }
3 Commits (2c77784345e6280021a304ea848718e350079d3f)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
3845e53329 |
fix: remove parent-reaches-into-child patterns, fix a real load-order bug
Two parent-looks-for-child patterns found and removed, per the child-emits-events-parent-never-reaches-in principle: - leaflet-control-layers: #childLayers() queried children directly via querySelectorAll + reading their leafletObject/attributes, in two call sites. Verified empirically that a parent's connectedCallback always completes before a freshly-connected child's does (even for an already-built subtree attached in one shot), which means both call sites always ran against unpopulated children -- dead code. Deleted; #onChildRegister (already event-driven) was doing all the real work. - leaflet-polygon/leaflet-polyline: #coords() queried <leaflet-line> children via querySelectorAll + read their .latlng property directly, using a MutationObserver + a payload-less event only as a "something changed, rescan everyone" signal. Rewritten to be purely event-driven: <leaflet-line> now fires leaflet-line-sync (connect + every lat/lng change, carrying its own position) and leaflet-line-remove (disconnect) on itself; a new shared VertexTracker (src/core/vertex-tracker.ts) turns that event stream into an ordered coordinate list, using compareDocumentPosition only to place a newly-registered vertex at its real document position rather than assuming registration order matches DOM order. No querySelectorAll, no MutationObserver, no reading a child's property. Testing the polygon rewrite in an actual browser (not jsdom) surfaced two real bugs, both fixed: 1. disconnectedCallback fires *after* a node is already detached from its parent, so leaflet-line's removal event had nowhere to bubble to. Fixed by caching parentNode while still connected and dispatching from that cached reference instead of from the (by-then-detached) node. 2. A load-order hazard affecting every "parent listens for a specific child tag's announcement" relationship in this codebase: customElements.define() upgrades every matching element already parsed into the page immediately and synchronously, so whichever tag gets defined first wins a race -- a child tag defined before its listening parent fires its one-shot connect-time announcement into a parent that doesn't exist yet, and it's lost for good. This broke polygon/polyline (introduced by this rewrite, since leaflet-line was exported before leaflet-polygon) and, independently, was already silently broken for leaflet-control-layers (a base/overlay layer leaked directly onto the map, bypassing the control entirely) and latently for leaflet-layer-group/leaflet-feature-group. src/index.ts's export order now encodes and documents the real dependency hierarchy (map -> containers that listen for child announcements -> concrete layer types -> their own children). Added test/load-order.test.ts, which is structurally different from every other test file: it never statically imports a component module, building the DOM with plain undefined elements first and only dynamically import()ing src/index.ts afterward -- reproducing a real page's actual load order, which every other test's "define everything first" pattern cannot catch. Confirmed it fails against the old ordering and passes against the fix. |
4 weeks ago |
|
|
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 |
|
|
9b6c7ca598 |
test: add a Vitest + jsdom test suite
No test coverage existed before this. Adds vitest + jsdom (2 new devDependencies) and a suite that runs entirely without a browser: real Leaflet objects work fine under jsdom for everything this library needs to verify (option/attribute wiring, event forwarding), given a ResizeObserver stub in test/setup.ts (jsdom's only real gap here). - test/core/with-props.test.ts: the WithProps mixin itself, against a fake Leaflet-like class -- attribute<->setter dispatch, get/attribute/default fallback order, event-driven attribute sync-back, positional/recreate/ attach modes, and the generic fire()-patch event forwarding. Child registration (popup/tooltip/layer binding) uses real Popup/Tooltip/Marker instances since #onChildRegister discriminates by instanceof. - test/core/props.test.ts: the codec functions in isolation. - test/components/*.test.ts: grouped smoke tests across all components. - test/integration.test.ts: full tree wiring (map + tile-layer + feature-group + marker + popup). Caught and fixed one real bug along the way: urlProp's "live url getter" from the last refactor was dead code -- neither ImageOverlay nor VideoOverlay actually expose getUrl(). Removed it and the now-pointless getUrl?() from the Sourced interface in shared-props.ts. tsconfig.test.json keeps test/ out of the tsc build (dist/ stays test-free) while still typechecking it; oxlint.config.ts now covers test/ too, with max-classes-per-file relaxed there since testing a class factory means many small one-off element classes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
4 weeks ago |