JSPM

trans-render

0.0.12
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 685
  • Score
    100M100P100Q113158F
  • License MIT

TBD

Package Exports

  • trans-render

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (trans-render) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

trans-render

Published on webcomponents.org

trans-render provides an alternative way of instantiating a template. It draws inspiration from the (least) popular features of xslt. Like xslt, trans-render performs transforms on elements by matching tests on elements. Whereas xslt uses xpath for its tests, trans-render uses the css matches() method.

XSLT can take pure XML with no formatting instructions as its input. Generally speaking, the XML that XSLT acts on isn't a bunch of semantically meaningless div tags, but rather a nice semantic document, whose intrinsic structure is enough to go on, in order to formulate a "transform" that doesn't feel like a hack.

Likewise, with the advent of custom elements, the template markup will tend to be much more semantic, like XML. trans-render tries to rely as much as possible on this intrinisic semantic nature of the template markup, to give enough clues on how to fill in the needed "potholes" like innerText's and property setting. But trans-render is completely extensible, so it can certainly accommodate custom markup (like string interpolation, or common binding attributes) by using additional, optional helper libraries.

This leaves the template markup quite pristine, but it does mean that the binding instructions will tend to require looking in two places, rather one.

The transform can be provided in the function "init". If the transform is not present in the call, then it looks for a script tag with attribute "transform" where it expects the instructions.

One distinct advantage of separating the binding like this, is that one can insert console.log's and/or breakpoints, in order to walk through the binding process.

Syntax:

<template id="test">
    <detail>
        <summary></summary>
    </detail>
    <script transform>
        ({
            'detail': i => {
                i.ctx.matchFirstChild = true;
            },
            'summary': i => {
                i.target.textContent = i.ctx.model.summaryText;
            },
        })
    </script>
</template>
<div id="target">

</div>
<script type="module">
    import { init } from '../trans-render-init.js';
    const ctx = {
        model: {
            summaryText: 'hello'
        }
    };
    init(test, ctx, target);
</script>

Produces

<div id="target">
    <detail>
        <summary>hello</summary>
    </detail>
</div>

"ctx" stands for "context", a place to pass things throughout the processing process. "target" is the HTML element we are populating.

The transform script can also be nested, and it should be noted that the matches() function works with *. So the transform above could be mofied to:

<template id="test">
    <detail>
        <summary></summary>
    </detail>
    <script transform>
        ({
            '*': ({ctx}) => {
                ctx.matchFirstChild = {
                    '*': ({target, ctx}) => {
                        target.textContent = ctx.model.summaryText;
                    },
                };
            },

        })
    </script>
</template>

By design, trans-render is loathe to do any unnessary work. Each transform can specify whether to proceed to the next sibling:

cts.matchNextSib = true;

And/or it can specify to match the first child:

cts.matchFirstChild = true;

These match statements can either be booleans, as illustrated above, or they can provide a new transform match:

<script transform>
    ({
        '.opening': ({ target, ctx }) => {
            ctx.init(Opening, Object.assign({}, ctx), target);
            ctx.matchFirstChild = true;
        },

        'div': ({ ctx }) => {
            ctx.matchFirstChild = {
                'span.Friday': ({ target, ctx }) => {
                    ctx.init(Friday, {}, target);
                },
                'span[x-d]': ({ target, ctx }) => {
                    target.textContent = ctx.interpolate(target.innerText, ctx);
                },
                '*': ({ ctx }) => {
                    ctx.matchNextSib = true;
                },

            };
            ctx.matchNextSib = true;
        },


    })
</script>

Use Case 1: Applying the DRY principle to (post) punk rock lyrics

Example 1a (only viewable at webcomponents.org )

Example 1b (only viewable at webcomponents.org )