/nclearseam

front-end templating for Nim with direct DOM modification and no specific syntax

Primary LanguageHTML

nclearseam

This is a templating library targetting javascript in browsers. The aim is to keep it just a library, not make it into a full framework, and to get out of your way. It also aims to be fast and avoids complexities of Virtual DOMs. It gets inspiration from Svelte.js for that well as Weld, PureJS and my own Clearseam for the syntax.

Key features:

  • lightweight, library only
  • be fast, avoids Virtual DOM by patching only the required part of the browser DOM when necessary. Uses the same technique as Svelte.js.
  • No extra syntax to learn, uses plain HTML <template> elements with a mapping between the dataset and the elements that you provide
  • No extra selectors to learn, uses plain CSS and Nim language for the mapping
  • Full control over what you do to the DOM nodes (HTML attributes, Javascript properties, event handlers or anything you can think of)

Rationale is explained in docs/svelte_with_nim.md.

Warning: this is a very young project, use at your own risks

Example

Note: Samples might be out of date, check external projects too.

Templating is always the combinaison of three factors: the HTML markup, the data (generally JSON, but it's generic) and the mapping.

You can also view live examples:

  • Sample 1: basics and iteration (JSON dataset)
  • Sample 2: mounting other components (JSON dataset)
  • Sample 3: using something else than JSON for data
  • Sample 4: Event handlers

See real world examples:

Hello World

Simple example with two-way binding.

<template>
  <h1>hello <span class="name"></span>!</h1>
  <p>Please enter your name: <input type="text" name="name" /></p>
</template>
type Data = ref object
  name: string

let data = Data(name: "John")
var t = create(Data) do(t: auto):
  t.match("h1 .name", t.access->name).refresh(setText)
  t.match("[name=name]", t.access->name).refresh(bindValue(string))

Iterations

<template>
  <ul>
    <li>item: <span class="name"></span></li>
  </ul>
</template>
{
  "items": ["Apple", "Orange", "Kiwi"]
}
var t = create(JsonNode) do(t: auto):
  t.iter("ul li", jsonIter("items")) do(item: auto):
    item.match(".name").refresh do(node: dom.Node, data: JsonNode):
      node.textContent = $data

Mounting components

<template>
  <div class="placeholder"></div>
</template>
{
  "placeholder-data": {}
}
var t = create(JsonNode) do(t: auto):
  t.match("div.placeholder", get("placeholder-data")) do(placeholder: auto):
    placeholder.mount(other_component)

Use it

This is very experimental still, use at your own risks.

  • see examples, you can rebuild samples with:

    nim js samples/sample1
  • copy a sample elsewhere and build it the same way

  • try it in a browser by spawining a simple HTTP server:

    python -m http.server 8000
    xdg-open http://localhost:8000/samples/sample1.html

Develop

Generate documentation (requires at least version from 2020-05-09 for the --backend option):

nim doc --backend:js svelte