Home

Awesome

Comfey StandWithUkraine RussianWarship Rate this package

SWUbanner

Comfey is a tiny data binding library inspired by React hook useState. Read more in Comfey Wiki

Features

Table of content

Install

Using NPM

npm install comfey

Using Yarn

yarn add comfey

Initialize component

Instantiate Comfey - optionally passing a DOMElement as root of the component. By default document will be used.

import Comfey from 'comfey';
const myComponent = new Comfey(document.getElementById('my-component'));

Initialize state

Use .useState() method to initialize a state, useState() accepts 3 parameters. Returns getter and setter functions

/**
 *
 * @param {string} state name of the state
 * @param {any} initialVal initial value
 * @param {function} watcher watcher function that will be called everytime the value of the state changes
 *
 * @returns {Array<[function, function]>} getterFunction and SetterFunction
 */

Example:

const [count, setCount] = app.useState('count', 3, countWatcher);

Watch

Watch gets newValue, oldValue and name of the state and is invoked everytime the state changes.

function countWatcher(newVal, oldVal, stateName) {
  // Do something when value of count state changes
}

Multi Apps

You can have any number of applications on a page. Instanciate a new Comfey whenever you need.

Example

// scoped code blocks can use same getters / setters, etc names if desired.
// name uniquely if needs to be in the same scope
(() => {
  const app = new Comfey(document.getElementById('app1'), COMFEY_DEBUG);
  const [, setActive] = app.useState('stateActive', false);

  setInterval(() => {
    setActive(Math.random() > 0.5);
  }, 1000);
})();

(() => {
  const app = new Comfey(document.getElementById('app2'), COMFEY_DEBUG);
  const [, setActive] = app.useState('stateActive', false);

  setInterval(() => {
    setActive(Math.random() > 0.5);
  }, 1000);
})();

More Multi App DEMOs

Templating

Bind state value to an element

Use data-bind attribute with stateName as its value to bind the innerHTML of the element to the state's value.

Visibility

Bind visible and hidden accepts value to compare.

Example

data-bind-visible="numberStatus::medium"

means the element will be visible if the state numberStatus is set to medium value.

Class

Bind class accepts value to compare, but will not interpolate the bound value as a classname.

Example

data-bind-class="currentPage::active::home"

means the element will get active class if the state currentPage is set to home value.

More bind-class DEMOs

Bind attributes

You can bind an attribute to a state's value w/ data-bind-attr. Data bind attributes can take values delimited by :: which will make each delimited string an argument. The argument pattern looks like

<state>::<dynamic-attr>::<value>

Example:

data-bind-attr="count::style::font-size: $rem"

means, a dynamic attribute will be added to the HTML element when the state count has a value, the attribute added will be style attribute and the value for the style attribute will be

font-size: <StateValue>rem

Examples

Counter Example

CodeSandbox

<div id="my-component">
  <div>
    Count:
    <span data-bind="count">
      <!--   This placeholder will be updated with value of count state -->
    </span>
  </div>
  <div>Show plus: <span data-bind="showPlus">x</span></div>
  <div>Hide minus: <span data-bind="hideMinus">x</span></div>
  <div class="buttons">
    <!--   Increment button will be visible if showPlus state is set to true   -->
    <button id="increment" data-bind-visible="showPlus">+</button>
    <button id="decrement" data-bind-hidden="hideMinus">-</button>

    <!-- Bind attribute, state :: attr :: value, $ for stateValue placeholder -->
    <button id="increment" data-bind-attr="disablePlus::disabled::">+</button>
    <div>
      Count:<span
        data-bind-attr="count::style::font-size: $rem"
        data-bind="count"
        >x</span
      >
    </div>
    <div>
      NumberStatus:
      <span data-bind-visible="numberStatus::medium">Medium</span>
      <span data-bind-visible="numberStatus::max">Max</span>
      <span data-bind-visible="numberStatus::min">Min</span>
    </div>
  </div>
</div>
import Comfey from 'comfey';
const app = new Comfey(document.getElementById('app'));

// Select buttons
const btnIncrement = document.getElementById('increment');
const btnDecrement = document.getElementById('decrement');

// Initialize states
const [, setShowPlus] = app.useState('showPlus', true);
const [, setHideMinus] = app.useState('hideMinus', false);
const [count, setCount] = app.useState('count', 3, countWatcher);

function countWatcher(newVal) {
  if (newVal > 4) {
    setShowPlus(false);
  } else {
    setShowPlus(true);
    if (newVal < 1) {
      setHideMinus(true);
    } else {
      setHideMinus(false);
    }
  }
}

// Button behaviours
btnIncrement.addEventListener('click', () => {
  setCount(count() + 1);
});
btnDecrement.addEventListener('click', () => {
  setCount(count() - 1);
});

Comfey - Pokemon buddy game

Codesandbox

Multi level navigation

Codesandbox