Lit is a great library but its js api is kinda messed up. I made a version of lit that is optimized to build things rapidly without ts.
- tag name is automatically set to the class name in kebab case
- global state with simple syntax and automatic subscription
- declare reactive properties and set defaults in the same place
- (no shadow dom by default (just add
static shadow = true))
let's look at the syntax it gives us
import { VLitElement, html, init } from "./vlit.js"
// global state
const state = init({
s: 2,
})
class MyMain extends VLitElement {
r(state) {
return html`
<my-pair></my-pair>
<my-pair></my-pair>
<my-pair></my-pair>
`
}
}
MyMain.done
class MyPair extends VLitElement {
static props = () => ({ k: 0 })
r(state) {
return html`
<button @click=${e => this.k++}>prop ${this.k}</button>
<button @click=${e => state.s++}>state ${state.s}</button> <br />
`
}
}
MyPair.doneprobable faqs:
-
why
rand notrender?rendermethod will return a call ofrmethod but with thestateargument which is used for global state. -
where are Property options?
they're still there instatic propertiesbut you can also write it withprops. it defines a default reactive properties with{}but if if you have options already inpropertiesthey won't be overwritten. -
what is the
stateargument? and whyr?
the argument is a proxy which will give you whatever you would got from the real state (which can be used by importing. alsoinitsets and returns to this state) but it will record whatever you used inrender. here we usestate.sfrom the argument so it knows that this component uses the states. but if we'd just importstateand use it then the result would be correct but changing the state wouldn't refresh the component. -
I want my shadow back
static shadow = true -
why the
.donetho?
this getter will define the dynamic properties frompropsand define the tag. so you must.doneafter defining a class.(also makes the class observe the old way manually defined state in
props) (currently no way to pass other arguments tocustomElements.define())
VLitElement is also exported as V and html is exported as v if you're
a lazy typer or don't want a 4 letter prefix when using in template literals
the older version of vlit used manual subscription for state. if you need to
define render rather than the wrapper r, it's possible this way or get the
automatic subscribing state in render simply by this.state or
const { state } = this.
import { VLitElement, html, state } from "./vlit.js"
class MyPair extends VLitElement {
static props = ({
s, // observes global state
}) => ({
k: 0, // reactive property
})
render() {
return html`
<button @click=${e => this.k++}>prop ${this.k}</button>
<button @click=${e => state.s++}>state ${state.s}</button> <br />
`
}
}
MyPair.done-
how does this
({ s }) => ({ k: 0 })weird syntax work?
the one before arrow is argument deconstruction. a proxy is given as an argument and this way you are deconstructing the propertysfrom it. if we'd write it with a traditional arguments that'd be like:proxy => { let s = proxy.s return { k: 0 } }
or we also could use
let { s } = proxy. the point here is to signal that this element usessfrom state. the most straightforward way would be an array of strings["s"]but we can use shiny JavaScript features to make it a bit more appealing and easy to write and read. the return object's properties will be assigned to the element one-by-one so you don't have to write the properties in the constructor again.- should I deconstruct what properties of state the element observes?
no. if the parent element hassthen all its inherited classes will update whenstate.sis set. but for the default properties yes you should. the best way is to make another function and use .
- should I deconstruct what properties of state the element observes?
I know it's a bit disgusting to see deconstructed properties from an argument that aren't gonna be used but I just didn't want to write observing state property names just in strings. Indeed it does look elegant to me - being before the default property values and it has no default cuz uses the global. also it's recommended to use first way with automatic subscription.