Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/yairEO/knobs

UI knobs controllers for JS/CSS live manipulation of various parameters
https://github.com/yairEO/knobs

Last synced: about 2 months ago
JSON representation

UI knobs controllers for JS/CSS live manipulation of various parameters

Awesome Lists containing this project

README

        





Knobs











Knobs 🎛️ UI controllers for JS/CSS manipulation


👉 Demo 👈







Minified
54kb


Brotli
13.5kb


GZIP
15kb




What is this:



Started as something I needed for my many Codepens - A way to provide viewers, and myself, a set
of controllers, for manipulating the DOM instantaneously.



Imagine certain aspects of a web page, or a specific *component*, which you would like to add the ability
to control on-the-fly. Change the visual looks or certain javascript parameters with a move or a slider.



CSS-variables (custom properties) are a great match for this script as they compute in real-time. Javascript is of course a benefitor because every knobs can be attached with a callback that recieves the current value, and additional data, as to what that value should be applied on.



It's so easy & quick to use Knobs, about 1 minute!


⚠️ Supported only in modern browsers


### Features:

* `range` input (*wheel*-supported)
* `color` input with awesome custom [color picker](https://github.com/yairEO/color-picker)
* `checkbox` input
* `radio` inputs group
* `select` dropdown (native)
* Custom HTML-Knobs (add your own buttons or whatever)
* Resset all knobs (to defaults)
* Reset individual knob
* Labels - group all the knobb defined after a certain label
* **Expand/Collapse** knobs groups
* Apply changes live, on-the-fly, or with an Apply button
* Auto-detect CSS variables defined in knobs as their initialvalues, if possible
* Knobs are completely **isolated** within an *iframe* (unaffected by your page styles)
* Allows 3 states of visibility:
- `0` - Starts as hidden
- `1` - Starts as visible
- `2` - Always visible
* Knobs component placement `position` (relative to window viewport):
* `top right` (default)
* `bottom right`
* `top left`
* `bottom left`
* Allows theme customization (*currently very limited*)

## Configuration:

All is needed is to include the knobs script on the page, and set it up.

```js
new Knobs(settings)
```

### Settings

| Name | Type | Default | Info
|--------------|-----------------------|---------|--------------------------------------------------------------------------------------------------------------------
| theme | `Object` | | Knobs theme variables. Since the Knobs are encapsulated within an iframe, they cannot be be styled from outside.
| live | `Boolean` | `true` | Should changes be immediately applied
| persist | `Boolean` | `false` | Persist changes using the browser's localstorage. Store `key/value` per knob, where `key` is the knob's *label*.
| visible | `Number` | `0` | `0` - Starts as hidden
`1` - Starts as visible
`2` - Always visible
| CSSVarTarget | `Element`/`NodeList ` | | Global HTML element(s) for which to apply the CSS custom properties.
Can also be configured per-knob.
| knobsToggle | `Boolean` | `false` | if `true` - adds a checkbox next to each knob, which allows temporarily disabling the knob, reverting to default
| knobs | `Array` | | Array of Objects describing the knobs controllers on-screen
| standalone | `Boolean` | `false` | if `true` - does not create an iframe and appends it to the page, but simply gives the developer the DOM node, as is, to inject manually with `knobs.DOM.scope` node. Note that CSS in also needed ('./src/styles/styles.scss`)

theme (defaults)

```js
{
styles : ``, // optioanlly add any CSS and it will be injected into the iframe
flow : 'horizontal', // use 'compact' to keep things tight
position : 'top right',
primaryColor: '#0366D6', // mainly for links / range sliders
'base-color': "rgba(0,0,0,1)", // mainly for the background color but also for input fields such as text or number
textColor : "#CCC",
border : 'none'
}
```

knobs

An array of Objects, where the properties describe a *knob*.

It is ***possible*** to define/update the `knobs` Array **after** instance initialization, like so:

```js
var myKnobs = new Knobs({ CSSVarTarget:document.body }) // only if working with CSS variables

myKnobs.knobs = [{...}, ...] // Add/change the knobs. will automatically re-render (see example further below)
```

All defined *knob* properties, beside a special few, are attributes that
are applied on the HTML *input* element that controls the knob, so it is up
to the developer who set up the knobs to use the appropriate attributes, for
each type of of the supported knobs (`range`, `color`, `checkbox`).

The special other properties are:

**`onChange`**

Callback which fires on every `input` event

**`cssVar`**

Optional. An array of 3 items:
1. (`String`) - CSS variable name
2. (`String`) - Units (*optional* - Ex. `%` or `px`)
3. (`HTML NODE`) - Reference to an HTML node to apply the knob's CSS variable on (*optional*)

Sometimes it is wanted for variables to be defined unitless, for calculation-purposes, like so:

```css
div{
--size: 10;
/* limits with width to a minimum of 10px by using unitless variable for the "max" function */
width: calc(Max(50, var(--size)) * 1px);
}
```

So, when a unitless-variable is desired, but ultimatly it will have a unit, then `units` (*2nd* item in the array)
should be written with a dash prefix, Ex.: `-px`, and it will be displayed in the label correctly but ignored when
applying the variable.

**`cssVarsHSLA`** (boolean)

Applies only to *color* knobs and if set to `true` will generate 4 CSS variables for the HSLA version of the color.

`--main-color-h`, `--main-color-s`, `--main-color-l` & `--main-color-a`.

```js
{
cssVar: ['main-color'],
cssVarsHSLA: true,
label: 'Page background',
type: 'color',
defaultFormat: 'hsla',
},
```

**`defaultFormat`** (string)

Applies only to *color* knobs. Sets the default format displayed to the user and also the value which will
be set to the input. Possible values are: `hsla`, `rgba`, `hex`.

**`label`** (string)

A text which is displayed alongside the knob

**`labelTitle`** (string)

Optional `title` attribute for the knob's label

**`value`** (string, number)

Acts as the initial value of the *knob*, except for `checkbox` *knobs*, in which case,
if the knob also has `cssVar` property set, then the checkbox is *checked*, that CSS variable
`value` will be the `value` property of the knob, Ex.

```js
{
cssVar: ['hide'], // CSS variable name "--hide"
label: 'Show',
type: 'checkbox',
// checked: true, // not checked by default
value: 'none', // if checked: --hide: none;
}
```

Then in your CSS you can write the below, so when `--hide` is not defined,
`block` is used as the `display` property value.

```css
display: var(--hide, block);
```

It is possible to use an *already-declared* CSS-varaible (on the target element) by emmiting the `value`
prop from the *knob* decleration. The program will try to get the value using `getComputedStyle` and `getPropertyValue`.

Variables which has `calc` or any other computations might result in `NaN`. In which case, a `console.warn` will be presented
and a manually typed `value` property for the *knob* would be advised.

**`isToggled`** (boolean)
If this property is set to `false`, the knob will be toggled *off* by default.

Will only take affect if `knobsToggle` setting is set to `true`

**`options`** (array)
Used for knobs of type `select`. An Array of options to render.

[20, 150, [200, '200 nice pixels'], 500]

An option can be split to the actual value it represents and its textual value, as the above example shows.

**`knobClass`** (string)
Add your own *class* to the knob (row) element itself (for styling purposes).
Remember that in order to add custom styles, the `theme.styles` setting should be used, because all knobs
are encapsulated within an *iframe* so your page styles won't affect anything that's inside.

**`render`** (string)
Allows to render anything you want in the knob area.
Should return a *string* of HTML, for example:

```js
{
render: `
1
2
`,
knobClass: 'custom-actions'
}
```

**`script`** (function)
A function to be called which has logic related to the custom HTML in the `render` property (shown above).
The function recieves 2 arguments: The knobs instance referece and the (auto)generated knob `name` string.

```js
{
label: 'Custom HTML with label',
render: `
1
2
`,
script(knobs, name){
knobs.getKnobElm(name).addEventListener("click", e => {
if( e.target.tagName == 'BUTTON' )
alert(e.target.textContent)
})
},
},
```

## Install:

```
npm i @yaireo/knobs
```

**CDN source:**

[https://unpkg.com/@yaireo/knobs@latest](https://unpkg.com/@yaireo/knobs@latest)

## Example:

### When Using with NPM, first import `Knobs`
```js
import Knobs from '@yaireo/knobs'
```

#### Color manipulation methods:

`format` & `CSStoHSLA` are defined on Knobs' instances in `color` property, for example:

```js
const myKnobs = new Knobs({
...,
knobs: [
{
cssVar: ['bg'], // alias for the CSS variable
label: 'Color',
type: 'color',
value: '#45FDA9',
onChange(e, knobData, hsla) => {
console.log( myKnobs.format(knobData.value, 'rgb') ) // will print a color string in RGBA
}
}
]
})

myKnobs.color.format()
```

See [color-picker docs](https://github.com/yairEO/color-picker#helper-methods-exported-alongside-the-default-colorpicker)

### Defining Knobs:

```js
var settings = {
theme: {
position: 'bottom right', // default is 'top left'
},

// should update immediately (default true)
live: false,

// 0 - starts as hidden, 1 - starts as visible, 2 - always visible
visible: 0,

CSSVarTarget: document.querySelector('.testSubject'),

knobs: [
{
cssVar: ['width', '-px'], // prefix unit with '-' makes it only a part of the title but not of the variable
label: 'Width',
labelTitle: 'Changes the width at steps of 50 pixels',
type: 'range',
value: 200,
min: 0,
max: 500,
step: 50,
onChange: console.log // javascript callback on every "input" event
},

{
cssVar: ['width', '-px'],
label: 'Width preset',
type: 'select',
options: [20, 150, [200, '200 nice pixels'], 500],
value: 150, // should be one of the options
defaultValue: 150 // value for which to reset to (optional)
isToggled: false, // this knob will not take affect by default
},

{
cssVar: ['height', 'vh'],
label: 'Height',
type: 'range',
// value: 20, // if a value is not defined, Knobs will try to get it from the CSS ("CSSVarTarget" selector) automatically
min: 0,
max: 100,
onChange: console.log
},

{
cssVar: ['align'],
label: 'Align boxes',
type: 'radio',
name: 'align-radio-group',
options: [
{ value:'left', hidden:true, label: ' console.log(e, knobData, hsla, knobData.value)
},

{
cssVar: ['main-bg', null, document.body], // [alias for the CSS variable, units, applies on element]
label: 'Background',
type: 'color',
value: '#FFFFFF',
onChange: (e, knobData, hsla) => console.log(e, knobData, hsla, knobData.value)
},

["Label example", false] // group is collapsed by default
{
cssVar: ['hide'], // alias for the CSS variable
label: 'Show',
type: 'checkbox',
// checked: true, // default
value: 'none',
onChange: console.log
},

{
label: 'Custom with label',
render: `
1
2
`,
script(knobs, name){
knobs.getKnobElm(name).addEventListener("click", e => {
if( e.target.tagName == 'BUTTON' )
alert(e.target.textContent)
})
},
},

{
render: `
😎
`,
script(knobs){
const elm = knobs.DOM.scope.querySelector('.specialBtn3')
elm.addEventListener("click", () => alert('😎'))
},
knobClass: 'custom-actions'
}
]
}

var penKnobs = new Knobs(settings)
```