@ -1,6 +1,6 @@
import { Path } from 'leaflet' ;
import type { PropDef , PropTypesFromTable } from './props.ts' ;
import type { LatLngBoundsExpression } from 'leaflet' ;
import { Path } from 'leaflet' ;
import type { PropDef } from './props.ts' ;
// Reads a numeric attribute from an element, falling back to the default
// value declared in the PROPS table. Handles the common pattern of
@ -72,57 +72,6 @@ export function parseAttributeValue(value: string | null): unknown {
}
}
// Builds the initial Leaflet options object from the PROPS table and the
// element's current attributes at connection time. Props listed in
// `exclude` are skipped (they're passed separately to Leaflet
// constructors, like coordinates or URLs). Null attributes use the
// default from PROPS if one exists (skipping empty-string defaults to
// avoid Leaflet rejecting them).
//
// The return type is derived from the PROPS table: each prop name maps
// to its kind's value type (number for `num`, boolean for `bool-on`/`bool-off`,
// string for `str`). The `const` type parameter makes literal exclude arrays
// narrow correctly, so excluded keys are stripped from the return type.
export function buildOptions <
TProps extends Record < string , PropDef > ,
const TExclude extends readonly string [ ] = [ ] ,
> (
el : HTMLElement ,
props : TProps ,
exclude : TExclude = [ ] as unknown as TExclude ,
) : Omit < PropTypesFromTable < TProps > , TExclude [ number ] > {
const opts = { } as Record < string , unknown > ;
for ( const [ propName , spec ] of Object . entries ( props ) ) {
if ( exclude . includes ( propName ) ) continue ;
const val = el . getAttribute ( spec . attr ) ;
if ( val === null ) {
if ( 'default' in spec && spec . default !== '' ) opts [ propName ] = spec . default ;
continue ;
}
if ( spec . kind === 'num' ) opts [ propName ] = + val ;
else if ( spec . kind === 'bool-on' ) opts [ propName ] = true ;
else if ( spec . kind === 'bool-off' ) opts [ propName ] = false ;
else opts [ propName ] = val ;
}
return opts as Omit < PropTypesFromTable < TProps > , TExclude [ number ] > ;
}
// Dispatches a custom `leaflet-register` event upward through the DOM
// tree, carrying a Leaflet object and its host element. Parent components
// (map, circles, groups, etc.) intercept this event and add the layer,
// bind the popup, or bind the tooltip. This is the core wiring mechanism
// that replaces the parent-child relationship that Leaflet normally
// manages via imperative code.
export function registerWithParent ( el : HTMLElement , obj : unknown ) {
el . dispatchEvent (
new CustomEvent ( 'leaflet-register' , {
detail : { leafletObject : obj , element : el } ,
bubbles : true ,
composed : true ,
} ) ,
) ;
}
const PATH_STYLE_ATTRS = new Set ( [
'color' ,
'weight' ,