import { Popup } from 'leaflet'; import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import type { PropDef, PropTypesFromTable } from '../types/props.js'; const PROPS = { lat: { kind: 'num', attr: 'lat', default: 0 }, lng: { kind: 'num', attr: 'lng', default: 0 }, maxWidth: { kind: 'num', attr: 'max-width', default: 300 }, minWidth: { kind: 'num', attr: 'min-width', default: 50 }, maxHeight: { kind: 'num', attr: 'max-height', default: 0 }, autoPan: { kind: 'bool-on', attr: 'auto-pan' }, closeButton: { kind: 'bool-on', attr: 'close-button' }, autoClose: { kind: 'bool-on', attr: 'auto-close' }, } satisfies Record; type PropTypes = PropTypesFromTable; const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes; export class LeafletPopup extends TypedBase { #obj?: Popup; #observer?: MutationObserver; static get observedAttributes() { return Object.values(PROPS).map((s) => s.attr); } static { definePropAccessors(LeafletPopup.prototype, PROPS); } connectedCallback() { this.#obj = new Popup({ ...buildOptions(this, PROPS, ['lat', 'lng']), content: this.innerHTML, }); if (this.hasAttribute('lat') && this.hasAttribute('lng')) { this.#obj.setLatLng([this.#num('lat'), this.#num('lng')]); } registerWithParent(this, this.#obj); this.#observer = new MutationObserver(() => { this.#obj?.setContent(this.innerHTML); }); this.#observer.observe(this, { childList: true, characterData: true, subtree: true, }); } disconnectedCallback() { this.#observer?.disconnect(); this.#observer = undefined; this.#obj?.remove(); this.#obj = undefined; } attributeChangedCallback(name: string) { if (!this.#obj) return; if (name === 'lat' || name === 'lng') { this.#obj.setLatLng([this.#num('lat'), this.#num('lng')]); } } #num(name: string): number { const v = this.getAttribute(name); return v !== null ? Number(v) : (PROPS[name as keyof typeof PROPS] as { default: number }).default; } } customElements.define('leaflet-popup', LeafletPopup);