lit-tea
v0.2.0-rc-2
Published
An implementation of The Elm Architecture in Typescript, defaults with lit-html.
Downloads
2
Readme
lit-tea
An implementation of The Elm Architecture in typescript, using lit-html to render the view.
The idea is to make spinning up a frontend app fast, easy, and reliable. It shouldn't be hard to add new functionality to an app, and whenever possible we should get compile time or linting checks when refactoring or adding new features. Elm gives a superb developer experience in this regard to maintenance, but there is at least some of that we can get with Typescript - and so this package is born!
Quick start
You can quickly get going with a yo generator:
# ensure you have yo available, and the lit-tea generator
npm i -g yo generator-lit-tea
# make a dir and invoke the generator
mkdir my-lit-app
cd my-lit-app
yo lit-tea my-lit-app
Then you'll have a fully workable app.
code . # if you have VSCode
npm start
Edit index.html
or src/index.ts
and parcel will do its magicks.
How to use
Code from examples/simple-counter.ts
.
import { html } from 'lit-html';
import { run, Dispatcher } from 'lit-tea';
type Msg = { incr: number }
const INC: Msg = { incr: 1 };
const DEC: Msg = { incr: -1 };
type Model = {
counter: number
}
type MsgHandler = (d: Dispatcher<Msg>) => void;
const increment: MsgHandler = dispatch => dispatch(INC);
const decrement: MsgHandler = dispatch => dispatch(DEC);
run<Model, Msg>({
init: { counter: 0 },
update: (model, msg) => ({
...model,
counter: model.counter + msg.incr
}),
view: (model, dispatch) =>
html`
<h2>${model.counter}</h2>
<div>
<button @click=${increment(dispatch)}>+1</button>
<button @click=${decrement(dispatch)}>-1</button>
</div>
`
});
ADT Message Type
Typescript has two compiler flags, noFallthroughCasesInSwitch
and strictNullChecks
, which enable exhaustive switch statements. Together with unions, we can get very close to Elm's way of defining messages and update functions.
Code from examples/adt.ts
(TODO - use remote data fetching example).
import { html } from 'lit-html';
import { run, View, Update } from '../src'
// MODEL - application state
type Model = {
saying: string,
itrs: number
}
const init: Model = {
saying: 'hello',
itrs: 50
};
// MESSAGES - application transitions
type NewSaying = {
tag: 'NewSaying',
value: string
}
const mkNewSaying = (newSaying: string): NewSaying => ({
tag: 'NewSaying',
value: newSaying
});
type Noop = {
tag: 'Noop'
}
type Msg =
NewSaying
| Noop
// UPDATE - transform the model with the incoming message
const update: Update<Model, Msg> = (model, msg) => {
switch (msg.tag) {
case "NewSaying":
return { ...model, saying: msg.value};
case "Noop":
return model;
}
}
// VIEW - dat sweet html
const view: View<Model, Msg> = (model, dispatcher) => {
const nextSaying = model.saying === 'hello' ? 'ahoy' : 'hello';
const onBtnClick = () =>
dispatcher(mkNewSaying(nextSaying));
return html`
<section>
<p>Well, it is ${model.saying}</p>
<button @click=${onBtnClick}>Change it</button>
</section>
`;
}
// APP - tyingit all together
run({ init, update, view });
Publishing
This project is built with Typescript, and is configured to compile to the /dist
folder. We copy the package.json
into the dist folder and publish from there.