refactor: replace any with generics in NumProp and BoolOffProp

Make NumProp and BoolOffProp generic (NumProp<T>, BoolOffProp<T>)
instead of using any, with T inferred from callback parameters at
call sites via the num<T>() and off<T>() factory helpers. Remove
unused num import from leaflet-tile-layer-wms. Fix prettier
formatting issues.
main
Buddy 3 months ago
parent f95cc3b1f6
commit d8bdc2dcfa

@ -55,10 +55,14 @@ const PROPS = defineProps({
transform3DLimit: num(8388608), transform3DLimit: num(8388608),
// Boolean defaults-true → disable-* attribute; handler-based options have live mapSet // Boolean defaults-true → disable-* attribute; handler-based options have live mapSet
scrollWheelZoom: off((m: LMap, v: boolean) => (v ? m.scrollWheelZoom.enable() : m.scrollWheelZoom.disable())), scrollWheelZoom: off((m: LMap, v: boolean) =>
v ? m.scrollWheelZoom.enable() : m.scrollWheelZoom.disable(),
),
dragging: off((m: LMap, v: boolean) => (v ? m.dragging.enable() : m.dragging.disable())), dragging: off((m: LMap, v: boolean) => (v ? m.dragging.enable() : m.dragging.disable())),
touchZoom: off((m: LMap, v: boolean) => (v ? m.touchZoom.enable() : m.touchZoom.disable())), touchZoom: off((m: LMap, v: boolean) => (v ? m.touchZoom.enable() : m.touchZoom.disable())),
doubleClickZoom: off((m: LMap, v: boolean) => (v ? m.doubleClickZoom.enable() : m.doubleClickZoom.disable())), doubleClickZoom: off((m: LMap, v: boolean) =>
v ? m.doubleClickZoom.enable() : m.doubleClickZoom.disable(),
),
boxZoom: off((m: LMap, v: boolean) => (v ? m.boxZoom.enable() : m.boxZoom.disable())), boxZoom: off((m: LMap, v: boolean) => (v ? m.boxZoom.enable() : m.boxZoom.disable())),
keyboard: off((m: LMap, v: boolean) => (v ? m.keyboard.enable() : m.keyboard.disable())), keyboard: off((m: LMap, v: boolean) => (v ? m.keyboard.enable() : m.keyboard.disable())),
closePopupOnClick: off(), closePopupOnClick: off(),

@ -3,7 +3,7 @@ import { buildOptions, buildAttrMap, setLayerAttr, parseAttributeValue } from '.
import { WithProps } from '../core/with-props.ts'; import { WithProps } from '../core/with-props.ts';
import { registerChildren, unregisterChildren } from '../core/register.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts';
import { defineProps, num, str, on } from '../core/props.ts'; import { defineProps, str, on } from '../core/props.ts';
const PROPS = defineProps({ const PROPS = defineProps({
url: str(), url: str(),
@ -22,10 +22,7 @@ export default class LeafletTileLayerWMS extends WithProps(HTMLElement, PROPS) {
connectedCallback() { connectedCallback() {
const url = this.getAttribute('url') || ''; const url = this.getAttribute('url') || '';
this.#obj = new TileLayer.WMS( this.#obj = new TileLayer.WMS(url, buildOptions(this, PROPS, ['url']));
url,
buildOptions(this, PROPS, ['url']),
);
registerChildren(this, this.#obj); registerChildren(this, this.#obj);
} }

@ -2,7 +2,7 @@ import { Path } from 'leaflet';
import { parseAttributeValue } from './utils.ts'; import { parseAttributeValue } from './utils.ts';
// The set of HTML attribute names that map to Leaflet Path style options. // The set of HTML attribute names that map to Leaflet Path style options.
// These are handled specially because Leaflet exposes them through // These are handled especially because Leaflet exposes them through
// setStyle() rather than individual setter methods, and they are shared // setStyle() rather than individual setter methods, and they are shared
// across many vector components (polyline, polygon, circle, rectangle). // across many vector components (polyline, polygon, circle, rectangle).
const PATH_STYLE_ATTRS = new Set([ const PATH_STYLE_ATTRS = new Set([

@ -1,9 +1,9 @@
export type NumProp = { export type NumProp<T = unknown> = {
kind: 'num'; kind: 'num';
attr: string; attr: string;
default: number; default: number;
mapGet?: (m: any) => number | undefined; mapGet?: (m: T) => number | undefined;
mapSet?: (m: any, v: number) => void; mapSet?: (m: T, v: number) => void;
viewState?: boolean; viewState?: boolean;
event?: string; event?: string;
}; };
@ -19,13 +19,13 @@ export type BoolOnProp = {
attr: string; attr: string;
}; };
export type BoolOffProp = { export type BoolOffProp<T = unknown> = {
kind: 'bool-off'; kind: 'bool-off';
attr: string; attr: string;
mapSet?: (m: any, enabled: boolean) => void; mapSet?: (m: T, enabled: boolean) => void;
}; };
export type PropDef = NumProp | StrProp | BoolOnProp | BoolOffProp; export type PropDef = NumProp<unknown> | StrProp | BoolOnProp | BoolOffProp<unknown>;
export type PropTypeOf<T extends PropDef> = T extends NumProp export type PropTypeOf<T extends PropDef> = T extends NumProp
? number ? number
@ -41,29 +41,36 @@ export type PropTypesFromTable<T extends Record<string, PropDef>> = {
type OptionalAttr<T> = Omit<T, 'attr'> & { attr?: string }; type OptionalAttr<T> = Omit<T, 'attr'> & { attr?: string };
type NumPropInput = OptionalAttr<NumProp>; type NumPropInput<T = unknown> = OptionalAttr<NumProp<T>>;
type StrPropInput = OptionalAttr<StrProp>; type StrPropInput = OptionalAttr<StrProp>;
type BoolOnPropInput = OptionalAttr<BoolOnProp>; type BoolOnPropInput = OptionalAttr<BoolOnProp>;
type BoolOffPropInput = OptionalAttr<BoolOffProp>; type BoolOffPropInput<T = unknown> = OptionalAttr<BoolOffProp<T>>;
type PropDefInput = NumPropInput | StrPropInput | BoolOnPropInput | BoolOffPropInput; type PropDefInput =
| NumPropInput<unknown>
| StrPropInput
| BoolOnPropInput
| BoolOffPropInput<unknown>;
type PropDefFromInput<T> = type PropDefFromInput<T> =
T extends { kind: 'num' } ? NumProp T extends NumPropInput<infer U>
: T extends { kind: 'str' } ? StrProp ? NumProp<U>
: T extends { kind: 'bool-off' } ? BoolOffProp : T extends { kind: 'str' }
? StrProp
: T extends BoolOffPropInput<infer U>
? BoolOffProp<U>
: BoolOnProp; : BoolOnProp;
function camelToKebab(s: string): string { function camelToKebab(s: string): string {
return s.replace(/[A-Z]/g, c => '-' + c.toLowerCase()); return s.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase());
} }
export function num( export function num<T = unknown>(
def: number = 0, def: number = 0,
opts?: string | (Omit<NumProp, 'kind' | 'default' | 'attr'> & { attr?: string }), opts?: string | (Omit<NumProp<T>, 'kind' | 'default' | 'attr'> & { attr?: string }),
): NumPropInput { ): NumPropInput<T> {
if (typeof opts === 'string') opts = { attr: opts }; if (typeof opts === 'string') opts = { attr: opts };
return { kind: 'num', default: def, ...opts }; return { kind: 'num', default: def, ...opts } as NumPropInput<T>;
} }
export function str(def: string = '', attr?: string): StrPropInput { export function str(def: string = '', attr?: string): StrPropInput {
@ -74,19 +81,20 @@ export function on(attr?: string): BoolOnPropInput {
return { kind: 'bool-on', ...(attr ? { attr } : {}) }; return { kind: 'bool-on', ...(attr ? { attr } : {}) };
} }
export function off(mapSet?: (m: any, enabled: boolean) => void): BoolOffPropInput { export function off<T = unknown>(mapSet?: (m: T, enabled: boolean) => void): BoolOffPropInput<T> {
return { kind: 'bool-off', ...(mapSet ? { mapSet } : {}) }; return { kind: 'bool-off', ...(mapSet ? { mapSet } : {}) } as BoolOffPropInput<T>;
} }
export function defineProps<T extends Record<string, PropDefInput>>( export function defineProps<T extends Record<string, unknown>>(
input: T, input: T,
): { [K in keyof T]: PropDefFromInput<T[K]> } { ): { [K in keyof T]: PropDefFromInput<T[K]> } {
const output = {} as Record<string, PropDef>; const output = {} as Record<string, PropDef>;
for (const key of Object.keys(input)) { for (const key of Object.keys(input)) {
const val = input[key] as PropDefInput; const val = input[key] as PropDefInput;
const { attr: override, ...rest } = val as any; const { attr: override, ...rest } = val as unknown as Record<string, unknown>;
const attr = override ?? (rest.kind === 'bool-off' ? 'disable-' + camelToKebab(key) : camelToKebab(key)); const attr =
override ?? (rest.kind === 'bool-off' ? 'disable-' + camelToKebab(key) : camelToKebab(key));
output[key] = { ...rest, attr } as PropDef; output[key] = { ...rest, attr } as PropDef;
} }
return output as any; return output as unknown as { [K in keyof T]: PropDefFromInput<T[K]> };
} }

Loading…
Cancel
Save