Input bindings provide a two way binding between an HTML input element and an object property.
To declare an input binding, use the input key of the template node
and set it to a string identifying the property on the component.
In this example, the input text field will be initialized to the value
of userName and as the user edits the value, the userName property
will be updated.
class Main extends Component
{
    userName = "darth-vader";
    static template = [
        {
            type: "input type=text",
            input: "userName"
        },
        " ",
        {
            type: "button",
            text: "Show Value",
            on_click: c => alert(c.userName),
        }
    ]
}
Most input field types map from the input element's value property
directly to the object property value.
There are some exceptions:
boolean value and the input
field's checked property (and vice-versa)checked input element's value property to a single
string property value.  An input binding needs to be declared on each radio
button.<select> elements with the multiple option are mapped as an array of
strings - one entry for each selected option.Often you will want to update other displayed values when an input changes. One way to do this is to declare property accessors that invalidate the component.
This example reflects the value of the input field converted to upper-case.
class Main extends Component
{
    #userName = "darth-vader";
    get userName()
    {
        return this.#userName;
    }
    set userName(value)
    {
        this.#userName = value;
        this.invalidate();
    }
    static template = [
        {
            type: "input type=text",
            input: "userName"
        },
        {
            type: "span .output",
            text: c => c.userName.toUpperCase(),
        }
    ]
}
In the above examples, the input binding was targeted to a property of the component.
To target a sub-object of the component, use dotted notation:
class Main extends Component
{
    user = {
        name: "darth-vader",
        position: "Sith Lord",
    }
    static template =  [
        {
            type: "input type=text",
            input: "user.name"
        },
        {
            type: "input type=text",
            input: "user.position"
        },
        {
            type: "button",
            text: "Show Values",
            on_click: c => alert(JSON.stringify(c.user, null, 4))
        },
    ]
}
For more complex input bindings the value of the input key
needs to be specified as an object.
In the above examples, a simple string value was used as the
input binding target.  When using an options object, the property
name is declared using the prop key of the options object.
input: {
    prop: 'userName',
    // other settings here
}
eventNormally, input bindings trigger in response to the HTML input event giving
immediate updates when the user interacts with the input field.
The event option lets you choose a different trigger event.
eg: setting this to change will fire when the input value changes, but only
after the user leaves the field (not every keystroke)
    input: {
        prop: 'myField',
        event: "change" Trigger on "change" event instead of "input" 
    }
A callback to format a property value for display in an input field.
eg: to display a floating point value as a percentage with two decimal places:
class Main extends Component
{
    #percent = 1;
    get percent()
    {
        return this.#percent;
    }
    set percent(value)
    {
        this.#percent = value;
        this.invalidate();
    }
    static template = {
        type: "input type=number",
        input: {
            prop: 'percent',
            event: 'change',
            parse: v => parseFloat(v) / 100,
            format: v => (v * 100).toFixed(2).toString(),
        }
    }
}
get / setThe get and set input options let you completely replace the
default target.prop mapping with your own accessor functions.
These callbacks, will be invoked with the following parameters
get(model, ctx)set(model, value, ctx)Where
model is the template's model object (usually the component)ctx is the template's context object (not usually needed)value is the value received from the input field and to be
assigned/stored.    input: {
        get: (model) => model.myField,
        set: (model, value) => model.myField = value,
    }
on_changeThe on_change option specifies a callback to be invoked whenever the
input binding is triggered.
This could be used for example to invalidate a component when an input field changes.
    input: {
        prop: 'user.name',
        on_change: c => c.invalidate()
    }
This field is always called on_change - regardless of the actual underlying
HTML event (ie: input vs change).
A callback to convert the original value from the HTML input field to a format expected by the target property.
eg: if the target property must be an integer:
    input: {
        prop: 'count',
        parse: v => parseInt(v),
    }
propThe name of the property on the target object to bind to/from.
targetThe target option specifies the target object of the input
binding.  ie: the object whose prop is to be used.
eg: suppose you had a global appSettings object with a darkMode
setting, you could bind a checkbox like so:
import { appSettings } from "./appSettings.js"
class MyComponent extends Component
{
    static template = {
        type: "input type=checkbox",
        input: {
            prop: 'darkMode',
            target: appSettings,
        }
    }
}
The target property can also be a callback.
eg: in this contrived example, the checkbox would update the enabled
field on one of the objects in an array:
class MyComponent extends Component
{
    options = [{
        enabled: true,
    }];
    selectedIndex = 0;
    static template = {
        type: "input type=checkbox",
        input: {
            prop: 'enabled',
            target: c => c.options[c.selectedIndex],
        }
    }
}
When not specified, the template's context.model (usually the
component) is used.
When using a target property you can still use the dotted
notation on the prop field to access sub-objects.