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

creme

v1.3.0

Published

Creme is a simple API for creating and managing DOM elements, built on top of Google's Incremental DOM.

Downloads

8

Readme

Crème

Creme is a simple API for creating and managing DOM elements, built on top of Google's Incremental DOM.

Creme works by encapsulating the Incremental DOM's rendering functions (e.g., elementVoid, elementOpen, patch, etc.) inside CremeElement objects, allowing users to express structure in a more hierarchical manner.

Example

var creme = require('creme');

var Greeting = creme.div({
  $id: 'greeting',
  'data-lang': 'en'
}, [
  creme.h1('Welcome!'),
  creme.p(creme.interpolate('Hello {name}!')),
  function(data) {
    if (data.username) {
      return creme.p('Your username is ' + data.username);
    }
    return creme.p('We don\'t know your username!');
  }
])

Greeting.patchInto(document.body, {name: 'Mark', username: 'keeto'});

/*
Renders:

<div id="greeting" data-lang="en">
  <h1>Welcome!</h1>
  <p>Hello Mark!</p>
  <p>Your username is keeto</p>
</div>
*/

Installation

$ npm install --save creme

CremeElements

Creme's main abstraction is the CremeElement, which is an object that contains properties and children. For example, you can create a div CremeElement like so:

var creme = require('creme');

var myDiv = creme.div('Hello World');

The creme.div function in the example above is an element factory, and Creme exposes factories for all the commons HTML elements. Once you have an element, you can "patch" an existing element's contents using the patchInto method:

var creme = require('creme');

var myDiv = creme.div('Hello World');

// Replace document.body's contents with <div>Hello World</div>
myDiv.patchInto(document.body);

Creating Custom CremeElement Factories

You can create a factory an element using the createElement function. The following example creates the same creme.div function above:

// createElement(tagName, isVoid) -> function(attribs, children)

var createElement = require('creme/lib/create_element');
var div = createElement('div', false);

var element = div('Hello World');

Attributes and Children

All element factories take in two optional arguments:

elementFactory(attributes, children) -> CremeElement
  • attributes is key-value map describing the attributes and properties of the element.
  • children could either be a string (representing a text node), an CremeElement created from a factory, or an array containing a mixture of both strings and CremeElement instances.

Special Attributes

When passing an object for the attributes argument, most of the fields are passed directly to the underlying Incremental DOM implementation. Creme, however, allows you to specify three special properties that affect how your element gets patched into a container.

$key and $static

The $key special attribute is used as a unique identifier for the element. Incremental DOM uses this value during its diff-ing process.

The $static special attribute must be key-value map of the static properties of an element. The value of these properties never change in-between renderings. Setting this attribute requires you to pass a $key as well.

var myInput = creme.input({
  $key: 'myInput',
  $static: {
    type: 'text'
  },
  disabled: true
});

// Renders <div type="text" disabled="true"></div>
myInput.patchInto(document.body);

$events

The $events attribute can be used to attach event listeners to the element. Internally, it calls addEventListener on the element.

var myInput = creme.input({
  $events: {
    focus: function(e) {
      // do something
    },
    blur: function(e) {
      // do something
    }
  }
});

If you need to add multiple event listeners, you can pass an array of listeners:

var myButton = creme.button({
  $events: {
    click: [
      function(e) {
        // Do something
      },
      function(e) {
        // Do something else
      }
    ]
  }
});

$ref

The special attribute $ref--when set to true--enables you to access a special property on CremeElement instances called node, which is a reference to the actual DOM node that was created.

The node property is dynamic: when your element is rendered, this property is updated to point to the rendered node. If your element is removed, this property is set to null. For elements without the $ref or $id attributes (see below), this will always be set to null.

Because the actual DOM element can change in between renderings, you should not store the value of the node property. Instead, it is adviced to access the property everytime you need to use it.

var myButton = creme.button({
  $ref: true
});


myButton.patchInto(document.body);

myButton.node; // <button>

$id

Since it's a common usecase to set the id property of an element as a $static attribute and as the value for $key, you can use the $id attribute to combine these two. The following declarations are similar:

// Using $key and $static separately
var div = creme.div({
  $key: 'my-id'
  $static: {
    id: 'my-id'
  }
});

var div = creme.div({
  $id: 'my-id'
})

The $id attribute also automatically sets the $ref attribute to true:

var myButton = creme.button({
  $id: 'my-button'
});


myButton.patchInto(document.body);

myButton.node; // <button>

$computed

The $computed special attribute is a key-value map of properties that will be computed during rendering time.

var myInput = creme.input({
  $computed: {
    value: function(data) {
      return data.confirmed ? 'Yes' : 'No';
    }
  }
});

// Renders <input value="Yes">
myInput.patchInto(document.body, {confirmed: true});

// Renders <input value="No">
myInput.patchInto(document.body, {confirmed: false});

Working with Data

Aside from $computed attributes, you can also have computed children for your elements.

Aside from strings, CremeElement instances and arrays, the children parameter element factories can also take in functions. These functions are similar to the functions for $computed properties, and are called during rendering time with the data that was passed with patchInto.

var greeting = creme.div(
  creme.p(function(data) {
    return 'Hello ' + data.name + '!';
  })
);

// Renders <div><p>Hello World!</p></div>
greeting.patchInto(document.body, {name: 'World'});

Functions allow for thing like conditional statements:

var greeting = creme.div([
  creme.h1('Welcome!'),
  function(data) {
    if (data.name) {
      return creme.p('Hello ' + data.name + '!');
    }
    return creme.p('Hello visitor! Welcome to the site!');
  }
]);

greeting.patchInto(document.body, {name: null});
/*
Renders:

<div>
  <h1>Welcome!</h1>
  <p>Hello visitor! Welcome to the site!</p>
</div>
*/

Functions can return strings, CremeElement instances and even more functions. Returning an array from the function will render each of the elements inside the array.

var myList = creme.ul(function(data) {
  return data.todos.map(function(todo, index) {
    return creme.li({$key: index.toString()}, todo);
  });
});

myList.patchInto(document.body, {
  todos: ['Walk the dog.', 'Get milk.']
})
/*
Renders:
<ul>
  <li>Walk the dog.</li>
  <li>Get milk.</li>
</ul>
*/

Interpolation

String interpolation is a common usecase for render-time functions. Creme has a helper interpolation module that creates an interpolator function so you don't have to write one yourself:

var creme = require('creme');
var interpolate = require('creme/lib/interpolate');

var div = creme.div({
  $computed: {
    'class': interpolate('{className}')
  }
}, [
  creme.p(interpolate('Your name is {user.name}.')),
  creme.p(interpolate('You are {user.age} years old.'))
]);

div.patchInto(document.body, {
  className: 'user-info',
  user: {
    name: 'Keeto',
    age: 23
  }
});
/*
Renders:

<div class="user-info">
  <p>Your name is Keeto.</p>
  <p>You are 23 years old.</p>
</div>
*/

About

Copyright 2016, Mark "Keeto" Obcena. Released under the MIT License.