Skip to content

Latest commit

 

History

History
309 lines (210 loc) · 6 KB

README.md

File metadata and controls

309 lines (210 loc) · 6 KB

hyperviews

hyperviews is a template language that transforms to hyperscript.

Use it as a build tool with any h(tag, props, children) compliant framework e.g. React, preact or hyperapp.

const hv = require('hyperviews')

hv("<div id='foo'>{state.name}</div>")
// => h('div', { id: 'foo' }, (state.name))

Installation

npm i hyperviews

API

hyperviews(tmpl, mode, name, argstr)

  • tmpl (required) - The template string.
  • mode - The output format. Can be one of [raw, esm, cjs, browser], or if any other value is passed the function is exported as a variable with that name. The default is raw.
  • name - The default output function name. The default is view.
  • args - The default function arguments. The default is props state.

CLI

Reads the template from stdin,

cat examples/test.html | hyperviews --mode esm --name foo --args bar > examples/test.js

See more CLI examples

Template language

Interpolation

Use curly braces in attributes and text.

<div>
  <a class={state.class} href='http://www.google.co.uk?q={state.query}'></a>
  My name is {state.name} my age is {state.age} and I live at {state.address}
</div>

See more interpolation examples

Conditionals

There are two forms of conditional.

Using an if attribute.

<span if='state.bar === 1'>Show Me!</span>

Or using tags <if>, <elseif> and <else>

<div>
  <if condition='state.bar === 1'>
    <span>1</span>
  <elseif condition='state.bar === 2'>
    <span>2</span>
  <else>
    <span>bar is neither 1 or 2, it's {state.bar}!</span>
  </if>
</div>

if tags can be nested.

See more conditional examples

Iteration

The each attribute can be used to repeat over items in an Array. Three additional variables are available during each iteration: $value, $index and $target.

It supports keyed elements as shown here.

<ul>
  <li each='post in state.posts' key={post.id}>
    <span>{post.title} {$index}</span>
  </li>
</ul>

produces

h('ul', {}, (state.posts || []).map(function ($value, $index, $target) {
  const post = $value
  return h('li', { key: (post.id) }, h('span', {}, (post.title) + ' ' + ($index)))
}, this))

See more iteration examples

Events

<a href='http://example.com' onclick=this.onClick>{state.foo}</a>

produces this output

h('a', { href: 'http://example.com', onclick: this.onClick, (state.foo))

See more event examples

Style

The style attribute expects an object

<p style="{ color: state.color, fontSize: '12px' }"></p>

produces this output

h('p', { style: { color: state.color, fontSize: '12px' } })

Literal

The script tag literally outputs it's contents.

<script>
  import { h, Component } from 'preact'
  import MyComponent from './component.js'
</script>

This is also useful for recursive nodes, e.g. a tree

<if condition=state.children>
  <div>
    <a href='#{state.path}'>{state.name}</a>
    <ul>
      <li each='child in state.children'>
        <script>view(props, child)</script>
      </li>
    </ul>
  </div>
<else>
  <a href='#{state.path}'>{state.name}</a>
</if>

produces this output

function view (props, state) {
  return (function () {
    if (state.children) {
      return h('div', {}, [
        h('a', { href: '#' + (state.path) }, (state.name)),
        h('ul', {}, (state.children || []).map(function ($value, $index, $target) {
          var child = $value
          return h('li', {}, view(props, child))
        }))
      ])
    } else {
      return h('a', { href: '#' + (state.path) }, (state.name))
    }
  })()
}

See more literal examples

Function

The function tag outputs a function, returning it's contents. Supports name and args attributes.

<function name='MyComponent' args='x y z'>
  <div>{x}</div>
</script>

produces this output

function MyComponent (x, y, z) {
  return h('div', null, (x))
}

Components

Components are declared with if the tag starts with a capital letter.

<div>
  <MyComponent foo='bar' />
</div>

produces this output

h('div', null, h(MyComponent, { foo: 'bar' }))

Module example

How you structure your app is down to you. I like to keep js and html in separate files so a component might look like this:

  • MyComponent
    • view.html (The template file e.g. <div>{state.name}</div>)
    • view.html.js (The transformed h output of the file above)
    • index.js (Imports the transformed view and exports the component)

but if you want you could build entire modules in a html file like this:

<script>

  import { h, Component } from 'preact'

  export default class MyComponent extends Component {
    constructor (props) {
      super(props)
      this.render = view

      this.onSubmit = e => {
        e.preventDefault()
        // ...
      }
    }
  }

</script>

<function>
  <section>
    <form onsubmit=this.onSubmit>
      <input type=text name=text value={state.text} />
      <input type=text name=description value={state.description} />
    </form>
  </section>        
</function>

Compiles to

import { h, Component } from 'preact'

export default class MyComponent extends Component {
  constructor (props) {
    super(props)
    this.render = view

    this.onSubmit = e => {
      e.preventDefault()
    // ...
    }
  }
}

function view (props, state) {
  return h('section', null, h('form', { onsubmit: this.onSubmit }, [
    h('input', { type: 'text', name: 'text', value: (state.text) }),
    h('input', { type: 'text', name: 'description', value: (state.description) })
  ]))
}

More examples here

Using browserify? Then install the hyperviewify transform so you can simply require templates.

const view = require('./my-view.html')

npm i hyperviewify