Tweakit v0.7.2

Markup

The second way in: write [data-twk] markup and enhance() upgrades each host into a live control in place. Importing tweakit binds nothing by itself. Import tweakit/auto instead, the same API, and it runs enhance(document) once the page has parsed; this page does, so the first three examples are plain HTML, no page script at all. Or call enhance() yourself, for the whole page or for DOM added later.

A static panel shell

A .twk-panel shell with [data-twk] hosts inside becomes the real thing: collapsible header, copy + reset toolbar operating over its controls, the works. Each control writes its live value back onto its host's data-value attribute. A data-key names the control in the toolbar's copied JSON (and stands in for a missing data-label); without one, the label is the key.

Static
<div class="twk-panel" data-mode="inline" style="max-width: 300px">
  <div class="twk-header"><span class="twk-title">Static</span></div>
  <div class="twk-controls">
    <div data-twk="slider" data-label="Blur" data-value="12" data-min="0" data-max="40" data-unit="px"></div>
    <div data-twk="checkbox" data-label="Visible" data-checked="true"></div>
    <div data-twk="list" data-label="Blend" data-options="normal, multiply, screen" data-value="normal"></div>
  </div>
</div>

Heavy controls from markup

Most controls work declaratively: their config flattens into data-* attributes, and the lazy ones load on demand exactly as they do from a schema. Markup understands slider, number, checkbox (with data-options it becomes a radio grid), radiogrid (or segmented), list, text, color, gradient, image, button, buttongroup, separator, interval, spring, cubicbezier, motion, shadow, sides, point, plot, monitor and fpsgraph, plus the folder wrapper below. An image with data-options, a comma list of URLs, is the gallery. tabs is panel-only; a host naming it is left untouched.

Heavy
<div class="twk-panel" data-mode="inline" style="max-width: 300px">
  <div class="twk-header"><span class="twk-title">Heavy</span></div>
  <div class="twk-controls">
    <div data-twk="color" data-label="Tint" data-value="#7C5CFF"></div>
    <div data-twk="spring" data-label="Motion" data-stiffness="220" data-damping="18" data-mass="1"></div>
    <div data-twk="point" data-label="Offset" data-components="X,Y" data-value="0,0" data-min="-50" data-max="50" data-pad="true"></div>
    <div data-twk="interval" data-label="Band" data-value="30,70" data-min="0" data-max="100" data-step="1"></div>
  </div>
</div>

Bare hosts, anywhere

Hosts don't need a panel shell: a [data-twk] div in any layout enhances in place (a data-hint rides along as the ⓘ tooltip). A data-twk="folder" wraps its children in a collapsible group.

<div style="max-width: 300px">
  <div data-twk="folder" data-label="Inline anywhere">
    <div data-twk="slider" data-label="Speed" data-value="1.5" data-min="0" data-max="3" data-step="0.1"
         data-hint="Just a div in the page"></div>
    <div data-twk="radiogrid" data-label="Size" data-options="S, M, L, XL" data-cols="2" data-value="M"></div>
  </div>
</div>

Listening for changes

Every edit on a host writes its data-value and dispatches a bubbling twk:change event with { key, value } in detail (key is the host's data-key, or its label), so one listener on an ancestor hears every control under it. The host also keeps its handle at host._tw.ctrl: get() reads the value and set(v) applies one and runs the same change path (data-value + event). Drag the slider, then hit the button.

Observed
Change something
const log = target.querySelector(".mk-log");
target.addEventListener("twk:change", (e) => {
  log.textContent = e.detail.key + " → " + JSON.stringify(e.detail.value) + "  (data-value=" + e.target.dataset.value + ")";
});
enhance(target).then(() => {
  const host = target.querySelector("[data-twk]");
  target.querySelector(".mk-set").addEventListener("click", () => host._tw.ctrl.set(Math.round(Math.random() * 40)));
});

Binding on load, or yourself

tweakit/auto covers the document as it parsed. Without it, call enhance(), which binds the whole document by default. For markup you inject later (a modal, a CMS block, a partial render), call it on the new root, which counts too when it is itself a [data-twk] host. Hosts that are already live are skipped, so re-running is safe. With the single-file build and no bundler, the same call goes in your module script: import { enhance } from "./tweaks.js"; enhance();

import "tweakit/auto";   // binds the page's [data-twk] hosts once it has parsed

// or, from tweakit or tweakit/single:
import { enhance } from "tweakit";

await enhance();         // the whole document
modal.innerHTML = controlsMarkup;
await enhance(modal);    // resolves once any lazy modules have loaded