-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Creating Web Apps
Following on from #2, the wool/browser package provide programs for creating websites and applications.
It uses the same underlying wool/ui package as wool/terminal and wool/native to describe the layout of its elements.
Programs
All these programs allow the website / app to be built into the html, css and javascript artifacts.
wool run hello/world build
wool/browser is a disappearing framework in a similar vein to Svelte. When compiled, the framework code that is required is embedded into your app and the rest is ditched.
It is a functional library, with a single store of state at the root and declarative view functions that describe how that state is presented.
Sandbox
A sandbox application can not communicate with the outside world but can react to user input.
interface Sandbox<Model, Msg> {
init: () => Model;
view: (model: Model) => UI.Layout;
update: (msg: Msg, model: Model) => Model;
}import * as Browser from 'wool/browser';
import { layout, el, text } from 'wool/ui';
export default Browser.sandbox({
init: () => {},
view: (model) => layout([], el([], text`Hello, World!`)),
update: (msg, model) => model,
});The syntax and functionality of
wool/uiis a separate work-in-progress.
Messages
Events are declaratively added to interactions, such as pressing a button. The event is given a message that will be passed into the program's update function. This can then be used to update the model. The new model is then passed into the view function to create the new view.
Custom types are discussed in #3
import * as Browser from 'wool/browser';
import { Maybe, Type } from 'wool/core';
import { Events, Input, layout, column, el, button, text } from 'wool/ui';
interface Model {
greeting: string;
}
const SetGreeting = Type.custom('SetGreeting', Type.string);
const init = (): Model => ({
greeting: 'Hello',
});
const view = ({ greeting }: Model) => layout(
[],
column([], [
text`${greeting}, World!`,
Input.button([], {
onPress: Maybe.just(SetGreeting('Bonjour')),
label: el([], text`Change greeting`),
}),
]),
);
const update = (msg, model) => Type.matchOn(msg, {
[SetGreeting]: (greeting) => ({ greeting }),
});
export default Browser.sandbox({ init, view, update });Application
An application provides access to the document head and url. Though a routed application is probably more useful.
interface Application<Model, Msg> {
init: (url: Url, key?) => Tuple<Model, Cmd<Msg>>;
view: (model: Model) => Document<Msg>;
update: (msg: Msg, model: Model) => Tuple<Model, Cmd<Msg>>;
onUrlRequest: (req: UrlRequest) => Msg;
onUrlChange: (url: Url) => Msg;
}
interface Document<Msg> {
head: { title: String };
body: UI.Layout;
}Routed Application
The routed application is a simplified application that handles routing for you. This is probably the ideal for most web apps.
interface RoutedApplication<Model, Msg> {
init: (url: Url, key?) => Tuple<Model, Cmd<Msg>>;
view: (model: Model) => Document<Msg>;
update: (msg: Msg, model: Model) => Tuple<Model, Cmd<Msg>>;
}It will populate your model with the updated route whenever it changes.
const init = () => {};
const update = (msg, model) => model;
const view = (model) => ({
head: [],
body: layout(
[],
Type.matchOn(model[Browser.routeKey], {
'/': () => el([], text`Welcome`),
'/with-params': ({ greeting }) => el([], text`${greeting}`),
}),
),
});
export default Browser.routedApplication({ init, update, view });Possible implementation of Browser.routedApplication
const RouteRequest = Type.custom('RouteRequest', Browser.Type.routeRequest);
const RouteChange = Type.custom('RouteChange', Browser.Type.routeChange);
const routeKey = Type.custom('routeKey', Type.string);
Browser.routedApplication = (config) => Browser.application({
init: () => ({
...config.init(),
[routeKey]: new Route('/'),
}),
view: config.view,
update: (msg, model) => {
case newModel = Type.matchOn(msg, {
[RouteRequest]: (req) => ({...model, route: req }),
[RouteChange]: (url) => model,
});
return {
...config.update(msg, newModel),
[routeKey]: newModel[routeKey],
};
},
onUrlRequest: (req) => RouteRequest(req),
onUrlChange: (url) => RouteChange(url),
});Questions
Extra programs?
This design borrows heavily from elm/browser, which provides two further programs: element and document.
The element program provides a way to embed an elm app within an existing webpage, which won't be needed with wool.
The document program is the same as the application but without the url routing. Is that useful? Or can users who want that just noop the url functions on application?