diff --git a/src/components/leaflet-circle-marker.ts b/src/components/leaflet-circle-marker.ts index bd14f9e..d2c0e6a 100644 --- a/src/components/leaflet-circle-marker.ts +++ b/src/components/leaflet-circle-marker.ts @@ -4,19 +4,19 @@ import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - lat: { kind: 'num', attr: 'lat', default: 0 }, - lng: { kind: 'num', attr: 'lng', default: 0 }, - radius: { kind: 'num', attr: 'radius', default: 10 }, - color: { kind: 'str', attr: 'color', default: '#3388ff' }, - weight: { kind: 'num', attr: 'weight', default: 3 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - fill: { kind: 'bool-on', attr: 'fill' }, - fillColor: { kind: 'str', attr: 'fill-color', default: '#3388ff' }, - fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, -} satisfies Record; +const PROPS = defineProps({ + lat: num(), + lng: num(), + radius: num(10), + color: str('#3388ff'), + weight: num(3), + opacity: num(1.0), + fill: on(), + fillColor: str('#3388ff'), + fillOpacity: num(0.2), +}); export default class LeafletCircleMarker extends withProps(HTMLElement, PROPS) { #obj?: CircleMarker; diff --git a/src/components/leaflet-circle.ts b/src/components/leaflet-circle.ts index c3465a5..effed4d 100644 --- a/src/components/leaflet-circle.ts +++ b/src/components/leaflet-circle.ts @@ -4,19 +4,19 @@ import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - lat: { kind: 'num', attr: 'lat', default: 0 }, - lng: { kind: 'num', attr: 'lng', default: 0 }, - radius: { kind: 'num', attr: 'radius', default: 1000 }, - color: { kind: 'str', attr: 'color', default: '#3388ff' }, - weight: { kind: 'num', attr: 'weight', default: 3 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - fill: { kind: 'bool-on', attr: 'fill' }, - fillColor: { kind: 'str', attr: 'fill-color', default: '#3388ff' }, - fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, -} satisfies Record; +const PROPS = defineProps({ + lat: num(), + lng: num(), + radius: num(1000), + color: str('#3388ff'), + weight: num(3), + opacity: num(1.0), + fill: on(), + fillColor: str('#3388ff'), + fillOpacity: num(0.2), +}); export default class LeafletCircle extends withProps(HTMLElement, PROPS) { #obj?: Circle; diff --git a/src/components/leaflet-control-attribution.ts b/src/components/leaflet-control-attribution.ts index 4cfb46f..ad9e632 100644 --- a/src/components/leaflet-control-attribution.ts +++ b/src/components/leaflet-control-attribution.ts @@ -2,12 +2,12 @@ import { Control, ControlPosition } from 'leaflet'; import { registerWithParent } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, str } from '../core/props.ts'; -const PROPS = { - position: { kind: 'str', attr: 'position', default: 'bottomright' }, - prefix: { kind: 'str', attr: 'prefix', default: '' }, -} satisfies Record; +const PROPS = defineProps({ + position: str('bottomright'), + prefix: str(), +}); export default class LeafletControlAttribution extends withProps(HTMLElement, PROPS) { #obj?: Control.Attribution; diff --git a/src/components/leaflet-control-scale.ts b/src/components/leaflet-control-scale.ts index 2827090..f373028 100644 --- a/src/components/leaflet-control-scale.ts +++ b/src/components/leaflet-control-scale.ts @@ -2,15 +2,15 @@ import { Control, ControlPosition } from 'leaflet'; import { registerWithParent } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - position: { kind: 'str', attr: 'position', default: 'bottomleft' }, - maxWidth: { kind: 'num', attr: 'max-width', default: 100 }, - metric: { kind: 'bool-on', attr: 'metric' }, - imperial: { kind: 'bool-on', attr: 'imperial' }, - updateWhenIdle: { kind: 'bool-on', attr: 'update-when-idle' }, -} satisfies Record; +const PROPS = defineProps({ + position: str('bottomleft'), + maxWidth: num(100), + metric: on(), + imperial: on(), + updateWhenIdle: on(), +}); export default class LeafletControlScale extends withProps(HTMLElement, PROPS) { #obj?: Control.Scale; diff --git a/src/components/leaflet-control-zoom.ts b/src/components/leaflet-control-zoom.ts index 7eed9a2..1f9b317 100644 --- a/src/components/leaflet-control-zoom.ts +++ b/src/components/leaflet-control-zoom.ts @@ -2,15 +2,15 @@ import { Control, ControlPosition } from 'leaflet'; import { registerWithParent } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, str } from '../core/props.ts'; -const PROPS = { - position: { kind: 'str', attr: 'position', default: 'topleft' }, - zoomInText: { kind: 'str', attr: 'zoom-in-text', default: '+' }, - zoomInTitle: { kind: 'str', attr: 'zoom-in-title', default: 'Zoom in' }, - zoomOutText: { kind: 'str', attr: 'zoom-out-text', default: '-' }, - zoomOutTitle: { kind: 'str', attr: 'zoom-out-title', default: 'Zoom out' }, -} satisfies Record; +const PROPS = defineProps({ + position: str('topleft'), + zoomInText: str('+'), + zoomInTitle: str('Zoom in'), + zoomOutText: str('-'), + zoomOutTitle: str('Zoom out'), +}); export default class LeafletControlZoom extends withProps(HTMLElement, PROPS) { #obj?: Control.Zoom; diff --git a/src/components/leaflet-geojson.ts b/src/components/leaflet-geojson.ts index df0f183..b87279b 100644 --- a/src/components/leaflet-geojson.ts +++ b/src/components/leaflet-geojson.ts @@ -3,23 +3,23 @@ import { buildOptions } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren, getChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - data: { kind: 'str', attr: 'data', default: '' }, - stroke: { kind: 'str', attr: 'stroke', default: '' }, - color: { kind: 'str', attr: 'color', default: '#3388ff' }, - weight: { kind: 'num', attr: 'weight', default: 3 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - lineCap: { kind: 'str', attr: 'line-cap', default: 'round' }, - lineJoin: { kind: 'str', attr: 'line-join', default: 'round' }, - dashArray: { kind: 'str', attr: 'dash-array', default: '' }, - dashOffset: { kind: 'str', attr: 'dash-offset', default: '' }, - fill: { kind: 'bool-on', attr: 'fill' }, - fillColor: { kind: 'str', attr: 'fill-color', default: '#3388ff' }, - fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, - fillRule: { kind: 'str', attr: 'fill-rule', default: 'evenodd' }, -} satisfies Record; +const PROPS = defineProps({ + data: str(), + stroke: str(), + color: str('#3388ff'), + weight: num(3), + opacity: num(1.0), + lineCap: str('round'), + lineJoin: str('round'), + dashArray: str(), + dashOffset: str(), + fill: on(), + fillColor: str('#3388ff'), + fillOpacity: num(0.2), + fillRule: str('evenodd'), +}); const PROP_BY_ATTR = new Map( Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]), diff --git a/src/components/leaflet-image-overlay.ts b/src/components/leaflet-image-overlay.ts index a746652..d3a24de 100644 --- a/src/components/leaflet-image-overlay.ts +++ b/src/components/leaflet-image-overlay.ts @@ -4,19 +4,19 @@ import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../co import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; - -const PROPS = { - url: { kind: 'str', attr: 'url', default: '' }, - bounds: { kind: 'str', attr: 'bounds', default: '' }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - alt: { kind: 'str', attr: 'alt', default: '' }, - interactive: { kind: 'bool-on', attr: 'interactive' }, - crossOrigin: { kind: 'str', attr: 'cross-origin', default: '' }, - errorOverlayUrl: { kind: 'str', attr: 'error-overlay-url', default: '' }, - zIndex: { kind: 'num', attr: 'z-index', default: 0 }, - className: { kind: 'str', attr: 'class-name', default: '' }, -} satisfies Record; +import { defineProps, num, str, on } from '../core/props.ts'; + +const PROPS = defineProps({ + url: str(), + bounds: str(), + opacity: num(1.0), + alt: str(), + interactive: on(), + crossOrigin: str(), + errorOverlayUrl: str(), + zIndex: num(), + className: str(), +}); const PROP_BY_ATTR = buildAttrMap(PROPS); diff --git a/src/components/leaflet-marker.ts b/src/components/leaflet-marker.ts index adb6a66..a90736c 100644 --- a/src/components/leaflet-marker.ts +++ b/src/components/leaflet-marker.ts @@ -3,17 +3,17 @@ import { buildOptions, numAttr, buildAttrMap, setLayerAttr } from '../core/utils import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - lat: { kind: 'num', attr: 'lat', default: 0 }, - lng: { kind: 'num', attr: 'lng', default: 0 }, - title: { kind: 'str', attr: 'title', default: '' }, - alt: { kind: 'str', attr: 'alt', default: '' }, - draggable: { kind: 'bool-on', attr: 'draggable' }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - zIndexOffset: { kind: 'num', attr: 'z-index-offset', default: 0 }, -} satisfies Record; +const PROPS = defineProps({ + lat: num(), + lng: num(), + title: str(), + alt: str(), + draggable: on(), + opacity: num(1.0), + zIndexOffset: num(), +}); const PROP_BY_ATTR = buildAttrMap(PROPS); diff --git a/src/components/leaflet-polygon.ts b/src/components/leaflet-polygon.ts index 03f966f..98d6ddd 100644 --- a/src/components/leaflet-polygon.ts +++ b/src/components/leaflet-polygon.ts @@ -4,17 +4,17 @@ import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; import type LeafletLine from './leaflet-line.ts'; -const PROPS = { - color: { kind: 'str', attr: 'color', default: '#3388ff' }, - weight: { kind: 'num', attr: 'weight', default: 3 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - fill: { kind: 'bool-on', attr: 'fill' }, - fillColor: { kind: 'str', attr: 'fill-color', default: '#3388ff' }, - fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, -} satisfies Record; +const PROPS = defineProps({ + color: str('#3388ff'), + weight: num(3), + opacity: num(1.0), + fill: on(), + fillColor: str('#3388ff'), + fillOpacity: num(0.2), +}); export default class LeafletPolygon extends withProps(HTMLElement, PROPS) { #obj?: Polygon; diff --git a/src/components/leaflet-polyline.ts b/src/components/leaflet-polyline.ts index 353544e..60a5a56 100644 --- a/src/components/leaflet-polyline.ts +++ b/src/components/leaflet-polyline.ts @@ -4,17 +4,17 @@ import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; import type LeafletLine from './leaflet-line.ts'; -const PROPS = { - color: { kind: 'str', attr: 'color', default: '#3388ff' }, - weight: { kind: 'num', attr: 'weight', default: 3 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - fill: { kind: 'bool-on', attr: 'fill' }, - fillColor: { kind: 'str', attr: 'fill-color', default: '#3388ff' }, - fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, -} satisfies Record; +const PROPS = defineProps({ + color: str('#3388ff'), + weight: num(3), + opacity: num(1.0), + fill: on(), + fillColor: str('#3388ff'), + fillOpacity: num(0.2), +}); export default class LeafletPolyline extends withProps(HTMLElement, PROPS) { #obj?: Polyline; diff --git a/src/components/leaflet-popup.ts b/src/components/leaflet-popup.ts index f7d9a8b..4d11e74 100644 --- a/src/components/leaflet-popup.ts +++ b/src/components/leaflet-popup.ts @@ -2,18 +2,18 @@ import { Popup } from 'leaflet'; import { registerWithParent, buildOptions, numAttr } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; -import type { PropDef } from '../core/props.ts'; - -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; +import { defineProps, num, on } from '../core/props.ts'; + +const PROPS = defineProps({ + lat: num(), + lng: num(), + maxWidth: num(300), + minWidth: num(50), + maxHeight: num(), + autoPan: on(), + closeButton: on(), + autoClose: on(), +}); export default class LeafletPopup extends withProps(HTMLElement, PROPS) { #obj?: Popup; diff --git a/src/components/leaflet-rectangle.ts b/src/components/leaflet-rectangle.ts index 17f9beb..f6e788c 100644 --- a/src/components/leaflet-rectangle.ts +++ b/src/components/leaflet-rectangle.ts @@ -4,17 +4,17 @@ import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; import { isPathStyleAttr, updatePathStyle } from '../core/path-style.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - bounds: { kind: 'str', attr: 'bounds', default: '' }, - color: { kind: 'str', attr: 'color', default: '#3388ff' }, - weight: { kind: 'num', attr: 'weight', default: 3 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - fill: { kind: 'bool-on', attr: 'fill' }, - fillColor: { kind: 'str', attr: 'fill-color', default: '#3388ff' }, - fillOpacity: { kind: 'num', attr: 'fill-opacity', default: 0.2 }, -} satisfies Record; +const PROPS = defineProps({ + bounds: str(), + color: str('#3388ff'), + weight: num(3), + opacity: num(1.0), + fill: on(), + fillColor: str('#3388ff'), + fillOpacity: num(0.2), +}); export default class LeafletRectangle extends withProps(HTMLElement, PROPS) { #obj?: Rectangle; diff --git a/src/components/leaflet-svg-overlay.ts b/src/components/leaflet-svg-overlay.ts index ac76e97..a057c88 100644 --- a/src/components/leaflet-svg-overlay.ts +++ b/src/components/leaflet-svg-overlay.ts @@ -4,16 +4,16 @@ import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../co import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; - -const PROPS = { - bounds: { kind: 'str', attr: 'bounds', default: '' }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - interactive: { kind: 'bool-on', attr: 'interactive' }, - crossOrigin: { kind: 'str', attr: 'cross-origin', default: '' }, - zIndex: { kind: 'num', attr: 'z-index', default: 0 }, - className: { kind: 'str', attr: 'class-name', default: '' }, -} satisfies Record; +import { defineProps, num, str, on } from '../core/props.ts'; + +const PROPS = defineProps({ + bounds: str(), + opacity: num(1.0), + interactive: on(), + crossOrigin: str(), + zIndex: num(), + className: str(), +}); const PROP_BY_ATTR = buildAttrMap(PROPS); diff --git a/src/components/leaflet-tile-layer-wms.ts b/src/components/leaflet-tile-layer-wms.ts index 67db6a4..c1fc13a 100644 --- a/src/components/leaflet-tile-layer-wms.ts +++ b/src/components/leaflet-tile-layer-wms.ts @@ -3,17 +3,17 @@ import { buildOptions, buildAttrMap, setLayerAttr, parseAttributeValue } from '. import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; - -const PROPS = { - url: { kind: 'str', attr: 'url', default: '' }, - layers: { kind: 'str', attr: 'layers', default: '' }, - styles: { kind: 'str', attr: 'styles', default: '' }, - format: { kind: 'str', attr: 'format', default: 'image/jpeg' }, - transparent: { kind: 'bool-on', attr: 'transparent' }, - version: { kind: 'str', attr: 'version', default: '1.1.1' }, - uppercase: { kind: 'bool-on', attr: 'uppercase' }, -} satisfies Record; +import { defineProps, num, str, on } from '../core/props.ts'; + +const PROPS = defineProps({ + url: str(), + layers: str(), + styles: str(), + format: str('image/jpeg'), + transparent: on(), + version: str('1.1.1'), + uppercase: on(), +}); const PROP_BY_ATTR = buildAttrMap(PROPS); diff --git a/src/components/leaflet-tile-layer.ts b/src/components/leaflet-tile-layer.ts index 1d6595b..089ac45 100644 --- a/src/components/leaflet-tile-layer.ts +++ b/src/components/leaflet-tile-layer.ts @@ -3,16 +3,16 @@ import { buildOptions, buildAttrMap, setLayerAttr } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; - -const PROPS = { - url: { kind: 'str', attr: 'url', default: '' }, - attribution: { kind: 'str', attr: 'attribution', default: '' }, - minZoom: { kind: 'num', attr: 'min-zoom', default: 0 }, - maxZoom: { kind: 'num', attr: 'max-zoom', default: 18 }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - zIndex: { kind: 'num', attr: 'z-index', default: 0 }, -} satisfies Record; +import { defineProps, num, str } from '../core/props.ts'; + +const PROPS = defineProps({ + url: str(), + attribution: str(), + minZoom: num(), + maxZoom: num(18), + opacity: num(1.0), + zIndex: num(), +}); const PROP_BY_ATTR = buildAttrMap(PROPS); diff --git a/src/components/leaflet-tooltip.ts b/src/components/leaflet-tooltip.ts index d835b3d..3a463d5 100644 --- a/src/components/leaflet-tooltip.ts +++ b/src/components/leaflet-tooltip.ts @@ -3,18 +3,18 @@ import type { TooltipOptions } from 'leaflet'; import { registerWithParent, buildOptions, numAttr } from '../core/utils.ts'; import { withProps } from '../core/with-props.ts'; -import type { PropDef } from '../core/props.ts'; - -const PROPS = { - lat: { kind: 'num', attr: 'lat', default: 0 }, - lng: { kind: 'num', attr: 'lng', default: 0 }, - pane: { kind: 'str', attr: 'pane', default: '' }, - offset: { kind: 'str', attr: 'offset', default: '' }, - direction: { kind: 'str', attr: 'direction', default: 'auto' }, - permanent: { kind: 'bool-on', attr: 'permanent' }, - sticky: { kind: 'bool-on', attr: 'sticky' }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, -} satisfies Record; +import { defineProps, num, str, on } from '../core/props.ts'; + +const PROPS = defineProps({ + lat: num(), + lng: num(), + pane: str(), + offset: str(), + direction: str('auto'), + permanent: on(), + sticky: on(), + opacity: num(1.0), +}); export default class LeafletTooltip extends withProps(HTMLElement, PROPS) { #obj?: Tooltip; diff --git a/src/components/leaflet-video-overlay.ts b/src/components/leaflet-video-overlay.ts index 1ff1a64..91b67fb 100644 --- a/src/components/leaflet-video-overlay.ts +++ b/src/components/leaflet-video-overlay.ts @@ -4,20 +4,20 @@ import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../co import { withProps } from '../core/with-props.ts'; import { registerChildren, unregisterChildren } from '../core/register.ts'; -import type { PropDef } from '../core/props.ts'; +import { defineProps, num, str, on } from '../core/props.ts'; -const PROPS = { - url: { kind: 'str', attr: 'url', default: '' }, - bounds: { kind: 'str', attr: 'bounds', default: '' }, - opacity: { kind: 'num', attr: 'opacity', default: 1.0 }, - alt: { kind: 'str', attr: 'alt', default: '' }, - interactive: { kind: 'bool-on', attr: 'interactive' }, - crossOrigin: { kind: 'str', attr: 'cross-origin', default: '' }, - loop: { kind: 'bool-on', attr: 'loop' }, - autoplay: { kind: 'bool-on', attr: 'autoplay' }, - muted: { kind: 'bool-on', attr: 'muted' }, - playsInline: { kind: 'bool-on', attr: 'playsinline' }, -} satisfies Record; +const PROPS = defineProps({ + url: str(), + bounds: str(), + opacity: num(1.0), + alt: str(), + interactive: on(), + crossOrigin: str(), + loop: on(), + autoplay: on(), + muted: on(), + playsInline: on('playsinline'), +}); const PROP_BY_ATTR = buildAttrMap(PROPS); diff --git a/src/core/props.ts b/src/core/props.ts index 0769333..7aef835 100644 --- a/src/core/props.ts +++ b/src/core/props.ts @@ -31,3 +31,46 @@ export type PropTypeOf = T extends NumProp export type PropTypesFromTable> = { [K in keyof T]: PropTypeOf; }; + +// --- Factory helpers --- + +type OptionalAttr = Omit & { attr?: string }; + +type NumPropInput = OptionalAttr; +type StrPropInput = OptionalAttr; +type BoolOnPropInput = OptionalAttr; + +type PropDefInput = NumPropInput | StrPropInput | BoolOnPropInput; + +type PropDefFromInput = + T extends { kind: 'num' } ? NumProp + : T extends { kind: 'str' } ? StrProp + : BoolOnProp; + +function camelToKebab(s: string): string { + return s.replace(/[A-Z]/g, c => '-' + c.toLowerCase()); +} + +export function num(def: number = 0, attr?: string): NumPropInput { + return { kind: 'num', default: def, ...(attr ? { attr } : {}) }; +} + +export function str(def: string = '', attr?: string): StrPropInput { + return { kind: 'str', default: def, ...(attr ? { attr } : {}) }; +} + +export function on(attr?: string): BoolOnPropInput { + return { kind: 'bool-on', ...(attr ? { attr } : {}) }; +} + +export function defineProps>( + input: T, +): { [K in keyof T]: PropDefFromInput } { + const output = {} as Record; + for (const key of Object.keys(input)) { + const val = input[key] as PropDefInput; + const { attr: override, ...rest } = val as any; + output[key] = { ...rest, attr: override ?? camelToKebab(key) } as PropDef; + } + return output as any; +}