Superfine

Minimal view layer for creating declarative web user interfaces

Github星跟蹤圖

Superfine npm

Superfine is a minimal view layer for building web interfaces. Think React without the framework—no flux, hooks, or components—just the bare minimum to survive. Mix it with your favorite state management solution, or use it standalone for maximum flexibility.

Quickstart

Install Superfine with npm or Yarn:

npm i superfine

Then with a module bundler like Parcel or Webpack, import what you need and start using it in your project.

import { h, patch } from "superfine"

Fear the build step? Import Superfine in a <script> tag as a module. Don't worry; modules are supported in all evergreen, self-updating desktop, and mobile browsers.

<script type="module">
  import { h, patch } from "https://unpkg.com/superfine"
</script>

How about we start with something simple: let's create a counter that can go up or down. You can copy and paste the following code in a new HTML file or go ahead and try it here.

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module">
      import { h, patch } from "https://unpkg.com/superfine"

      const node = document.getElementById("app")

      const setState = state => {
        patch(
          node,
          h("div", {}, [
            h("h1", {}, state),
            h("button", { onclick: () => setState(state - 1) }, "-"),
            h("button", { onclick: () => setState(state + 1) }, "+")
          ])
        )
      }

      setState(0) // Start app with initial state.
    </script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

The hyperscript function h describes our view as a tree of nodes. The view isn't made out of real DOM nodes, but a virtual DOM: a representation of how the DOM should look using a plain object.

The patch function updates the DOM to match our view. By comparing the old and new virtual DOM we can patch only the parts of the DOM that changed instead of rendering the entire document from scratch. Profit!

The next example uses the same custom setState approach to show a heading syncronized to a text field (try it here).

<script type="module">
  import { h, patch } from "https://unpkg.com/superfine"

  const node = document.getElementById("app")

  const setState = state => {
    patch(
      node,
      h("div", {}, [
        h("h1", {}, state),
        h("input", {
          type: "text",
          value: state,
          oninput: e => setState(e.target.value),
          autofocus: true
        })
      ])
    )
  }

  setState("Hello!")
</script>

Spend some time thinking about how the view reacts to changes in the state. Rather than anonymous state updates, how about dispatching messages to a central store a-la Elm/Redux? Let's work on that next (or try it here).

<script type="module">
  import { h, patch } from "https://unpkg.com/superfine"

  const start = ({ init, view, update, node }, state) => {
    const setState = newState => {
      state = newState
      node = patch(node, view(app))
    }
    const app = {
      dispatch: name => setState(update(state, name)),
      getState: () => state
    }
    setState(init())
  }

  start({
    init: () => 0,
    view: app =>
      h("div", {}, [
        h("h1", {}, app.getState()),
        h("button", { onclick: () => app.dispatch("DOWN") }, "-"),
        h("button", { onclick: () => app.dispatch("UP") }, "+")
      ]),
    update: (state, msg) =>
      msg === "DOWN" ? state - 1 : msg === "UP" ? state + 1 : 0,
    node: document.getElementById("app")
  })
</script>

Why init instead of state, or update rather than actions is not important. Moving start to a different module would be a good idea too, but having it all in the same file helps to see the big picture.

Now it's your turn to take Superfine for a spin. If you get stuck and need help, please file an issue, and we'll try to help you out. In particular, the Hyperapp Slack is a great way to get help quickly. Looking for more examples? Here you go.

Attributes

Superfine nodes can use all your favorite HTML attributes, SVG attributes, DOM events, and also keys.

Keys

Keys help identify nodes whenever we update the DOM. By setting the key property on a virtual node, you declare that the node should correspond to a particular DOM element. This allows us to re-order the element into its new position, if the position changed, rather than risk destroying it. Keys must be unique among sibling nodes.

Warning: Keys are not registered on the top-level node of your view. If you are toggling the top-level view, and you must use keys, wrap them in an unchanging node.

import { h } from "superfine"

export const ImageGallery = images =>
  images.map(({ hash, url, description }) =>
    h("li", { key: hash }, [
      h("img", {
        src: url,
        alt: description
      })
    ])
  )

API

h(name, props, children)

Create virtual DOM nodes. h takes three arguments: a string that specifies the name of the node; an object of HTML or SVG properties, and array of child nodes (or a string for text nodes).

const link = h("div", { class: "container" }, [
  h("a", { href: "#" }, "Click Me")
])

patch(node, vdom)

Render a virtual DOM. patch takes a DOM node, a virtual DOM, and returns the updated DOM node.

const main = patch(document.getElementById("main"), h("h1", {}, "Superfine!"))

License

MIT

主要指標

概覽
名稱與所有者jorgebucaran/superfine
主編程語言JavaScript
編程語言JavaScript (語言數: 1)
平台
許可證MIT License
所有者活动
創建於2017-05-19 12:53:23
推送於2022-08-16 03:08:33
最后一次提交
發布數45
最新版本名稱8.2.0 (發布於 2021-02-09 02:14:36)
第一版名稱0.0.8 (發布於 )
用户参与
星數1.6k
關注者數55
派生數78
提交數307
已啟用問題?
問題數116
打開的問題數3
拉請求數36
打開的拉請求數2
關閉的拉請求數33
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?