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.
main
Buddy 3 months ago
parent 26e110d0b4
commit 80c87468b6

@ -1,5 +1,6 @@
import { CircleMarker } from 'leaflet'; import { CircleMarker } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
@ -7,7 +8,7 @@ import {
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
lat: { kind: 'num', attr: 'lat', default: 0 }, lat: { kind: 'num', attr: 'lat', default: 0 },
@ -21,22 +22,11 @@ const PROPS = {
fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletCircleMarker extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletCircleMarker extends TypedBase {
#obj?: CircleMarker; #obj?: CircleMarker;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletCircleMarker.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new CircleMarker( this.#obj = new CircleMarker(
[this.#num('lat'), this.#num('lng')], [this.#num('lat'), this.#num('lng')],

@ -1,5 +1,6 @@
import { Circle } from 'leaflet'; import { Circle } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
@ -7,7 +8,7 @@ import {
type LeafletRegisterEvent, type LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
lat: { kind: 'num', attr: 'lat', default: 0 }, lat: { kind: 'num', attr: 'lat', default: 0 },
@ -21,22 +22,11 @@ const PROPS = {
fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletCircle extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletCircle extends TypedBase {
#obj?: Circle; #obj?: Circle;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletCircle.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Circle( this.#obj = new Circle(
[this.#num('lat'), this.#num('lng')], [this.#num('lat'), this.#num('lng')],

@ -1,27 +1,17 @@
import { Control, ControlPosition } from 'leaflet'; import { Control, ControlPosition } from 'leaflet';
import { registerWithParent, definePropAccessors } from '../core/utils.js'; import { registerWithParent } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
position: { kind: 'str', attr: 'position', default: 'bottomright' }, position: { kind: 'str', attr: 'position', default: 'bottomright' },
prefix: { kind: 'str', attr: 'prefix', default: '' }, prefix: { kind: 'str', attr: 'prefix', default: '' },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletControlAttribution extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletControlAttribution extends TypedBase {
#obj?: Control.Attribution; #obj?: Control.Attribution;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletControlAttribution.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Control.Attribution({ this.#obj = new Control.Attribution({
position: this.getAttribute('position') as ControlPosition | undefined, position: this.getAttribute('position') as ControlPosition | undefined,

@ -1,7 +1,8 @@
import { Control, ControlPosition } from 'leaflet'; import { Control, ControlPosition } from 'leaflet';
import { registerWithParent, definePropAccessors } from '../core/utils.js'; import { registerWithParent } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
position: { kind: 'str', attr: 'position', default: 'bottomleft' }, position: { kind: 'str', attr: 'position', default: 'bottomleft' },
@ -11,20 +12,9 @@ const PROPS = {
updateWhenIdle: { kind: 'bool-on', attr: 'update-when-idle' }, updateWhenIdle: { kind: 'bool-on', attr: 'update-when-idle' },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletControlScale extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletControlScale extends TypedBase {
#obj?: Control.Scale; #obj?: Control.Scale;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletControlScale.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Control.Scale({ this.#obj = new Control.Scale({
position: this.getAttribute('position') as ControlPosition | undefined, position: this.getAttribute('position') as ControlPosition | undefined,

@ -1,7 +1,8 @@
import { Control, ControlPosition } from 'leaflet'; import { Control, ControlPosition } from 'leaflet';
import { registerWithParent, definePropAccessors } from '../core/utils.js'; import { registerWithParent } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
position: { kind: 'str', attr: 'position', default: 'topleft' }, position: { kind: 'str', attr: 'position', default: 'topleft' },
@ -11,20 +12,9 @@ const PROPS = {
zoomOutTitle: { kind: 'str', attr: 'zoom-out-title', default: 'Zoom out' }, zoomOutTitle: { kind: 'str', attr: 'zoom-out-title', default: 'Zoom out' },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletControlZoom extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletControlZoom extends TypedBase {
#obj?: Control.Zoom; #obj?: Control.Zoom;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletControlZoom.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Control.Zoom({ this.#obj = new Control.Zoom({
position: this.getAttribute('position') as ControlPosition | undefined, position: this.getAttribute('position') as ControlPosition | undefined,

@ -1,12 +1,13 @@
import { GeoJSON, PathOptions, Layer } from 'leaflet'; import { GeoJSON, PathOptions, Layer } from 'leaflet';
import { buildOptions, registerWithParent, definePropAccessors } from '../core/utils.js'; import { buildOptions, registerWithParent } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
data: { kind: 'str', attr: 'data', default: '' }, data: { kind: 'str', attr: 'data', default: '' },
@ -28,22 +29,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletGeoJSON extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletGeoJSON extends TypedBase {
#obj?: GeoJSON; #obj?: GeoJSON;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletGeoJSON.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
const raw = this.getAttribute('data'); const raw = this.getAttribute('data');
const data = raw ? JSON.parse(raw) : undefined; const data = raw ? JSON.parse(raw) : undefined;

@ -1,17 +1,13 @@
import { ImageOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet'; import { ImageOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet';
import { import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js';
registerWithParent, import { withProps } from '../core/with-props.js';
buildOptions,
parseAttributeValue,
definePropAccessors,
} from '../core/utils.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
url: { kind: 'str', attr: 'url', default: '' }, url: { kind: 'str', attr: 'url', default: '' },
@ -29,22 +25,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletImageOverlay extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletImageOverlay extends TypedBase {
#obj?: ImageOverlay; #obj?: ImageOverlay;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletImageOverlay.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
const url = this.getAttribute('url') || ''; const url = this.getAttribute('url') || '';
this.#obj = new ImageOverlay( this.#obj = new ImageOverlay(

@ -1,17 +1,13 @@
import { Marker } from 'leaflet'; import { Marker } from 'leaflet';
import { import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js';
registerWithParent, import { withProps } from '../core/with-props.js';
buildOptions,
parseAttributeValue,
definePropAccessors,
} from '../core/utils.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
lat: { kind: 'num', attr: 'lat', default: 0 }, lat: { kind: 'num', attr: 'lat', default: 0 },
@ -27,22 +23,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletMarker extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletMarker extends TypedBase {
#obj?: Marker; #obj?: Marker;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletMarker.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Marker( this.#obj = new Marker(
[this.#num('lat'), this.#num('lng')], [this.#num('lat'), this.#num('lng')],

@ -1,5 +1,6 @@
import { Polygon } from 'leaflet'; import { Polygon } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
@ -7,7 +8,7 @@ import {
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
import type { LeafletLine } from './leaflet-line.js'; import type { LeafletLine } from './leaflet-line.js';
const PROPS = { const PROPS = {
@ -19,23 +20,12 @@ const PROPS = {
fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletPolygon extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletPolygon extends TypedBase {
#obj?: Polygon; #obj?: Polygon;
#observer?: MutationObserver; #observer?: MutationObserver;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletPolygon.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Polygon(this.#getCoords(), buildOptions(this, PROPS)); this.#obj = new Polygon(this.#getCoords(), buildOptions(this, PROPS));
this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); this.#childHandler = createChildRegisterHandler(this.#obj, this.#children);

@ -1,5 +1,6 @@
import { Polyline } from 'leaflet'; import { Polyline } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
@ -7,7 +8,7 @@ import {
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
import type { LeafletLine } from './leaflet-line.js'; import type { LeafletLine } from './leaflet-line.js';
const PROPS = { const PROPS = {
@ -19,23 +20,12 @@ const PROPS = {
fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletPolyline extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletPolyline extends TypedBase {
#obj?: Polyline; #obj?: Polyline;
#observer?: MutationObserver; #observer?: MutationObserver;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletPolyline.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Polyline(this.#getCoords(), buildOptions(this, PROPS)); this.#obj = new Polyline(this.#getCoords(), buildOptions(this, PROPS));
this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); this.#childHandler = createChildRegisterHandler(this.#obj, this.#children);

@ -1,7 +1,8 @@
import { Popup } from 'leaflet'; import { Popup } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
lat: { kind: 'num', attr: 'lat', default: 0 }, lat: { kind: 'num', attr: 'lat', default: 0 },
@ -14,21 +15,10 @@ const PROPS = {
autoClose: { kind: 'bool-on', attr: 'auto-close' }, autoClose: { kind: 'bool-on', attr: 'auto-close' },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletPopup extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletPopup extends TypedBase {
#obj?: Popup; #obj?: Popup;
#observer?: MutationObserver; #observer?: MutationObserver;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletPopup.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Popup({ this.#obj = new Popup({
...buildOptions(this, PROPS, ['lat', 'lng']), ...buildOptions(this, PROPS, ['lat', 'lng']),

@ -1,5 +1,6 @@
import { Rectangle, LatLngBoundsExpression } from 'leaflet'; import { Rectangle, LatLngBoundsExpression } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
@ -7,7 +8,7 @@ import {
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
bounds: { kind: 'str', attr: 'bounds', default: '' }, bounds: { kind: 'str', attr: 'bounds', default: '' },
@ -19,22 +20,11 @@ const PROPS = {
fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletRectangle extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletRectangle extends TypedBase {
#obj?: Rectangle; #obj?: Rectangle;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletRectangle.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Rectangle(this.#parsedBounds(), buildOptions(this, PROPS, ['bounds'])); this.#obj = new Rectangle(this.#parsedBounds(), buildOptions(this, PROPS, ['bounds']));
this.#childHandler = createChildRegisterHandler(this.#obj, this.#children); this.#childHandler = createChildRegisterHandler(this.#obj, this.#children);

@ -1,17 +1,13 @@
import { SVGOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet'; import { SVGOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet';
import { import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js';
registerWithParent, import { withProps } from '../core/with-props.js';
buildOptions,
parseAttributeValue,
definePropAccessors,
} from '../core/utils.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
bounds: { kind: 'str', attr: 'bounds', default: '' }, bounds: { kind: 'str', attr: 'bounds', default: '' },
@ -26,22 +22,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletSVGOverlay extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletSVGOverlay extends TypedBase {
#obj?: SVGOverlay; #obj?: SVGOverlay;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletSVGOverlay.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
const svg = this.querySelector('svg'); const svg = this.querySelector('svg');
const dummy = !svg ? document.createElementNS('http://www.w3.org/2000/svg', 'svg') : undefined; const dummy = !svg ? document.createElementNS('http://www.w3.org/2000/svg', 'svg') : undefined;

@ -1,17 +1,13 @@
import { TileLayer } from 'leaflet'; import { TileLayer } from 'leaflet';
import { import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js';
registerWithParent, import { withProps } from '../core/with-props.js';
buildOptions,
parseAttributeValue,
definePropAccessors,
} from '../core/utils.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
url: { kind: 'str', attr: 'url', default: '' }, url: { kind: 'str', attr: 'url', default: '' },
@ -27,22 +23,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletTileLayerWMS extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletTileLayerWMS extends TypedBase {
#obj?: TileLayer.WMS; #obj?: TileLayer.WMS;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletTileLayerWMS.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
const url = this.getAttribute('url') || ''; const url = this.getAttribute('url') || '';
this.#obj = new TileLayer.WMS( this.#obj = new TileLayer.WMS(

@ -1,17 +1,13 @@
import { TileLayer } from 'leaflet'; import { TileLayer } from 'leaflet';
import { import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js';
registerWithParent, import { withProps } from '../core/with-props.js';
buildOptions,
parseAttributeValue,
definePropAccessors,
} from '../core/utils.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
url: { kind: 'str', attr: 'url', default: '' }, url: { kind: 'str', attr: 'url', default: '' },
@ -26,22 +22,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletTileLayer extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletTileLayer extends TypedBase {
#obj?: TileLayer; #obj?: TileLayer;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletTileLayer.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
const url = this.getAttribute('url') || ''; const url = this.getAttribute('url') || '';
this.#obj = new TileLayer(url, buildOptions(this, PROPS, ['url'])); this.#obj = new TileLayer(url, buildOptions(this, PROPS, ['url']));

@ -1,7 +1,8 @@
import { Tooltip } from 'leaflet'; import { Tooltip } from 'leaflet';
import { registerWithParent, buildOptions, definePropAccessors } from '../core/utils.js'; import { registerWithParent, buildOptions } from '../core/utils.js';
import { withProps } from '../core/with-props.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
lat: { kind: 'num', attr: 'lat', default: 0 }, lat: { kind: 'num', attr: 'lat', default: 0 },
@ -14,21 +15,10 @@ const PROPS = {
opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, opacity: { kind: 'num', attr: 'opacity', default: 1.0 },
} satisfies Record<string, PropDef>; } satisfies Record<string, PropDef>;
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletTooltip extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletTooltip extends TypedBase {
#obj?: Tooltip; #obj?: Tooltip;
#observer?: MutationObserver; #observer?: MutationObserver;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletTooltip.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
this.#obj = new Tooltip({ this.#obj = new Tooltip({
...buildOptions(this, PROPS, ['lat', 'lng']), ...buildOptions(this, PROPS, ['lat', 'lng']),

@ -1,17 +1,13 @@
import { VideoOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet'; import { VideoOverlay, LatLngBounds, LatLngBoundsExpression, LatLngExpression } from 'leaflet';
import { import { registerWithParent, buildOptions, parseAttributeValue } from '../core/utils.js';
registerWithParent, import { withProps } from '../core/with-props.js';
buildOptions,
parseAttributeValue,
definePropAccessors,
} from '../core/utils.js';
import { import {
createChildRegisterHandler, createChildRegisterHandler,
type ChildEntry, type ChildEntry,
LeafletRegisterEvent, LeafletRegisterEvent,
} from '../core/register.js'; } from '../core/register.js';
import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { PropDef } from '../types/props.js';
const PROPS = { const PROPS = {
url: { kind: 'str', attr: 'url', default: '' }, url: { kind: 'str', attr: 'url', default: '' },
@ -30,22 +26,11 @@ const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
); );
type PropTypes = PropTypesFromTable<typeof PROPS>; export class LeafletVideoOverlay extends withProps(HTMLElement, PROPS) {
const TypedBase = HTMLElement as unknown as new () => HTMLElement & PropTypes;
export class LeafletVideoOverlay extends TypedBase {
#obj?: VideoOverlay; #obj?: VideoOverlay;
#children = new Map<HTMLElement, ChildEntry>(); #children = new Map<HTMLElement, ChildEntry>();
#childHandler?: (e: LeafletRegisterEvent) => void; #childHandler?: (e: LeafletRegisterEvent) => void;
static get observedAttributes() {
return Object.values(PROPS).map((s) => s.attr);
}
static {
definePropAccessors(LeafletVideoOverlay.prototype, PROPS);
}
connectedCallback() { connectedCallback() {
const url = this.getAttribute('url') || ''; const url = this.getAttribute('url') || '';
this.#obj = new VideoOverlay( this.#obj = new VideoOverlay(

@ -0,0 +1,21 @@
import type { PropDef, PropTypesFromTable } from '../types/props.js';
import { definePropAccessors } from './utils.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Ctor<T = object> = new (...args: any[]) => T;
export function withProps<TBase extends Ctor<HTMLElement>, TProps extends Record<string, PropDef>>(
Base: TBase,
props: TProps,
): TBase & Ctor<HTMLElement & PropTypesFromTable<TProps>> {
class WithProps extends Base {
static {
definePropAccessors(WithProps.prototype, props);
}
static get observedAttributes(): string[] {
return Object.values(props).map((s) => s.attr);
}
}
return WithProps as TBase & Ctor<HTMLElement & PropTypesFromTable<TProps>>;
}

@ -1,4 +1,5 @@
export * from './core/utils.js'; export * from './core/utils.js';
export * from './core/with-props.js';
export * from './core/path-style.js'; export * from './core/path-style.js';
export * from './core/register.js'; export * from './core/register.js';
export * from './types/props.js'; export * from './types/props.js';

Loading…
Cancel
Save