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
This commit is contained in:
parent
11cae8c89f
commit
c283632262
18
README.md
18
README.md
@ -161,13 +161,27 @@ Boolean options that default to `false` are enabled by adding the attribute:
|
||||
|
||||
```js
|
||||
const el = document.querySelector('leaflet-map');
|
||||
el.map; // L.Map instance (undefined before connected)
|
||||
el.zoom; // current zoom (reads live from map, falls back to attribute)
|
||||
el.leafletObject; // L.Map instance (undefined before connected)
|
||||
el.zoom; // current zoom (reads live from map, falls back to attribute)
|
||||
el.scrollWheelZoom = false; // disable at runtime
|
||||
```
|
||||
|
||||
All `leaflet-map` properties are two-way: reading returns the live map value; writing updates both the attribute and the map.
|
||||
|
||||
## Escape hatch
|
||||
|
||||
Every component exposes a `leafletObject` getter that returns the underlying Leaflet instance. This is useful when you need to call Leaflet API methods directly:
|
||||
|
||||
```js
|
||||
const marker = document.querySelector('leaflet-marker');
|
||||
marker.leafletObject?.setLatLng([51.5, -0.09]);
|
||||
|
||||
const map = document.querySelector('leaflet-map');
|
||||
map.leafletObject?.flyTo([48.86, 2.35], 13);
|
||||
```
|
||||
|
||||
Returns `undefined` while the element isn't connected to the DOM.
|
||||
|
||||
### CSS
|
||||
|
||||
Leaflet's stylesheet is loaded from a CDN via a `<link>` in the shadow DOM. Marker icon paths are derived from the CSS URL automatically.
|
||||
|
||||
@ -320,6 +320,13 @@
|
||||
<leaflet-control-scale position="bottomleft"></leaflet-control-scale>
|
||||
</leaflet-map>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"leaflet": "/node_modules/leaflet/dist/leaflet-src.esm.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module" src="/dist/index.js"></script>
|
||||
<script type="module">
|
||||
// ── Component metadata ──────────────────────────────────────────────────
|
||||
|
||||
@ -21,25 +21,32 @@ const PROPS = defineProps({
|
||||
fillOpacity: num(0.2),
|
||||
});
|
||||
|
||||
export default class LeafletCircleMarker extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletCircleMarker extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: CircleMarker;
|
||||
#syncing = false;
|
||||
|
||||
connectedCallback() {
|
||||
this.#obj = new CircleMarker(
|
||||
[numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')],
|
||||
buildOptions(this, PROPS, ['lat', 'lng']),
|
||||
);
|
||||
this.#obj.on('move', this.#onMove, this);
|
||||
registerChildren(this, this.#obj);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.#obj?.off('move', this.#onMove, this);
|
||||
unregisterChildren(this);
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
if (name === 'lat' || name === 'lng') {
|
||||
this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]);
|
||||
} else if (name === 'radius') {
|
||||
@ -48,6 +55,15 @@ export default class LeafletCircleMarker extends WithProps(HTMLElement, PROPS) {
|
||||
updatePathStyle(this.#obj, name, val);
|
||||
}
|
||||
}
|
||||
|
||||
#onMove() {
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
this.#syncing = true;
|
||||
const pos = this.#obj.getLatLng();
|
||||
this.setAttribute('lat', `${pos.lat}`);
|
||||
this.setAttribute('lng', `${pos.lng}`);
|
||||
this.#syncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-circle-marker', LeafletCircleMarker);
|
||||
|
||||
@ -21,25 +21,32 @@ const PROPS = defineProps({
|
||||
fillOpacity: num(0.2),
|
||||
});
|
||||
|
||||
export default class LeafletCircle extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletCircle extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Circle;
|
||||
#syncing = false;
|
||||
|
||||
connectedCallback() {
|
||||
this.#obj = new Circle(
|
||||
[numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')],
|
||||
buildOptions(this, PROPS, ['lat', 'lng']),
|
||||
);
|
||||
this.#obj.on('move', this.#onMove, this);
|
||||
registerChildren(this, this.#obj);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.#obj?.off('move', this.#onMove, this);
|
||||
unregisterChildren(this);
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
if (name === 'lat' || name === 'lng') {
|
||||
this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]);
|
||||
} else if (name === 'radius') {
|
||||
@ -48,6 +55,15 @@ export default class LeafletCircle extends WithProps(HTMLElement, PROPS) {
|
||||
updatePathStyle(this.#obj, name, val);
|
||||
}
|
||||
}
|
||||
|
||||
#onMove() {
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
this.#syncing = true;
|
||||
const pos = this.#obj.getLatLng();
|
||||
this.setAttribute('lat', `${pos.lat}`);
|
||||
this.setAttribute('lng', `${pos.lng}`);
|
||||
this.#syncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-circle', LeafletCircle);
|
||||
|
||||
@ -7,7 +7,7 @@ const PROPS = defineProps({
|
||||
prefix: str(),
|
||||
});
|
||||
|
||||
export default class LeafletControlAttribution extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletControlAttribution extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Control.Attribution;
|
||||
|
||||
connectedCallback() {
|
||||
@ -22,6 +22,10 @@ export default class LeafletControlAttribution extends WithProps(HTMLElement, PR
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-control-attribution', LeafletControlAttribution);
|
||||
|
||||
@ -10,7 +10,7 @@ const PROPS = defineProps({
|
||||
updateWhenIdle: on(),
|
||||
});
|
||||
|
||||
export default class LeafletControlScale extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletControlScale extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Control.Scale;
|
||||
|
||||
connectedCallback() {
|
||||
@ -29,6 +29,10 @@ export default class LeafletControlScale extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-control-scale', LeafletControlScale);
|
||||
|
||||
@ -10,7 +10,7 @@ const PROPS = defineProps({
|
||||
zoomOutTitle: str('Zoom out'),
|
||||
});
|
||||
|
||||
export default class LeafletControlZoom extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletControlZoom extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Control.Zoom;
|
||||
|
||||
connectedCallback() {
|
||||
@ -28,6 +28,10 @@ export default class LeafletControlZoom extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-control-zoom', LeafletControlZoom);
|
||||
|
||||
@ -2,7 +2,7 @@ import { FeatureGroup, Layer } from 'leaflet';
|
||||
import { registerChildren, unregisterChildren, getChildren } from '../core/register.ts';
|
||||
import { buildOptions } from '../core/utils.ts';
|
||||
|
||||
export default class LeafletFeatureGroup extends HTMLElement {
|
||||
export class LeafletFeatureGroup extends HTMLElement {
|
||||
#obj?: FeatureGroup;
|
||||
|
||||
static get observedAttributes() {
|
||||
@ -24,6 +24,10 @@ export default class LeafletFeatureGroup extends HTMLElement {
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-feature-group', LeafletFeatureGroup);
|
||||
|
||||
@ -23,7 +23,7 @@ const PROP_BY_ATTR = new Map<string, string>(
|
||||
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
|
||||
);
|
||||
|
||||
export default class LeafletGeoJSON extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletGeoJSON extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: GeoJSON;
|
||||
|
||||
connectedCallback() {
|
||||
@ -47,6 +47,10 @@ export default class LeafletGeoJSON extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'data') {
|
||||
|
||||
@ -24,7 +24,7 @@ const PROPS = defineProps({
|
||||
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export default class LeafletImageOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletImageOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: ImageOverlay;
|
||||
|
||||
connectedCallback() {
|
||||
@ -43,6 +43,10 @@ export default class LeafletImageOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'url') {
|
||||
|
||||
@ -2,7 +2,7 @@ import { LayerGroup, Layer } from 'leaflet';
|
||||
import { registerChildren, unregisterChildren, getChildren } from '../core/register.ts';
|
||||
import { buildOptions } from '../core/utils.ts';
|
||||
|
||||
export default class LeafletLayerGroup extends HTMLElement {
|
||||
export class LeafletLayerGroup extends HTMLElement {
|
||||
#obj?: LayerGroup;
|
||||
|
||||
static get observedAttributes() {
|
||||
@ -24,6 +24,10 @@ export default class LeafletLayerGroup extends HTMLElement {
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-layer-group', LeafletLayerGroup);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default class LeafletLine extends HTMLElement {
|
||||
export class LeafletLine extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ['lat', 'lng'];
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ type PropTypes = {
|
||||
|
||||
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
|
||||
|
||||
export default class LeafletMap extends TypedBase {
|
||||
export class LeafletMap extends TypedBase {
|
||||
#map?: LMap;
|
||||
#container!: HTMLDivElement;
|
||||
#cssLink?: HTMLLinkElement;
|
||||
@ -309,7 +309,7 @@ export default class LeafletMap extends TypedBase {
|
||||
}
|
||||
};
|
||||
|
||||
get map(): LMap | undefined {
|
||||
get leafletObject() {
|
||||
return this.#map;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ const PROPS = defineProps({
|
||||
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export default class LeafletMarker extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletMarker extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Marker;
|
||||
#syncing = false;
|
||||
|
||||
@ -24,17 +24,21 @@ export default class LeafletMarker extends WithProps(HTMLElement, PROPS) {
|
||||
[numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')],
|
||||
buildOptions(this, PROPS, ['lat', 'lng']),
|
||||
);
|
||||
this.#obj.on('dragend', this.#onDragEnd);
|
||||
this.#obj.on('dragend move', this.#onChange, this);
|
||||
registerChildren(this, this.#obj);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.#obj?.off('dragend', this.#onDragEnd);
|
||||
this.#obj?.off('dragend move', this.#onChange, this);
|
||||
unregisterChildren(this);
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
if (name === 'lat' || name === 'lng') {
|
||||
@ -53,14 +57,14 @@ export default class LeafletMarker extends WithProps(HTMLElement, PROPS) {
|
||||
}
|
||||
}
|
||||
|
||||
#onDragEnd = () => {
|
||||
#onChange() {
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
this.#syncing = true;
|
||||
const pos = this.#obj.getLatLng();
|
||||
this.setAttribute('lat', `${pos.lat}`);
|
||||
this.setAttribute('lng', `${pos.lng}`);
|
||||
this.#syncing = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-marker', LeafletMarker);
|
||||
|
||||
@ -2,7 +2,7 @@ import { Polygon } from 'leaflet';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, buildOptions, isPathStyleAttr, updatePathStyle } from '../core/utils.ts';
|
||||
import type LeafletLine from './leaflet-line.ts';
|
||||
import type { LeafletLine } from './leaflet-line.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
color: str('#3388ff'),
|
||||
@ -13,7 +13,7 @@ const PROPS = defineProps({
|
||||
fillOpacity: num(0.2),
|
||||
});
|
||||
|
||||
export default class LeafletPolygon extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletPolygon extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Polygon;
|
||||
#observer?: MutationObserver;
|
||||
|
||||
@ -35,6 +35,10 @@ export default class LeafletPolygon extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (isPathStyleAttr(name)) {
|
||||
|
||||
@ -2,7 +2,7 @@ import { Polyline } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import { WithProps, buildOptions, isPathStyleAttr, updatePathStyle } from '../core/utils.ts';
|
||||
import type LeafletLine from './leaflet-line.ts';
|
||||
import type { LeafletLine } from './leaflet-line.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
color: str('#3388ff'),
|
||||
@ -13,7 +13,7 @@ const PROPS = defineProps({
|
||||
fillOpacity: num(0.2),
|
||||
});
|
||||
|
||||
export default class LeafletPolyline extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletPolyline extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Polyline;
|
||||
#observer?: MutationObserver;
|
||||
|
||||
@ -35,6 +35,10 @@ export default class LeafletPolyline extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (isPathStyleAttr(name)) {
|
||||
|
||||
@ -13,9 +13,10 @@ const PROPS = defineProps({
|
||||
autoClose: on(),
|
||||
});
|
||||
|
||||
export default class LeafletPopup extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletPopup extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Popup;
|
||||
#observer?: MutationObserver;
|
||||
#syncing = false;
|
||||
|
||||
connectedCallback() {
|
||||
this.#obj = new Popup({
|
||||
@ -25,6 +26,7 @@ export default class LeafletPopup extends WithProps(HTMLElement, PROPS) {
|
||||
if (this.hasAttribute('lat') && this.hasAttribute('lng')) {
|
||||
this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]);
|
||||
}
|
||||
this.#obj.on('move', this.#onChange, this);
|
||||
registerWithParent(this, this.#obj);
|
||||
|
||||
this.#observer = new MutationObserver(() => {
|
||||
@ -38,18 +40,33 @@ export default class LeafletPopup extends WithProps(HTMLElement, PROPS) {
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.#obj?.off('move', this.#onChange, this);
|
||||
this.#observer?.disconnect();
|
||||
this.#observer = undefined;
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string) {
|
||||
if (!this.#obj) return;
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
if (name === 'lat' || name === 'lng') {
|
||||
this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]);
|
||||
}
|
||||
}
|
||||
|
||||
#onChange() {
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
const pos = this.#obj.getLatLng();
|
||||
if (!pos) return;
|
||||
this.#syncing = true;
|
||||
this.setAttribute('lat', `${pos.lat}`);
|
||||
this.setAttribute('lng', `${pos.lng}`);
|
||||
this.#syncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-popup', LeafletPopup);
|
||||
|
||||
@ -19,7 +19,7 @@ const PROPS = defineProps({
|
||||
fillOpacity: num(0.2),
|
||||
});
|
||||
|
||||
export default class LeafletRectangle extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletRectangle extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Rectangle;
|
||||
|
||||
connectedCallback() {
|
||||
@ -33,6 +33,10 @@ export default class LeafletRectangle extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'bounds') {
|
||||
|
||||
@ -21,7 +21,7 @@ const PROPS = defineProps({
|
||||
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export default class LeafletSVGOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletSVGOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: SVGOverlay;
|
||||
|
||||
connectedCallback() {
|
||||
@ -41,6 +41,10 @@ export default class LeafletSVGOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'bounds') {
|
||||
|
||||
@ -21,7 +21,7 @@ const PROPS = defineProps({
|
||||
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export default class LeafletTileLayerWMS extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletTileLayerWMS extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: TileLayer.WMS;
|
||||
|
||||
connectedCallback() {
|
||||
@ -36,6 +36,10 @@ export default class LeafletTileLayerWMS extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'url') {
|
||||
|
||||
@ -14,7 +14,7 @@ const PROPS = defineProps({
|
||||
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export default class LeafletTileLayer extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletTileLayer extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: TileLayer;
|
||||
|
||||
connectedCallback() {
|
||||
@ -29,6 +29,10 @@ export default class LeafletTileLayer extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'url') {
|
||||
|
||||
@ -14,9 +14,10 @@ const PROPS = defineProps({
|
||||
opacity: num(1.0),
|
||||
});
|
||||
|
||||
export default class LeafletTooltip extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletTooltip extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: Tooltip;
|
||||
#observer?: MutationObserver;
|
||||
#syncing = false;
|
||||
|
||||
connectedCallback() {
|
||||
this.#obj = new Tooltip({
|
||||
@ -26,6 +27,7 @@ export default class LeafletTooltip extends WithProps(HTMLElement, PROPS) {
|
||||
if (this.hasAttribute('lat') && this.hasAttribute('lng')) {
|
||||
this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]);
|
||||
}
|
||||
this.#obj.on('move', this.#onChange, this);
|
||||
registerWithParent(this, this.#obj);
|
||||
|
||||
this.#observer = new MutationObserver(() => {
|
||||
@ -39,18 +41,33 @@ export default class LeafletTooltip extends WithProps(HTMLElement, PROPS) {
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.#obj?.off('move', this.#onChange, this);
|
||||
this.#observer?.disconnect();
|
||||
this.#observer = undefined;
|
||||
this.#obj?.remove();
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string) {
|
||||
if (!this.#obj) return;
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
if (name === 'lat' || name === 'lng') {
|
||||
this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]);
|
||||
}
|
||||
}
|
||||
|
||||
#onChange() {
|
||||
if (!this.#obj || this.#syncing) return;
|
||||
const pos = this.#obj.getLatLng();
|
||||
if (!pos) return;
|
||||
this.#syncing = true;
|
||||
this.setAttribute('lat', `${pos.lat}`);
|
||||
this.setAttribute('lng', `${pos.lng}`);
|
||||
this.#syncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('leaflet-tooltip', LeafletTooltip);
|
||||
|
||||
@ -25,7 +25,7 @@ const PROPS = defineProps({
|
||||
|
||||
const PROP_BY_ATTR = buildAttrMap(PROPS);
|
||||
|
||||
export default class LeafletVideoOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
export class LeafletVideoOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
#obj?: VideoOverlay;
|
||||
|
||||
connectedCallback() {
|
||||
@ -44,6 +44,10 @@ export default class LeafletVideoOverlay extends WithProps(HTMLElement, PROPS) {
|
||||
this.#obj = undefined;
|
||||
}
|
||||
|
||||
get leafletObject() {
|
||||
return this.#obj;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _old: string | null, val: string | null) {
|
||||
if (!this.#obj) return;
|
||||
if (name === 'url') {
|
||||
|
||||
42
src/index.ts
42
src/index.ts
@ -1,24 +1,24 @@
|
||||
export * from './core/utils.ts';
|
||||
export * from './core/register.ts';
|
||||
export * from './core/props.ts';
|
||||
export { default as LeafletMap } from './components/leaflet-map.ts';
|
||||
export { default as LeafletMarker } from './components/leaflet-marker.ts';
|
||||
export { default as LeafletCircle } from './components/leaflet-circle.ts';
|
||||
export { default as LeafletCircleMarker } from './components/leaflet-circle-marker.ts';
|
||||
export { default as LeafletLine } from './components/leaflet-line.ts';
|
||||
export { default as LeafletPolygon } from './components/leaflet-polygon.ts';
|
||||
export { default as LeafletPolyline } from './components/leaflet-polyline.ts';
|
||||
export { default as LeafletRectangle } from './components/leaflet-rectangle.ts';
|
||||
export { default as LeafletTileLayer } from './components/leaflet-tile-layer.ts';
|
||||
export { default as LeafletTileLayerWMS } from './components/leaflet-tile-layer-wms.ts';
|
||||
export { default as LeafletImageOverlay } from './components/leaflet-image-overlay.ts';
|
||||
export { default as LeafletVideoOverlay } from './components/leaflet-video-overlay.ts';
|
||||
export { default as LeafletSVGOverlay } from './components/leaflet-svg-overlay.ts';
|
||||
export { default as LeafletLayerGroup } from './components/leaflet-layer-group.ts';
|
||||
export { default as LeafletFeatureGroup } from './components/leaflet-feature-group.ts';
|
||||
export { default as LeafletGeoJSON } from './components/leaflet-geojson.ts';
|
||||
export { default as LeafletControlZoom } from './components/leaflet-control-zoom.ts';
|
||||
export { default as LeafletControlAttribution } from './components/leaflet-control-attribution.ts';
|
||||
export { default as LeafletControlScale } from './components/leaflet-control-scale.ts';
|
||||
export { default as LeafletPopup } from './components/leaflet-popup.ts';
|
||||
export { default as LeafletTooltip } from './components/leaflet-tooltip.ts';
|
||||
export { LeafletMap } from './components/leaflet-map.ts';
|
||||
export { LeafletMarker } from './components/leaflet-marker.ts';
|
||||
export { LeafletCircle } from './components/leaflet-circle.ts';
|
||||
export { LeafletCircleMarker } from './components/leaflet-circle-marker.ts';
|
||||
export { LeafletLine } from './components/leaflet-line.ts';
|
||||
export { LeafletPolygon } from './components/leaflet-polygon.ts';
|
||||
export { LeafletPolyline } from './components/leaflet-polyline.ts';
|
||||
export { LeafletRectangle } from './components/leaflet-rectangle.ts';
|
||||
export { LeafletTileLayer } from './components/leaflet-tile-layer.ts';
|
||||
export { LeafletTileLayerWMS } from './components/leaflet-tile-layer-wms.ts';
|
||||
export { LeafletImageOverlay } from './components/leaflet-image-overlay.ts';
|
||||
export { LeafletVideoOverlay } from './components/leaflet-video-overlay.ts';
|
||||
export { LeafletSVGOverlay } from './components/leaflet-svg-overlay.ts';
|
||||
export { LeafletLayerGroup } from './components/leaflet-layer-group.ts';
|
||||
export { LeafletFeatureGroup } from './components/leaflet-feature-group.ts';
|
||||
export { LeafletGeoJSON } from './components/leaflet-geojson.ts';
|
||||
export { LeafletControlZoom } from './components/leaflet-control-zoom.ts';
|
||||
export { LeafletControlAttribution } from './components/leaflet-control-attribution.ts';
|
||||
export { LeafletControlScale } from './components/leaflet-control-scale.ts';
|
||||
export { LeafletPopup } from './components/leaflet-popup.ts';
|
||||
export { LeafletTooltip } from './components/leaflet-tooltip.ts';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user