Skip to content

yelouafi/mobx-static-dom

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Caution! this is isn't something ready for production; you may try it though in a side project

Getting starts

npm i --save mobx-static-dom

Simple Demo

Sandbox demo

import { h, p, on, render } from "mobx-static-dom";
import { observable } from "mobx";

const state = observable({
  count: 0
});

export const counterApp = h.h1(
  p.style("cursor: pointer"),
  () => `Count ${state.count}`,
  on.click(() => state.count++)
);

// assuming your html file contains an element with id="app"
render(counterApp, document.getElementById("app"));
  • Use h to create HTML elements
  • Use p to set DOM properties
  • Use on to attach event handlers
  • Use mobx to create observable values (values that will be changed by your app)
  • When createing HTML elements, wrap dynamic values in a function (() => state.count)
  • Call render to append the created element

Do not append the create elements directly to the parent DOM, it won't work

Dynamic lists of elements

Sandbox demo

import { h, p, on, map, render } from "mobx-static-dom";
import { observable, computed } from "mobx";

const state = observable({
  input: "",
  todos: []
});

function addTodo() {
  state.todos.push({ title: state.input, done: false });
  state.input = "";
}

export const todoApp = h.div(
  h.input(
    p.value(() => state.input),
    on.input(event => (state.input = event.target.value)),
    on.keydown(event => {
      if (event.which === 13) addTodo();
    })
  ),
  map(() => state.todos, todoView)
);

function todoView(todo) {
  return h.label(
    p.style(
      () => `
        display: block;
        text-decoration: ${todo.done ? "line-through" : "none"}`
    ),
    p.for("cb-done"),
    h.input(
      p.type("checkbox"),
      p.id("cb-done"),
      p.checked(() => todo.done),
      on.click(event => (todo.done = event.target.checked))
    ),
    () => todo.title
  );
}

render(todoApp, document.getElementById("app"));

Notes

  • Use map to render dynamic arrays
  • Event handlers are automatically wrapped with mobx actions

Local state

Sandbox demo

function panel(...children) {
  const state = observable({
    isContentVisible: true
  });

  function toggleContent() {
    state.isContentVisible = !state.isContentVisible;
  }

  return h.section(
    h.button(
      () => (state.isContentVisible ? "Hide content" : "Show content"),
      on.click(toggleContent)
    ),
    h.div(
      p.style(() => (state.isContentVisible ? visibleStyle : collapsedStyle)),
      ...children
    )
  );
}
  • Simply declare local state inside your function
  • Children elements are passed as ordinary function arguments

Simple router (dynamic element)

Sandbox demo

import { h, p, on, dynamic } from "mobx-static-dom";
import { observable } from "mobx";
import { createBrowserHistory } from "history";

export const history = createBrowserHistory();

export function router(config) {
  const state = observable({
    currentView: config(history.location.pathname)
  });

  history.listen((location, action) => {
    console.log(action, location.pathname, location.state);
    state.currentView = config(history.location.pathname);
  });

  // switch the current view
  return dynamic(() => state.currentView);
}

export function link(path, label) {
  return h.a(
    label,
    p.href("#"),
    on.click(event => {
      event.preventDefault();
      if (path === history.location.pathname) return;
      history.push(path);
    })
  );
}
  • Use dynamic to create dynamically changing HTML elements
  • Note the dynamic dierctive mounts a new instance of the wrapped element, so the internal state is gone when you switch back to the same element.

About

Dynamic UI using static DOM and mobx

Resources

License

Stars

Watchers

Forks

Packages

No packages published