refactor: move WithProps mixin from utils.ts to props.ts
WithProps is tightly coupled to PropDef types, so it belongs in props.ts alongside defineProps and the type definitions. - Move WithProps, definePropAccessors, and Ctor to props.ts - Import PropTypesFromTable in utils.ts (used by buildOptions) - Update all 18 component imports to source WithProps from props.ts
This commit is contained in:
parent
d6f7304313
commit
3854c62896
@ -1,8 +1,7 @@
|
||||
import { CircleMarker } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildOptions,
|
||||
isPathStyleAttr,
|
||||
numAttr,
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { Circle } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildOptions,
|
||||
isPathStyleAttr,
|
||||
numAttr,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Control, ControlPosition } from 'leaflet';
|
||||
import { defineProps, str } from '../core/props.ts';
|
||||
import { WithProps, registerWithParent } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, str } from '../core/props.ts';
|
||||
import { registerWithParent } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
position: str('bottomright'),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Control, ControlPosition, Layer } from 'leaflet';
|
||||
import { defineProps, str } from '../core/props.ts';
|
||||
import { WithProps, registerWithParent } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, str } from '../core/props.ts';
|
||||
import { registerWithParent } from '../core/utils.ts';
|
||||
import { LeafletRegisterEvent } from '../core/register.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Control, ControlPosition } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, registerWithParent } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerWithParent } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
position: str('bottomleft'),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Control, ControlPosition } from 'leaflet';
|
||||
import { defineProps, str } from '../core/props.ts';
|
||||
import { WithProps, registerWithParent } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, str } from '../core/props.ts';
|
||||
import { registerWithParent } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
position: str('topleft'),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { GeoJSON, PathOptions, Layer } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren, getChildren } from '../core/register.ts';
|
||||
import { WithProps, buildOptions } from '../core/utils.ts';
|
||||
import { buildOptions } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
data: str(),
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { ImageOverlay, LatLngBounds, LatLngExpression } from 'leaflet';
|
||||
import type { ImageOverlayOptions } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildAttrMap,
|
||||
buildOptions,
|
||||
parseBoundsAttr,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Icon, Marker } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { LeafletIconChangedEvent, registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import { WithProps, buildAttrMap, buildOptions, numAttr, setLayerAttr } from '../core/utils.ts';
|
||||
import { buildAttrMap, buildOptions, numAttr, setLayerAttr } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
lat: num(),
|
||||
|
||||
@ -1,7 +1,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 { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { buildOptions, isPathStyleAttr, updatePathStyle } from '../core/utils.ts';
|
||||
import type { LeafletLine } from './leaflet-line.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Polyline } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, 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 { buildOptions, isPathStyleAttr, updatePathStyle } from '../core/utils.ts';
|
||||
import type { LeafletLine } from './leaflet-line.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Popup } from 'leaflet';
|
||||
import { defineProps, num, on } from '../core/props.ts';
|
||||
import { WithProps, buildOptions, numAttr, registerWithParent } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, num, on } from '../core/props.ts';
|
||||
import { buildOptions, numAttr, registerWithParent } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
lat: num(),
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { Rectangle } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildOptions,
|
||||
isPathStyleAttr,
|
||||
parseBoundsAttr,
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { SVGOverlay, LatLngBounds, LatLngExpression } from 'leaflet';
|
||||
import type { ImageOverlayOptions } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildAttrMap,
|
||||
buildOptions,
|
||||
parseBoundsAttr,
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { TileLayer } from 'leaflet';
|
||||
import { defineProps, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildAttrMap,
|
||||
buildOptions,
|
||||
parseAttributeValue,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { TileLayer } from 'leaflet';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import { defineProps, num, str } from '../core/props.ts';
|
||||
import { WithProps, buildAttrMap, buildOptions, setLayerAttr } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, num, str } from '../core/props.ts';
|
||||
import { buildAttrMap, buildOptions, setLayerAttr } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
url: str(),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Tooltip } from 'leaflet';
|
||||
import type { TooltipOptions } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, buildOptions, numAttr, registerWithParent } from '../core/utils.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { buildOptions, numAttr, registerWithParent } from '../core/utils.ts';
|
||||
|
||||
const PROPS = defineProps({
|
||||
lat: num(),
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { VideoOverlay, LatLngBounds, LatLngExpression } from 'leaflet';
|
||||
import type { VideoOverlayOptions } from 'leaflet';
|
||||
import { defineProps, num, str, on } from '../core/props.ts';
|
||||
import { WithProps, defineProps, num, str, on } from '../core/props.ts';
|
||||
import { registerChildren, unregisterChildren } from '../core/register.ts';
|
||||
import {
|
||||
WithProps,
|
||||
buildAttrMap,
|
||||
buildOptions,
|
||||
parseBoundsAttr,
|
||||
|
||||
@ -37,8 +37,6 @@ export type PropTypesFromTable<T extends Record<string, PropDef>> = {
|
||||
[K in keyof T]: PropTypeOf<T[K]>;
|
||||
};
|
||||
|
||||
// --- Factory helpers ---
|
||||
|
||||
type OptionalAttr<T> = Omit<T, 'attr'> & { attr?: string };
|
||||
|
||||
type NumPropInput<T = unknown> = OptionalAttr<NumProp<T>>;
|
||||
@ -98,3 +96,40 @@ export function defineProps<T extends Record<string, unknown>>(
|
||||
}
|
||||
return output as unknown as { [K in keyof T]: PropDefFromInput<T[K]> };
|
||||
}
|
||||
|
||||
// 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 get observedAttributes(): string[] {
|
||||
return Object.values(props).map((s) => s.attr);
|
||||
}
|
||||
}
|
||||
definePropAccessors(WithProps.prototype, props);
|
||||
return WithProps as TBase & Ctor<HTMLElement & PropTypesFromTable<TProps>>;
|
||||
}
|
||||
|
||||
function definePropAccessors(proto: object, props: Record<string, PropDef>) {
|
||||
for (const [name, spec] of Object.entries(props)) {
|
||||
Object.defineProperty(proto, name, {
|
||||
get() {
|
||||
const el = this as HTMLElement;
|
||||
const val = el.getAttribute(spec.attr);
|
||||
if (spec.kind === 'num') return val !== null ? +val : spec.default;
|
||||
if (spec.kind === 'bool-on') return el.hasAttribute(spec.attr);
|
||||
return val ?? (spec as { default: string }).default;
|
||||
},
|
||||
set(v: unknown) {
|
||||
const el = this as HTMLElement;
|
||||
if (spec.kind === 'bool-on') el.toggleAttribute(spec.attr, !!v);
|
||||
else el.setAttribute(spec.attr, `${v}`);
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,50 +2,6 @@ import { Path } from 'leaflet';
|
||||
import type { PropDef, PropTypesFromTable } from './props.ts';
|
||||
import type { LatLngBoundsExpression } from 'leaflet';
|
||||
|
||||
// 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>>;
|
||||
}
|
||||
|
||||
// Installs reactive getter/setter pairs on a prototype for every entry in
|
||||
// a PROPS table. Each getter reads from the attribute (coerced to the
|
||||
// correct type), each setter writes via setAttribute/toggleAttribute.
|
||||
// Used by the WithProps() mixin so components have `el.lat = 51.5` sugar.
|
||||
function definePropAccessors(proto: object, props: Record<string, PropDef>) {
|
||||
for (const [name, spec] of Object.entries(props)) {
|
||||
Object.defineProperty(proto, name, {
|
||||
get() {
|
||||
const el = this as HTMLElement;
|
||||
const val = el.getAttribute(spec.attr);
|
||||
if (spec.kind === 'num') return val !== null ? +val : spec.default;
|
||||
if (spec.kind === 'bool-on') return el.hasAttribute(spec.attr);
|
||||
return val ?? (spec as { default: string }).default;
|
||||
},
|
||||
set(v: unknown) {
|
||||
const el = this as HTMLElement;
|
||||
if (spec.kind === 'bool-on') el.toggleAttribute(spec.attr, !!v);
|
||||
else el.setAttribute(spec.attr, `${v}`);
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Reads a numeric attribute from an element, falling back to the default
|
||||
// value declared in the PROPS table. Handles the common pattern of
|
||||
// reading lat/lng/radius/opacity with a guaranteed number return.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user