🪨 @benev/slate
🚧 prerelease wip under constructon subject to change
- frontend ui framework
- lit compatible, uses lit-html for templating
GoldElement
is a replacement for LitElementSilverElement
is just like GoldElement but for the light domShaleView
is a sophisticated view classFlat
is a state management systemPipe
is cool syntax for.. pipingOp
is a system for showing loading spinnersprepare_frontend
connects your components and views with app-level context and state management
👷 recommended setup
- install slate into your project
npm i @benev/slate
- establish a "context" for your app
import {css} from "lit"
import {BaseContext} from "@benev/slate"
export class Context extends BaseContext {
flat = new Flat()
theme = css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
`
}
- prepare your frontend
export const {component, components, view, views} = prepare_frontend<Context>()
- register all your components to the dom
import {register_to_dom} from `@benev/slate`
const context = new Context()
register_to_dom(components(context, {
MyElement,
AnotherElement,
WhateverElement,
}))
🥇 GoldElement
import {html, css} from "lit"
import {GoldElement} from "@benev/slate"
export const MyElement = component(context => class extends GoldElement {
static styles = css``
#state = context.flat.state({
count: 0,
})
#increment => () => {
this.#state.count++
}
#attrs = Attributes.setup(this as GoldElement, {
"example-string": String,
"example-number": Number,
"example-boolean": Boolean,
})
#views = views(context, {
MyView,
})
render() {
return html`
<p>count: ${this.#state.count}</p>
<button @click=${this.#increment}>increment</button>
${this.#views.MyView({props: [this.#state.count]})}
`
}
})
🥈 SilverElement
- it's just like
GoldElement
, except it's light dom (no shadow dom), and thus it cannot have its own stylesheet (relies on styling from above).
🗿 ShaleView
export const MyView = view(context => class extends ShaleView {
static name = "my-view"
static styles = css``
#state = context.flat.state({
count: 0,
})
#increment => () => {
this.#state.count++
}
#attrs = Attributes.setup(this as ShaleView, {
"example-string": String,
})
#views = views(context, {
SomeOtherView,
})
render(x: number) {
return html`<p>${x}</p>`
}
})
- views are very similar to components
- you can use all the same
#state
, #attrs
, #views
patterns as your components
- views even have their own shadow dom
- but they are not custom elements
- they don't need to be registered to the dom
- they do this cool thing called
auto_exportparts
- it automatically exports shadow parts across many shadow layers
- it's on by default
- you just give the view a
part
, and it will use that part as the prefix to any sub-parts - so each view auto exports any child parts
- so when you have a hierarchy of views, parts get exported all the way up to the top, and prefixed too, so you don't have name collisions
more utilities with new docs coming soon