npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

punybind

v1.2.1

Published

A minimalist binding helper

Downloads

3,516

Readme

punybind 🦴

Node.js CI Mutation Testing Package Quality Known Vulnerabilities punybind punybind install size MIT License

A minimalist (2889 bytes) one-way binding helper.

Usage

1. Include the punybind helper

<script src="https://cdn.jsdelivr.net/npm/punybind/dist/punybind.js"></script>

2. Define bindings in the HTML

<html>
  <head>
    <title>TODO list</title>
  </head>
  <body>
    <h1>{{ title }}</h1>
    <ul>
      <li
        {{for}}="item of items"
        class="todo{{ item.done ? ' done' : '' }}"
      >{{ item.text }}</li>
    </ul>
  </body>
</html>

See below for supported syntaxes.

3. Bind the section

const update = await punybind(document.body)

The update asynchronous method exposes the following properties :

  • bindingsCount (number) : The number of bindings detected
  • model (object) : The reactive model (see below)
  • done (function) : Returns a promise being fulfilled when the last update completes (see below).

Upon update invocation, the returned promise is fulfilled when the DOM update is completed.

4. Update the section by passing a context object

await update({
  title: 'My TODO list',
  items: [{
    done: true,
    text: 'Forget about heavy frameworks'
  }, {
    done: false,
    text: 'Adopt punybind'
  }]
})

Or use the reactive model (see below).

5. Enjoy !

Supported syntaxes

Text and attribute binding

Text nodes and attribute values leverage binding using the {{ expression }} syntax.

The expression is evaluated with the properties of the contextual object.

It is possible to mix static content with computed one but any error clears the whole value.

Iterators

Iterators allow the repetition of elements.

An iterator is declared on the element to repeat using the special attribute {{for}} with the value being either :

  • {{for}}="item of expression"
  • {{for}}="item, index of expression"

Where :

  • item is the contextual property receiving the value of the current iteration (to use in the subsequent bindings),
  • index is the contextual property receiving the index of the current iteration (0-based),
  • expression must evaluate to an iterable object.

Conditionals

Conditionals rule the rendering of elements.

They can form an if / elseif / else chain. Their expression must evaluate to a truthy value to enable rendering.

To work properly, the attributes must be set on contiguous sibling elements :

  • {{if}}="expression" : must be the first element of the chain,
  • {{elseif}}="expression" : (optional) is evaluated and rendered only if the previous if / elseif did not evaluate to a truthy value,
  • {{else}} : (optional) terminates the chain and is rendered only if the previous if / elseif did not evaluate to a truthy value.

Reactive model

const { model, done } = await punybind(document.body, {
  title: 'Hello World !',
  items: []
})
console.log(model.title) // Hello World !
// The following lines of code trigger updates
model.title = 'My TODO list'
model.items.push({
  done: false,
  text: 'Adopt punybind'
})
await done() // Wait for the DOM update to be completed

Customizing

It is possible to tweak some settings with punybind.use, for instance :

// see https://www.npmjs.com/package/punyexpr
const safebind = punybind.use({
  compiler: punyexpr
})
// safebind offers the same features as punybind
const { model, done } = await safebind(document.body, {
  title: 'Hello World !',
  items: []
})

Available options :

  • compiler: (expression: string) => (context: object) => any
    • Function that compiles the expression and return a function that evaluates it with the given context. Default compiler uses an eval-like syntax.

Implementation notes

  • The default expression compiler implementation is not compliant with Content Security Policy.
  • Only properties coming from the contextual object can be used in evaluated expressions.
  • Bound elements are hidden under template elements.
  • When any error occurs (inconsistent binding, invalid syntax), the binding silently fails.