{"id":13576048,"url":"https://github.com/yairEO/knobs","last_synced_at":"2025-04-05T05:30:40.672Z","repository":{"id":43085597,"uuid":"303325423","full_name":"yairEO/knobs","owner":"yairEO","description":"UI knobs controllers for JS/CSS live manipulation of various parameters","archived":false,"fork":false,"pushed_at":"2023-04-02T15:15:59.000Z","size":7747,"stargazers_count":320,"open_issues_count":3,"forks_count":6,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-04T19:13:21.592Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yairEO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-12T08:23:50.000Z","updated_at":"2025-04-01T11:02:12.000Z","dependencies_parsed_at":"2024-05-01T19:24:52.075Z","dependency_job_id":"c0d352b1-6597-4b36-9d5a-ba8083fc4e6a","html_url":"https://github.com/yairEO/knobs","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yairEO%2Fknobs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yairEO%2Fknobs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yairEO%2Fknobs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yairEO%2Fknobs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yairEO","download_url":"https://codeload.github.com/yairEO/knobs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294034,"owners_count":20915329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T15:01:06.593Z","updated_at":"2025-04-05T05:30:35.658Z","avatar_url":"https://github.com/yairEO.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cbr\u003e\n  \u003ca href='https://codepen.io/vsync/pen/KKMwyRO'\u003e\n      \u003cimg src=\"./demo.apng?sanitize=true\" alt=\"Knobs\"/\u003e\n  \u003c/a\u003e\n\u003cbr\u003e\n\u003cp\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href='https://www.npmjs.com/package/@yaireo/knobs'\u003e\n      \u003cimg src=\"https://img.shields.io/npm/v/@yaireo/knobs.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href='https://simple.wikipedia.org/wiki/MIT_License'\u003e\n      \u003cimg src=\"https://img.shields.io/badge/license-MIT-lightgrey\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e\n  \u003ca href='https://codepen.io/vsync/pen/KKMwyRO'\u003eKnobs\u003c/a\u003e 🎛️ UI controllers for JS/CSS manipulation\n\u003c/h1\u003e\n\n\u003ch3 align=\"center\"\u003e\n  👉 \u003ca href='https://codepen.io/vsync/pen/KKMwyRO' target='_blank'\u003eDemo\u003c/a\u003e 👈\n  \u003cbr\u003e\u003cbr\u003e\n\u003c/h3\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd \u003e\n      \u003ctable\u003e\n        \u003ctr\u003e\n          \u003ctd\u003eMinified\u003c/td\u003e\n          \u003ctd align=\"right\"\u003e\u003cstrong\u003e54kb\u003c/strong\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n          \u003ctd\u003eBrotli\u003c/td\u003e\n          \u003ctd align=\"right\"\u003e\u003cstrong\u003e13.5kb\u003c/strong\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n          \u003ctd\u003eGZIP\u003c/td\u003e\n          \u003ctd align=\"right\"\u003e\u003cstrong\u003e15kb\u003c/strong\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n      \u003c/table\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n\u003ch2\u003eWhat is this:\u003c/h2\u003e\n\u003cp\u003e\nStarted as something I needed for my many Codepens - A way to provide viewers, and myself, a set\nof controllers, for manipulating the DOM instantaneously.\n\u003c/p\u003e\n\u003cp\u003e\nImagine certain aspects of a web page, or a specific *component*, which you would like to add the ability\nto control on-the-fly. Change the visual looks or certain javascript parameters with a move or a slider.\n\u003c/p\u003e\n\u003cp\u003e\nCSS-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.\n\u003c/p\u003e\n\u003cp\u003e\nIt's so easy \u0026 quick to use Knobs, about 1 minute!\n\u003c/p\u003e\n\u003cstrong\u003e⚠️ Supported only in modern browsers\u003c/strong\u003e\u003cbr\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n### Features:\n\n* `range` input (*wheel*-supported)\n* `color` input with awesome custom [color picker](https://github.com/yairEO/color-picker)\n* `checkbox` input\n* `radio` inputs group\n* `select` dropdown (native)\n* Custom HTML-Knobs (add your own buttons or whatever)\n* Resset all knobs (to defaults)\n* Reset individual knob\n* Labels - group all the knobb defined after a certain label\n* **Expand/Collapse** knobs groups\n* Apply changes live, on-the-fly, or with an \u003ckbd\u003eApply\u003c/kbd\u003e button\n* Auto-detect CSS variables defined in knobs as their initialvalues, if possible\n* Knobs are completely **isolated** within an *iframe* (unaffected by your page styles)\n* Allows 3 states of visibility:\n  - `0` - Starts as hidden\n  - `1` - Starts as visible\n  - `2` - Always visible\n* Knobs component placement `position` (relative to window viewport):\n  * `top right` (default)\n  * `bottom right`\n  * `top left`\n  * `bottom left`\n* Allows theme customization (*currently very limited*)\n\n## Configuration:\n\nAll is needed is to include the knobs script on the page, and set it up.\n\n```js\nnew Knobs(settings)\n```\n\n\n### Settings\n\n| Name         | Type                  | Default | Info\n|--------------|-----------------------|---------|--------------------------------------------------------------------------------------------------------------------\n| theme        | `Object`              |         | Knobs theme variables. Since the Knobs are encapsulated within an iframe, they cannot be be styled from outside.\n| live         | `Boolean`             | `true`  | Should changes be immediately applied\n| persist      | `Boolean`             | `false` | Persist changes using the browser's localstorage. Store `key/value` per knob, where `key` is the knob's *label*.\n| visible      | `Number`              | `0`     | `0` - Starts as hidden\u003cbr\u003e `1` - Starts as visible\u003cbr\u003e `2` - Always visible\n| CSSVarTarget | `Element`/`NodeList ` |         | Global HTML element(s) for which to apply the CSS custom properties.\u003cbr\u003e Can also be configured per-knob.\n| knobsToggle  | `Boolean`             | `false` | if `true` - adds a checkbox next to each knob, which allows temporarily disabling the knob, reverting to default\n| knobs        | `Array`               |         | Array of Objects describing the knobs controllers on-screen\n| 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`)\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003etheme\u003c/strong\u003e (defaults)\u003c/summary\u003e\n\n```js\n{\n  styles      : ``,                // optioanlly add any CSS and it will be injected into the iframe\n  flow        : 'horizontal',      // use 'compact' to keep things tight\n  position    : 'top right',\n  primaryColor: '#0366D6',         // mainly for links / range sliders\n  'base-color': \"rgba(0,0,0,1)\",   // mainly for the background color but also for input fields such as text or number\n  textColor   : \"#CCC\",\n  border      : 'none'\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eknobs\u003c/strong\u003e\u003c/summary\u003e\n\nAn array of Objects, where the properties describe a *knob*.\n\nIt is ***possible*** to define/update the `knobs` Array **after** instance initialization, like so:\n\n```js\nvar myKnobs = new Knobs({ CSSVarTarget:document.body }) // only if working with CSS variables\n\nmyKnobs.knobs = [{...}, ...] // Add/change the knobs. will automatically re-render (see example further below)\n```\n\nAll defined *knob* properties, beside a special few, are attributes that\nare applied on the HTML *input* element that controls the knob, so it is up\nto the developer who set up the knobs to use the appropriate attributes, for\neach type of of the supported knobs (`range`, `color`, `checkbox`).\n\nThe special other properties are:\n\n**`onChange`**\n\nCallback which fires on every `input` event\n\n**`cssVar`**\n\nOptional. An array of 3 items:\n1. (`String`) - CSS variable name\n2. (`String`) - Units (*optional* - Ex. `%` or `px`)\n3. (`HTML NODE`) - Reference to an HTML node to apply the knob's CSS variable on (*optional*)\n\nSometimes it is wanted for variables to be defined unitless, for calculation-purposes, like so:\n\n```css\ndiv{\n  --size: 10;\n  /* limits with width to a minimum of 10px by using unitless variable for the \"max\" function */\n  width: calc(Max(50, var(--size)) * 1px);\n}\n```\n\nSo, when a unitless-variable is desired, but ultimatly it will have a unit, then `units` (*2nd* item in the array)\nshould be written with a dash prefix, Ex.: `-px`, and it will be displayed in the label correctly but ignored when\napplying the variable.\n\n**`cssVarsHSLA`** (boolean)\n\nApplies only to *color* knobs and if set to `true` will generate 4 CSS variables for the HSLA version of the color.\n\n`--main-color-h`, `--main-color-s`, `--main-color-l` \u0026 `--main-color-a`.\n\n```js\n{\n  cssVar: ['main-color'],\n  cssVarsHSLA: true,\n  label: 'Page background',\n  type: 'color',\n  defaultFormat: 'hsla',\n},\n```\n\n**`defaultFormat`** (string)\n\nApplies only to *color* knobs. Sets the default format displayed to the user and also the value which will\nbe set to the input. Possible values are: `hsla`, `rgba`, `hex`.\n\n\n**`label`** (string)\n\nA text which is displayed alongside the knob\n\n**`labelTitle`** (string)\n\nOptional `title` attribute for the knob's label\n\n**`value`** (string, number)\n\nActs as the initial value of the *knob*, except for `checkbox` *knobs*, in which case,\nif the knob also has `cssVar` property set, then the checkbox is *checked*, that CSS variable\n`value` will be the `value` property of the knob, Ex.\n\n```js\n{\n  cssVar: ['hide'], // CSS variable name \"--hide\"\n  label: 'Show',\n  type: 'checkbox',\n  // checked: true,  // not checked by default\n  value: 'none', // if checked: --hide: none;\n}\n```\n\nThen in your CSS you can write the below, so when `--hide` is not defined,\n`block` is used as the `display` property value.\n\n```css\ndisplay: var(--hide, block);\n```\n\nIt is possible to use an *already-declared* CSS-varaible (on the target element) by emmiting the `value`\nprop from the *knob* decleration. The program will try to get the value using `getComputedStyle` and `getPropertyValue`.\n\nVariables which has `calc` or any other computations might result in `NaN`. In which case, a `console.warn` will be presented\nand a manually typed `value` property for the *knob* would be advised.\n\n**`isToggled`** (boolean)\nIf this property is set to `false`, the knob will be toggled *off* by default.\n\nWill only take affect if `knobsToggle` setting is set to `true`\n\n**`options`** (array)\nUsed for knobs of type `select`. An Array of options to render.\n\n    [20, 150, [200, '200 nice pixels'], 500]\n\nAn option can be split to the actual value it represents and its textual value, as the above example shows.\n\n**`knobClass`** (string)\nAdd your own *class* to the knob (row) element itself (for styling purposes).\nRemember that in order to add custom styles, the `theme.styles` setting should be used, because all knobs\nare encapsulated within an *iframe* so your page styles won't affect anything that's inside.\n\n**`render`** (string)\nAllows to render anything you want in the knob area.\nShould return a *string* of HTML, for example:\n\n```js\n{\n  render: `\n    \u003cbutton onclick='alert(1)'\u003e1\u003c/button\u003e\n    \u003cbutton onclick='alert(2)'\u003e2\u003c/button\u003e\n  `,\n  knobClass: 'custom-actions'\n}\n```\n\n**`script`** (function)\nA function to be called which has logic related to the custom HTML in the `render` property (shown above).\nThe function recieves 2 arguments: The knobs instance referece and the (auto)generated knob `name` string.\n\n```js\n{\n  label: 'Custom HTML with label',\n  render: `\n    \u003cbutton type='button' class='specialBtn1'\u003e1\u003c/button\u003e\n    \u003cbutton type='button' class='specialBtn2'\u003e2\u003c/button\u003e\n  `,\n  script(knobs, name){\n    knobs.getKnobElm(name).addEventListener(\"click\", e =\u003e {\n      if( e.target.tagName == 'BUTTON' )\n        alert(e.target.textContent)\n    })\n  },\n},\n```\n\u003c/details\u003e\n\n\n## Install:\n\n```\nnpm i @yaireo/knobs\n```\n\n**CDN source:**\n\n[https://unpkg.com/@yaireo/knobs@latest](https://unpkg.com/@yaireo/knobs@latest)\n\n\n## Example:\n\n### When Using with NPM, first import `Knobs`\n```js\nimport Knobs from '@yaireo/knobs'\n```\n\n#### Color manipulation methods:\n\n`format` \u0026 `CSStoHSLA` are defined on Knobs' instances in `color` property, for example:\n\n```js\nconst myKnobs = new Knobs({\n  ...,\n  knobs: [\n    {\n      cssVar: ['bg'], // alias for the CSS variable\n      label: 'Color',\n      type: 'color',\n      value: '#45FDA9',\n      onChange(e, knobData, hsla) =\u003e {\n        console.log( myKnobs.format(knobData.value, 'rgb') )  // will print a color string in RGBA\n      }\n    }\n  ]\n})\n\nmyKnobs.color.format()\n```\n\nSee [color-picker docs](https://github.com/yairEO/color-picker#helper-methods-exported-alongside-the-default-colorpicker)\n\n\n### Defining Knobs:\n\n```js\nvar settings = {\n  theme: {\n    position: 'bottom right', // default is 'top left'\n  },\n\n  // should update immediately (default true)\n  live: false,\n\n  // 0 - starts as hidden, 1 - starts as visible, 2 - always visible\n  visible: 0,\n\n  CSSVarTarget: document.querySelector('.testSubject'),\n\n  knobs: [\n    {\n      cssVar: ['width', '-px'], // prefix unit with '-' makes it only a part of the title but not of the variable\n      label: 'Width',\n      labelTitle: 'Changes the width at steps of 50 pixels',\n      type: 'range',\n      value: 200,\n      min: 0,\n      max: 500,\n      step: 50,\n      onChange: console.log  // javascript callback on every \"input\" event\n    },\n\n    {\n      cssVar: ['width', '-px'],\n      label: 'Width preset',\n      type: 'select',\n      options: [20, 150, [200, '200 nice pixels'], 500],\n      value: 150, // should be one of the options\n      defaultValue: 150 // value for which to reset to (optional)\n      isToggled: false, // this knob will not take affect by default\n    },\n\n    {\n      cssVar: ['height', 'vh'],\n      label: 'Height',\n      type: 'range',\n      // value: 20,  // if a value is not defined, Knobs will try to get it from the CSS (\"CSSVarTarget\" selector) automatically\n      min: 0,\n      max: 100,\n      onChange: console.log\n    },\n\n    {\n      cssVar: ['align'],\n      label: 'Align boxes',\n      type: 'radio',\n      name: 'align-radio-group',\n      options: [\n        { value:'left', hidden:true, label: '\u003csvg ...' },\n        { value: 'center', label:'Center' },\n        { value:'right', hidden:true, label:'\u003csvg ...' }\n      ],\n      value: 'center',\n      defaultValue: 'left'\n    },\n\n    {\n      cssVar: ['radius', '%'],\n      label: 'Radius of the big square here',\n      type: 'range',\n      value: 0,\n      min: 0,\n      max: 50,\n      onChange: console.log\n    },\n\n    \"Label example\",\n\n    {\n      cssVar: ['bg'], // alias for the CSS variable\n      label: 'Color',\n      type: 'color',\n      defaultFormat: 'hsla',\n      cssVarsHSLA: true,\n      value: '#45FDA9',\n      swatches: ['red', 'gold'],  //  swatches which can be selected inside the color picker\n      onChange: (e, knobData, hsla) =\u003e console.log(e, knobData, hsla, knobData.value)\n    },\n\n    {\n      cssVar: ['main-bg', null, document.body], // [alias for the CSS variable, units, applies on element]\n      label: 'Background',\n      type: 'color',\n      value: '#FFFFFF',\n      onChange: (e, knobData, hsla) =\u003e console.log(e, knobData, hsla, knobData.value)\n    },\n\n    [\"Label example\", false] // group is collapsed by default\n    {\n      cssVar: ['hide'], // alias for the CSS variable\n      label: 'Show',\n      type: 'checkbox',\n      // checked: true,  // default\n      value: 'none',\n      onChange: console.log\n    },\n\n    {\n      label: 'Custom with label',\n      render: `\n        \u003cbutton type='button' class='specialBtn1'\u003e1\u003c/button\u003e\n        \u003cbutton type='button' class='specialBtn2'\u003e2\u003c/button\u003e\n      `,\n      script(knobs, name){\n        knobs.getKnobElm(name).addEventListener(\"click\", e =\u003e {\n          if( e.target.tagName == 'BUTTON' )\n            alert(e.target.textContent)\n        })\n      },\n    },\n\n    {\n      render: `\n        \u003cbutton type='button' class='specialBtn3'\u003e😎\u003c/button\u003e\n      `,\n      script(knobs){\n        const elm = knobs.DOM.scope.querySelector('.specialBtn3')\n        elm.addEventListener(\"click\", () =\u003e alert('😎'))\n      },\n      knobClass: 'custom-actions'\n    }\n  ]\n}\n\nvar penKnobs = new Knobs(settings)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FyairEO%2Fknobs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FyairEO%2Fknobs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FyairEO%2Fknobs/lists"}