From 1ebacc826e91943a2d60b3e959d6e0119f58c2f3 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Tue, 31 Oct 2023 22:07:32 +0900 Subject: [PATCH] add theme --- dist/0.x/muigui.js | 224 +++++++++++++++++++++++++++------- dist/0.x/muigui.min.js | 2 +- dist/0.x/muigui.module.js | 224 +++++++++++++++++++++++++++------- dist/0.x/muigui.module.min.js | 2 +- examples/js/index.js | 27 ++-- src/muigui.js | 5 +- src/styles/muigui.css.js | 66 +++++++++- 7 files changed, 444 insertions(+), 106 deletions(-) diff --git a/dist/0.x/muigui.js b/dist/0.x/muigui.js index 0e4fdda..f4d2fe8 100644 --- a/dist/0.x/muigui.js +++ b/dist/0.x/muigui.js @@ -1,14 +1,16 @@ -/* muigui@0.0.6, license MIT */ +/* muigui@0.0.7, license MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.GUI = factory()); })(this, (function () { 'use strict'; - var css = ` -.muigui-colors { + var css = { + default: ` +.muigui { --bg-color: #ddd; --color: #222; + --contrast-color: #eee; --value-color: #145 ; --value-bg-color: #eeee; --disabled-color: #999; @@ -31,9 +33,10 @@ } @media (prefers-color-scheme: dark) { - .muigui-colors { + .muigui { --bg-color: #222222; --color: #dddddd; + --contrast-color: #000; --value-color: #43e5f7; --value-bg-color: #444444; --disabled-color: #666666; @@ -685,7 +688,67 @@ z-index: 100001; } -`; +`, + themes: { + default: '', + float: ` + :root { + color-scheme: light dark, + } + + .muigui { + --width: 400px; + --bg-color: initial; + --label-width: 25%; + } + + input, + .muigui-label-controller>label { + text-shadow: + -1px -1px 0 var(--contrast-color), + 1px -1px 0 var(--contrast-color), + -1px 1px 0 var(--contrast-color), + 1px 1px 0 var(--contrast-color); + } + + .muigui-controller > label:nth-child(1) { + place-content: center end; + margin-right: 1em; + } + + .muigui-value > :nth-child(2) { + margin-left: 1em; + } + + .muigui-root>*:nth-child(1) { + display: none; + } + + .muigui-range input[type=range]::-webkit-slider-thumb { + border-radius: 1em; + } + + .muigui-range input[type=range]::-webkit-slider-runnable-track { + -webkit-appearance: initial; + appearance: none; + border: 1px solid rgba(0, 0, 0, 0.25); + height: 2px; + } + + .muigui-colors { + --value-color: var(--color ); + --value-bg-color: rgba(0, 0, 0, 0.1); + --disabled-color: #cccccc; + --menu-bg-color: rgba(0, 0, 0, 0.1); + --menu-sep-color: #bbbbbb; + --hover-bg-color: rgba(0, 0, 0, 0); + --invalid-color: #FF0000; + --selected-color: rgba(0, 0, 0, 0.3); + --range-color: rgba(0, 0, 0, 0.125); + } +`, + }, + }; function setElemProps(elem, attrs, children) { for (const [key, value] of Object.entries(attrs)) { @@ -794,6 +857,42 @@ }; }; + // TODO: remove an use one in conversions. Move makeRangeConverters there? + const identity$1 = { + to: v => v, + from: v => [true, v], + }; + function makeMinMaxPair(gui, properties, minPropName, maxPropName, options) { + const { converters: { from } = identity$1 } = options; + const { min, max } = options; + const guiMinRange = options.minRange || 0; + const valueMinRange = from(guiMinRange)[1]; + console.log('guiMinRange', guiMinRange); + console.log('valueMinRange', valueMinRange); + return [ + gui + .add(properties, minPropName, { + ...options, + min, + max: max - guiMinRange, + }) + .listen() + .onChange(v => { + properties[maxPropName] = Math.min(max, Math.max(v + valueMinRange, properties[maxPropName])); + }), + gui + .add(properties, maxPropName, { + ...options, + min: min + guiMinRange, + max, + }) + .listen() + .onChange(v => { + properties[minPropName] = Math.max(min, Math.min(v - valueMinRange, properties[minPropName])); + }), + ]; + } + class View { #childDestElem; #views = []; @@ -1521,16 +1620,22 @@ type: 'range', onInput: () => { this.#skipUpdate = true; - const [valid, v] = this.#from(parseFloat(this.domElement.value)); + const {min, max, step} = this.#options; + const v = parseFloat(this.domElement.value); + const newV = clamp$1(stepify(v, v => v, step), min, max); + const [valid, validV] = this.#from(newV); if (valid) { - setter.setValue(v); + setter.setValue(validV); } }, onChange: () => { this.#skipUpdate = true; - const [valid, v] = this.#from(parseFloat(this.domElement.value)); + const {min, max, step} = this.#options; + const v = parseFloat(this.domElement.value); + const newV = clamp$1(stepify(v, v => v, step), min, max); + const [valid, validV] = this.#from(newV); if (valid) { - setter.setFinalValue(v); + setter.setFinalValue(validV); } }, onWheel: e => { @@ -2361,9 +2466,6 @@ } } - let stylesInjected = false; - const styleElem = createElem('style'); - class GUIFolder extends Folder { add(object, property, ...args) { const controller = object instanceof Controller @@ -2388,11 +2490,51 @@ } } + class MuiguiElement extends HTMLElement { + constructor() { + super(); + this.shadow = this.attachShadow({mode: 'open'}); + } + } + + customElements.define('muigui-element', MuiguiElement); + + const baseStyleSheet = new CSSStyleSheet(); + baseStyleSheet.replaceSync(css.default); + const userStyleSheet = new CSSStyleSheet(); + + function makeStyleSheetUpdater(styleSheet) { + let newCss; + let newCssPromise; + + function updateStyle() { + if (newCss && !newCssPromise) { + const s = newCss; + newCss = undefined; + newCssPromise = styleSheet.replace(s).then(() => { + console.log(s); + newCssPromise = undefined; + updateStyle(); + }); + } + } + + return function updateStyleSheet(css) { + newCss = css; + updateStyle(); + }; + } + + const updateBaseStyle = makeStyleSheetUpdater(baseStyleSheet); + const updateUserStyle = makeStyleSheetUpdater(userStyleSheet); + class GUI extends GUIFolder { static converters = converters; static mapRange = mapRange; static makeRangeConverters = makeRangeConverters; static makeRangeOptions = makeRangeOptions; + static makeMinMaxPair = makeMinMaxPair; + #localStyleSheet = new CSSStyleSheet(); constructor(options = {}) { super('Controls', 'muigui-root'); @@ -2403,16 +2545,11 @@ autoPlace = true, width, title = 'Controls', - injectStyles = true, } = options; let { parent, } = options; - if (injectStyles && !stylesInjected) { - stylesInjected = true; - (document.head || document.documentElement).appendChild(styleElem); - styleElem.textContent = css; - } + if (width) { this.domElement.style.width = /^\d+$/.test(width) ? `${width}px` : width; } @@ -2421,13 +2558,34 @@ this.domElement.classList.add('muigui-auto-place'); } if (parent) { - parent.appendChild(this.domElement); + const muiguiElement = createElem('muigui-element'); + muiguiElement.shadowRoot.adoptedStyleSheets = [baseStyleSheet, userStyleSheet, this.#localStyleSheet]; + muiguiElement.shadow.appendChild(this.domElement); + parent.appendChild(muiguiElement); } if (title) { this.title(title); } this.domElement.classList.add('muigui', 'muigui-colors'); } + setStyle(css) { + this.#localStyleSheet.replace(css); + } + static setBaseStyles(css) { + updateBaseStyle(css); + } + static getBaseStyleSheet() { + return baseStyleSheet; + } + static setUserStyles(css) { + updateUserStyle(css); + } + static getUserStyleSheet() { + return userStyleSheet; + } + static setTheme(name) { + GUI.setBaseStyles(`${css.default}\n${css.themes[name] || ''}`); + } } function noop$1() { @@ -2461,9 +2619,9 @@ elem.releasePointerCapture(event.pointerId); elem.removeEventListener('pointermove', pointerMove); elem.removeEventListener('pointerup', pointerUp); - + document.body.style.backgroundColor = ''; - + onUp('up'); }; @@ -2622,17 +2780,6 @@ */ - function makeSetter(object, property) { - return { - setValue(v) { - object[property] = v; - }, - setFinalValue(v) { - this.setValue(v); - }, - }; - } - class PopDownController extends ValueController { #top; #valuesView; @@ -3170,19 +3317,6 @@ } } - class GridView extends View { - // FIX: should this be 'options'? - constructor(cols) { - super(createElem('div', { - className: 'muigui-grid', - })); - this.cols(cols); - } - cols(cols) { - this.domElement.style.gridTemplateColumns = `repeat(${cols}, 1fr)`; - } - } - const svg = ` diff --git a/dist/0.x/muigui.min.js b/dist/0.x/muigui.min.js index 061ebff..e6f7d7b 100644 --- a/dist/0.x/muigui.min.js +++ b/dist/0.x/muigui.min.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).GUI=e()}(this,(function(){"use strict";function t(t,e={},n=[]){const i=document.createElement(t);return function(t,e,n){for(const[n,i]of Object.entries(e))if("function"==typeof i&&n.startsWith("on")){const e=n.substring(2).toLowerCase();t.addEventListener(e,i,{passive:!1})}else if("object"==typeof i)for(const[e,o]of Object.entries(i))t[n][e]=o;else void 0===t[n]?t.setAttribute(n,i):t[n]=i;for(const e of n)t.appendChild(e)}(i,e,n),i}function e(t,e){const n=t.indexOf(e);return n&&t.splice(n,1),t}function n(t,e,n){return Math.max(e,Math.min(n,t))}const i="undefined"!=typeof SharedArrayBuffer?function(t){return t&&t.buffer&&(t.buffer instanceof ArrayBuffer||t.buffer instanceof SharedArrayBuffer)}:function(t){return t&&t.buffer&&t.buffer instanceof ArrayBuffer},o=(t,e,n)=>Math.round(e(t)/n)/(1/n),s=(t,e)=>(t%e+e)%e;function r(t,e){for(const n in e)n in t&&(t[n]=e[n]);return t}const a=(t,e,n,i,o)=>(t-e)*(o-i)/(n-e)+i,l=({from:t,to:e})=>({to:n=>a(n,...t,...e),from:n=>[!0,a(n,...e,...t)]}),u=({from:t,to:e,step:n})=>({min:e[0],max:e[1],...n&&{step:n},converters:l({from:t,to:e})});class c{#t;#e=[];constructor(t){this.domElement=t,this.#t=t}addElem(t){return this.#t.appendChild(t),t}removeElem(t){return this.#t.removeChild(t),t}pushSubElem(t){this.#t.appendChild(t),this.#t=t}popSubElem(){this.#t=this.#t.parentElement}add(t){return this.#e.push(t),this.addElem(t.domElement),t}remove(t){return this.removeElem(t.domElement),e(this.#e,t),t}pushSubView(t){this.pushSubElem(t.domElement)}popSubView(){this.popSubElem()}setOptions(t){for(const e of this.#e)e.setOptions(t)}updateDisplayIfNeeded(t,e){for(const n of this.#e)n.updateDisplayIfNeeded(t,e);return this}$(t){return this.domElement.querySelector(t)}}class h extends c{#n;#i;#o;constructor(e){super(t("div",{className:"muigui-controller"})),this.#n=[],this.#i=[],e&&this.domElement.classList.add(e)}get parent(){return this.#o}setParent(t){this.#o=t,this.enable(!this.disabled())}show(t=!0){return this.domElement.classList.toggle("muigui-hide",!t),this.domElement.classList.toggle("muigui-show",t),this}hide(){return this.show(!1)}disabled(){return!!this.domElement.closest(".muigui-disabled")}enable(t=!0){return this.domElement.classList.toggle("muigui-disabled",!t),["input","button","select","textarea"].forEach((t=>{this.domElement.querySelectorAll(t).forEach((t=>{const e=!!t.closest(".muigui-disabled");t.disabled=e}))})),this}disable(t=!0){return this.enable(!t)}onChange(t){return this.removeChange(t),this.#n.push(t),this}removeChange(t){return e(this.#n,t),this}onFinishChange(t){return this.removeFinishChange(t),this.#i.push(t),this}removeFinishChange(t){return e(this.#i,t),this}#s(t,e){for(const n of t)n.call(this,e)}emitChange(t,e,n){this.#s(this.#n,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitChange({object:e,property:n,value:t,controller:this}))}emitFinalChange(t,e,n){this.#s(this.#i,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitFinalChange({object:e,property:n,value:t,controller:this}))}getColors(){const e=t=>t.replace(/-([a-z])/g,((t,e)=>e.toUpperCase())),n=t("div");this.domElement.appendChild(n);const i=Object.fromEntries(["color","bg-color","value-color","value-bg-color","hover-bg-color","menu-bg-color","menu-sep-color","disabled-color"].map((t=>{n.style.color=`var(--${t})`;const i=getComputedStyle(n);return[e(t),i.color]})));return n.remove(),i}}class d extends h{#r;#a;#l;#u={name:""};constructor(e,n,i={}){super("muigui-button",""),this.#r=e,this.#a=n,this.#l=this.addElem(t("button",{type:"button",onClick:()=>{this.#r[this.#a](this)}})),this.setOptions({name:n,...i})}setOptions(t){r(this.#u,t);const{name:e}=this.#u;this.#l.textContent=e}}function p(t,e){if(t.length!==e.length)return!1;for(let n=0;n{e.setValue(i.checked)},onChange:()=>{e.setFinalValue(i.checked)}});super(t("label",{},[i]))}updateDisplay(t){this.domElement.checked=t}}const f=[],b=new Set;let v,x;function w(){v=void 0,x=!0;for(const t of f)b.has(t)||t();x=!1,b.size&&(x?y():(b.forEach((t=>{e(f,t)})),b.clear())),y()}function y(){!v&&f.length&&(v=requestAnimationFrame(w))}let k=0;function E(){return"muigui-"+ ++k}class $ extends c{constructor(e=""){super(t("div",{className:"muigui-value"})),e&&this.domElement.classList.add(e)}}class C extends h{#b;#v;constructor(e="",n=""){super("muigui-label-controller"),this.#b=E(),this.#v=t("label",{for:this.#b}),this.domElement.appendChild(this.#v),this.pushSubView(new $(e)),this.name(n)}get id(){return this.#b}name(t){return this.#v.title===this.#v.textContent&&(this.#v.title=t),this.#v.textContent=t,this}tooltip(t){this.#v.title=t}}class V extends C{#r;#a;#x;#w;#e;#y;constructor(t,e,n=""){super(n,e),this.#r=t,this.#a=e,this.#x=this.getValue(),this.#w=!1,this.#e=[]}get initialValue(){return this.#x}get object(){return this.#r}get property(){return this.#a}add(t){return this.#e.push(t),super.add(t),this.updateDisplay(),t}#k(t,e){if("object"==typeof t){const e=this.#r[this.#a];if(Array.isArray(t))for(let n=0;n=0&&f.splice(e,1)}(this.#y)),this}}class M extends V{constructor(t,e){super(t,e,"muigui-checkbox");const n=this.id;this.add(new g(this,n)),this.updateDisplay()}}const I={to:t=>t,from:t=>[!0,t]},D={to:t=>t.toString(),from:t=>{const e=parseFloat(t);return[!Number.isNaN(e),e]}},F={radToDeg:l({to:[0,180],from:[0,Math.PI]})};function L(){let t=0;return function(e,n,i=5){t-=e.deltaY*n/i;const o=Math.floor(Math.abs(t)/n)*Math.sign(t)*n;return t-=o,o}}class N extends m{#E;#$;#C;#V;#u={step:.01,converters:D,min:Number.NEGATIVE_INFINITY,max:Number.POSITIVE_INFINITY};constructor(e,i){const s=e.setValue.bind(e),r=e.setFinalValue.bind(e),a=L();super(t("input",{type:"number",onInput:()=>this.#M(s,!0),onChange:()=>this.#M(r,!1),onWheel:t=>{t.preventDefault();const{min:i,max:s,step:r}=this.#u,l=a(t,r),u=parseFloat(this.domElement.value),c=n(o(u+l,(t=>t),r),i,s);e.setValue(c)}})),this.setOptions(i)}#M(t,e){const i=parseFloat(this.domElement.value),[o,s]=this.#$(i);let r;if(o&&!Number.isNaN(i)){const{min:i,max:o}=this.#u;r=s>=i&&s<=o,this.#V=e,t(n(s,i,o))}this.domElement.classList.toggle("muigui-invalid-value",!o||!r)}updateDisplay(t){this.#V||(this.domElement.value=o(t,this.#E,this.#C)),this.#V=!1}setOptions(t){r(this.#u,t);const{step:e,converters:{to:n,from:i}}=this.#u;return this.#E=n,this.#$=i,this.#C=e,this}}class S extends V{#I;#C;constructor(t,e,n={}){super(t,e,"muigui-checkbox"),this.#I=this.add(new N(this,n)),this.updateDisplay()}}class A extends m{#D;constructor(e,n){const i=[];super(t("select",{onChange:()=>{e.setFinalValue(this.#D[this.domElement.selectedIndex])}},n.map((([e,n])=>(i.push(n),t("option",{textContent:e})))))),this.#D=i}updateDisplay(t){const e=this.#D.indexOf(t);this.domElement.selectedIndex=e}}function U(t,e){return Array.isArray(t)?Array.isArray(t[0])?t:e?t.map(((t,e)=>[t,e])):t.map((t=>[t,t])):[...Object.entries(t)]}class O extends V{constructor(t,e,n){super(t,e,"muigui-select");const i="number"==typeof this.getValue(),{keyValues:o}=n,s=U(o,i);this.add(new A(this,s)),this.updateDisplay()}}class j extends m{#E;#$;#C;#V;#u={step:.01,min:0,max:1,converters:I};constructor(e,i){const s=L();super(t("input",{type:"range",onInput:()=>{this.#V=!0;const[t,n]=this.#$(parseFloat(this.domElement.value));t&&e.setValue(n)},onChange:()=>{this.#V=!0;const[t,n]=this.#$(parseFloat(this.domElement.value));t&&e.setFinalValue(n)},onWheel:t=>{t.preventDefault();const[i,r]=this.#$(parseFloat(this.domElement.value));if(!i)return;const{min:a,max:l,step:u}=this.#u,c=s(t,u),h=n(o(r+c,(t=>t),u),a,l);e.setValue(h)}})),this.setOptions(i)}updateDisplay(t){this.#V||(this.domElement.value=o(t,this.#E,this.#C)),this.#V=!1}setOptions(t){r(this.#u,t);const{step:e,min:n,max:i,converters:{to:o,from:s}}=this.#u;return this.#E=o,this.#$=s,this.#C=e,this.domElement.step=e,this.domElement.min=n,this.domElement.max=i,this}}class T extends V{constructor(t,e,n){super(t,e,"muigui-range"),this.add(new j(this,n)),this.add(new N(this,n))}}class P extends m{#E;#$;#V;#u={converters:I};constructor(e,n){const i=e.setValue.bind(e),o=e.setFinalValue.bind(e);super(t("input",{type:"text",onInput:()=>this.#M(i,!0),onChange:()=>this.#M(o,!1)})),this.setOptions(n)}#M(t,e){const[n,i]=this.#$(this.domElement.value);n&&(this.#V=e,t(i)),this.domElement.style.color=n?"":"var(--invalid-color)"}updateDisplay(t){this.#V||(this.domElement.value=this.#E(t),this.domElement.style.color=""),this.#V=!1}setOptions(t){r(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#$=n,this}}class z extends V{constructor(t,e){super(t,e,"muigui-checkbox"),this.add(new P(this)),this.updateDisplay()}}class G extends c{constructor(e,n){super(t(e,{className:n}))}}class B extends C{#F;constructor(){super("muigui-canvas"),this.#F=this.add(new G("canvas","muigui-canvas")).domElement}get canvas(){return this.#F}}const H=(t,e,n)=>Math.max(e,Math.min(n,t)),R=t=>+t.toFixed(3),Y=t=>parseInt(t.substring(1,3),16)<<16|parseInt(t.substring(3,5),16)<<8|parseInt(t.substring(5,7),16),W=t=>[parseInt(t.substring(1,3),16),parseInt(t.substring(3,5),16),parseInt(t.substring(5,7),16)],q=t=>`#${Array.from(t).map((t=>t.toString(16).padStart(2,"0"))).join("")}`,_=t=>W(t).map((t=>R(t/255))),J=t=>q(Array.from(t).map((t=>Math.round(H(255*t,0,255))))),K=t=>({r:parseInt(t.substring(1,3),16)/255,g:parseInt(t.substring(3,5),16)/255,b:parseInt(t.substring(5,7),16)/255}),X=t=>H(Math.round(255*t),0,255).toString(16).padStart(2,"0"),Z=t=>`rgb(${W(t).join(", ")})`,Q=/^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,tt=t=>{const e=it(W(t)).map((t=>(t=>+t.toFixed(0))(t)));return`hsl(${e[0]}, ${e[1]}%, ${e[2]}%)`},et=/^\s*hsl\(\s*(\d+)(?:deg|)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)\s*$/,nt=(t,e)=>(t%e+e)%e;const it=t=>{const[e,n,i]=function([t,e,n]){const i=Math.max(t,e,n),o=Math.min(t,e,n),s=.5*(o+i),r=i-o;let a=0,l=0;if(0!==r)switch(l=0===s||1===s?0:(i-s)/Math.min(s,1-s),i){case t:a=(e-n)/r+(et/255)));return[360*e,100*n,100*i]};function ot([t,e,n]){return e=H(e,0,1),n=H(n,0,1),[t,t+2/3,t+1/3].map((t=>{return i=1,o=H(Math.abs(6*(t=>t>=0?t%1:1-t%1)(t)-3)-1,0,1),(i+(o-i)*e)*n;var i,o}))}const st=t=>Math.round(1e3*t)/1e3;function rt([t,e,n]){const i=n>e?[n,e,-1,2/3]:[e,n,0,-1/3],o=i[0]>t?[i[0],i[1],i[3],t]:[t,i[1],i[2],i[0]],s=o[0]-Math.min(o[3],o[1]);return[Math.abs(o[2]+(o[3]-o[1])/(6*s+Number.EPSILON)),s/(o[0]+Number.EPSILON),o[0]].map(st)}window.hsv01ToRGBFloat=ot,window.rgbFloatToHSV01=rt;const at=[{re:/^#(?:[0-9a-f]){6}$/i,format:"hex6"},{re:/^(?:[0-9a-f]){6}$/i,format:"hex6-no-hash"},{re:/^#(?:[0-9a-f]){3}$/i,format:"hex3"},{re:/^(?:[0-9a-f]){3}$/i,format:"hex3-no-hash"},{re:Q,format:"css-rgb"},{re:et,format:"css-hsl"}];function lt(t){switch(typeof t){case"number":return"uint32-rgb";case"string":{const e=function(t){for(const e of at)if(e.re.test(t))return e}(t.trim());if(e)return e.format;break}case"object":if(t instanceof Uint8Array||t instanceof Uint8ClampedArray){if(3===t.length)return"uint8-rgb"}else if(t instanceof Float32Array){if(3===t.length)return"float-rgb"}else if(Array.isArray(t)){if(3===t.length)return"float-rgb"}else if("r"in t&&"g"in t&&"b"in t)return"object-rgb"}throw new Error(`unknown color format: ${t}`)}function ut(t){return t.trim(t)}function ct(t){return t[1]===t[2]&&t[3]===t[4]&&t[5]===t[6]?`#${t[1]}${t[3]}${t[5]}`:t}const ht=/^(#|)([0-9a-f]{3})$/i;function dt(t){const e=ht.exec(t);if(e){const[,,t]=e;return"#"+`${(n=t)[0]}${n[0]}${n[1]}${n[1]}${n[2]}${n[2]}`}var n;return t}function pt(t){return ct(ut(t))}const mt=t=>{const e=Q.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),`rgb(${n.join(", ")})`]},gt=t=>{const e=et.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseFloat(t)));return[!n.find((t=>Number.isNaN(t))),`hsl(${n[0]}, ${n[1]}%, ${n[2]}%)`]},ft=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$/,bt=/^\s*(?:0x){0,1}([0-9a-z]{1,6})\s*$/i,vt=/^\s*#[a-f0-9]{6}\s*$|^\s*#[a-f0-9]{3}\s*$/i,xt=/^\s*[a-f0-9]{6}\s*$/i,wt={hex6:{color:{from:t=>[!0,t],to:ut},text:{from:t=>[vt.test(t),t.trim()],to:t=>t}},hex3:{color:{from:t=>[!0,pt(t)],to:dt},text:{from:t=>[vt.test(t),ct(t.trim())],to:t=>t}},"hex6-no-hash":{color:{from:t=>[!0,t.substring(1)],to:t=>`#${ut(t)}`},text:{from:t=>[xt.test(t),t.trim()],to:t=>t}},"hex3-no-hash":{color:{from:t=>[!0,pt(t).substring(1)],to:dt},text:{from:t=>[xt.test(t),ct(t.trim())],to:t=>t}},"uint32-rgb":{color:{from:t=>[!0,Y(t)],to:t=>`#${Math.round(t).toString(16).padStart(6,"0")}`},text:{from:t=>(t=>{const e=bt.exec(t);return e?[!0,parseInt(e[1],16)]:[!1]})(t),to:t=>`0x${t.toString(16).padStart(6,"0")}`}},"uint8-rgb":{color:{from:t=>[!0,W(t)],to:q},text:{from:t=>{const e=ft.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),n]},to:t=>t.join(", ")}},"float-rgb":{color:{from:t=>[!0,_(t)],to:J},text:{from:t=>{const e=t.split(",").map((t=>t.trim())),n=e.map((t=>parseFloat(t)));if(3!==n.length)return[!1];const i=e.findIndex((t=>isNaN(t)));return[i<0,n.map((t=>R(t)))]},to:t=>Array.from(t).map((t=>R(t))).join(", ")}},"object-rgb":{color:{from:t=>[!0,K(t)],to:t=>`#${X(t.r)}${X(t.g)}${X(t.b)}`},text:{from:t=>{try{const e=t.replace(/([a-z])/g,'"$1"'),n=JSON.parse(e);if(Number.isNaN(n.r)||Number.isNaN(n.g)||Number.isNaN(n.b))throw new Error("not {r, g, b}");return[!0,n]}catch(t){return[!1]}},to:t=>`{r:${R(t.r)}, g:${R(t.g)}, b:${R(t.b)}}`}},"css-rgb":{color:{from:t=>[!0,Z(t)],to:t=>{const e=Q.exec(t);return q([e[1],e[2],e[3]].map((t=>parseInt(t))))}},text:{from:mt,to:t=>mt(t)[1]}},"css-hsl":{color:{from:t=>[!0,tt(t)],to:t=>{const e=et.exec(t),n=function([t,e,n]){t=nt(t,360),e=H(e/100,0,1),n=H(n/100,0,1);const i=e*Math.min(n,1-n);function o(e){const o=(e+t/30)%12;return n-i*Math.max(-1,Math.min(o-3,9-o,1))}return[o(0),o(8),o(4)].map((t=>Math.round(255*t)))}([e[1],e[2],e[3]].map((t=>parseFloat(t))));return q(n)}},text:{from:gt,to:t=>gt(t)[1]}}};class yt extends m{#E;#$;#L;#V;#u={converters:I};constructor(e,n){const i=t("input",{type:"color",onInput:()=>{const[t,n]=this.#$(i.value);t&&(this.#V=!0,e.setValue(n))},onChange:()=>{const[t,n]=this.#$(i.value);t&&(this.#V=!0,e.setFinalValue(n))}});super(t("div",{},[i])),this.setOptions(n),this.#L=i}updateDisplay(t){this.#V||(this.#L.value=this.#E(t)),this.#V=!1}setOptions(t){r(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#$=n,this}}class kt extends V{#N;#I;constructor(t,e,n={}){super(t,e,"muigui-color");const i=n.format||lt(this.getValue()),{color:o,text:s}=wt[i];this.#N=this.add(new yt(this,{converters:o})),this.#I=this.add(new P(this,{converters:s})),this.updateDisplay()}setOptions(t){const{format:e}=t;if(e){const{color:t,text:n}=wt[e];this.#N.setOptions({converters:t}),this.#I.setOptions({converters:n})}return super.setOptions(t),this}}class Et extends h{constructor(){super("muigui-divider")}}class $t extends h{#S;#A;constructor(t){super(t),this.#S=[],this.#A=this}get children(){return this.#S}get controllers(){return this.#S.filter((t=>!(t instanceof $t)))}get folders(){return this.#S.filter((t=>t instanceof $t))}reset(t=!0){for(const e of this.#S)e instanceof $t&&!t||e.reset(t);return this}remove(t){const e=this.#S.indexOf(t);if(e>=0){const t=this.#S.splice(e,1)[0];t.domElement.remove(),t.setParent(null)}return this}_addControllerImpl(t){return this.domElement.appendChild(t.domElement),this.#S.push(t),t.setParent(this),t}addController(t){return this.#A._addControllerImpl(t)}pushContainer(t){return this.addController(t),this.#A=t,t}popContainer(){return this.#A=this.#A.parent,this}}class Ct extends $t{#U;constructor(e="Controls",n="muigui-menu"){super(n),this.#U=t("label"),this.addElem(t("button",{type:"button",onClick:()=>this.toggleOpen()},[this.#U])),this.pushContainer(new $t),this.name(e),this.open()}open(t=!0){return this.domElement.classList.toggle("muigui-closed",!t),this.domElement.classList.toggle("muigui-open",t),this}close(){return this.open(!1)}name(t){return this.#U.textContent=t,this}title(t){return this.name(t)}toggleOpen(){return this.open(!this.domElement.classList.contains("muigui-open")),this}}class Vt extends h{constructor(t){super("muigui-label"),this.text(t)}text(t){return this.domElement.textContent=t,this}}let Mt=!1;const It=t("style");class Dt extends Ct{add(t,e,...n){const i=t instanceof h?t:function(t,e,...n){const[i]=n;if(Array.isArray(i))return new O(t,e,{keyValues:i});const o=typeof t[e];switch(o){case"number":if("number"==typeof n[0]&&"number"==typeof n[1]){const i=n[0],o=n[1],s=n[2];return new T(t,e,{min:i,max:o,...s&&{step:s}})}return 0===n.length?new S(t,e,...n):new T(t,e,...n);case"boolean":return new M(t,e,...n);case"function":return new d(t,e,...n);case"string":return new z(t,e,...n);case"undefined":throw new Error(`no property named ${e}`);default:throw new Error(`unhandled type ${o} for property ${e}`)}}(t,e,...n);return this.addController(i)}addCanvas(t){return this.addController(new B(t))}addColor(t,e,...n){return this.addController(new kt(t,e,...n))}addDivider(){return this.addController(new Et)}addFolder(t){return this.addController(new Dt(t))}addLabel(t){return this.addController(new Vt(t))}}class Ft extends Dt{static converters=F;static mapRange=a;static makeRangeConverters=l;static makeRangeOptions=u;constructor(t={}){super("Controls","muigui-root"),t instanceof HTMLElement&&(t={parent:t});const{autoPlace:e=!0,width:n,title:i="Controls",injectStyles:o=!0}=t;let{parent:s}=t;o&&!Mt&&(Mt=!0,(document.head||document.documentElement).appendChild(It),It.textContent='\n.muigui-colors {\n --bg-color: #ddd;\n --color: #222;\n --value-color: #145 ;\n --value-bg-color: #eeee;\n --disabled-color: #999;\n --menu-bg-color: #f8f8f8;\n --menu-sep-color: #bbb;\n --hover-bg-color: #999;\n --focus-color: #68C;\n --range-color: #888888;\n --invalid-color: #FF0000;\n --selected-color: rgb(255, 255, 255, 0.9);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n}\n\n@media (prefers-color-scheme: dark) {\n .muigui-colors {\n --bg-color: #222222;\n --color: #dddddd;\n --value-color: #43e5f7;\n --value-bg-color: #444444;\n --disabled-color: #666666;\n --menu-bg-color: #080808;\n --menu-sep-color: #444444;\n --hover-bg-color: #666666;\n --focus-color: #88AAFF;\n --range-color: #888888;\n --invalid-color: #FF6666;\n --selected-color: rgba(255, 255, 255, 0.3);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n }\n}\n\n.muigui {\n --width: 250px;\n --label-width: 45%;\n --number-width: 40%;\n\n\n --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;\n --font-size: 11px;\n --font-family-mono: Menlo, Monaco, Consolas, "Droid Sans Mono", monospace;\n --font-size-mono: 11px;\n\n --line-height: 1.7em;\n --border-radius: 0px;\n\n width: var(--width);\n font-family: var(--font-family);\n font-size: var(--font-size);\n box-sizing: border-box;\n line-height: 100%;\n}\n.muigui * {\n box-sizing: inherit;\n}\n\n.muigui-no-scroll {\n touch-action: none;\n}\n.muigui-no-h-scroll {\n touch-action: pan-y;\n}\n.muigui-no-v-scroll {\n touch-action: pan-x;\n}\n\n.muigui-invalid-value {\n background-color: red !important;\n color: white !important;\n}\n\n.muigui-grid {\n display: grid;\n}\n.muigui-rows {\n display: flex;\n flex-direction: column;\n\n min-height: 20px;\n border: 2px solid red;\n}\n.muigui-columns {\n display: flex;\n flex-direction: row;\n\n height: 20px;\n border: 2px solid green;\n}\n.muigui-rows>*,\n.muigui-columns>* {\n flex: 1 1 auto;\n align-items: stretch;\n min-height: 0;\n min-width: 0;\n}\n\n.muigui-row {\n border: 2px solid yellow;\n min-height: 10px\n}\n.muigui-column {\n border: 2px solid lightgreen;\n}\n\n/* -------- */\n\n.muigui-show { /* */ }\n.muigui-hide { \n display: none !important;\n}\n.muigui-disabled {\n pointer-events: none;\n --color: var(--disabled-color) !important;\n --value-color: var(--disabled-color) !important;\n --range-left-color: var(--disabled-color) !important;\n}\n\n.muigui canvas,\n.muigui svg {\n display: block;\n border-radius: var(--border-radius);\n}\n.muigui canvas {\n background-color: var(--value-bg-color);\n}\n\n.muigui-controller {\n min-width: 0;\n min-height: var(--line-height);\n}\n.muigui-root,\n.muigui-menu {\n display: flex;\n flex-direction: column;\n position: relative;\n user-select: none;\n height: fit-content;\n margin: 0;\n padding-bottom: 0.1em;\n border-radius: var(--border-radius);\n}\n.muigui-menu {\n border-bottom: 1px solid var(--menu-sep-color);\n}\n\n.muigui-root>button:nth-child(1),\n.muigui-menu>button:nth-child(1) {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n position: relative;\n text-align: left;\n color: var(--color);\n background-color: var(--menu-bg-color);\n min-height: var(--line-height);\n padding-top: 0.2em;\n padding-bottom: 0.2em;\n cursor: pointer;\n border-radius: var(--border-radius);\n}\n.muigui-root>div:nth-child(2),\n.muigui-menu>div:nth-child(2) {\n flex: 1 1 auto;\n}\n\n.muigui-controller {\n margin-left: 0.2em;\n margin-right: 0.2em;\n}\n.muigui-root.muigui-controller,\n.muigui-menu.muigui-controller {\n margin-left: 0;\n margin-right: 0;\n}\n.muigui-controller>*:nth-child(1) {\n flex: 1 0 var(--label-width);\n min-width: 0;\n white-space: pre;\n}\n.muigui-controller>label:nth-child(1) {\n place-content: center start;\n display: inline-grid;\n overflow: hidden;\n}\n.muigui-controller>*:nth-child(2) {\n flex: 1 1 75%;\n min-width: 0;\n}\n\n/* -----------------------------------------\n a label controller is [[label][value]]\n*/\n\n.muigui-label-controller {\n display: flex;\n margin: 0.4em 0 0.4em 0;\n word-wrap: initial;\n align-items: stretch;\n}\n\n.muigui-value {\n display: flex;\n align-items: stretch;\n}\n.muigui-value>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n.muigui-value>*:nth-child(1) {\n flex: 1 1 calc(100% - var(--number-width));\n}\n.muigui-value>*:nth-child(2) {\n flex: 1 1 var(--number-width);\n margin-left: 0.2em;\n}\n\n/* fix! */\n.muigui-open>button>label::before,\n.muigui-closed>button>label::before {\n width: 1.25em;\n height: var(--line-height);\n display: inline-grid;\n place-content: center start;\n pointer-events: none;\n}\n.muigui-open>button>label::before {\n content: "ⓧ"; /*"▼";*/\n}\n.muigui-closed>button>label::before {\n content: "⨁"; /*"▶";*/\n}\n.muigui-open>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 0.5s ease-out;\n max-height: 100vh;\n overflow: auto;\n opacity: 1;\n}\n\n.muigui-closed>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 1s;\n max-height: 0;\n opacity: 0;\n overflow: hidden;\n}\n\n/* ---- popdown ---- */\n\n.muigui-pop-down-top {\n display: flex;\n}\n/* fix? */\n.muigui-value>*:nth-child(1).muigui-pop-down-top {\n flex: 0;\n}\n.muigui-pop-down-bottom {\n\n}\n\n.muigui-pop-down-values {\n min-width: 0;\n display: flex;\n}\n.muigui-pop-down-values>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.muigui-value.muigui-pop-down-controller {\n flex-direction: column;\n}\n\n.muigui-pop-down-top input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-pop-down-top input[type=checkbox]::before {\n content: "+";\n display: grid;\n place-content: center;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n color: var(--value-bg-color);\n width: calc(var(--line-height) - 4px);\n height: calc(var(--line-height) - 4px);\n}\n\n.muigui-pop-down-top input[type=checkbox]:checked::before {\n content: "X";\n}\n\n\n/* ---- select ---- */\n\n.muigui select,\n.muigui option,\n.muigui input,\n.muigui button {\n color: var(--value-color);\n background-color: var(--value-bg-color);\n font-family: var(--font-family);\n font-size: var(--font-size);\n border: none;\n margin: 0;\n border-radius: var(--border-radius);\n}\n.muigui select {\n appearance: none;\n margin: 0;\n margin-left: 0; /*?*/\n overflow: hidden; /* Safari */\n}\n\n.muigui select:focus,\n.muigui input:focus,\n.muigui button:focus {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui select:hover,\n.muigui option:hover,\n.muigui input:hover,\n.muigui button:hover {\n background-color: var(--hover-bg-color); \n}\n\n/* ------ [ label ] ------ */\n\n.muigui-label {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n padding-top: 0.4em;\n padding-bottom: 0.3em;\n place-content: center start;\n background-color: var(--menu-bg-color);\n white-space: pre;\n border-radius: var(--border-radius);\n}\n\n/* ------ [ divider] ------ */\n\n.muigui-divider {\n min-height: 6px;\n border-top: 2px solid var(--menu-sep-color);\n margin-top: 6px;\n}\n\n/* ------ [ button ] ------ */\n\n.muigui-button {\n display: grid;\n\n}\n.muigui-button button {\n border: none;\n color: var(--value-color);\n background-color: var(--button-bg-color);\n cursor: pointer;\n place-content: center center;\n}\n\n/* ------ [ color ] ------ */\n\n.muigui-color>div {\n overflow: hidden;\n position: relative;\n margin-left: 0;\n margin-right: 0; /* why? */\n max-width: var(--line-height);\n border-radius: var(--border-radius);\n}\n\n.muigui-color>div:focus-within {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui-color input[type=color] {\n border: none;\n padding: 0;\n background: inherit;\n cursor: pointer;\n position: absolute;\n width: 200%;\n left: -10px;\n top: -10px;\n height: 200%;\n}\n.muigui-disabled canvas,\n.muigui-disabled svg,\n.muigui-disabled img,\n.muigui-disabled .muigui-color input[type=color] {\n opacity: 0.2;\n}\n\n/* ------ [ checkbox ] ------ */\n\n.muigui-checkbox>label:nth-child(2) {\n display: grid;\n place-content: center start;\n margin: 0;\n}\n\n.muigui-checkbox input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-checkbox input[type=checkbox]::before {\n content: "";\n color: var(--value-color);\n display: grid;\n place-content: center;\n}\n\n.muigui-checkbox input[type=checkbox]:checked::before {\n content: "✔";\n}\n\n.muigui input[type=number]::-webkit-inner-spin-button, \n.muigui input[type=number]::-webkit-outer-spin-button { \n -webkit-appearance: none;\n appearance: none;\n margin: 0; \n}\n.muigui input[type=number] {\n -moz-appearance: textfield;\n}\n\n/* ------ [ radio grid ] ------ */\n\n.muigui-radio-grid>div {\n display: grid;\n gap: 2px;\n}\n\n.muigui-radio-grid input {\n appearance: none;\n display: none;\n}\n\n.muigui-radio-grid button {\n color: var(--color);\n width: 100%;\n text-align: left;\n}\n\n.muigui-radio-grid input:checked + button {\n color: var(--value-color);\n background-color: var(--selected-color);\n}\n\n/* ------ [ color-chooser ] ------ */\n\n.muigui-color-chooser-cursor {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n.muigui-color-chooser-circle {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n\n\n/* ------ [ vec2 ] ------ */\n\n.muigui-vec2 svg {\n background-color: var(--value-bg-color);\n}\n\n.muigui-vec2-axis {\n stroke: 1px;\n stroke: var(--focus-color);\n}\n\n.muigui-vec2-line {\n stroke-width: 1px;\n stroke: var(--value-color);\n fill: var(--value-color);\n}\n\n/* ------ [ direction ] ------ */\n\n.muigui-direction svg {\n background-color: rgba(0,0,0,0.2);\n}\n\n.muigui-direction:focus-within svg {\n outline: none;\n}\n.muigui-direction-range {\n fill: var(--value-bg-color);\n}\n.muigui-direction svg:focus {\n outline: none;\n}\n.muigui-direction svg:focus .muigui-direction-range {\n stroke-width: 0.5px;\n stroke: var(--focus-color);\n}\n\n.muigui-direction-arrow {\n fill: var(--value-color);\n}\n\n/* ------ [ slider ] ------ */\n\n.muigui-slider>div {\n display: flex;\n align-items: stretch;\n height: var(--line-height);\n}\n.muigui-slider svg {\n flex: 1 1 auto;\n}\n.muigui-slider .muigui-slider-up #muigui-orientation {\n transform: scale(1, -1) translateY(-100%);\n}\n\n.muigui-slider .muigui-slider-up #muigui-number-orientation {\n transform: scale(1,-1);\n}\n\n.muigui-ticks {\n stroke: var(--range-color);\n}\n.muigui-thicks {\n stroke: var(--color);\n stroke-width: 2px;\n}\n.muigui-svg-text {\n fill: var(--color);\n font-size: 7px;\n}\n.muigui-mark {\n fill: var(--value-color);\n}\n\n/* ------ [ range ] ------ */\n\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: transparent;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n margin-top: calc((var(--line-height) - 2px) / -2);\n width: calc(var(--line-height) - 2px);\n height: calc(var(--line-height) - 2px);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n border: 1px solid var(--menu-sep-color);\n height: 2px;\n}\n\n\n/* dat.gui style - doesn\'t work on Safari iOS */\n\n/*\n.muigui-range input[type=range] {\n cursor: ew-resize;\n overflow: hidden;\n}\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: var(--range-right-color);\n margin: 0;\n}\n.muigui-range input[type=range]:hover {\n background-color: var(--range-right-hover-color);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n height: max-content;\n color: var(--range-left-color);\n margin-top: -1px;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 0px;\n height: max-content;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n}\n*/\n\n/* FF */\n/*\n.muigui-range input[type=range]::-moz-slider-progress {\n background-color: var(--range-left-color); \n}\n.muigui-range input[type=range]::-moz-slider-thumb {\n height: max-content;\n width: 0;\n border: none;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n box-sizing: border-box;\n}\n*/\n\n/* ---------------------------------------------------------- */\n\n/* needs to be at bottom to take precedence */\n.muigui-auto-place {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 100001;\n}\n\n'),n&&(this.domElement.style.width=/^\d+$/.test(n)?`${n}px`:n),void 0===s&&e&&(s=document.body,this.domElement.classList.add("muigui-auto-place")),s&&s.appendChild(this.domElement),i&&this.title(i),this.domElement.classList.add("muigui","muigui-colors")}}function Lt(){}function Nt(t,e,n){const i=t.getBoundingClientRect(),o=e.clientX-i.left,s=e.clientY-i.top,r=o/i.width,a=s/i.height,l=o-(n=n||[o,s])[0],u=s-n[1];return{x:o,y:s,nx:r,ny:a,dx:l,dy:u,ndx:l/i.width,ndy:u/i.width}}function St(t,{onDown:e=Lt,onMove:n=Lt,onUp:i=Lt}){let o;const s=function(e){const i={type:"move",...Nt(t,e,o)};n(i)},r=function(e){t.releasePointerCapture(e.pointerId),t.removeEventListener("pointermove",s),t.removeEventListener("pointerup",r),document.body.style.backgroundColor="",i("up")},a=function(n){t.addEventListener("pointermove",s),t.addEventListener("pointerup",r),t.setPointerCapture(n.pointerId);const i=Nt(t,n);o=[i.x,i.y],e({type:"down",...i})};return t.addEventListener("pointerdown",a),function(){t.removeEventListener("pointerdown",a)}}class At extends m{#O;#j;#T;#P;#z;#G;#B;#H;constructor(e){super(t("div",{innerHTML:'\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n',className:"muigui-no-scroll"})),this.#O=this.domElement.children[0],this.#j=this.domElement.children[1],this.#T=this.$(".muigui-color-chooser-circle"),this.#P=this.$("#muigui-color-chooser-hue"),this.#z=this.$(".muigui-color-chooser-cursor");const i=t=>{const i=n(t.nx,0,1),o=n(t.ny,0,1);this.#G[1]=i,this.#G[2]=1-o,this.#B=!0,e.setValue(J(ot(this.#G)))},o=t=>{const i=n(t.nx,0,1);this.#G[0]=i,this.#H=!0,e.setValue(J(ot(this.#G)))};St(this.#O,{onDown:i,onMove:i}),St(this.#j,{onDown:o,onMove:o})}updateDisplay(t){this.#G||(this.#G=rt(_(t)));{const[e,n,i]=rt(_(t));this.#B||(this.#G[0]=n>.001&&i>.001?e:this.#G[0]),this.#H||(this.#G[1]=n,this.#G[2]=i)}{const[t,e,n]=this.#G;this.#B||(this.#z.setAttribute("transform",`translate(${64*t}, 0)`),this.#P.children[0].setAttribute("stop-color",`hsl(${360*t}, 0%, 100%)`),this.#P.children[1].setAttribute("stop-color",`hsl(${360*t}, 100%, 50%)`)),this.#H||(this.#T.setAttribute("cx",""+64*e),this.#T.setAttribute("cy",""+48*(1-n)))}this.#B=!1,this.#H=!1}}class Ut extends V{#R;#Y;#W;#u={open:!1};constructor(e,n,i={}){super(e,n,"muigui-pop-down-controller"),this.#R=this.add(new G("div","muigui-pop-down-top"));const o=this.#R.addElem(t("input",{type:"checkbox",onChange:()=>{this.#u.open=o.checked}}));this.#Y=this.#R.add(new G("div","muigui-pop-down-values")),this.#W=this.add(new G("div","muigui-pop-down-bottom")),this.setOptions(i)}updateDisplay(){super.updateDisplay();const{open:t}=this.#u;this.domElement.children[1].classList.toggle("muigui-open",t),this.domElement.children[1].classList.toggle("muigui-closed",!t)}setOptions(t){r(this.#u,t),super.setOptions(t),this.updateDisplay()}addTop(t){return this.#Y.add(t)}addBottom(t){return this.#W.add(t)}}function Ot(){}const jt={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]};function Tt(t,{onDown:e=Ot,onUp:n=Ot}){const i=function(t){const i=t.shiftKey?10:1,[o,s]=(jt[t.key]||[0,0]).map((t=>t*i));("keydown"===t.type?e:n)({type:t.type.substring(3),dx:o,dy:s,event:t})};return t.addEventListener("keydown",i),t.addEventListener("keyup",i),function(){t.removeEventListener("keydown",i),t.removeEventListener("keyup",i)}}function Pt(t,e=""){if(!t)throw new Error(e)}function zt(t,e,n,i,o,s){const r=Math.abs(n)*Math.cos(s),a=Math.abs(i)*Math.sin(s);return[t+Math.cos(o)*r-Math.sin(o)*a,e+Math.sin(o)*r+Math.cos(o)*a]}function Gt(t,e,n,i,o){Pt(Math.abs(i-o)<=2*Math.PI),Pt(i>=-Math.PI&&i<=2*Math.PI),Pt(i<=o),Pt(o>=-Math.PI&&o<=4*Math.PI);const{x1:s,y1:r,x2:a,y2:l,fa:u,fs:c}=function(t,e,n,i,o,s,r){const[a,l]=zt(t,e,n,i,o,s),[u,c]=zt(t,e,n,i,o,s+r);return{x1:a,y1:l,x2:u,y2:c,fa:Math.abs(r)>Math.PI?1:0,fs:r>0?1:0}}(t,e,n,n,0,i,o-i);return Math.abs(Math.abs(i-o)-2*Math.PI)>Number.EPSILON?`M${t} ${e} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l} L${t} ${e}`:`M${s} ${r} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l}`}const Bt=t=>s(t+Math.PI,2*Math.PI)-Math.PI;class Ht extends m{#q;#_;#J;#K;#u={step:1,min:-180,max:180,dirMin:-Math.PI,dirMax:Math.PI,wrap:void 0,converters:I};constructor(e,i={}){const r=L();super(t("div",{className:"muigui-direction muigui-no-scroll",innerHTML:'\n\n \x3c!----\x3e\n \n \n \n \n \n \n\n',onWheel:t=>{t.preventDefault();const{min:i,max:a,step:l}=this.#u,u=r(t,l);let c=this.#J+u;this.#K&&(c=s(c-i,a-i)+i);const h=n(o(c,(t=>t),l),i,a);e.setValue(h)}}));const a=t=>{const{min:i,max:s,step:r,dirMin:a,dirMax:l}=this.#u,u=2*t.nx-1,c=2*t.ny-1,h=Math.atan2(c,u),d=(a+l)/2,p=n((Bt(h-d)-Bt(a-d))/(l-a),0,1),m=o(i+(s-i)*p,(t=>t),r);e.setValue(m)};St(this.domElement,{onDown:a,onMove:a}),Tt(this.domElement,{onDown:t=>{const{min:i,max:s,step:r}=this.#u,a=n(o(this.#J+t.dx*r,(t=>t),r),i,s);e.setValue(a)}}),this.#q=this.$("#muigui-arrow"),this.#_=this.$("#muigui-range"),this.setOptions(i)}updateDisplay(t){this.#J=t;const{min:e,max:n}=this.#u,i=(t-e)/(n-e),o=(s=this.#u.dirMin,r=this.#u.dirMax,s+(r-s)*i);var s,r;this.#q.style.transform=`rotate(${o}rad)`}setOptions(t){r(this.#u,t);const{dirMin:e,dirMax:n,wrap:i}=this.#u;this.#K=void 0!==i?i:Math.abs(e-n)>=2*Math.PI-Number.EPSILON;const[o,s]=e(o.push(i),t("label",{},[t("input",{type:"radio",name:s,value:a,onChange:function(){this.checked&&e.setFinalValue(r.#D[this.value])}}),t("button",{type:"button",textContent:n,onClick:function(){this.previousElementSibling.click()}})]))))));const r=this;this.#D=o,this.cols(i)}updateDisplay(t){const e=this.#D.indexOf(t);for(let t=0;t{e({rect:t.getBoundingClientRect(),elem:t})})).observe(t)}function Wt(t,e,n,i){Yt(t,(({rect:o})=>{const{width:s,height:r}=o;t.setAttribute("viewBox",`-${s*e} -${r*n} ${s} ${r}`),i({elem:t,rect:o})}))}function qt(t,e,n,i,s,r){const a=[];tt),n)),e=Math.min(e,s);for(let i=t;i<=e;i+=n)a.push(`M${i} 0 l0 ${r}`);return a.join(" ")}class _t extends m{#X;#Z;#Q;#tt;#et;#nt;#it;#ot;#st;#J;#rt;#u={min:-100,max:100,step:1,unit:10,unitSize:10,ticksPerUnit:5,labelFn:t=>t,tickHeight:1,limits:!0,thicksColor:void 0,orientation:void 0};constructor(e,i){const s=L();let r;super(t("div",{innerHTML:'\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \x3c!----\x3e\n \x3c!----\x3e\n \n \n \n \n\n',className:"muigui-no-v-scroll",onWheel:t=>{t.preventDefault();const{min:i,max:r,step:a}=this.#u,l=s(t,a),u=n(o(this.#J+l,(t=>t),a),i,r);e.setValue(u)}})),this.#X=this.$("svg"),this.#Z=this.$("#muigui-origin"),this.#Q=this.$("#muigui-ticks"),this.#tt=this.$("#muigui-thicks"),this.#et=this.$("#muigui-numbers"),this.#nt=this.$("#muigui-left-grad"),this.#it=this.$("#muigui-right-grad"),this.setOptions(i),St(this.domElement,{onDown:()=>{r=this.#J},onMove:t=>{const{min:i,max:s,unitSize:a,unit:l,step:u}=this.#u,c=n(o(r-t.dx/a*l,(t=>t),u),i,s);e.setValue(c)}}),Tt(this.domElement,{onDown:t=>{const{min:i,max:s,step:r}=this.#u,a=n(o(this.#J+t.dx*r,(t=>t),r),i,s);e.setValue(a)}}),Wt(this.#X,.5,0,(({rect:{width:t}})=>{this.#nt.setAttribute("x",-t/2),this.#it.setAttribute("x",t/2-20),this.#rt=function(t){const e=t.innerHTML;t.innerHTML="- ";const n=t.querySelector("text").getComputedTextLength();return t.innerHTML=e,n}(this.#et),this.#ot=t,this.#at()}))}#at(){if(!this.#ot||void 0===this.#J)return;const{labelFn:t,limits:e,min:n,max:i,orientation:s,tickHeight:r,ticksPerUnit:a,unit:l,unitSize:u,thicksColor:c}=this.#u,h=Math.ceil(this.#ot/u),d=this.#J/l,p=Math.round(d-h),m=p*u,g=(p+2*h)*u,f=e?n*u/l:m,b=e?i*u/l:g,v=""===t(1)?10:5;a>1&&this.#Q.setAttribute("d",qt(m,g,u/a,f,b,v*r)),this.#tt.style.stroke=c,this.#tt.setAttribute("d",qt(m,g,u,f,b,v)),this.#et.innerHTML=function(t,e,n,i,s,r,a,l){const u=[];tt),n)),e=Math.min(e,a);const c=Math.max(0,-Math.log10(i));for(let o=t;o<=e;o+=n)u.push(`${h=o/n*i,l(h.toFixed(c))}`);var h;return u.join("\n")}(m,g,u,l,this.#rt,f,b,t),this.#Z.setAttribute("transform",`translate(${-this.#J*u/l} 0)`),this.#X.classList.toggle("muigui-slider-up","up"===s)}updateDisplay(t){this.#J=t,this.#at()}setOptions(t){return r(this.#u,t),this}}class Jt extends m{#X;#q;#T;#J=[];constructor(e){super(t("div",{innerHTML:'\n\n \n \n \n \n \n\n',className:"muigui-no-scroll"}));const n=t=>{const{width:n,height:i}=this.#X.getBoundingClientRect(),o=2*t.nx-1,s=2*t.ny-1;e.setValue([o*n*.5,s*i*.5])};St(this.domElement,{onDown:n,onMove:n}),this.#X=this.$("svg"),this.#q=this.$("#muigui-arrow"),this.#T=this.$("#muigui-circle"),Wt(this.#X,.5,.5,(()=>this.#lt))}#lt(){const[t,e]=this.#J;this.#q.setAttribute("d",`M0,0L${t},${e}`),this.#T.setAttribute("transform",`translate(${t}, ${e})`)}updateDisplay(t){this.#J[0]=t[0],this.#J[1]=t[1],this.#lt()}}return Ft.ColorChooser=class extends Ut{constructor(t,e){super(t,e,"muigui-color-chooser"),this.addTop(new P(this)),this.addBottom(new At(this)),this.updateDisplay()}},Ft.Direction=class extends Ut{#u;constructor(t,e,n){super(t,e,"muigui-direction"),this.#u=n,this.addTop(new N(this,I)),this.addBottom(new Ht(this,n)),this.updateDisplay()}},Ft.RadioGrid=class extends V{constructor(t,e,n){super(t,e,"muigui-radio-grid");const i="number"==typeof this.getValue(),{keyValues:o,cols:s=3}=n,r=U(o,i);this.add(new Rt(this,r,s)),this.updateDisplay()}},Ft.Range=T,Ft.Select=O,Ft.Slider=class extends V{constructor(t,e,n={}){super(t,e,"muigui-slider"),this.add(new _t(this,n)),this.add(new N(this,n)),this.updateDisplay()}},Ft.TextNumber=S,Ft.Vec2=class extends Ut{constructor(t,e){super(t,e,"muigui-vec2");const n=t=>({setValue:e=>{const n=this.getValue();n[t]=e,this.setValue(n)},setFinalValue:e=>{const n=this.getValue();n[t]=e,this.setFinalValue(n)}});this.addTop(new N(n(0),{converters:{to:t=>t[0],from:D.from}})),this.addTop(new N(n(1),{converters:{to:t=>t[1],from:D.from}})),this.addBottom(new Jt(this)),this.updateDisplay()}},Ft})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).GUI=e()}(this,(function(){"use strict";var t={default:'\n.muigui {\n --bg-color: #ddd;\n --color: #222;\n --contrast-color: #eee;\n --value-color: #145 ;\n --value-bg-color: #eeee;\n --disabled-color: #999;\n --menu-bg-color: #f8f8f8;\n --menu-sep-color: #bbb;\n --hover-bg-color: #999;\n --focus-color: #68C;\n --range-color: #888888;\n --invalid-color: #FF0000;\n --selected-color: rgb(255, 255, 255, 0.9);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n}\n\n@media (prefers-color-scheme: dark) {\n .muigui {\n --bg-color: #222222;\n --color: #dddddd;\n --contrast-color: #000;\n --value-color: #43e5f7;\n --value-bg-color: #444444;\n --disabled-color: #666666;\n --menu-bg-color: #080808;\n --menu-sep-color: #444444;\n --hover-bg-color: #666666;\n --focus-color: #88AAFF;\n --range-color: #888888;\n --invalid-color: #FF6666;\n --selected-color: rgba(255, 255, 255, 0.3);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n }\n}\n\n.muigui {\n --width: 250px;\n --label-width: 45%;\n --number-width: 40%;\n\n\n --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;\n --font-size: 11px;\n --font-family-mono: Menlo, Monaco, Consolas, "Droid Sans Mono", monospace;\n --font-size-mono: 11px;\n\n --line-height: 1.7em;\n --border-radius: 0px;\n\n width: var(--width);\n font-family: var(--font-family);\n font-size: var(--font-size);\n box-sizing: border-box;\n line-height: 100%;\n}\n.muigui * {\n box-sizing: inherit;\n}\n\n.muigui-no-scroll {\n touch-action: none;\n}\n.muigui-no-h-scroll {\n touch-action: pan-y;\n}\n.muigui-no-v-scroll {\n touch-action: pan-x;\n}\n\n.muigui-invalid-value {\n background-color: red !important;\n color: white !important;\n}\n\n.muigui-grid {\n display: grid;\n}\n.muigui-rows {\n display: flex;\n flex-direction: column;\n\n min-height: 20px;\n border: 2px solid red;\n}\n.muigui-columns {\n display: flex;\n flex-direction: row;\n\n height: 20px;\n border: 2px solid green;\n}\n.muigui-rows>*,\n.muigui-columns>* {\n flex: 1 1 auto;\n align-items: stretch;\n min-height: 0;\n min-width: 0;\n}\n\n.muigui-row {\n border: 2px solid yellow;\n min-height: 10px\n}\n.muigui-column {\n border: 2px solid lightgreen;\n}\n\n/* -------- */\n\n.muigui-show { /* */ }\n.muigui-hide { \n display: none !important;\n}\n.muigui-disabled {\n pointer-events: none;\n --color: var(--disabled-color) !important;\n --value-color: var(--disabled-color) !important;\n --range-left-color: var(--disabled-color) !important;\n}\n\n.muigui canvas,\n.muigui svg {\n display: block;\n border-radius: var(--border-radius);\n}\n.muigui canvas {\n background-color: var(--value-bg-color);\n}\n\n.muigui-controller {\n min-width: 0;\n min-height: var(--line-height);\n}\n.muigui-root,\n.muigui-menu {\n display: flex;\n flex-direction: column;\n position: relative;\n user-select: none;\n height: fit-content;\n margin: 0;\n padding-bottom: 0.1em;\n border-radius: var(--border-radius);\n}\n.muigui-menu {\n border-bottom: 1px solid var(--menu-sep-color);\n}\n\n.muigui-root>button:nth-child(1),\n.muigui-menu>button:nth-child(1) {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n position: relative;\n text-align: left;\n color: var(--color);\n background-color: var(--menu-bg-color);\n min-height: var(--line-height);\n padding-top: 0.2em;\n padding-bottom: 0.2em;\n cursor: pointer;\n border-radius: var(--border-radius);\n}\n.muigui-root>div:nth-child(2),\n.muigui-menu>div:nth-child(2) {\n flex: 1 1 auto;\n}\n\n.muigui-controller {\n margin-left: 0.2em;\n margin-right: 0.2em;\n}\n.muigui-root.muigui-controller,\n.muigui-menu.muigui-controller {\n margin-left: 0;\n margin-right: 0;\n}\n.muigui-controller>*:nth-child(1) {\n flex: 1 0 var(--label-width);\n min-width: 0;\n white-space: pre;\n}\n.muigui-controller>label:nth-child(1) {\n place-content: center start;\n display: inline-grid;\n overflow: hidden;\n}\n.muigui-controller>*:nth-child(2) {\n flex: 1 1 75%;\n min-width: 0;\n}\n\n/* -----------------------------------------\n a label controller is [[label][value]]\n*/\n\n.muigui-label-controller {\n display: flex;\n margin: 0.4em 0 0.4em 0;\n word-wrap: initial;\n align-items: stretch;\n}\n\n.muigui-value {\n display: flex;\n align-items: stretch;\n}\n.muigui-value>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n.muigui-value>*:nth-child(1) {\n flex: 1 1 calc(100% - var(--number-width));\n}\n.muigui-value>*:nth-child(2) {\n flex: 1 1 var(--number-width);\n margin-left: 0.2em;\n}\n\n/* fix! */\n.muigui-open>button>label::before,\n.muigui-closed>button>label::before {\n width: 1.25em;\n height: var(--line-height);\n display: inline-grid;\n place-content: center start;\n pointer-events: none;\n}\n.muigui-open>button>label::before {\n content: "ⓧ"; /*"▼";*/\n}\n.muigui-closed>button>label::before {\n content: "⨁"; /*"▶";*/\n}\n.muigui-open>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 0.5s ease-out;\n max-height: 100vh;\n overflow: auto;\n opacity: 1;\n}\n\n.muigui-closed>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 1s;\n max-height: 0;\n opacity: 0;\n overflow: hidden;\n}\n\n/* ---- popdown ---- */\n\n.muigui-pop-down-top {\n display: flex;\n}\n/* fix? */\n.muigui-value>*:nth-child(1).muigui-pop-down-top {\n flex: 0;\n}\n.muigui-pop-down-bottom {\n\n}\n\n.muigui-pop-down-values {\n min-width: 0;\n display: flex;\n}\n.muigui-pop-down-values>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.muigui-value.muigui-pop-down-controller {\n flex-direction: column;\n}\n\n.muigui-pop-down-top input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-pop-down-top input[type=checkbox]::before {\n content: "+";\n display: grid;\n place-content: center;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n color: var(--value-bg-color);\n width: calc(var(--line-height) - 4px);\n height: calc(var(--line-height) - 4px);\n}\n\n.muigui-pop-down-top input[type=checkbox]:checked::before {\n content: "X";\n}\n\n\n/* ---- select ---- */\n\n.muigui select,\n.muigui option,\n.muigui input,\n.muigui button {\n color: var(--value-color);\n background-color: var(--value-bg-color);\n font-family: var(--font-family);\n font-size: var(--font-size);\n border: none;\n margin: 0;\n border-radius: var(--border-radius);\n}\n.muigui select {\n appearance: none;\n margin: 0;\n margin-left: 0; /*?*/\n overflow: hidden; /* Safari */\n}\n\n.muigui select:focus,\n.muigui input:focus,\n.muigui button:focus {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui select:hover,\n.muigui option:hover,\n.muigui input:hover,\n.muigui button:hover {\n background-color: var(--hover-bg-color); \n}\n\n/* ------ [ label ] ------ */\n\n.muigui-label {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n padding-top: 0.4em;\n padding-bottom: 0.3em;\n place-content: center start;\n background-color: var(--menu-bg-color);\n white-space: pre;\n border-radius: var(--border-radius);\n}\n\n/* ------ [ divider] ------ */\n\n.muigui-divider {\n min-height: 6px;\n border-top: 2px solid var(--menu-sep-color);\n margin-top: 6px;\n}\n\n/* ------ [ button ] ------ */\n\n.muigui-button {\n display: grid;\n\n}\n.muigui-button button {\n border: none;\n color: var(--value-color);\n background-color: var(--button-bg-color);\n cursor: pointer;\n place-content: center center;\n}\n\n/* ------ [ color ] ------ */\n\n.muigui-color>div {\n overflow: hidden;\n position: relative;\n margin-left: 0;\n margin-right: 0; /* why? */\n max-width: var(--line-height);\n border-radius: var(--border-radius);\n}\n\n.muigui-color>div:focus-within {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui-color input[type=color] {\n border: none;\n padding: 0;\n background: inherit;\n cursor: pointer;\n position: absolute;\n width: 200%;\n left: -10px;\n top: -10px;\n height: 200%;\n}\n.muigui-disabled canvas,\n.muigui-disabled svg,\n.muigui-disabled img,\n.muigui-disabled .muigui-color input[type=color] {\n opacity: 0.2;\n}\n\n/* ------ [ checkbox ] ------ */\n\n.muigui-checkbox>label:nth-child(2) {\n display: grid;\n place-content: center start;\n margin: 0;\n}\n\n.muigui-checkbox input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-checkbox input[type=checkbox]::before {\n content: "";\n color: var(--value-color);\n display: grid;\n place-content: center;\n}\n\n.muigui-checkbox input[type=checkbox]:checked::before {\n content: "✔";\n}\n\n.muigui input[type=number]::-webkit-inner-spin-button, \n.muigui input[type=number]::-webkit-outer-spin-button { \n -webkit-appearance: none;\n appearance: none;\n margin: 0; \n}\n.muigui input[type=number] {\n -moz-appearance: textfield;\n}\n\n/* ------ [ radio grid ] ------ */\n\n.muigui-radio-grid>div {\n display: grid;\n gap: 2px;\n}\n\n.muigui-radio-grid input {\n appearance: none;\n display: none;\n}\n\n.muigui-radio-grid button {\n color: var(--color);\n width: 100%;\n text-align: left;\n}\n\n.muigui-radio-grid input:checked + button {\n color: var(--value-color);\n background-color: var(--selected-color);\n}\n\n/* ------ [ color-chooser ] ------ */\n\n.muigui-color-chooser-cursor {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n.muigui-color-chooser-circle {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n\n\n/* ------ [ vec2 ] ------ */\n\n.muigui-vec2 svg {\n background-color: var(--value-bg-color);\n}\n\n.muigui-vec2-axis {\n stroke: 1px;\n stroke: var(--focus-color);\n}\n\n.muigui-vec2-line {\n stroke-width: 1px;\n stroke: var(--value-color);\n fill: var(--value-color);\n}\n\n/* ------ [ direction ] ------ */\n\n.muigui-direction svg {\n background-color: rgba(0,0,0,0.2);\n}\n\n.muigui-direction:focus-within svg {\n outline: none;\n}\n.muigui-direction-range {\n fill: var(--value-bg-color);\n}\n.muigui-direction svg:focus {\n outline: none;\n}\n.muigui-direction svg:focus .muigui-direction-range {\n stroke-width: 0.5px;\n stroke: var(--focus-color);\n}\n\n.muigui-direction-arrow {\n fill: var(--value-color);\n}\n\n/* ------ [ slider ] ------ */\n\n.muigui-slider>div {\n display: flex;\n align-items: stretch;\n height: var(--line-height);\n}\n.muigui-slider svg {\n flex: 1 1 auto;\n}\n.muigui-slider .muigui-slider-up #muigui-orientation {\n transform: scale(1, -1) translateY(-100%);\n}\n\n.muigui-slider .muigui-slider-up #muigui-number-orientation {\n transform: scale(1,-1);\n}\n\n.muigui-ticks {\n stroke: var(--range-color);\n}\n.muigui-thicks {\n stroke: var(--color);\n stroke-width: 2px;\n}\n.muigui-svg-text {\n fill: var(--color);\n font-size: 7px;\n}\n.muigui-mark {\n fill: var(--value-color);\n}\n\n/* ------ [ range ] ------ */\n\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: transparent;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n margin-top: calc((var(--line-height) - 2px) / -2);\n width: calc(var(--line-height) - 2px);\n height: calc(var(--line-height) - 2px);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n border: 1px solid var(--menu-sep-color);\n height: 2px;\n}\n\n\n/* dat.gui style - doesn\'t work on Safari iOS */\n\n/*\n.muigui-range input[type=range] {\n cursor: ew-resize;\n overflow: hidden;\n}\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: var(--range-right-color);\n margin: 0;\n}\n.muigui-range input[type=range]:hover {\n background-color: var(--range-right-hover-color);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n height: max-content;\n color: var(--range-left-color);\n margin-top: -1px;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 0px;\n height: max-content;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n}\n*/\n\n/* FF */\n/*\n.muigui-range input[type=range]::-moz-slider-progress {\n background-color: var(--range-left-color); \n}\n.muigui-range input[type=range]::-moz-slider-thumb {\n height: max-content;\n width: 0;\n border: none;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n box-sizing: border-box;\n}\n*/\n\n/* ---------------------------------------------------------- */\n\n/* needs to be at bottom to take precedence */\n.muigui-auto-place {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 100001;\n}\n\n',themes:{default:"",float:"\n :root {\n color-scheme: light dark,\n }\n\n .muigui {\n --width: 400px;\n --bg-color: initial;\n --label-width: 25%;\n }\n\n input,\n .muigui-label-controller>label {\n text-shadow:\n -1px -1px 0 var(--contrast-color),\n 1px -1px 0 var(--contrast-color),\n -1px 1px 0 var(--contrast-color),\n 1px 1px 0 var(--contrast-color);\n }\n\n .muigui-controller > label:nth-child(1) {\n place-content: center end;\n margin-right: 1em;\n }\n\n .muigui-value > :nth-child(2) {\n margin-left: 1em;\n }\n\n .muigui-root>*:nth-child(1) {\n display: none;\n }\n\n .muigui-range input[type=range]::-webkit-slider-thumb {\n border-radius: 1em;\n }\n\n .muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: initial;\n appearance: none;\n border: 1px solid rgba(0, 0, 0, 0.25);\n height: 2px;\n }\n\n .muigui-colors {\n --value-color: var(--color );\n --value-bg-color: rgba(0, 0, 0, 0.1);\n --disabled-color: #cccccc;\n --menu-bg-color: rgba(0, 0, 0, 0.1);\n --menu-sep-color: #bbbbbb;\n --hover-bg-color: rgba(0, 0, 0, 0);\n --invalid-color: #FF0000;\n --selected-color: rgba(0, 0, 0, 0.3);\n --range-color: rgba(0, 0, 0, 0.125);\n }\n"}};function e(t,e={},n=[]){const i=document.createElement(t);return function(t,e,n){for(const[n,i]of Object.entries(e))if("function"==typeof i&&n.startsWith("on")){const e=n.substring(2).toLowerCase();t.addEventListener(e,i,{passive:!1})}else if("object"==typeof i)for(const[e,o]of Object.entries(i))t[n][e]=o;else void 0===t[n]?t.setAttribute(n,i):t[n]=i;for(const e of n)t.appendChild(e)}(i,e,n),i}function n(t,e){const n=t.indexOf(e);return n&&t.splice(n,1),t}function i(t,e,n){return Math.max(e,Math.min(n,t))}const o="undefined"!=typeof SharedArrayBuffer?function(t){return t&&t.buffer&&(t.buffer instanceof ArrayBuffer||t.buffer instanceof SharedArrayBuffer)}:function(t){return t&&t.buffer&&t.buffer instanceof ArrayBuffer},s=(t,e,n)=>Math.round(e(t)/n)/(1/n),r=(t,e)=>(t%e+e)%e;function a(t,e){for(const n in e)n in t&&(t[n]=e[n]);return t}const l=(t,e,n,i,o)=>(t-e)*(o-i)/(n-e)+i,u=({from:t,to:e})=>({to:n=>l(n,...t,...e),from:n=>[!0,l(n,...e,...t)]}),c=({from:t,to:e,step:n})=>({min:e[0],max:e[1],...n&&{step:n},converters:u({from:t,to:e})}),h={to:t=>t,from:t=>[!0,t]};function d(t,e,n,i,o){const{converters:{from:s}=h}=o,{min:r,max:a}=o,l=o.minRange||0,u=s(l)[1];return console.log("guiMinRange",l),console.log("valueMinRange",u),[t.add(e,n,{...o,min:r,max:a-l}).listen().onChange((t=>{e[i]=Math.min(a,Math.max(t+u,e[i]))})),t.add(e,i,{...o,min:r+l,max:a}).listen().onChange((t=>{e[n]=Math.max(r,Math.min(t-u,e[n]))}))]}class p{#t;#e=[];constructor(t){this.domElement=t,this.#t=t}addElem(t){return this.#t.appendChild(t),t}removeElem(t){return this.#t.removeChild(t),t}pushSubElem(t){this.#t.appendChild(t),this.#t=t}popSubElem(){this.#t=this.#t.parentElement}add(t){return this.#e.push(t),this.addElem(t.domElement),t}remove(t){return this.removeElem(t.domElement),n(this.#e,t),t}pushSubView(t){this.pushSubElem(t.domElement)}popSubView(){this.popSubElem()}setOptions(t){for(const e of this.#e)e.setOptions(t)}updateDisplayIfNeeded(t,e){for(const n of this.#e)n.updateDisplayIfNeeded(t,e);return this}$(t){return this.domElement.querySelector(t)}}class m extends p{#n;#i;#o;constructor(t){super(e("div",{className:"muigui-controller"})),this.#n=[],this.#i=[],t&&this.domElement.classList.add(t)}get parent(){return this.#o}setParent(t){this.#o=t,this.enable(!this.disabled())}show(t=!0){return this.domElement.classList.toggle("muigui-hide",!t),this.domElement.classList.toggle("muigui-show",t),this}hide(){return this.show(!1)}disabled(){return!!this.domElement.closest(".muigui-disabled")}enable(t=!0){return this.domElement.classList.toggle("muigui-disabled",!t),["input","button","select","textarea"].forEach((t=>{this.domElement.querySelectorAll(t).forEach((t=>{const e=!!t.closest(".muigui-disabled");t.disabled=e}))})),this}disable(t=!0){return this.enable(!t)}onChange(t){return this.removeChange(t),this.#n.push(t),this}removeChange(t){return n(this.#n,t),this}onFinishChange(t){return this.removeFinishChange(t),this.#i.push(t),this}removeFinishChange(t){return n(this.#i,t),this}#s(t,e){for(const n of t)n.call(this,e)}emitChange(t,e,n){this.#s(this.#n,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitChange({object:e,property:n,value:t,controller:this}))}emitFinalChange(t,e,n){this.#s(this.#i,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitFinalChange({object:e,property:n,value:t,controller:this}))}getColors(){const t=t=>t.replace(/-([a-z])/g,((t,e)=>e.toUpperCase())),n=e("div");this.domElement.appendChild(n);const i=Object.fromEntries(["color","bg-color","value-color","value-bg-color","hover-bg-color","menu-bg-color","menu-sep-color","disabled-color"].map((e=>{n.style.color=`var(--${e})`;const i=getComputedStyle(n);return[t(e),i.color]})));return n.remove(),i}}class g extends m{#r;#a;#l;#u={name:""};constructor(t,n,i={}){super("muigui-button",""),this.#r=t,this.#a=n,this.#l=this.addElem(e("button",{type:"button",onClick:()=>{this.#r[this.#a](this)}})),this.setOptions({name:n,...i})}setOptions(t){a(this.#u,t);const{name:e}=this.#u;this.#l.textContent=e}}function f(t,e){if(t.length!==e.length)return!1;for(let n=0;n{t.setValue(i.checked)},onChange:()=>{t.setFinalValue(i.checked)}});super(e("label",{},[i]))}updateDisplay(t){this.domElement.checked=t}}const x=[],w=new Set;let y,k;function E(){y=void 0,k=!0;for(const t of x)w.has(t)||t();k=!1,w.size&&(k?C():(w.forEach((t=>{n(x,t)})),w.clear())),C()}function C(){!y&&x.length&&(y=requestAnimationFrame(E))}let $=0;function M(){return"muigui-"+ ++$}class V extends p{constructor(t=""){super(e("div",{className:"muigui-value"})),t&&this.domElement.classList.add(t)}}class S extends m{#b;#v;constructor(t="",n=""){super("muigui-label-controller"),this.#b=M(),this.#v=e("label",{for:this.#b}),this.domElement.appendChild(this.#v),this.pushSubView(new V(t)),this.name(n)}get id(){return this.#b}name(t){return this.#v.title===this.#v.textContent&&(this.#v.title=t),this.#v.textContent=t,this}tooltip(t){this.#v.title=t}}class I extends S{#r;#a;#x;#w;#e;#y;constructor(t,e,n=""){super(n,e),this.#r=t,this.#a=e,this.#x=this.getValue(),this.#w=!1,this.#e=[]}get initialValue(){return this.#x}get object(){return this.#r}get property(){return this.#a}add(t){return this.#e.push(t),super.add(t),this.updateDisplay(),t}#k(t,e){if("object"==typeof t){const e=this.#r[this.#a];if(Array.isArray(t))for(let n=0;n=0&&x.splice(e,1)}(this.#y)),this}}class D extends I{constructor(t,e){super(t,e,"muigui-checkbox");const n=this.id;this.add(new v(this,n)),this.updateDisplay()}}const F={to:t=>t,from:t=>[!0,t]},L={to:t=>t.toString(),from:t=>{const e=parseFloat(t);return[!Number.isNaN(e),e]}},N={radToDeg:u({to:[0,180],from:[0,Math.PI]})};function A(){let t=0;return function(e,n,i=5){t-=e.deltaY*n/i;const o=Math.floor(Math.abs(t)/n)*Math.sign(t)*n;return t-=o,o}}class U extends b{#E;#C;#$;#M;#u={step:.01,converters:L,min:Number.NEGATIVE_INFINITY,max:Number.POSITIVE_INFINITY};constructor(t,n){const o=t.setValue.bind(t),r=t.setFinalValue.bind(t),a=A();super(e("input",{type:"number",onInput:()=>this.#V(o,!0),onChange:()=>this.#V(r,!1),onWheel:e=>{e.preventDefault();const{min:n,max:o,step:r}=this.#u,l=a(e,r),u=parseFloat(this.domElement.value),c=i(s(u+l,(t=>t),r),n,o);t.setValue(c)}})),this.setOptions(n)}#V(t,e){const n=parseFloat(this.domElement.value),[o,s]=this.#C(n);let r;if(o&&!Number.isNaN(n)){const{min:n,max:o}=this.#u;r=s>=n&&s<=o,this.#M=e,t(i(s,n,o))}this.domElement.classList.toggle("muigui-invalid-value",!o||!r)}updateDisplay(t){this.#M||(this.domElement.value=s(t,this.#E,this.#$)),this.#M=!1}setOptions(t){a(this.#u,t);const{step:e,converters:{to:n,from:i}}=this.#u;return this.#E=n,this.#C=i,this.#$=e,this}}class O extends I{#S;#$;constructor(t,e,n={}){super(t,e,"muigui-checkbox"),this.#S=this.add(new U(this,n)),this.updateDisplay()}}class j extends b{#I;constructor(t,n){const i=[];super(e("select",{onChange:()=>{t.setFinalValue(this.#I[this.domElement.selectedIndex])}},n.map((([t,n])=>(i.push(n),e("option",{textContent:t})))))),this.#I=i}updateDisplay(t){const e=this.#I.indexOf(t);this.domElement.selectedIndex=e}}function T(t,e){return Array.isArray(t)?Array.isArray(t[0])?t:e?t.map(((t,e)=>[t,e])):t.map((t=>[t,t])):[...Object.entries(t)]}class P extends I{constructor(t,e,n){super(t,e,"muigui-select");const i="number"==typeof this.getValue(),{keyValues:o}=n,s=T(o,i);this.add(new j(this,s)),this.updateDisplay()}}class z extends b{#E;#C;#$;#M;#u={step:.01,min:0,max:1,converters:F};constructor(t,n){const o=A();super(e("input",{type:"range",onInput:()=>{this.#M=!0;const{min:e,max:n,step:o}=this.#u,r=parseFloat(this.domElement.value),a=i(s(r,(t=>t),o),e,n),[l,u]=this.#C(a);l&&t.setValue(u)},onChange:()=>{this.#M=!0;const{min:e,max:n,step:o}=this.#u,r=parseFloat(this.domElement.value),a=i(s(r,(t=>t),o),e,n),[l,u]=this.#C(a);l&&t.setFinalValue(u)},onWheel:e=>{e.preventDefault();const[n,r]=this.#C(parseFloat(this.domElement.value));if(!n)return;const{min:a,max:l,step:u}=this.#u,c=o(e,u),h=i(s(r+c,(t=>t),u),a,l);t.setValue(h)}})),this.setOptions(n)}updateDisplay(t){this.#M||(this.domElement.value=s(t,this.#E,this.#$)),this.#M=!1}setOptions(t){a(this.#u,t);const{step:e,min:n,max:i,converters:{to:o,from:s}}=this.#u;return this.#E=o,this.#C=s,this.#$=e,this.domElement.step=e,this.domElement.min=n,this.domElement.max=i,this}}class B extends I{constructor(t,e,n){super(t,e,"muigui-range"),this.add(new z(this,n)),this.add(new U(this,n))}}class G extends b{#E;#C;#M;#u={converters:F};constructor(t,n){const i=t.setValue.bind(t),o=t.setFinalValue.bind(t);super(e("input",{type:"text",onInput:()=>this.#V(i,!0),onChange:()=>this.#V(o,!1)})),this.setOptions(n)}#V(t,e){const[n,i]=this.#C(this.domElement.value);n&&(this.#M=e,t(i)),this.domElement.style.color=n?"":"var(--invalid-color)"}updateDisplay(t){this.#M||(this.domElement.value=this.#E(t),this.domElement.style.color=""),this.#M=!1}setOptions(t){a(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#C=n,this}}class H extends I{constructor(t,e){super(t,e,"muigui-checkbox"),this.add(new G(this)),this.updateDisplay()}}class R extends p{constructor(t,n){super(e(t,{className:n}))}}class Y extends S{#D;constructor(){super("muigui-canvas"),this.#D=this.add(new R("canvas","muigui-canvas")).domElement}get canvas(){return this.#D}}const W=(t,e,n)=>Math.max(e,Math.min(n,t)),q=t=>+t.toFixed(3),_=t=>parseInt(t.substring(1,3),16)<<16|parseInt(t.substring(3,5),16)<<8|parseInt(t.substring(5,7),16),J=t=>[parseInt(t.substring(1,3),16),parseInt(t.substring(3,5),16),parseInt(t.substring(5,7),16)],K=t=>`#${Array.from(t).map((t=>t.toString(16).padStart(2,"0"))).join("")}`,X=t=>J(t).map((t=>q(t/255))),Z=t=>K(Array.from(t).map((t=>Math.round(W(255*t,0,255))))),Q=t=>({r:parseInt(t.substring(1,3),16)/255,g:parseInt(t.substring(3,5),16)/255,b:parseInt(t.substring(5,7),16)/255}),tt=t=>W(Math.round(255*t),0,255).toString(16).padStart(2,"0"),et=t=>`rgb(${J(t).join(", ")})`,nt=/^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,it=t=>{const e=rt(J(t)).map((t=>(t=>+t.toFixed(0))(t)));return`hsl(${e[0]}, ${e[1]}%, ${e[2]}%)`},ot=/^\s*hsl\(\s*(\d+)(?:deg|)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)\s*$/,st=(t,e)=>(t%e+e)%e;const rt=t=>{const[e,n,i]=function([t,e,n]){const i=Math.max(t,e,n),o=Math.min(t,e,n),s=.5*(o+i),r=i-o;let a=0,l=0;if(0!==r)switch(l=0===s||1===s?0:(i-s)/Math.min(s,1-s),i){case t:a=(e-n)/r+(et/255)));return[360*e,100*n,100*i]};function at([t,e,n]){return e=W(e,0,1),n=W(n,0,1),[t,t+2/3,t+1/3].map((t=>{return i=1,o=W(Math.abs(6*(t=>t>=0?t%1:1-t%1)(t)-3)-1,0,1),(i+(o-i)*e)*n;var i,o}))}const lt=t=>Math.round(1e3*t)/1e3;function ut([t,e,n]){const i=n>e?[n,e,-1,2/3]:[e,n,0,-1/3],o=i[0]>t?[i[0],i[1],i[3],t]:[t,i[1],i[2],i[0]],s=o[0]-Math.min(o[3],o[1]);return[Math.abs(o[2]+(o[3]-o[1])/(6*s+Number.EPSILON)),s/(o[0]+Number.EPSILON),o[0]].map(lt)}window.hsv01ToRGBFloat=at,window.rgbFloatToHSV01=ut;const ct=[{re:/^#(?:[0-9a-f]){6}$/i,format:"hex6"},{re:/^(?:[0-9a-f]){6}$/i,format:"hex6-no-hash"},{re:/^#(?:[0-9a-f]){3}$/i,format:"hex3"},{re:/^(?:[0-9a-f]){3}$/i,format:"hex3-no-hash"},{re:nt,format:"css-rgb"},{re:ot,format:"css-hsl"}];function ht(t){switch(typeof t){case"number":return"uint32-rgb";case"string":{const e=function(t){for(const e of ct)if(e.re.test(t))return e}(t.trim());if(e)return e.format;break}case"object":if(t instanceof Uint8Array||t instanceof Uint8ClampedArray){if(3===t.length)return"uint8-rgb"}else if(t instanceof Float32Array){if(3===t.length)return"float-rgb"}else if(Array.isArray(t)){if(3===t.length)return"float-rgb"}else if("r"in t&&"g"in t&&"b"in t)return"object-rgb"}throw new Error(`unknown color format: ${t}`)}function dt(t){return t.trim(t)}function pt(t){return t[1]===t[2]&&t[3]===t[4]&&t[5]===t[6]?`#${t[1]}${t[3]}${t[5]}`:t}const mt=/^(#|)([0-9a-f]{3})$/i;function gt(t){const e=mt.exec(t);if(e){const[,,t]=e;return"#"+`${(n=t)[0]}${n[0]}${n[1]}${n[1]}${n[2]}${n[2]}`}var n;return t}function ft(t){return pt(dt(t))}const bt=t=>{const e=nt.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),`rgb(${n.join(", ")})`]},vt=t=>{const e=ot.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseFloat(t)));return[!n.find((t=>Number.isNaN(t))),`hsl(${n[0]}, ${n[1]}%, ${n[2]}%)`]},xt=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$/,wt=/^\s*(?:0x){0,1}([0-9a-z]{1,6})\s*$/i,yt=/^\s*#[a-f0-9]{6}\s*$|^\s*#[a-f0-9]{3}\s*$/i,kt=/^\s*[a-f0-9]{6}\s*$/i,Et={hex6:{color:{from:t=>[!0,t],to:dt},text:{from:t=>[yt.test(t),t.trim()],to:t=>t}},hex3:{color:{from:t=>[!0,ft(t)],to:gt},text:{from:t=>[yt.test(t),pt(t.trim())],to:t=>t}},"hex6-no-hash":{color:{from:t=>[!0,t.substring(1)],to:t=>`#${dt(t)}`},text:{from:t=>[kt.test(t),t.trim()],to:t=>t}},"hex3-no-hash":{color:{from:t=>[!0,ft(t).substring(1)],to:gt},text:{from:t=>[kt.test(t),pt(t.trim())],to:t=>t}},"uint32-rgb":{color:{from:t=>[!0,_(t)],to:t=>`#${Math.round(t).toString(16).padStart(6,"0")}`},text:{from:t=>(t=>{const e=wt.exec(t);return e?[!0,parseInt(e[1],16)]:[!1]})(t),to:t=>`0x${t.toString(16).padStart(6,"0")}`}},"uint8-rgb":{color:{from:t=>[!0,J(t)],to:K},text:{from:t=>{const e=xt.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),n]},to:t=>t.join(", ")}},"float-rgb":{color:{from:t=>[!0,X(t)],to:Z},text:{from:t=>{const e=t.split(",").map((t=>t.trim())),n=e.map((t=>parseFloat(t)));if(3!==n.length)return[!1];const i=e.findIndex((t=>isNaN(t)));return[i<0,n.map((t=>q(t)))]},to:t=>Array.from(t).map((t=>q(t))).join(", ")}},"object-rgb":{color:{from:t=>[!0,Q(t)],to:t=>`#${tt(t.r)}${tt(t.g)}${tt(t.b)}`},text:{from:t=>{try{const e=t.replace(/([a-z])/g,'"$1"'),n=JSON.parse(e);if(Number.isNaN(n.r)||Number.isNaN(n.g)||Number.isNaN(n.b))throw new Error("not {r, g, b}");return[!0,n]}catch(t){return[!1]}},to:t=>`{r:${q(t.r)}, g:${q(t.g)}, b:${q(t.b)}}`}},"css-rgb":{color:{from:t=>[!0,et(t)],to:t=>{const e=nt.exec(t);return K([e[1],e[2],e[3]].map((t=>parseInt(t))))}},text:{from:bt,to:t=>bt(t)[1]}},"css-hsl":{color:{from:t=>[!0,it(t)],to:t=>{const e=ot.exec(t),n=function([t,e,n]){t=st(t,360),e=W(e/100,0,1),n=W(n/100,0,1);const i=e*Math.min(n,1-n);function o(e){const o=(e+t/30)%12;return n-i*Math.max(-1,Math.min(o-3,9-o,1))}return[o(0),o(8),o(4)].map((t=>Math.round(255*t)))}([e[1],e[2],e[3]].map((t=>parseFloat(t))));return K(n)}},text:{from:vt,to:t=>vt(t)[1]}}};class Ct extends b{#E;#C;#F;#M;#u={converters:F};constructor(t,n){const i=e("input",{type:"color",onInput:()=>{const[e,n]=this.#C(i.value);e&&(this.#M=!0,t.setValue(n))},onChange:()=>{const[e,n]=this.#C(i.value);e&&(this.#M=!0,t.setFinalValue(n))}});super(e("div",{},[i])),this.setOptions(n),this.#F=i}updateDisplay(t){this.#M||(this.#F.value=this.#E(t)),this.#M=!1}setOptions(t){a(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#C=n,this}}class $t extends I{#L;#S;constructor(t,e,n={}){super(t,e,"muigui-color");const i=n.format||ht(this.getValue()),{color:o,text:s}=Et[i];this.#L=this.add(new Ct(this,{converters:o})),this.#S=this.add(new G(this,{converters:s})),this.updateDisplay()}setOptions(t){const{format:e}=t;if(e){const{color:t,text:n}=Et[e];this.#L.setOptions({converters:t}),this.#S.setOptions({converters:n})}return super.setOptions(t),this}}class Mt extends m{constructor(){super("muigui-divider")}}class Vt extends m{#N;#A;constructor(t){super(t),this.#N=[],this.#A=this}get children(){return this.#N}get controllers(){return this.#N.filter((t=>!(t instanceof Vt)))}get folders(){return this.#N.filter((t=>t instanceof Vt))}reset(t=!0){for(const e of this.#N)e instanceof Vt&&!t||e.reset(t);return this}remove(t){const e=this.#N.indexOf(t);if(e>=0){const t=this.#N.splice(e,1)[0];t.domElement.remove(),t.setParent(null)}return this}_addControllerImpl(t){return this.domElement.appendChild(t.domElement),this.#N.push(t),t.setParent(this),t}addController(t){return this.#A._addControllerImpl(t)}pushContainer(t){return this.addController(t),this.#A=t,t}popContainer(){return this.#A=this.#A.parent,this}}class St extends Vt{#U;constructor(t="Controls",n="muigui-menu"){super(n),this.#U=e("label"),this.addElem(e("button",{type:"button",onClick:()=>this.toggleOpen()},[this.#U])),this.pushContainer(new Vt),this.name(t),this.open()}open(t=!0){return this.domElement.classList.toggle("muigui-closed",!t),this.domElement.classList.toggle("muigui-open",t),this}close(){return this.open(!1)}name(t){return this.#U.textContent=t,this}title(t){return this.name(t)}toggleOpen(){return this.open(!this.domElement.classList.contains("muigui-open")),this}}class It extends m{constructor(t){super("muigui-label"),this.text(t)}text(t){return this.domElement.textContent=t,this}}class Dt extends St{add(t,e,...n){const i=t instanceof m?t:function(t,e,...n){const[i]=n;if(Array.isArray(i))return new P(t,e,{keyValues:i});const o=typeof t[e];switch(o){case"number":if("number"==typeof n[0]&&"number"==typeof n[1]){const i=n[0],o=n[1],s=n[2];return new B(t,e,{min:i,max:o,...s&&{step:s}})}return 0===n.length?new O(t,e,...n):new B(t,e,...n);case"boolean":return new D(t,e,...n);case"function":return new g(t,e,...n);case"string":return new H(t,e,...n);case"undefined":throw new Error(`no property named ${e}`);default:throw new Error(`unhandled type ${o} for property ${e}`)}}(t,e,...n);return this.addController(i)}addCanvas(t){return this.addController(new Y(t))}addColor(t,e,...n){return this.addController(new $t(t,e,...n))}addDivider(){return this.addController(new Mt)}addFolder(t){return this.addController(new Dt(t))}addLabel(t){return this.addController(new It(t))}}class Ft extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"})}}customElements.define("muigui-element",Ft);const Lt=new CSSStyleSheet;Lt.replaceSync(t.default);const Nt=new CSSStyleSheet;function At(t){let e,n;function i(){if(e&&!n){const o=e;e=void 0,n=t.replace(o).then((()=>{console.log(o),n=void 0,i()}))}}return function(t){e=t,i()}}const Ut=At(Lt),Ot=At(Nt);class jt extends Dt{static converters=N;static mapRange=l;static makeRangeConverters=u;static makeRangeOptions=c;static makeMinMaxPair=d;#O=new CSSStyleSheet;constructor(t={}){super("Controls","muigui-root"),t instanceof HTMLElement&&(t={parent:t});const{autoPlace:n=!0,width:i,title:o="Controls"}=t;let{parent:s}=t;if(i&&(this.domElement.style.width=/^\d+$/.test(i)?`${i}px`:i),void 0===s&&n&&(s=document.body,this.domElement.classList.add("muigui-auto-place")),s){const t=e("muigui-element");t.shadowRoot.adoptedStyleSheets=[Lt,Nt,this.#O],t.shadow.appendChild(this.domElement),s.appendChild(t)}o&&this.title(o),this.domElement.classList.add("muigui","muigui-colors")}setStyle(t){this.#O.replace(t)}static setBaseStyles(t){Ut(t)}static getBaseStyleSheet(){return Lt}static setUserStyles(t){Ot(t)}static getUserStyleSheet(){return Nt}static setTheme(e){jt.setBaseStyles(`${t.default}\n${t.themes[e]||""}`)}}function Tt(){}function Pt(t,e,n){const i=t.getBoundingClientRect(),o=e.clientX-i.left,s=e.clientY-i.top,r=o/i.width,a=s/i.height,l=o-(n=n||[o,s])[0],u=s-n[1];return{x:o,y:s,nx:r,ny:a,dx:l,dy:u,ndx:l/i.width,ndy:u/i.width}}function zt(t,{onDown:e=Tt,onMove:n=Tt,onUp:i=Tt}){let o;const s=function(e){const i={type:"move",...Pt(t,e,o)};n(i)},r=function(e){t.releasePointerCapture(e.pointerId),t.removeEventListener("pointermove",s),t.removeEventListener("pointerup",r),document.body.style.backgroundColor="",i("up")},a=function(n){t.addEventListener("pointermove",s),t.addEventListener("pointerup",r),t.setPointerCapture(n.pointerId);const i=Pt(t,n);o=[i.x,i.y],e({type:"down",...i})};return t.addEventListener("pointerdown",a),function(){t.removeEventListener("pointerdown",a)}}class Bt extends b{#j;#T;#P;#z;#B;#G;#H;#R;constructor(t){super(e("div",{innerHTML:'\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n',className:"muigui-no-scroll"})),this.#j=this.domElement.children[0],this.#T=this.domElement.children[1],this.#P=this.$(".muigui-color-chooser-circle"),this.#z=this.$("#muigui-color-chooser-hue"),this.#B=this.$(".muigui-color-chooser-cursor");const n=e=>{const n=i(e.nx,0,1),o=i(e.ny,0,1);this.#G[1]=n,this.#G[2]=1-o,this.#H=!0,t.setValue(Z(at(this.#G)))},o=e=>{const n=i(e.nx,0,1);this.#G[0]=n,this.#R=!0,t.setValue(Z(at(this.#G)))};zt(this.#j,{onDown:n,onMove:n}),zt(this.#T,{onDown:o,onMove:o})}updateDisplay(t){this.#G||(this.#G=ut(X(t)));{const[e,n,i]=ut(X(t));this.#H||(this.#G[0]=n>.001&&i>.001?e:this.#G[0]),this.#R||(this.#G[1]=n,this.#G[2]=i)}{const[t,e,n]=this.#G;this.#H||(this.#B.setAttribute("transform",`translate(${64*t}, 0)`),this.#z.children[0].setAttribute("stop-color",`hsl(${360*t}, 0%, 100%)`),this.#z.children[1].setAttribute("stop-color",`hsl(${360*t}, 100%, 50%)`)),this.#R||(this.#P.setAttribute("cx",""+64*e),this.#P.setAttribute("cy",""+48*(1-n)))}this.#H=!1,this.#R=!1}}class Gt extends I{#Y;#W;#q;#u={open:!1};constructor(t,n,i={}){super(t,n,"muigui-pop-down-controller"),this.#Y=this.add(new R("div","muigui-pop-down-top"));const o=this.#Y.addElem(e("input",{type:"checkbox",onChange:()=>{this.#u.open=o.checked}}));this.#W=this.#Y.add(new R("div","muigui-pop-down-values")),this.#q=this.add(new R("div","muigui-pop-down-bottom")),this.setOptions(i)}updateDisplay(){super.updateDisplay();const{open:t}=this.#u;this.domElement.children[1].classList.toggle("muigui-open",t),this.domElement.children[1].classList.toggle("muigui-closed",!t)}setOptions(t){a(this.#u,t),super.setOptions(t),this.updateDisplay()}addTop(t){return this.#W.add(t)}addBottom(t){return this.#q.add(t)}}function Ht(){}const Rt={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]};function Yt(t,{onDown:e=Ht,onUp:n=Ht}){const i=function(t){const i=t.shiftKey?10:1,[o,s]=(Rt[t.key]||[0,0]).map((t=>t*i));("keydown"===t.type?e:n)({type:t.type.substring(3),dx:o,dy:s,event:t})};return t.addEventListener("keydown",i),t.addEventListener("keyup",i),function(){t.removeEventListener("keydown",i),t.removeEventListener("keyup",i)}}function Wt(t,e=""){if(!t)throw new Error(e)}function qt(t,e,n,i,o,s){const r=Math.abs(n)*Math.cos(s),a=Math.abs(i)*Math.sin(s);return[t+Math.cos(o)*r-Math.sin(o)*a,e+Math.sin(o)*r+Math.cos(o)*a]}function _t(t,e,n,i,o){Wt(Math.abs(i-o)<=2*Math.PI),Wt(i>=-Math.PI&&i<=2*Math.PI),Wt(i<=o),Wt(o>=-Math.PI&&o<=4*Math.PI);const{x1:s,y1:r,x2:a,y2:l,fa:u,fs:c}=function(t,e,n,i,o,s,r){const[a,l]=qt(t,e,n,i,o,s),[u,c]=qt(t,e,n,i,o,s+r);return{x1:a,y1:l,x2:u,y2:c,fa:Math.abs(r)>Math.PI?1:0,fs:r>0?1:0}}(t,e,n,n,0,i,o-i);return Math.abs(Math.abs(i-o)-2*Math.PI)>Number.EPSILON?`M${t} ${e} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l} L${t} ${e}`:`M${s} ${r} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l}`}const Jt=t=>r(t+Math.PI,2*Math.PI)-Math.PI;class Kt extends b{#_;#J;#K;#X;#u={step:1,min:-180,max:180,dirMin:-Math.PI,dirMax:Math.PI,wrap:void 0,converters:F};constructor(t,n={}){const o=A();super(e("div",{className:"muigui-direction muigui-no-scroll",innerHTML:'\n\n \x3c!----\x3e\n \n \n \n \n \n \n\n',onWheel:e=>{e.preventDefault();const{min:n,max:a,step:l}=this.#u,u=o(e,l);let c=this.#K+u;this.#X&&(c=r(c-n,a-n)+n);const h=i(s(c,(t=>t),l),n,a);t.setValue(h)}}));const a=e=>{const{min:n,max:o,step:r,dirMin:a,dirMax:l}=this.#u,u=2*e.nx-1,c=2*e.ny-1,h=Math.atan2(c,u),d=(a+l)/2,p=i((Jt(h-d)-Jt(a-d))/(l-a),0,1),m=s(n+(o-n)*p,(t=>t),r);t.setValue(m)};zt(this.domElement,{onDown:a,onMove:a}),Yt(this.domElement,{onDown:e=>{const{min:n,max:o,step:r}=this.#u,a=i(s(this.#K+e.dx*r,(t=>t),r),n,o);t.setValue(a)}}),this.#_=this.$("#muigui-arrow"),this.#J=this.$("#muigui-range"),this.setOptions(n)}updateDisplay(t){this.#K=t;const{min:e,max:n}=this.#u,i=(t-e)/(n-e),o=(s=this.#u.dirMin,r=this.#u.dirMax,s+(r-s)*i);var s,r;this.#_.style.transform=`rotate(${o}rad)`}setOptions(t){a(this.#u,t);const{dirMin:e,dirMax:n,wrap:i}=this.#u;this.#X=void 0!==i?i:Math.abs(e-n)>=2*Math.PI-Number.EPSILON;const[o,s]=e(o.push(i),e("label",{},[e("input",{type:"radio",name:s,value:a,onChange:function(){this.checked&&t.setFinalValue(r.#I[this.value])}}),e("button",{type:"button",textContent:n,onClick:function(){this.previousElementSibling.click()}})]))))));const r=this;this.#I=o,this.cols(i)}updateDisplay(t){const e=this.#I.indexOf(t);for(let t=0;t{e({rect:t.getBoundingClientRect(),elem:t})})).observe(t)}function Qt(t,e,n,i){Zt(t,(({rect:o})=>{const{width:s,height:r}=o;t.setAttribute("viewBox",`-${s*e} -${r*n} ${s} ${r}`),i({elem:t,rect:o})}))}function te(t,e,n,i,o,r){const a=[];tt),n)),e=Math.min(e,o);for(let i=t;i<=e;i+=n)a.push(`M${i} 0 l0 ${r}`);return a.join(" ")}class ee extends b{#Z;#Q;#tt;#et;#nt;#it;#ot;#st;#rt;#K;#at;#u={min:-100,max:100,step:1,unit:10,unitSize:10,ticksPerUnit:5,labelFn:t=>t,tickHeight:1,limits:!0,thicksColor:void 0,orientation:void 0};constructor(t,n){const o=A();let r;super(e("div",{innerHTML:'\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \x3c!----\x3e\n \x3c!----\x3e\n \n \n \n \n\n',className:"muigui-no-v-scroll",onWheel:e=>{e.preventDefault();const{min:n,max:r,step:a}=this.#u,l=o(e,a),u=i(s(this.#K+l,(t=>t),a),n,r);t.setValue(u)}})),this.#Z=this.$("svg"),this.#Q=this.$("#muigui-origin"),this.#tt=this.$("#muigui-ticks"),this.#et=this.$("#muigui-thicks"),this.#nt=this.$("#muigui-numbers"),this.#it=this.$("#muigui-left-grad"),this.#ot=this.$("#muigui-right-grad"),this.setOptions(n),zt(this.domElement,{onDown:()=>{r=this.#K},onMove:e=>{const{min:n,max:o,unitSize:a,unit:l,step:u}=this.#u,c=i(s(r-e.dx/a*l,(t=>t),u),n,o);t.setValue(c)}}),Yt(this.domElement,{onDown:e=>{const{min:n,max:o,step:r}=this.#u,a=i(s(this.#K+e.dx*r,(t=>t),r),n,o);t.setValue(a)}}),Qt(this.#Z,.5,0,(({rect:{width:t}})=>{this.#it.setAttribute("x",-t/2),this.#ot.setAttribute("x",t/2-20),this.#at=function(t){const e=t.innerHTML;t.innerHTML="- ";const n=t.querySelector("text").getComputedTextLength();return t.innerHTML=e,n}(this.#nt),this.#st=t,this.#lt()}))}#lt(){if(!this.#st||void 0===this.#K)return;const{labelFn:t,limits:e,min:n,max:i,orientation:o,tickHeight:r,ticksPerUnit:a,unit:l,unitSize:u,thicksColor:c}=this.#u,h=Math.ceil(this.#st/u),d=this.#K/l,p=Math.round(d-h),m=p*u,g=(p+2*h)*u,f=e?n*u/l:m,b=e?i*u/l:g,v=""===t(1)?10:5;a>1&&this.#tt.setAttribute("d",te(m,g,u/a,f,b,v*r)),this.#et.style.stroke=c,this.#et.setAttribute("d",te(m,g,u,f,b,v)),this.#nt.innerHTML=function(t,e,n,i,o,r,a,l){const u=[];tt),n)),e=Math.min(e,a);const c=Math.max(0,-Math.log10(i));for(let s=t;s<=e;s+=n)u.push(`${h=s/n*i,l(h.toFixed(c))}`);var h;return u.join("\n")}(m,g,u,l,this.#at,f,b,t),this.#Q.setAttribute("transform",`translate(${-this.#K*u/l} 0)`),this.#Z.classList.toggle("muigui-slider-up","up"===o)}updateDisplay(t){this.#K=t,this.#lt()}setOptions(t){return a(this.#u,t),this}}class ne extends b{#Z;#_;#P;#K=[];constructor(t){super(e("div",{innerHTML:'\n\n \n \n \n \n \n\n',className:"muigui-no-scroll"}));const n=e=>{const{width:n,height:i}=this.#Z.getBoundingClientRect(),o=2*e.nx-1,s=2*e.ny-1;t.setValue([o*n*.5,s*i*.5])};zt(this.domElement,{onDown:n,onMove:n}),this.#Z=this.$("svg"),this.#_=this.$("#muigui-arrow"),this.#P=this.$("#muigui-circle"),Qt(this.#Z,.5,.5,(()=>this.#ut))}#ut(){const[t,e]=this.#K;this.#_.setAttribute("d",`M0,0L${t},${e}`),this.#P.setAttribute("transform",`translate(${t}, ${e})`)}updateDisplay(t){this.#K[0]=t[0],this.#K[1]=t[1],this.#ut()}}return jt.ColorChooser=class extends Gt{constructor(t,e){super(t,e,"muigui-color-chooser"),this.addTop(new G(this)),this.addBottom(new Bt(this)),this.updateDisplay()}},jt.Direction=class extends Gt{#u;constructor(t,e,n){super(t,e,"muigui-direction"),this.#u=n,this.addTop(new U(this,F)),this.addBottom(new Kt(this,n)),this.updateDisplay()}},jt.RadioGrid=class extends I{constructor(t,e,n){super(t,e,"muigui-radio-grid");const i="number"==typeof this.getValue(),{keyValues:o,cols:s=3}=n,r=T(o,i);this.add(new Xt(this,r,s)),this.updateDisplay()}},jt.Range=B,jt.Select=P,jt.Slider=class extends I{constructor(t,e,n={}){super(t,e,"muigui-slider"),this.add(new ee(this,n)),this.add(new U(this,n)),this.updateDisplay()}},jt.TextNumber=O,jt.Vec2=class extends Gt{constructor(t,e){super(t,e,"muigui-vec2");const n=t=>({setValue:e=>{const n=this.getValue();n[t]=e,this.setValue(n)},setFinalValue:e=>{const n=this.getValue();n[t]=e,this.setFinalValue(n)}});this.addTop(new U(n(0),{converters:{to:t=>t[0],from:L.from}})),this.addTop(new U(n(1),{converters:{to:t=>t[1],from:L.from}})),this.addBottom(new ne(this)),this.updateDisplay()}},jt})); diff --git a/dist/0.x/muigui.module.js b/dist/0.x/muigui.module.js index 8c20a72..c77fd35 100644 --- a/dist/0.x/muigui.module.js +++ b/dist/0.x/muigui.module.js @@ -1,8 +1,10 @@ -/* muigui@0.0.6, license MIT */ -var css = ` -.muigui-colors { +/* muigui@0.0.7, license MIT */ +var css = { + default: ` +.muigui { --bg-color: #ddd; --color: #222; + --contrast-color: #eee; --value-color: #145 ; --value-bg-color: #eeee; --disabled-color: #999; @@ -25,9 +27,10 @@ var css = ` } @media (prefers-color-scheme: dark) { - .muigui-colors { + .muigui { --bg-color: #222222; --color: #dddddd; + --contrast-color: #000; --value-color: #43e5f7; --value-bg-color: #444444; --disabled-color: #666666; @@ -679,7 +682,67 @@ var css = ` z-index: 100001; } -`; +`, +themes: { + default: '', + float: ` + :root { + color-scheme: light dark, + } + + .muigui { + --width: 400px; + --bg-color: initial; + --label-width: 25%; + } + + input, + .muigui-label-controller>label { + text-shadow: + -1px -1px 0 var(--contrast-color), + 1px -1px 0 var(--contrast-color), + -1px 1px 0 var(--contrast-color), + 1px 1px 0 var(--contrast-color); + } + + .muigui-controller > label:nth-child(1) { + place-content: center end; + margin-right: 1em; + } + + .muigui-value > :nth-child(2) { + margin-left: 1em; + } + + .muigui-root>*:nth-child(1) { + display: none; + } + + .muigui-range input[type=range]::-webkit-slider-thumb { + border-radius: 1em; + } + + .muigui-range input[type=range]::-webkit-slider-runnable-track { + -webkit-appearance: initial; + appearance: none; + border: 1px solid rgba(0, 0, 0, 0.25); + height: 2px; + } + + .muigui-colors { + --value-color: var(--color ); + --value-bg-color: rgba(0, 0, 0, 0.1); + --disabled-color: #cccccc; + --menu-bg-color: rgba(0, 0, 0, 0.1); + --menu-sep-color: #bbbbbb; + --hover-bg-color: rgba(0, 0, 0, 0); + --invalid-color: #FF0000; + --selected-color: rgba(0, 0, 0, 0.3); + --range-color: rgba(0, 0, 0, 0.125); + } +`, +}, +}; function setElemProps(elem, attrs, children) { for (const [key, value] of Object.entries(attrs)) { @@ -788,6 +851,42 @@ const makeRangeOptions = ({from, to, step}) => { }; }; +// TODO: remove an use one in conversions. Move makeRangeConverters there? +const identity$1 = { + to: v => v, + from: v => [true, v], +}; +function makeMinMaxPair(gui, properties, minPropName, maxPropName, options) { + const { converters: { from } = identity$1 } = options; + const { min, max } = options; + const guiMinRange = options.minRange || 0; + const valueMinRange = from(guiMinRange)[1]; + console.log('guiMinRange', guiMinRange); + console.log('valueMinRange', valueMinRange); + return [ + gui + .add(properties, minPropName, { + ...options, + min, + max: max - guiMinRange, + }) + .listen() + .onChange(v => { + properties[maxPropName] = Math.min(max, Math.max(v + valueMinRange, properties[maxPropName])); + }), + gui + .add(properties, maxPropName, { + ...options, + min: min + guiMinRange, + max, + }) + .listen() + .onChange(v => { + properties[minPropName] = Math.max(min, Math.min(v - valueMinRange, properties[minPropName])); + }), + ]; +} + class View { #childDestElem; #views = []; @@ -1515,16 +1614,22 @@ class RangeView extends EditView { type: 'range', onInput: () => { this.#skipUpdate = true; - const [valid, v] = this.#from(parseFloat(this.domElement.value)); + const {min, max, step} = this.#options; + const v = parseFloat(this.domElement.value); + const newV = clamp$1(stepify(v, v => v, step), min, max); + const [valid, validV] = this.#from(newV); if (valid) { - setter.setValue(v); + setter.setValue(validV); } }, onChange: () => { this.#skipUpdate = true; - const [valid, v] = this.#from(parseFloat(this.domElement.value)); + const {min, max, step} = this.#options; + const v = parseFloat(this.domElement.value); + const newV = clamp$1(stepify(v, v => v, step), min, max); + const [valid, validV] = this.#from(newV); if (valid) { - setter.setFinalValue(v); + setter.setFinalValue(validV); } }, onWheel: e => { @@ -2355,9 +2460,6 @@ class Row extends Layout { } } -let stylesInjected = false; -const styleElem = createElem('style'); - class GUIFolder extends Folder { add(object, property, ...args) { const controller = object instanceof Controller @@ -2382,11 +2484,51 @@ class GUIFolder extends Folder { } } +class MuiguiElement extends HTMLElement { + constructor() { + super(); + this.shadow = this.attachShadow({mode: 'open'}); + } +} + +customElements.define('muigui-element', MuiguiElement); + +const baseStyleSheet = new CSSStyleSheet(); +baseStyleSheet.replaceSync(css.default); +const userStyleSheet = new CSSStyleSheet(); + +function makeStyleSheetUpdater(styleSheet) { + let newCss; + let newCssPromise; + + function updateStyle() { + if (newCss && !newCssPromise) { + const s = newCss; + newCss = undefined; + newCssPromise = styleSheet.replace(s).then(() => { + console.log(s); + newCssPromise = undefined; + updateStyle(); + }); + } + } + + return function updateStyleSheet(css) { + newCss = css; + updateStyle(); + }; +} + +const updateBaseStyle = makeStyleSheetUpdater(baseStyleSheet); +const updateUserStyle = makeStyleSheetUpdater(userStyleSheet); + class GUI extends GUIFolder { static converters = converters; static mapRange = mapRange; static makeRangeConverters = makeRangeConverters; static makeRangeOptions = makeRangeOptions; + static makeMinMaxPair = makeMinMaxPair; + #localStyleSheet = new CSSStyleSheet(); constructor(options = {}) { super('Controls', 'muigui-root'); @@ -2397,16 +2539,11 @@ class GUI extends GUIFolder { autoPlace = true, width, title = 'Controls', - injectStyles = true, } = options; let { parent, } = options; - if (injectStyles && !stylesInjected) { - stylesInjected = true; - (document.head || document.documentElement).appendChild(styleElem); - styleElem.textContent = css; - } + if (width) { this.domElement.style.width = /^\d+$/.test(width) ? `${width}px` : width; } @@ -2415,13 +2552,34 @@ class GUI extends GUIFolder { this.domElement.classList.add('muigui-auto-place'); } if (parent) { - parent.appendChild(this.domElement); + const muiguiElement = createElem('muigui-element'); + muiguiElement.shadowRoot.adoptedStyleSheets = [baseStyleSheet, userStyleSheet, this.#localStyleSheet]; + muiguiElement.shadow.appendChild(this.domElement); + parent.appendChild(muiguiElement); } if (title) { this.title(title); } this.domElement.classList.add('muigui', 'muigui-colors'); } + setStyle(css) { + this.#localStyleSheet.replace(css); + } + static setBaseStyles(css) { + updateBaseStyle(css); + } + static getBaseStyleSheet() { + return baseStyleSheet; + } + static setUserStyles(css) { + updateUserStyle(css); + } + static getUserStyleSheet() { + return userStyleSheet; + } + static setTheme(name) { + GUI.setBaseStyles(`${css.default}\n${css.themes[name] || ''}`); + } } function noop$1() { @@ -2455,9 +2613,9 @@ function addTouchEvents(elem, {onDown = noop$1, onMove = noop$1, onUp = noop$1}) elem.releasePointerCapture(event.pointerId); elem.removeEventListener('pointermove', pointerMove); elem.removeEventListener('pointerup', pointerUp); - + document.body.style.backgroundColor = ''; - + onUp('up'); }; @@ -2616,17 +2774,6 @@ pc.addBottom */ -function makeSetter(object, property) { - return { - setValue(v) { - object[property] = v; - }, - setFinalValue(v) { - this.setValue(v); - }, - }; -} - class PopDownController extends ValueController { #top; #valuesView; @@ -3164,19 +3311,6 @@ class Slider extends ValueController { } } -class GridView extends View { - // FIX: should this be 'options'? - constructor(cols) { - super(createElem('div', { - className: 'muigui-grid', - })); - this.cols(cols); - } - cols(cols) { - this.domElement.style.gridTemplateColumns = `repeat(${cols}, 1fr)`; - } -} - const svg = ` diff --git a/dist/0.x/muigui.module.min.js b/dist/0.x/muigui.module.min.js index 937ae05..ea72e29 100644 --- a/dist/0.x/muigui.module.min.js +++ b/dist/0.x/muigui.module.min.js @@ -1 +1 @@ -function t(t,e={},n=[]){const i=document.createElement(t);return function(t,e,n){for(const[n,i]of Object.entries(e))if("function"==typeof i&&n.startsWith("on")){const e=n.substring(2).toLowerCase();t.addEventListener(e,i,{passive:!1})}else if("object"==typeof i)for(const[e,o]of Object.entries(i))t[n][e]=o;else void 0===t[n]?t.setAttribute(n,i):t[n]=i;for(const e of n)t.appendChild(e)}(i,e,n),i}function e(t,e){const n=t.indexOf(e);return n&&t.splice(n,1),t}function n(t,e,n){return Math.max(e,Math.min(n,t))}const i="undefined"!=typeof SharedArrayBuffer?function(t){return t&&t.buffer&&(t.buffer instanceof ArrayBuffer||t.buffer instanceof SharedArrayBuffer)}:function(t){return t&&t.buffer&&t.buffer instanceof ArrayBuffer},o=(t,e,n)=>Math.round(e(t)/n)/(1/n),s=(t,e)=>(t%e+e)%e;function r(t,e){for(const n in e)n in t&&(t[n]=e[n]);return t}const a=(t,e,n,i,o)=>(t-e)*(o-i)/(n-e)+i,l=({from:t,to:e})=>({to:n=>a(n,...t,...e),from:n=>[!0,a(n,...e,...t)]}),u=({from:t,to:e,step:n})=>({min:e[0],max:e[1],...n&&{step:n},converters:l({from:t,to:e})});class c{#t;#e=[];constructor(t){this.domElement=t,this.#t=t}addElem(t){return this.#t.appendChild(t),t}removeElem(t){return this.#t.removeChild(t),t}pushSubElem(t){this.#t.appendChild(t),this.#t=t}popSubElem(){this.#t=this.#t.parentElement}add(t){return this.#e.push(t),this.addElem(t.domElement),t}remove(t){return this.removeElem(t.domElement),e(this.#e,t),t}pushSubView(t){this.pushSubElem(t.domElement)}popSubView(){this.popSubElem()}setOptions(t){for(const e of this.#e)e.setOptions(t)}updateDisplayIfNeeded(t,e){for(const n of this.#e)n.updateDisplayIfNeeded(t,e);return this}$(t){return this.domElement.querySelector(t)}}class h extends c{#n;#i;#o;constructor(e){super(t("div",{className:"muigui-controller"})),this.#n=[],this.#i=[],e&&this.domElement.classList.add(e)}get parent(){return this.#o}setParent(t){this.#o=t,this.enable(!this.disabled())}show(t=!0){return this.domElement.classList.toggle("muigui-hide",!t),this.domElement.classList.toggle("muigui-show",t),this}hide(){return this.show(!1)}disabled(){return!!this.domElement.closest(".muigui-disabled")}enable(t=!0){return this.domElement.classList.toggle("muigui-disabled",!t),["input","button","select","textarea"].forEach((t=>{this.domElement.querySelectorAll(t).forEach((t=>{const e=!!t.closest(".muigui-disabled");t.disabled=e}))})),this}disable(t=!0){return this.enable(!t)}onChange(t){return this.removeChange(t),this.#n.push(t),this}removeChange(t){return e(this.#n,t),this}onFinishChange(t){return this.removeFinishChange(t),this.#i.push(t),this}removeFinishChange(t){return e(this.#i,t),this}#s(t,e){for(const n of t)n.call(this,e)}emitChange(t,e,n){this.#s(this.#n,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitChange({object:e,property:n,value:t,controller:this}))}emitFinalChange(t,e,n){this.#s(this.#i,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitFinalChange({object:e,property:n,value:t,controller:this}))}getColors(){const e=t=>t.replace(/-([a-z])/g,((t,e)=>e.toUpperCase())),n=t("div");this.domElement.appendChild(n);const i=Object.fromEntries(["color","bg-color","value-color","value-bg-color","hover-bg-color","menu-bg-color","menu-sep-color","disabled-color"].map((t=>{n.style.color=`var(--${t})`;const i=getComputedStyle(n);return[e(t),i.color]})));return n.remove(),i}}class d extends h{#r;#a;#l;#u={name:""};constructor(e,n,i={}){super("muigui-button",""),this.#r=e,this.#a=n,this.#l=this.addElem(t("button",{type:"button",onClick:()=>{this.#r[this.#a](this)}})),this.setOptions({name:n,...i})}setOptions(t){r(this.#u,t);const{name:e}=this.#u;this.#l.textContent=e}}function p(t,e){if(t.length!==e.length)return!1;for(let n=0;n{e.setValue(i.checked)},onChange:()=>{e.setFinalValue(i.checked)}});super(t("label",{},[i]))}updateDisplay(t){this.domElement.checked=t}}const f=[],b=new Set;let v,x;function w(){v=void 0,x=!0;for(const t of f)b.has(t)||t();x=!1,b.size&&(x?y():(b.forEach((t=>{e(f,t)})),b.clear())),y()}function y(){!v&&f.length&&(v=requestAnimationFrame(w))}let k=0;function E(){return"muigui-"+ ++k}class $ extends c{constructor(e=""){super(t("div",{className:"muigui-value"})),e&&this.domElement.classList.add(e)}}class C extends h{#b;#v;constructor(e="",n=""){super("muigui-label-controller"),this.#b=E(),this.#v=t("label",{for:this.#b}),this.domElement.appendChild(this.#v),this.pushSubView(new $(e)),this.name(n)}get id(){return this.#b}name(t){return this.#v.title===this.#v.textContent&&(this.#v.title=t),this.#v.textContent=t,this}tooltip(t){this.#v.title=t}}class V extends C{#r;#a;#x;#w;#e;#y;constructor(t,e,n=""){super(n,e),this.#r=t,this.#a=e,this.#x=this.getValue(),this.#w=!1,this.#e=[]}get initialValue(){return this.#x}get object(){return this.#r}get property(){return this.#a}add(t){return this.#e.push(t),super.add(t),this.updateDisplay(),t}#k(t,e){if("object"==typeof t){const e=this.#r[this.#a];if(Array.isArray(t))for(let n=0;n=0&&f.splice(e,1)}(this.#y)),this}}class M extends V{constructor(t,e){super(t,e,"muigui-checkbox");const n=this.id;this.add(new g(this,n)),this.updateDisplay()}}const I={to:t=>t,from:t=>[!0,t]},D={to:t=>t.toString(),from:t=>{const e=parseFloat(t);return[!Number.isNaN(e),e]}},F={radToDeg:l({to:[0,180],from:[0,Math.PI]})};function L(){let t=0;return function(e,n,i=5){t-=e.deltaY*n/i;const o=Math.floor(Math.abs(t)/n)*Math.sign(t)*n;return t-=o,o}}class N extends m{#E;#$;#C;#V;#u={step:.01,converters:D,min:Number.NEGATIVE_INFINITY,max:Number.POSITIVE_INFINITY};constructor(e,i){const s=e.setValue.bind(e),r=e.setFinalValue.bind(e),a=L();super(t("input",{type:"number",onInput:()=>this.#M(s,!0),onChange:()=>this.#M(r,!1),onWheel:t=>{t.preventDefault();const{min:i,max:s,step:r}=this.#u,l=a(t,r),u=parseFloat(this.domElement.value),c=n(o(u+l,(t=>t),r),i,s);e.setValue(c)}})),this.setOptions(i)}#M(t,e){const i=parseFloat(this.domElement.value),[o,s]=this.#$(i);let r;if(o&&!Number.isNaN(i)){const{min:i,max:o}=this.#u;r=s>=i&&s<=o,this.#V=e,t(n(s,i,o))}this.domElement.classList.toggle("muigui-invalid-value",!o||!r)}updateDisplay(t){this.#V||(this.domElement.value=o(t,this.#E,this.#C)),this.#V=!1}setOptions(t){r(this.#u,t);const{step:e,converters:{to:n,from:i}}=this.#u;return this.#E=n,this.#$=i,this.#C=e,this}}class A extends V{#I;#C;constructor(t,e,n={}){super(t,e,"muigui-checkbox"),this.#I=this.add(new N(this,n)),this.updateDisplay()}}class S extends m{#D;constructor(e,n){const i=[];super(t("select",{onChange:()=>{e.setFinalValue(this.#D[this.domElement.selectedIndex])}},n.map((([e,n])=>(i.push(n),t("option",{textContent:e})))))),this.#D=i}updateDisplay(t){const e=this.#D.indexOf(t);this.domElement.selectedIndex=e}}function U(t,e){return Array.isArray(t)?Array.isArray(t[0])?t:e?t.map(((t,e)=>[t,e])):t.map((t=>[t,t])):[...Object.entries(t)]}class O extends V{constructor(t,e,n){super(t,e,"muigui-select");const i="number"==typeof this.getValue(),{keyValues:o}=n,s=U(o,i);this.add(new S(this,s)),this.updateDisplay()}}class j extends m{#E;#$;#C;#V;#u={step:.01,min:0,max:1,converters:I};constructor(e,i){const s=L();super(t("input",{type:"range",onInput:()=>{this.#V=!0;const[t,n]=this.#$(parseFloat(this.domElement.value));t&&e.setValue(n)},onChange:()=>{this.#V=!0;const[t,n]=this.#$(parseFloat(this.domElement.value));t&&e.setFinalValue(n)},onWheel:t=>{t.preventDefault();const[i,r]=this.#$(parseFloat(this.domElement.value));if(!i)return;const{min:a,max:l,step:u}=this.#u,c=s(t,u),h=n(o(r+c,(t=>t),u),a,l);e.setValue(h)}})),this.setOptions(i)}updateDisplay(t){this.#V||(this.domElement.value=o(t,this.#E,this.#C)),this.#V=!1}setOptions(t){r(this.#u,t);const{step:e,min:n,max:i,converters:{to:o,from:s}}=this.#u;return this.#E=o,this.#$=s,this.#C=e,this.domElement.step=e,this.domElement.min=n,this.domElement.max=i,this}}class P extends V{constructor(t,e,n){super(t,e,"muigui-range"),this.add(new j(this,n)),this.add(new N(this,n))}}class T extends m{#E;#$;#V;#u={converters:I};constructor(e,n){const i=e.setValue.bind(e),o=e.setFinalValue.bind(e);super(t("input",{type:"text",onInput:()=>this.#M(i,!0),onChange:()=>this.#M(o,!1)})),this.setOptions(n)}#M(t,e){const[n,i]=this.#$(this.domElement.value);n&&(this.#V=e,t(i)),this.domElement.style.color=n?"":"var(--invalid-color)"}updateDisplay(t){this.#V||(this.domElement.value=this.#E(t),this.domElement.style.color=""),this.#V=!1}setOptions(t){r(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#$=n,this}}class z extends V{constructor(t,e){super(t,e,"muigui-checkbox"),this.add(new T(this)),this.updateDisplay()}}class B extends c{constructor(e,n){super(t(e,{className:n}))}}class G extends C{#F;constructor(){super("muigui-canvas"),this.#F=this.add(new B("canvas","muigui-canvas")).domElement}get canvas(){return this.#F}}const H=(t,e,n)=>Math.max(e,Math.min(n,t)),R=t=>+t.toFixed(3),Y=t=>parseInt(t.substring(1,3),16)<<16|parseInt(t.substring(3,5),16)<<8|parseInt(t.substring(5,7),16),W=t=>[parseInt(t.substring(1,3),16),parseInt(t.substring(3,5),16),parseInt(t.substring(5,7),16)],q=t=>`#${Array.from(t).map((t=>t.toString(16).padStart(2,"0"))).join("")}`,_=t=>W(t).map((t=>R(t/255))),J=t=>q(Array.from(t).map((t=>Math.round(H(255*t,0,255))))),K=t=>({r:parseInt(t.substring(1,3),16)/255,g:parseInt(t.substring(3,5),16)/255,b:parseInt(t.substring(5,7),16)/255}),X=t=>H(Math.round(255*t),0,255).toString(16).padStart(2,"0"),Z=t=>`rgb(${W(t).join(", ")})`,Q=/^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,tt=t=>{const e=it(W(t)).map((t=>(t=>+t.toFixed(0))(t)));return`hsl(${e[0]}, ${e[1]}%, ${e[2]}%)`},et=/^\s*hsl\(\s*(\d+)(?:deg|)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)\s*$/,nt=(t,e)=>(t%e+e)%e;const it=t=>{const[e,n,i]=function([t,e,n]){const i=Math.max(t,e,n),o=Math.min(t,e,n),s=.5*(o+i),r=i-o;let a=0,l=0;if(0!==r)switch(l=0===s||1===s?0:(i-s)/Math.min(s,1-s),i){case t:a=(e-n)/r+(et/255)));return[360*e,100*n,100*i]};function ot([t,e,n]){return e=H(e,0,1),n=H(n,0,1),[t,t+2/3,t+1/3].map((t=>{return i=1,o=H(Math.abs(6*(t=>t>=0?t%1:1-t%1)(t)-3)-1,0,1),(i+(o-i)*e)*n;var i,o}))}const st=t=>Math.round(1e3*t)/1e3;function rt([t,e,n]){const i=n>e?[n,e,-1,2/3]:[e,n,0,-1/3],o=i[0]>t?[i[0],i[1],i[3],t]:[t,i[1],i[2],i[0]],s=o[0]-Math.min(o[3],o[1]);return[Math.abs(o[2]+(o[3]-o[1])/(6*s+Number.EPSILON)),s/(o[0]+Number.EPSILON),o[0]].map(st)}window.hsv01ToRGBFloat=ot,window.rgbFloatToHSV01=rt;const at=[{re:/^#(?:[0-9a-f]){6}$/i,format:"hex6"},{re:/^(?:[0-9a-f]){6}$/i,format:"hex6-no-hash"},{re:/^#(?:[0-9a-f]){3}$/i,format:"hex3"},{re:/^(?:[0-9a-f]){3}$/i,format:"hex3-no-hash"},{re:Q,format:"css-rgb"},{re:et,format:"css-hsl"}];function lt(t){switch(typeof t){case"number":return"uint32-rgb";case"string":{const e=function(t){for(const e of at)if(e.re.test(t))return e}(t.trim());if(e)return e.format;break}case"object":if(t instanceof Uint8Array||t instanceof Uint8ClampedArray){if(3===t.length)return"uint8-rgb"}else if(t instanceof Float32Array){if(3===t.length)return"float-rgb"}else if(Array.isArray(t)){if(3===t.length)return"float-rgb"}else if("r"in t&&"g"in t&&"b"in t)return"object-rgb"}throw new Error(`unknown color format: ${t}`)}function ut(t){return t.trim(t)}function ct(t){return t[1]===t[2]&&t[3]===t[4]&&t[5]===t[6]?`#${t[1]}${t[3]}${t[5]}`:t}const ht=/^(#|)([0-9a-f]{3})$/i;function dt(t){const e=ht.exec(t);if(e){const[,,t]=e;return"#"+`${(n=t)[0]}${n[0]}${n[1]}${n[1]}${n[2]}${n[2]}`}var n;return t}function pt(t){return ct(ut(t))}const mt=t=>{const e=Q.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),`rgb(${n.join(", ")})`]},gt=t=>{const e=et.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseFloat(t)));return[!n.find((t=>Number.isNaN(t))),`hsl(${n[0]}, ${n[1]}%, ${n[2]}%)`]},ft=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$/,bt=/^\s*(?:0x){0,1}([0-9a-z]{1,6})\s*$/i,vt=/^\s*#[a-f0-9]{6}\s*$|^\s*#[a-f0-9]{3}\s*$/i,xt=/^\s*[a-f0-9]{6}\s*$/i,wt={hex6:{color:{from:t=>[!0,t],to:ut},text:{from:t=>[vt.test(t),t.trim()],to:t=>t}},hex3:{color:{from:t=>[!0,pt(t)],to:dt},text:{from:t=>[vt.test(t),ct(t.trim())],to:t=>t}},"hex6-no-hash":{color:{from:t=>[!0,t.substring(1)],to:t=>`#${ut(t)}`},text:{from:t=>[xt.test(t),t.trim()],to:t=>t}},"hex3-no-hash":{color:{from:t=>[!0,pt(t).substring(1)],to:dt},text:{from:t=>[xt.test(t),ct(t.trim())],to:t=>t}},"uint32-rgb":{color:{from:t=>[!0,Y(t)],to:t=>`#${Math.round(t).toString(16).padStart(6,"0")}`},text:{from:t=>(t=>{const e=bt.exec(t);return e?[!0,parseInt(e[1],16)]:[!1]})(t),to:t=>`0x${t.toString(16).padStart(6,"0")}`}},"uint8-rgb":{color:{from:t=>[!0,W(t)],to:q},text:{from:t=>{const e=ft.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),n]},to:t=>t.join(", ")}},"float-rgb":{color:{from:t=>[!0,_(t)],to:J},text:{from:t=>{const e=t.split(",").map((t=>t.trim())),n=e.map((t=>parseFloat(t)));if(3!==n.length)return[!1];const i=e.findIndex((t=>isNaN(t)));return[i<0,n.map((t=>R(t)))]},to:t=>Array.from(t).map((t=>R(t))).join(", ")}},"object-rgb":{color:{from:t=>[!0,K(t)],to:t=>`#${X(t.r)}${X(t.g)}${X(t.b)}`},text:{from:t=>{try{const e=t.replace(/([a-z])/g,'"$1"'),n=JSON.parse(e);if(Number.isNaN(n.r)||Number.isNaN(n.g)||Number.isNaN(n.b))throw new Error("not {r, g, b}");return[!0,n]}catch(t){return[!1]}},to:t=>`{r:${R(t.r)}, g:${R(t.g)}, b:${R(t.b)}}`}},"css-rgb":{color:{from:t=>[!0,Z(t)],to:t=>{const e=Q.exec(t);return q([e[1],e[2],e[3]].map((t=>parseInt(t))))}},text:{from:mt,to:t=>mt(t)[1]}},"css-hsl":{color:{from:t=>[!0,tt(t)],to:t=>{const e=et.exec(t),n=function([t,e,n]){t=nt(t,360),e=H(e/100,0,1),n=H(n/100,0,1);const i=e*Math.min(n,1-n);function o(e){const o=(e+t/30)%12;return n-i*Math.max(-1,Math.min(o-3,9-o,1))}return[o(0),o(8),o(4)].map((t=>Math.round(255*t)))}([e[1],e[2],e[3]].map((t=>parseFloat(t))));return q(n)}},text:{from:gt,to:t=>gt(t)[1]}}};class yt extends m{#E;#$;#L;#V;#u={converters:I};constructor(e,n){const i=t("input",{type:"color",onInput:()=>{const[t,n]=this.#$(i.value);t&&(this.#V=!0,e.setValue(n))},onChange:()=>{const[t,n]=this.#$(i.value);t&&(this.#V=!0,e.setFinalValue(n))}});super(t("div",{},[i])),this.setOptions(n),this.#L=i}updateDisplay(t){this.#V||(this.#L.value=this.#E(t)),this.#V=!1}setOptions(t){r(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#$=n,this}}class kt extends V{#N;#I;constructor(t,e,n={}){super(t,e,"muigui-color");const i=n.format||lt(this.getValue()),{color:o,text:s}=wt[i];this.#N=this.add(new yt(this,{converters:o})),this.#I=this.add(new T(this,{converters:s})),this.updateDisplay()}setOptions(t){const{format:e}=t;if(e){const{color:t,text:n}=wt[e];this.#N.setOptions({converters:t}),this.#I.setOptions({converters:n})}return super.setOptions(t),this}}class Et extends h{constructor(){super("muigui-divider")}}class $t extends h{#A;#S;constructor(t){super(t),this.#A=[],this.#S=this}get children(){return this.#A}get controllers(){return this.#A.filter((t=>!(t instanceof $t)))}get folders(){return this.#A.filter((t=>t instanceof $t))}reset(t=!0){for(const e of this.#A)e instanceof $t&&!t||e.reset(t);return this}remove(t){const e=this.#A.indexOf(t);if(e>=0){const t=this.#A.splice(e,1)[0];t.domElement.remove(),t.setParent(null)}return this}_addControllerImpl(t){return this.domElement.appendChild(t.domElement),this.#A.push(t),t.setParent(this),t}addController(t){return this.#S._addControllerImpl(t)}pushContainer(t){return this.addController(t),this.#S=t,t}popContainer(){return this.#S=this.#S.parent,this}}class Ct extends $t{#U;constructor(e="Controls",n="muigui-menu"){super(n),this.#U=t("label"),this.addElem(t("button",{type:"button",onClick:()=>this.toggleOpen()},[this.#U])),this.pushContainer(new $t),this.name(e),this.open()}open(t=!0){return this.domElement.classList.toggle("muigui-closed",!t),this.domElement.classList.toggle("muigui-open",t),this}close(){return this.open(!1)}name(t){return this.#U.textContent=t,this}title(t){return this.name(t)}toggleOpen(){return this.open(!this.domElement.classList.contains("muigui-open")),this}}class Vt extends h{constructor(t){super("muigui-label"),this.text(t)}text(t){return this.domElement.textContent=t,this}}let Mt=!1;const It=t("style");class Dt extends Ct{add(t,e,...n){const i=t instanceof h?t:function(t,e,...n){const[i]=n;if(Array.isArray(i))return new O(t,e,{keyValues:i});const o=typeof t[e];switch(o){case"number":if("number"==typeof n[0]&&"number"==typeof n[1]){const i=n[0],o=n[1],s=n[2];return new P(t,e,{min:i,max:o,...s&&{step:s}})}return 0===n.length?new A(t,e,...n):new P(t,e,...n);case"boolean":return new M(t,e,...n);case"function":return new d(t,e,...n);case"string":return new z(t,e,...n);case"undefined":throw new Error(`no property named ${e}`);default:throw new Error(`unhandled type ${o} for property ${e}`)}}(t,e,...n);return this.addController(i)}addCanvas(t){return this.addController(new G(t))}addColor(t,e,...n){return this.addController(new kt(t,e,...n))}addDivider(){return this.addController(new Et)}addFolder(t){return this.addController(new Dt(t))}addLabel(t){return this.addController(new Vt(t))}}class Ft extends Dt{static converters=F;static mapRange=a;static makeRangeConverters=l;static makeRangeOptions=u;constructor(t={}){super("Controls","muigui-root"),t instanceof HTMLElement&&(t={parent:t});const{autoPlace:e=!0,width:n,title:i="Controls",injectStyles:o=!0}=t;let{parent:s}=t;o&&!Mt&&(Mt=!0,(document.head||document.documentElement).appendChild(It),It.textContent='\n.muigui-colors {\n --bg-color: #ddd;\n --color: #222;\n --value-color: #145 ;\n --value-bg-color: #eeee;\n --disabled-color: #999;\n --menu-bg-color: #f8f8f8;\n --menu-sep-color: #bbb;\n --hover-bg-color: #999;\n --focus-color: #68C;\n --range-color: #888888;\n --invalid-color: #FF0000;\n --selected-color: rgb(255, 255, 255, 0.9);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n}\n\n@media (prefers-color-scheme: dark) {\n .muigui-colors {\n --bg-color: #222222;\n --color: #dddddd;\n --value-color: #43e5f7;\n --value-bg-color: #444444;\n --disabled-color: #666666;\n --menu-bg-color: #080808;\n --menu-sep-color: #444444;\n --hover-bg-color: #666666;\n --focus-color: #88AAFF;\n --range-color: #888888;\n --invalid-color: #FF6666;\n --selected-color: rgba(255, 255, 255, 0.3);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n }\n}\n\n.muigui {\n --width: 250px;\n --label-width: 45%;\n --number-width: 40%;\n\n\n --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;\n --font-size: 11px;\n --font-family-mono: Menlo, Monaco, Consolas, "Droid Sans Mono", monospace;\n --font-size-mono: 11px;\n\n --line-height: 1.7em;\n --border-radius: 0px;\n\n width: var(--width);\n font-family: var(--font-family);\n font-size: var(--font-size);\n box-sizing: border-box;\n line-height: 100%;\n}\n.muigui * {\n box-sizing: inherit;\n}\n\n.muigui-no-scroll {\n touch-action: none;\n}\n.muigui-no-h-scroll {\n touch-action: pan-y;\n}\n.muigui-no-v-scroll {\n touch-action: pan-x;\n}\n\n.muigui-invalid-value {\n background-color: red !important;\n color: white !important;\n}\n\n.muigui-grid {\n display: grid;\n}\n.muigui-rows {\n display: flex;\n flex-direction: column;\n\n min-height: 20px;\n border: 2px solid red;\n}\n.muigui-columns {\n display: flex;\n flex-direction: row;\n\n height: 20px;\n border: 2px solid green;\n}\n.muigui-rows>*,\n.muigui-columns>* {\n flex: 1 1 auto;\n align-items: stretch;\n min-height: 0;\n min-width: 0;\n}\n\n.muigui-row {\n border: 2px solid yellow;\n min-height: 10px\n}\n.muigui-column {\n border: 2px solid lightgreen;\n}\n\n/* -------- */\n\n.muigui-show { /* */ }\n.muigui-hide { \n display: none !important;\n}\n.muigui-disabled {\n pointer-events: none;\n --color: var(--disabled-color) !important;\n --value-color: var(--disabled-color) !important;\n --range-left-color: var(--disabled-color) !important;\n}\n\n.muigui canvas,\n.muigui svg {\n display: block;\n border-radius: var(--border-radius);\n}\n.muigui canvas {\n background-color: var(--value-bg-color);\n}\n\n.muigui-controller {\n min-width: 0;\n min-height: var(--line-height);\n}\n.muigui-root,\n.muigui-menu {\n display: flex;\n flex-direction: column;\n position: relative;\n user-select: none;\n height: fit-content;\n margin: 0;\n padding-bottom: 0.1em;\n border-radius: var(--border-radius);\n}\n.muigui-menu {\n border-bottom: 1px solid var(--menu-sep-color);\n}\n\n.muigui-root>button:nth-child(1),\n.muigui-menu>button:nth-child(1) {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n position: relative;\n text-align: left;\n color: var(--color);\n background-color: var(--menu-bg-color);\n min-height: var(--line-height);\n padding-top: 0.2em;\n padding-bottom: 0.2em;\n cursor: pointer;\n border-radius: var(--border-radius);\n}\n.muigui-root>div:nth-child(2),\n.muigui-menu>div:nth-child(2) {\n flex: 1 1 auto;\n}\n\n.muigui-controller {\n margin-left: 0.2em;\n margin-right: 0.2em;\n}\n.muigui-root.muigui-controller,\n.muigui-menu.muigui-controller {\n margin-left: 0;\n margin-right: 0;\n}\n.muigui-controller>*:nth-child(1) {\n flex: 1 0 var(--label-width);\n min-width: 0;\n white-space: pre;\n}\n.muigui-controller>label:nth-child(1) {\n place-content: center start;\n display: inline-grid;\n overflow: hidden;\n}\n.muigui-controller>*:nth-child(2) {\n flex: 1 1 75%;\n min-width: 0;\n}\n\n/* -----------------------------------------\n a label controller is [[label][value]]\n*/\n\n.muigui-label-controller {\n display: flex;\n margin: 0.4em 0 0.4em 0;\n word-wrap: initial;\n align-items: stretch;\n}\n\n.muigui-value {\n display: flex;\n align-items: stretch;\n}\n.muigui-value>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n.muigui-value>*:nth-child(1) {\n flex: 1 1 calc(100% - var(--number-width));\n}\n.muigui-value>*:nth-child(2) {\n flex: 1 1 var(--number-width);\n margin-left: 0.2em;\n}\n\n/* fix! */\n.muigui-open>button>label::before,\n.muigui-closed>button>label::before {\n width: 1.25em;\n height: var(--line-height);\n display: inline-grid;\n place-content: center start;\n pointer-events: none;\n}\n.muigui-open>button>label::before {\n content: "ⓧ"; /*"▼";*/\n}\n.muigui-closed>button>label::before {\n content: "⨁"; /*"▶";*/\n}\n.muigui-open>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 0.5s ease-out;\n max-height: 100vh;\n overflow: auto;\n opacity: 1;\n}\n\n.muigui-closed>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 1s;\n max-height: 0;\n opacity: 0;\n overflow: hidden;\n}\n\n/* ---- popdown ---- */\n\n.muigui-pop-down-top {\n display: flex;\n}\n/* fix? */\n.muigui-value>*:nth-child(1).muigui-pop-down-top {\n flex: 0;\n}\n.muigui-pop-down-bottom {\n\n}\n\n.muigui-pop-down-values {\n min-width: 0;\n display: flex;\n}\n.muigui-pop-down-values>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.muigui-value.muigui-pop-down-controller {\n flex-direction: column;\n}\n\n.muigui-pop-down-top input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-pop-down-top input[type=checkbox]::before {\n content: "+";\n display: grid;\n place-content: center;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n color: var(--value-bg-color);\n width: calc(var(--line-height) - 4px);\n height: calc(var(--line-height) - 4px);\n}\n\n.muigui-pop-down-top input[type=checkbox]:checked::before {\n content: "X";\n}\n\n\n/* ---- select ---- */\n\n.muigui select,\n.muigui option,\n.muigui input,\n.muigui button {\n color: var(--value-color);\n background-color: var(--value-bg-color);\n font-family: var(--font-family);\n font-size: var(--font-size);\n border: none;\n margin: 0;\n border-radius: var(--border-radius);\n}\n.muigui select {\n appearance: none;\n margin: 0;\n margin-left: 0; /*?*/\n overflow: hidden; /* Safari */\n}\n\n.muigui select:focus,\n.muigui input:focus,\n.muigui button:focus {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui select:hover,\n.muigui option:hover,\n.muigui input:hover,\n.muigui button:hover {\n background-color: var(--hover-bg-color); \n}\n\n/* ------ [ label ] ------ */\n\n.muigui-label {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n padding-top: 0.4em;\n padding-bottom: 0.3em;\n place-content: center start;\n background-color: var(--menu-bg-color);\n white-space: pre;\n border-radius: var(--border-radius);\n}\n\n/* ------ [ divider] ------ */\n\n.muigui-divider {\n min-height: 6px;\n border-top: 2px solid var(--menu-sep-color);\n margin-top: 6px;\n}\n\n/* ------ [ button ] ------ */\n\n.muigui-button {\n display: grid;\n\n}\n.muigui-button button {\n border: none;\n color: var(--value-color);\n background-color: var(--button-bg-color);\n cursor: pointer;\n place-content: center center;\n}\n\n/* ------ [ color ] ------ */\n\n.muigui-color>div {\n overflow: hidden;\n position: relative;\n margin-left: 0;\n margin-right: 0; /* why? */\n max-width: var(--line-height);\n border-radius: var(--border-radius);\n}\n\n.muigui-color>div:focus-within {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui-color input[type=color] {\n border: none;\n padding: 0;\n background: inherit;\n cursor: pointer;\n position: absolute;\n width: 200%;\n left: -10px;\n top: -10px;\n height: 200%;\n}\n.muigui-disabled canvas,\n.muigui-disabled svg,\n.muigui-disabled img,\n.muigui-disabled .muigui-color input[type=color] {\n opacity: 0.2;\n}\n\n/* ------ [ checkbox ] ------ */\n\n.muigui-checkbox>label:nth-child(2) {\n display: grid;\n place-content: center start;\n margin: 0;\n}\n\n.muigui-checkbox input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-checkbox input[type=checkbox]::before {\n content: "";\n color: var(--value-color);\n display: grid;\n place-content: center;\n}\n\n.muigui-checkbox input[type=checkbox]:checked::before {\n content: "✔";\n}\n\n.muigui input[type=number]::-webkit-inner-spin-button, \n.muigui input[type=number]::-webkit-outer-spin-button { \n -webkit-appearance: none;\n appearance: none;\n margin: 0; \n}\n.muigui input[type=number] {\n -moz-appearance: textfield;\n}\n\n/* ------ [ radio grid ] ------ */\n\n.muigui-radio-grid>div {\n display: grid;\n gap: 2px;\n}\n\n.muigui-radio-grid input {\n appearance: none;\n display: none;\n}\n\n.muigui-radio-grid button {\n color: var(--color);\n width: 100%;\n text-align: left;\n}\n\n.muigui-radio-grid input:checked + button {\n color: var(--value-color);\n background-color: var(--selected-color);\n}\n\n/* ------ [ color-chooser ] ------ */\n\n.muigui-color-chooser-cursor {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n.muigui-color-chooser-circle {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n\n\n/* ------ [ vec2 ] ------ */\n\n.muigui-vec2 svg {\n background-color: var(--value-bg-color);\n}\n\n.muigui-vec2-axis {\n stroke: 1px;\n stroke: var(--focus-color);\n}\n\n.muigui-vec2-line {\n stroke-width: 1px;\n stroke: var(--value-color);\n fill: var(--value-color);\n}\n\n/* ------ [ direction ] ------ */\n\n.muigui-direction svg {\n background-color: rgba(0,0,0,0.2);\n}\n\n.muigui-direction:focus-within svg {\n outline: none;\n}\n.muigui-direction-range {\n fill: var(--value-bg-color);\n}\n.muigui-direction svg:focus {\n outline: none;\n}\n.muigui-direction svg:focus .muigui-direction-range {\n stroke-width: 0.5px;\n stroke: var(--focus-color);\n}\n\n.muigui-direction-arrow {\n fill: var(--value-color);\n}\n\n/* ------ [ slider ] ------ */\n\n.muigui-slider>div {\n display: flex;\n align-items: stretch;\n height: var(--line-height);\n}\n.muigui-slider svg {\n flex: 1 1 auto;\n}\n.muigui-slider .muigui-slider-up #muigui-orientation {\n transform: scale(1, -1) translateY(-100%);\n}\n\n.muigui-slider .muigui-slider-up #muigui-number-orientation {\n transform: scale(1,-1);\n}\n\n.muigui-ticks {\n stroke: var(--range-color);\n}\n.muigui-thicks {\n stroke: var(--color);\n stroke-width: 2px;\n}\n.muigui-svg-text {\n fill: var(--color);\n font-size: 7px;\n}\n.muigui-mark {\n fill: var(--value-color);\n}\n\n/* ------ [ range ] ------ */\n\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: transparent;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n margin-top: calc((var(--line-height) - 2px) / -2);\n width: calc(var(--line-height) - 2px);\n height: calc(var(--line-height) - 2px);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n border: 1px solid var(--menu-sep-color);\n height: 2px;\n}\n\n\n/* dat.gui style - doesn\'t work on Safari iOS */\n\n/*\n.muigui-range input[type=range] {\n cursor: ew-resize;\n overflow: hidden;\n}\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: var(--range-right-color);\n margin: 0;\n}\n.muigui-range input[type=range]:hover {\n background-color: var(--range-right-hover-color);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n height: max-content;\n color: var(--range-left-color);\n margin-top: -1px;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 0px;\n height: max-content;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n}\n*/\n\n/* FF */\n/*\n.muigui-range input[type=range]::-moz-slider-progress {\n background-color: var(--range-left-color); \n}\n.muigui-range input[type=range]::-moz-slider-thumb {\n height: max-content;\n width: 0;\n border: none;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n box-sizing: border-box;\n}\n*/\n\n/* ---------------------------------------------------------- */\n\n/* needs to be at bottom to take precedence */\n.muigui-auto-place {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 100001;\n}\n\n'),n&&(this.domElement.style.width=/^\d+$/.test(n)?`${n}px`:n),void 0===s&&e&&(s=document.body,this.domElement.classList.add("muigui-auto-place")),s&&s.appendChild(this.domElement),i&&this.title(i),this.domElement.classList.add("muigui","muigui-colors")}}function Lt(){}function Nt(t,e,n){const i=t.getBoundingClientRect(),o=e.clientX-i.left,s=e.clientY-i.top,r=o/i.width,a=s/i.height,l=o-(n=n||[o,s])[0],u=s-n[1];return{x:o,y:s,nx:r,ny:a,dx:l,dy:u,ndx:l/i.width,ndy:u/i.width}}function At(t,{onDown:e=Lt,onMove:n=Lt,onUp:i=Lt}){let o;const s=function(e){const i={type:"move",...Nt(t,e,o)};n(i)},r=function(e){t.releasePointerCapture(e.pointerId),t.removeEventListener("pointermove",s),t.removeEventListener("pointerup",r),document.body.style.backgroundColor="",i("up")},a=function(n){t.addEventListener("pointermove",s),t.addEventListener("pointerup",r),t.setPointerCapture(n.pointerId);const i=Nt(t,n);o=[i.x,i.y],e({type:"down",...i})};return t.addEventListener("pointerdown",a),function(){t.removeEventListener("pointerdown",a)}}class St extends m{#O;#j;#P;#T;#z;#B;#G;#H;constructor(e){super(t("div",{innerHTML:'\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n',className:"muigui-no-scroll"})),this.#O=this.domElement.children[0],this.#j=this.domElement.children[1],this.#P=this.$(".muigui-color-chooser-circle"),this.#T=this.$("#muigui-color-chooser-hue"),this.#z=this.$(".muigui-color-chooser-cursor");const i=t=>{const i=n(t.nx,0,1),o=n(t.ny,0,1);this.#B[1]=i,this.#B[2]=1-o,this.#G=!0,e.setValue(J(ot(this.#B)))},o=t=>{const i=n(t.nx,0,1);this.#B[0]=i,this.#H=!0,e.setValue(J(ot(this.#B)))};At(this.#O,{onDown:i,onMove:i}),At(this.#j,{onDown:o,onMove:o})}updateDisplay(t){this.#B||(this.#B=rt(_(t)));{const[e,n,i]=rt(_(t));this.#G||(this.#B[0]=n>.001&&i>.001?e:this.#B[0]),this.#H||(this.#B[1]=n,this.#B[2]=i)}{const[t,e,n]=this.#B;this.#G||(this.#z.setAttribute("transform",`translate(${64*t}, 0)`),this.#T.children[0].setAttribute("stop-color",`hsl(${360*t}, 0%, 100%)`),this.#T.children[1].setAttribute("stop-color",`hsl(${360*t}, 100%, 50%)`)),this.#H||(this.#P.setAttribute("cx",""+64*e),this.#P.setAttribute("cy",""+48*(1-n)))}this.#G=!1,this.#H=!1}}class Ut extends V{#R;#Y;#W;#u={open:!1};constructor(e,n,i={}){super(e,n,"muigui-pop-down-controller"),this.#R=this.add(new B("div","muigui-pop-down-top"));const o=this.#R.addElem(t("input",{type:"checkbox",onChange:()=>{this.#u.open=o.checked}}));this.#Y=this.#R.add(new B("div","muigui-pop-down-values")),this.#W=this.add(new B("div","muigui-pop-down-bottom")),this.setOptions(i)}updateDisplay(){super.updateDisplay();const{open:t}=this.#u;this.domElement.children[1].classList.toggle("muigui-open",t),this.domElement.children[1].classList.toggle("muigui-closed",!t)}setOptions(t){r(this.#u,t),super.setOptions(t),this.updateDisplay()}addTop(t){return this.#Y.add(t)}addBottom(t){return this.#W.add(t)}}class Ot extends Ut{constructor(t,e){super(t,e,"muigui-color-chooser"),this.addTop(new T(this)),this.addBottom(new St(this)),this.updateDisplay()}}function jt(){}const Pt={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]};function Tt(t,{onDown:e=jt,onUp:n=jt}){const i=function(t){const i=t.shiftKey?10:1,[o,s]=(Pt[t.key]||[0,0]).map((t=>t*i));("keydown"===t.type?e:n)({type:t.type.substring(3),dx:o,dy:s,event:t})};return t.addEventListener("keydown",i),t.addEventListener("keyup",i),function(){t.removeEventListener("keydown",i),t.removeEventListener("keyup",i)}}function zt(t,e=""){if(!t)throw new Error(e)}function Bt(t,e,n,i,o,s){const r=Math.abs(n)*Math.cos(s),a=Math.abs(i)*Math.sin(s);return[t+Math.cos(o)*r-Math.sin(o)*a,e+Math.sin(o)*r+Math.cos(o)*a]}function Gt(t,e,n,i,o){zt(Math.abs(i-o)<=2*Math.PI),zt(i>=-Math.PI&&i<=2*Math.PI),zt(i<=o),zt(o>=-Math.PI&&o<=4*Math.PI);const{x1:s,y1:r,x2:a,y2:l,fa:u,fs:c}=function(t,e,n,i,o,s,r){const[a,l]=Bt(t,e,n,i,o,s),[u,c]=Bt(t,e,n,i,o,s+r);return{x1:a,y1:l,x2:u,y2:c,fa:Math.abs(r)>Math.PI?1:0,fs:r>0?1:0}}(t,e,n,n,0,i,o-i);return Math.abs(Math.abs(i-o)-2*Math.PI)>Number.EPSILON?`M${t} ${e} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l} L${t} ${e}`:`M${s} ${r} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l}`}const Ht=t=>s(t+Math.PI,2*Math.PI)-Math.PI;class Rt extends m{#q;#_;#J;#K;#u={step:1,min:-180,max:180,dirMin:-Math.PI,dirMax:Math.PI,wrap:void 0,converters:I};constructor(e,i={}){const r=L();super(t("div",{className:"muigui-direction muigui-no-scroll",innerHTML:'\n\n \x3c!----\x3e\n \n \n \n \n \n \n\n',onWheel:t=>{t.preventDefault();const{min:i,max:a,step:l}=this.#u,u=r(t,l);let c=this.#J+u;this.#K&&(c=s(c-i,a-i)+i);const h=n(o(c,(t=>t),l),i,a);e.setValue(h)}}));const a=t=>{const{min:i,max:s,step:r,dirMin:a,dirMax:l}=this.#u,u=2*t.nx-1,c=2*t.ny-1,h=Math.atan2(c,u),d=(a+l)/2,p=n((Ht(h-d)-Ht(a-d))/(l-a),0,1),m=o(i+(s-i)*p,(t=>t),r);e.setValue(m)};At(this.domElement,{onDown:a,onMove:a}),Tt(this.domElement,{onDown:t=>{const{min:i,max:s,step:r}=this.#u,a=n(o(this.#J+t.dx*r,(t=>t),r),i,s);e.setValue(a)}}),this.#q=this.$("#muigui-arrow"),this.#_=this.$("#muigui-range"),this.setOptions(i)}updateDisplay(t){this.#J=t;const{min:e,max:n}=this.#u,i=(t-e)/(n-e),o=(s=this.#u.dirMin,r=this.#u.dirMax,s+(r-s)*i);var s,r;this.#q.style.transform=`rotate(${o}rad)`}setOptions(t){r(this.#u,t);const{dirMin:e,dirMax:n,wrap:i}=this.#u;this.#K=void 0!==i?i:Math.abs(e-n)>=2*Math.PI-Number.EPSILON;const[o,s]=e(o.push(i),t("label",{},[t("input",{type:"radio",name:s,value:a,onChange:function(){this.checked&&e.setFinalValue(r.#D[this.value])}}),t("button",{type:"button",textContent:n,onClick:function(){this.previousElementSibling.click()}})]))))));const r=this;this.#D=o,this.cols(i)}updateDisplay(t){const e=this.#D.indexOf(t);for(let t=0;t{e({rect:t.getBoundingClientRect(),elem:t})})).observe(t)}function Jt(t,e,n,i){_t(t,(({rect:o})=>{const{width:s,height:r}=o;t.setAttribute("viewBox",`-${s*e} -${r*n} ${s} ${r}`),i({elem:t,rect:o})}))}function Kt(t,e,n,i,s,r){const a=[];tt),n)),e=Math.min(e,s);for(let i=t;i<=e;i+=n)a.push(`M${i} 0 l0 ${r}`);return a.join(" ")}class Xt extends m{#X;#Z;#Q;#tt;#et;#nt;#it;#ot;#st;#J;#rt;#u={min:-100,max:100,step:1,unit:10,unitSize:10,ticksPerUnit:5,labelFn:t=>t,tickHeight:1,limits:!0,thicksColor:void 0,orientation:void 0};constructor(e,i){const s=L();let r;super(t("div",{innerHTML:'\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \x3c!----\x3e\n \x3c!----\x3e\n \n \n \n \n\n',className:"muigui-no-v-scroll",onWheel:t=>{t.preventDefault();const{min:i,max:r,step:a}=this.#u,l=s(t,a),u=n(o(this.#J+l,(t=>t),a),i,r);e.setValue(u)}})),this.#X=this.$("svg"),this.#Z=this.$("#muigui-origin"),this.#Q=this.$("#muigui-ticks"),this.#tt=this.$("#muigui-thicks"),this.#et=this.$("#muigui-numbers"),this.#nt=this.$("#muigui-left-grad"),this.#it=this.$("#muigui-right-grad"),this.setOptions(i),At(this.domElement,{onDown:()=>{r=this.#J},onMove:t=>{const{min:i,max:s,unitSize:a,unit:l,step:u}=this.#u,c=n(o(r-t.dx/a*l,(t=>t),u),i,s);e.setValue(c)}}),Tt(this.domElement,{onDown:t=>{const{min:i,max:s,step:r}=this.#u,a=n(o(this.#J+t.dx*r,(t=>t),r),i,s);e.setValue(a)}}),Jt(this.#X,.5,0,(({rect:{width:t}})=>{this.#nt.setAttribute("x",-t/2),this.#it.setAttribute("x",t/2-20),this.#rt=function(t){const e=t.innerHTML;t.innerHTML="- ";const n=t.querySelector("text").getComputedTextLength();return t.innerHTML=e,n}(this.#et),this.#ot=t,this.#at()}))}#at(){if(!this.#ot||void 0===this.#J)return;const{labelFn:t,limits:e,min:n,max:i,orientation:s,tickHeight:r,ticksPerUnit:a,unit:l,unitSize:u,thicksColor:c}=this.#u,h=Math.ceil(this.#ot/u),d=this.#J/l,p=Math.round(d-h),m=p*u,g=(p+2*h)*u,f=e?n*u/l:m,b=e?i*u/l:g,v=""===t(1)?10:5;a>1&&this.#Q.setAttribute("d",Kt(m,g,u/a,f,b,v*r)),this.#tt.style.stroke=c,this.#tt.setAttribute("d",Kt(m,g,u,f,b,v)),this.#et.innerHTML=function(t,e,n,i,s,r,a,l){const u=[];tt),n)),e=Math.min(e,a);const c=Math.max(0,-Math.log10(i));for(let o=t;o<=e;o+=n)u.push(`${h=o/n*i,l(h.toFixed(c))}`);var h;return u.join("\n")}(m,g,u,l,this.#rt,f,b,t),this.#Z.setAttribute("transform",`translate(${-this.#J*u/l} 0)`),this.#X.classList.toggle("muigui-slider-up","up"===s)}updateDisplay(t){this.#J=t,this.#at()}setOptions(t){return r(this.#u,t),this}}class Zt extends V{constructor(t,e,n={}){super(t,e,"muigui-slider"),this.add(new Xt(this,n)),this.add(new N(this,n)),this.updateDisplay()}}class Qt extends m{#X;#q;#P;#J=[];constructor(e){super(t("div",{innerHTML:'\n\n \n \n \n \n \n\n',className:"muigui-no-scroll"}));const n=t=>{const{width:n,height:i}=this.#X.getBoundingClientRect(),o=2*t.nx-1,s=2*t.ny-1;e.setValue([o*n*.5,s*i*.5])};At(this.domElement,{onDown:n,onMove:n}),this.#X=this.$("svg"),this.#q=this.$("#muigui-arrow"),this.#P=this.$("#muigui-circle"),Jt(this.#X,.5,.5,(()=>this.#lt))}#lt(){const[t,e]=this.#J;this.#q.setAttribute("d",`M0,0L${t},${e}`),this.#P.setAttribute("transform",`translate(${t}, ${e})`)}updateDisplay(t){this.#J[0]=t[0],this.#J[1]=t[1],this.#lt()}}class te extends Ut{constructor(t,e){super(t,e,"muigui-vec2");const n=t=>({setValue:e=>{const n=this.getValue();n[t]=e,this.setValue(n)},setFinalValue:e=>{const n=this.getValue();n[t]=e,this.setFinalValue(n)}});this.addTop(new N(n(0),{converters:{to:t=>t[0],from:D.from}})),this.addTop(new N(n(1),{converters:{to:t=>t[1],from:D.from}})),this.addBottom(new Qt(this)),this.updateDisplay()}}export{Ot as ColorChooser,Yt as Direction,qt as RadioGrid,P as Range,O as Select,Zt as Slider,A as TextNumber,te as Vec2,Ft as default}; +var t={default:'\n.muigui {\n --bg-color: #ddd;\n --color: #222;\n --contrast-color: #eee;\n --value-color: #145 ;\n --value-bg-color: #eeee;\n --disabled-color: #999;\n --menu-bg-color: #f8f8f8;\n --menu-sep-color: #bbb;\n --hover-bg-color: #999;\n --focus-color: #68C;\n --range-color: #888888;\n --invalid-color: #FF0000;\n --selected-color: rgb(255, 255, 255, 0.9);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n}\n\n@media (prefers-color-scheme: dark) {\n .muigui {\n --bg-color: #222222;\n --color: #dddddd;\n --contrast-color: #000;\n --value-color: #43e5f7;\n --value-bg-color: #444444;\n --disabled-color: #666666;\n --menu-bg-color: #080808;\n --menu-sep-color: #444444;\n --hover-bg-color: #666666;\n --focus-color: #88AAFF;\n --range-color: #888888;\n --invalid-color: #FF6666;\n --selected-color: rgba(255, 255, 255, 0.3);\n\n --button-bg-color: var(--value-bg-color);\n\n --range-left-color: var(--value-color);\n --range-right-color: var(--value-bg-color); \n --range-right-hover-color: var(--hover-bg-color);\n\n color: var(--color);\n background-color: var(--bg-color);\n }\n}\n\n.muigui {\n --width: 250px;\n --label-width: 45%;\n --number-width: 40%;\n\n\n --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;\n --font-size: 11px;\n --font-family-mono: Menlo, Monaco, Consolas, "Droid Sans Mono", monospace;\n --font-size-mono: 11px;\n\n --line-height: 1.7em;\n --border-radius: 0px;\n\n width: var(--width);\n font-family: var(--font-family);\n font-size: var(--font-size);\n box-sizing: border-box;\n line-height: 100%;\n}\n.muigui * {\n box-sizing: inherit;\n}\n\n.muigui-no-scroll {\n touch-action: none;\n}\n.muigui-no-h-scroll {\n touch-action: pan-y;\n}\n.muigui-no-v-scroll {\n touch-action: pan-x;\n}\n\n.muigui-invalid-value {\n background-color: red !important;\n color: white !important;\n}\n\n.muigui-grid {\n display: grid;\n}\n.muigui-rows {\n display: flex;\n flex-direction: column;\n\n min-height: 20px;\n border: 2px solid red;\n}\n.muigui-columns {\n display: flex;\n flex-direction: row;\n\n height: 20px;\n border: 2px solid green;\n}\n.muigui-rows>*,\n.muigui-columns>* {\n flex: 1 1 auto;\n align-items: stretch;\n min-height: 0;\n min-width: 0;\n}\n\n.muigui-row {\n border: 2px solid yellow;\n min-height: 10px\n}\n.muigui-column {\n border: 2px solid lightgreen;\n}\n\n/* -------- */\n\n.muigui-show { /* */ }\n.muigui-hide { \n display: none !important;\n}\n.muigui-disabled {\n pointer-events: none;\n --color: var(--disabled-color) !important;\n --value-color: var(--disabled-color) !important;\n --range-left-color: var(--disabled-color) !important;\n}\n\n.muigui canvas,\n.muigui svg {\n display: block;\n border-radius: var(--border-radius);\n}\n.muigui canvas {\n background-color: var(--value-bg-color);\n}\n\n.muigui-controller {\n min-width: 0;\n min-height: var(--line-height);\n}\n.muigui-root,\n.muigui-menu {\n display: flex;\n flex-direction: column;\n position: relative;\n user-select: none;\n height: fit-content;\n margin: 0;\n padding-bottom: 0.1em;\n border-radius: var(--border-radius);\n}\n.muigui-menu {\n border-bottom: 1px solid var(--menu-sep-color);\n}\n\n.muigui-root>button:nth-child(1),\n.muigui-menu>button:nth-child(1) {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n position: relative;\n text-align: left;\n color: var(--color);\n background-color: var(--menu-bg-color);\n min-height: var(--line-height);\n padding-top: 0.2em;\n padding-bottom: 0.2em;\n cursor: pointer;\n border-radius: var(--border-radius);\n}\n.muigui-root>div:nth-child(2),\n.muigui-menu>div:nth-child(2) {\n flex: 1 1 auto;\n}\n\n.muigui-controller {\n margin-left: 0.2em;\n margin-right: 0.2em;\n}\n.muigui-root.muigui-controller,\n.muigui-menu.muigui-controller {\n margin-left: 0;\n margin-right: 0;\n}\n.muigui-controller>*:nth-child(1) {\n flex: 1 0 var(--label-width);\n min-width: 0;\n white-space: pre;\n}\n.muigui-controller>label:nth-child(1) {\n place-content: center start;\n display: inline-grid;\n overflow: hidden;\n}\n.muigui-controller>*:nth-child(2) {\n flex: 1 1 75%;\n min-width: 0;\n}\n\n/* -----------------------------------------\n a label controller is [[label][value]]\n*/\n\n.muigui-label-controller {\n display: flex;\n margin: 0.4em 0 0.4em 0;\n word-wrap: initial;\n align-items: stretch;\n}\n\n.muigui-value {\n display: flex;\n align-items: stretch;\n}\n.muigui-value>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n.muigui-value>*:nth-child(1) {\n flex: 1 1 calc(100% - var(--number-width));\n}\n.muigui-value>*:nth-child(2) {\n flex: 1 1 var(--number-width);\n margin-left: 0.2em;\n}\n\n/* fix! */\n.muigui-open>button>label::before,\n.muigui-closed>button>label::before {\n width: 1.25em;\n height: var(--line-height);\n display: inline-grid;\n place-content: center start;\n pointer-events: none;\n}\n.muigui-open>button>label::before {\n content: "ⓧ"; /*"▼";*/\n}\n.muigui-closed>button>label::before {\n content: "⨁"; /*"▶";*/\n}\n.muigui-open>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 0.5s ease-out;\n max-height: 100vh;\n overflow: auto;\n opacity: 1;\n}\n\n.muigui-closed>*:nth-child(2) {\n transition: max-height 0.2s ease-out,\n opacity 1s;\n max-height: 0;\n opacity: 0;\n overflow: hidden;\n}\n\n/* ---- popdown ---- */\n\n.muigui-pop-down-top {\n display: flex;\n}\n/* fix? */\n.muigui-value>*:nth-child(1).muigui-pop-down-top {\n flex: 0;\n}\n.muigui-pop-down-bottom {\n\n}\n\n.muigui-pop-down-values {\n min-width: 0;\n display: flex;\n}\n.muigui-pop-down-values>* {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.muigui-value.muigui-pop-down-controller {\n flex-direction: column;\n}\n\n.muigui-pop-down-top input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-pop-down-top input[type=checkbox]::before {\n content: "+";\n display: grid;\n place-content: center;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n color: var(--value-bg-color);\n width: calc(var(--line-height) - 4px);\n height: calc(var(--line-height) - 4px);\n}\n\n.muigui-pop-down-top input[type=checkbox]:checked::before {\n content: "X";\n}\n\n\n/* ---- select ---- */\n\n.muigui select,\n.muigui option,\n.muigui input,\n.muigui button {\n color: var(--value-color);\n background-color: var(--value-bg-color);\n font-family: var(--font-family);\n font-size: var(--font-size);\n border: none;\n margin: 0;\n border-radius: var(--border-radius);\n}\n.muigui select {\n appearance: none;\n margin: 0;\n margin-left: 0; /*?*/\n overflow: hidden; /* Safari */\n}\n\n.muigui select:focus,\n.muigui input:focus,\n.muigui button:focus {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui select:hover,\n.muigui option:hover,\n.muigui input:hover,\n.muigui button:hover {\n background-color: var(--hover-bg-color); \n}\n\n/* ------ [ label ] ------ */\n\n.muigui-label {\n border-top: 1px solid var(--menu-sep-color);\n border-bottom: 1px solid var(--menu-sep-color);\n padding-top: 0.4em;\n padding-bottom: 0.3em;\n place-content: center start;\n background-color: var(--menu-bg-color);\n white-space: pre;\n border-radius: var(--border-radius);\n}\n\n/* ------ [ divider] ------ */\n\n.muigui-divider {\n min-height: 6px;\n border-top: 2px solid var(--menu-sep-color);\n margin-top: 6px;\n}\n\n/* ------ [ button ] ------ */\n\n.muigui-button {\n display: grid;\n\n}\n.muigui-button button {\n border: none;\n color: var(--value-color);\n background-color: var(--button-bg-color);\n cursor: pointer;\n place-content: center center;\n}\n\n/* ------ [ color ] ------ */\n\n.muigui-color>div {\n overflow: hidden;\n position: relative;\n margin-left: 0;\n margin-right: 0; /* why? */\n max-width: var(--line-height);\n border-radius: var(--border-radius);\n}\n\n.muigui-color>div:focus-within {\n outline: 1px solid var(--focus-color);\n}\n\n.muigui-color input[type=color] {\n border: none;\n padding: 0;\n background: inherit;\n cursor: pointer;\n position: absolute;\n width: 200%;\n left: -10px;\n top: -10px;\n height: 200%;\n}\n.muigui-disabled canvas,\n.muigui-disabled svg,\n.muigui-disabled img,\n.muigui-disabled .muigui-color input[type=color] {\n opacity: 0.2;\n}\n\n/* ------ [ checkbox ] ------ */\n\n.muigui-checkbox>label:nth-child(2) {\n display: grid;\n place-content: center start;\n margin: 0;\n}\n\n.muigui-checkbox input[type=checkbox] {\n -webkit-appearance: none;\n appearance: none;\n width: auto;\n color: var(--value-color);\n background-color: var(--value-bg-color);\n cursor: pointer;\n\n display: grid;\n place-content: center;\n margin: 0;\n font: inherit;\n color: currentColor;\n width: 1.7em;\n height: 1.7em;\n transform: translateY(-0.075em);\n}\n\n.muigui-checkbox input[type=checkbox]::before {\n content: "";\n color: var(--value-color);\n display: grid;\n place-content: center;\n}\n\n.muigui-checkbox input[type=checkbox]:checked::before {\n content: "✔";\n}\n\n.muigui input[type=number]::-webkit-inner-spin-button, \n.muigui input[type=number]::-webkit-outer-spin-button { \n -webkit-appearance: none;\n appearance: none;\n margin: 0; \n}\n.muigui input[type=number] {\n -moz-appearance: textfield;\n}\n\n/* ------ [ radio grid ] ------ */\n\n.muigui-radio-grid>div {\n display: grid;\n gap: 2px;\n}\n\n.muigui-radio-grid input {\n appearance: none;\n display: none;\n}\n\n.muigui-radio-grid button {\n color: var(--color);\n width: 100%;\n text-align: left;\n}\n\n.muigui-radio-grid input:checked + button {\n color: var(--value-color);\n background-color: var(--selected-color);\n}\n\n/* ------ [ color-chooser ] ------ */\n\n.muigui-color-chooser-cursor {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n.muigui-color-chooser-circle {\n stroke-width: 1px;\n stroke: white;\n fill: none;\n}\n\n\n/* ------ [ vec2 ] ------ */\n\n.muigui-vec2 svg {\n background-color: var(--value-bg-color);\n}\n\n.muigui-vec2-axis {\n stroke: 1px;\n stroke: var(--focus-color);\n}\n\n.muigui-vec2-line {\n stroke-width: 1px;\n stroke: var(--value-color);\n fill: var(--value-color);\n}\n\n/* ------ [ direction ] ------ */\n\n.muigui-direction svg {\n background-color: rgba(0,0,0,0.2);\n}\n\n.muigui-direction:focus-within svg {\n outline: none;\n}\n.muigui-direction-range {\n fill: var(--value-bg-color);\n}\n.muigui-direction svg:focus {\n outline: none;\n}\n.muigui-direction svg:focus .muigui-direction-range {\n stroke-width: 0.5px;\n stroke: var(--focus-color);\n}\n\n.muigui-direction-arrow {\n fill: var(--value-color);\n}\n\n/* ------ [ slider ] ------ */\n\n.muigui-slider>div {\n display: flex;\n align-items: stretch;\n height: var(--line-height);\n}\n.muigui-slider svg {\n flex: 1 1 auto;\n}\n.muigui-slider .muigui-slider-up #muigui-orientation {\n transform: scale(1, -1) translateY(-100%);\n}\n\n.muigui-slider .muigui-slider-up #muigui-number-orientation {\n transform: scale(1,-1);\n}\n\n.muigui-ticks {\n stroke: var(--range-color);\n}\n.muigui-thicks {\n stroke: var(--color);\n stroke-width: 2px;\n}\n.muigui-svg-text {\n fill: var(--color);\n font-size: 7px;\n}\n.muigui-mark {\n fill: var(--value-color);\n}\n\n/* ------ [ range ] ------ */\n\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: transparent;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n border-radius: calc(var(--border-radius) + 2px);\n border-left: 1px solid rgba(255,255,255,0.3);\n border-top: 1px solid rgba(255,255,255,0.3);\n border-bottom: 1px solid rgba(0,0,0,0.2);\n border-right: 1px solid rgba(0,0,0,0.2);\n background-color: var(--range-color);\n margin-top: calc((var(--line-height) - 2px) / -2);\n width: calc(var(--line-height) - 2px);\n height: calc(var(--line-height) - 2px);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n border: 1px solid var(--menu-sep-color);\n height: 2px;\n}\n\n\n/* dat.gui style - doesn\'t work on Safari iOS */\n\n/*\n.muigui-range input[type=range] {\n cursor: ew-resize;\n overflow: hidden;\n}\n\n.muigui-range input[type=range] {\n -webkit-appearance: none;\n appearance: none;\n background-color: var(--range-right-color);\n margin: 0;\n}\n.muigui-range input[type=range]:hover {\n background-color: var(--range-right-hover-color);\n}\n\n.muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: none;\n appearance: none;\n height: max-content;\n color: var(--range-left-color);\n margin-top: -1px;\n}\n\n.muigui-range input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 0px;\n height: max-content;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n}\n*/\n\n/* FF */\n/*\n.muigui-range input[type=range]::-moz-slider-progress {\n background-color: var(--range-left-color); \n}\n.muigui-range input[type=range]::-moz-slider-thumb {\n height: max-content;\n width: 0;\n border: none;\n box-shadow: -1000px 0 0 1000px var(--range-left-color);\n box-sizing: border-box;\n}\n*/\n\n/* ---------------------------------------------------------- */\n\n/* needs to be at bottom to take precedence */\n.muigui-auto-place {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 100001;\n}\n\n',themes:{default:"",float:"\n :root {\n color-scheme: light dark,\n }\n\n .muigui {\n --width: 400px;\n --bg-color: initial;\n --label-width: 25%;\n }\n\n input,\n .muigui-label-controller>label {\n text-shadow:\n -1px -1px 0 var(--contrast-color),\n 1px -1px 0 var(--contrast-color),\n -1px 1px 0 var(--contrast-color),\n 1px 1px 0 var(--contrast-color);\n }\n\n .muigui-controller > label:nth-child(1) {\n place-content: center end;\n margin-right: 1em;\n }\n\n .muigui-value > :nth-child(2) {\n margin-left: 1em;\n }\n\n .muigui-root>*:nth-child(1) {\n display: none;\n }\n\n .muigui-range input[type=range]::-webkit-slider-thumb {\n border-radius: 1em;\n }\n\n .muigui-range input[type=range]::-webkit-slider-runnable-track {\n -webkit-appearance: initial;\n appearance: none;\n border: 1px solid rgba(0, 0, 0, 0.25);\n height: 2px;\n }\n\n .muigui-colors {\n --value-color: var(--color );\n --value-bg-color: rgba(0, 0, 0, 0.1);\n --disabled-color: #cccccc;\n --menu-bg-color: rgba(0, 0, 0, 0.1);\n --menu-sep-color: #bbbbbb;\n --hover-bg-color: rgba(0, 0, 0, 0);\n --invalid-color: #FF0000;\n --selected-color: rgba(0, 0, 0, 0.3);\n --range-color: rgba(0, 0, 0, 0.125);\n }\n"}};function e(t,e={},n=[]){const i=document.createElement(t);return function(t,e,n){for(const[n,i]of Object.entries(e))if("function"==typeof i&&n.startsWith("on")){const e=n.substring(2).toLowerCase();t.addEventListener(e,i,{passive:!1})}else if("object"==typeof i)for(const[e,o]of Object.entries(i))t[n][e]=o;else void 0===t[n]?t.setAttribute(n,i):t[n]=i;for(const e of n)t.appendChild(e)}(i,e,n),i}function n(t,e){const n=t.indexOf(e);return n&&t.splice(n,1),t}function i(t,e,n){return Math.max(e,Math.min(n,t))}const o="undefined"!=typeof SharedArrayBuffer?function(t){return t&&t.buffer&&(t.buffer instanceof ArrayBuffer||t.buffer instanceof SharedArrayBuffer)}:function(t){return t&&t.buffer&&t.buffer instanceof ArrayBuffer},s=(t,e,n)=>Math.round(e(t)/n)/(1/n),r=(t,e)=>(t%e+e)%e;function a(t,e){for(const n in e)n in t&&(t[n]=e[n]);return t}const l=(t,e,n,i,o)=>(t-e)*(o-i)/(n-e)+i,u=({from:t,to:e})=>({to:n=>l(n,...t,...e),from:n=>[!0,l(n,...e,...t)]}),c=({from:t,to:e,step:n})=>({min:e[0],max:e[1],...n&&{step:n},converters:u({from:t,to:e})}),h={to:t=>t,from:t=>[!0,t]};function d(t,e,n,i,o){const{converters:{from:s}=h}=o,{min:r,max:a}=o,l=o.minRange||0,u=s(l)[1];return console.log("guiMinRange",l),console.log("valueMinRange",u),[t.add(e,n,{...o,min:r,max:a-l}).listen().onChange((t=>{e[i]=Math.min(a,Math.max(t+u,e[i]))})),t.add(e,i,{...o,min:r+l,max:a}).listen().onChange((t=>{e[n]=Math.max(r,Math.min(t-u,e[n]))}))]}class p{#t;#e=[];constructor(t){this.domElement=t,this.#t=t}addElem(t){return this.#t.appendChild(t),t}removeElem(t){return this.#t.removeChild(t),t}pushSubElem(t){this.#t.appendChild(t),this.#t=t}popSubElem(){this.#t=this.#t.parentElement}add(t){return this.#e.push(t),this.addElem(t.domElement),t}remove(t){return this.removeElem(t.domElement),n(this.#e,t),t}pushSubView(t){this.pushSubElem(t.domElement)}popSubView(){this.popSubElem()}setOptions(t){for(const e of this.#e)e.setOptions(t)}updateDisplayIfNeeded(t,e){for(const n of this.#e)n.updateDisplayIfNeeded(t,e);return this}$(t){return this.domElement.querySelector(t)}}class m extends p{#n;#i;#o;constructor(t){super(e("div",{className:"muigui-controller"})),this.#n=[],this.#i=[],t&&this.domElement.classList.add(t)}get parent(){return this.#o}setParent(t){this.#o=t,this.enable(!this.disabled())}show(t=!0){return this.domElement.classList.toggle("muigui-hide",!t),this.domElement.classList.toggle("muigui-show",t),this}hide(){return this.show(!1)}disabled(){return!!this.domElement.closest(".muigui-disabled")}enable(t=!0){return this.domElement.classList.toggle("muigui-disabled",!t),["input","button","select","textarea"].forEach((t=>{this.domElement.querySelectorAll(t).forEach((t=>{const e=!!t.closest(".muigui-disabled");t.disabled=e}))})),this}disable(t=!0){return this.enable(!t)}onChange(t){return this.removeChange(t),this.#n.push(t),this}removeChange(t){return n(this.#n,t),this}onFinishChange(t){return this.removeFinishChange(t),this.#i.push(t),this}removeFinishChange(t){return n(this.#i,t),this}#s(t,e){for(const n of t)n.call(this,e)}emitChange(t,e,n){this.#s(this.#n,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitChange({object:e,property:n,value:t,controller:this}))}emitFinalChange(t,e,n){this.#s(this.#i,t),this.#o&&(void 0===e?this.#o.emitChange(t):this.#o.emitFinalChange({object:e,property:n,value:t,controller:this}))}getColors(){const t=t=>t.replace(/-([a-z])/g,((t,e)=>e.toUpperCase())),n=e("div");this.domElement.appendChild(n);const i=Object.fromEntries(["color","bg-color","value-color","value-bg-color","hover-bg-color","menu-bg-color","menu-sep-color","disabled-color"].map((e=>{n.style.color=`var(--${e})`;const i=getComputedStyle(n);return[t(e),i.color]})));return n.remove(),i}}class g extends m{#r;#a;#l;#u={name:""};constructor(t,n,i={}){super("muigui-button",""),this.#r=t,this.#a=n,this.#l=this.addElem(e("button",{type:"button",onClick:()=>{this.#r[this.#a](this)}})),this.setOptions({name:n,...i})}setOptions(t){a(this.#u,t);const{name:e}=this.#u;this.#l.textContent=e}}function f(t,e){if(t.length!==e.length)return!1;for(let n=0;n{t.setValue(i.checked)},onChange:()=>{t.setFinalValue(i.checked)}});super(e("label",{},[i]))}updateDisplay(t){this.domElement.checked=t}}const x=[],w=new Set;let y,k;function E(){y=void 0,k=!0;for(const t of x)w.has(t)||t();k=!1,w.size&&(k?$():(w.forEach((t=>{n(x,t)})),w.clear())),$()}function $(){!y&&x.length&&(y=requestAnimationFrame(E))}let C=0;function M(){return"muigui-"+ ++C}class V extends p{constructor(t=""){super(e("div",{className:"muigui-value"})),t&&this.domElement.classList.add(t)}}class S extends m{#b;#v;constructor(t="",n=""){super("muigui-label-controller"),this.#b=M(),this.#v=e("label",{for:this.#b}),this.domElement.appendChild(this.#v),this.pushSubView(new V(t)),this.name(n)}get id(){return this.#b}name(t){return this.#v.title===this.#v.textContent&&(this.#v.title=t),this.#v.textContent=t,this}tooltip(t){this.#v.title=t}}class I extends S{#r;#a;#x;#w;#e;#y;constructor(t,e,n=""){super(n,e),this.#r=t,this.#a=e,this.#x=this.getValue(),this.#w=!1,this.#e=[]}get initialValue(){return this.#x}get object(){return this.#r}get property(){return this.#a}add(t){return this.#e.push(t),super.add(t),this.updateDisplay(),t}#k(t,e){if("object"==typeof t){const e=this.#r[this.#a];if(Array.isArray(t))for(let n=0;n=0&&x.splice(e,1)}(this.#y)),this}}class D extends I{constructor(t,e){super(t,e,"muigui-checkbox");const n=this.id;this.add(new v(this,n)),this.updateDisplay()}}const F={to:t=>t,from:t=>[!0,t]},L={to:t=>t.toString(),from:t=>{const e=parseFloat(t);return[!Number.isNaN(e),e]}},N={radToDeg:u({to:[0,180],from:[0,Math.PI]})};function A(){let t=0;return function(e,n,i=5){t-=e.deltaY*n/i;const o=Math.floor(Math.abs(t)/n)*Math.sign(t)*n;return t-=o,o}}class U extends b{#E;#$;#C;#M;#u={step:.01,converters:L,min:Number.NEGATIVE_INFINITY,max:Number.POSITIVE_INFINITY};constructor(t,n){const o=t.setValue.bind(t),r=t.setFinalValue.bind(t),a=A();super(e("input",{type:"number",onInput:()=>this.#V(o,!0),onChange:()=>this.#V(r,!1),onWheel:e=>{e.preventDefault();const{min:n,max:o,step:r}=this.#u,l=a(e,r),u=parseFloat(this.domElement.value),c=i(s(u+l,(t=>t),r),n,o);t.setValue(c)}})),this.setOptions(n)}#V(t,e){const n=parseFloat(this.domElement.value),[o,s]=this.#$(n);let r;if(o&&!Number.isNaN(n)){const{min:n,max:o}=this.#u;r=s>=n&&s<=o,this.#M=e,t(i(s,n,o))}this.domElement.classList.toggle("muigui-invalid-value",!o||!r)}updateDisplay(t){this.#M||(this.domElement.value=s(t,this.#E,this.#C)),this.#M=!1}setOptions(t){a(this.#u,t);const{step:e,converters:{to:n,from:i}}=this.#u;return this.#E=n,this.#$=i,this.#C=e,this}}class O extends I{#S;#C;constructor(t,e,n={}){super(t,e,"muigui-checkbox"),this.#S=this.add(new U(this,n)),this.updateDisplay()}}class j extends b{#I;constructor(t,n){const i=[];super(e("select",{onChange:()=>{t.setFinalValue(this.#I[this.domElement.selectedIndex])}},n.map((([t,n])=>(i.push(n),e("option",{textContent:t})))))),this.#I=i}updateDisplay(t){const e=this.#I.indexOf(t);this.domElement.selectedIndex=e}}function T(t,e){return Array.isArray(t)?Array.isArray(t[0])?t:e?t.map(((t,e)=>[t,e])):t.map((t=>[t,t])):[...Object.entries(t)]}class P extends I{constructor(t,e,n){super(t,e,"muigui-select");const i="number"==typeof this.getValue(),{keyValues:o}=n,s=T(o,i);this.add(new j(this,s)),this.updateDisplay()}}class z extends b{#E;#$;#C;#M;#u={step:.01,min:0,max:1,converters:F};constructor(t,n){const o=A();super(e("input",{type:"range",onInput:()=>{this.#M=!0;const{min:e,max:n,step:o}=this.#u,r=parseFloat(this.domElement.value),a=i(s(r,(t=>t),o),e,n),[l,u]=this.#$(a);l&&t.setValue(u)},onChange:()=>{this.#M=!0;const{min:e,max:n,step:o}=this.#u,r=parseFloat(this.domElement.value),a=i(s(r,(t=>t),o),e,n),[l,u]=this.#$(a);l&&t.setFinalValue(u)},onWheel:e=>{e.preventDefault();const[n,r]=this.#$(parseFloat(this.domElement.value));if(!n)return;const{min:a,max:l,step:u}=this.#u,c=o(e,u),h=i(s(r+c,(t=>t),u),a,l);t.setValue(h)}})),this.setOptions(n)}updateDisplay(t){this.#M||(this.domElement.value=s(t,this.#E,this.#C)),this.#M=!1}setOptions(t){a(this.#u,t);const{step:e,min:n,max:i,converters:{to:o,from:s}}=this.#u;return this.#E=o,this.#$=s,this.#C=e,this.domElement.step=e,this.domElement.min=n,this.domElement.max=i,this}}class B extends I{constructor(t,e,n){super(t,e,"muigui-range"),this.add(new z(this,n)),this.add(new U(this,n))}}class G extends b{#E;#$;#M;#u={converters:F};constructor(t,n){const i=t.setValue.bind(t),o=t.setFinalValue.bind(t);super(e("input",{type:"text",onInput:()=>this.#V(i,!0),onChange:()=>this.#V(o,!1)})),this.setOptions(n)}#V(t,e){const[n,i]=this.#$(this.domElement.value);n&&(this.#M=e,t(i)),this.domElement.style.color=n?"":"var(--invalid-color)"}updateDisplay(t){this.#M||(this.domElement.value=this.#E(t),this.domElement.style.color=""),this.#M=!1}setOptions(t){a(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#$=n,this}}class H extends I{constructor(t,e){super(t,e,"muigui-checkbox"),this.add(new G(this)),this.updateDisplay()}}class R extends p{constructor(t,n){super(e(t,{className:n}))}}class Y extends S{#D;constructor(){super("muigui-canvas"),this.#D=this.add(new R("canvas","muigui-canvas")).domElement}get canvas(){return this.#D}}const W=(t,e,n)=>Math.max(e,Math.min(n,t)),q=t=>+t.toFixed(3),_=t=>parseInt(t.substring(1,3),16)<<16|parseInt(t.substring(3,5),16)<<8|parseInt(t.substring(5,7),16),J=t=>[parseInt(t.substring(1,3),16),parseInt(t.substring(3,5),16),parseInt(t.substring(5,7),16)],K=t=>`#${Array.from(t).map((t=>t.toString(16).padStart(2,"0"))).join("")}`,X=t=>J(t).map((t=>q(t/255))),Z=t=>K(Array.from(t).map((t=>Math.round(W(255*t,0,255))))),Q=t=>({r:parseInt(t.substring(1,3),16)/255,g:parseInt(t.substring(3,5),16)/255,b:parseInt(t.substring(5,7),16)/255}),tt=t=>W(Math.round(255*t),0,255).toString(16).padStart(2,"0"),et=t=>`rgb(${J(t).join(", ")})`,nt=/^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,it=t=>{const e=rt(J(t)).map((t=>(t=>+t.toFixed(0))(t)));return`hsl(${e[0]}, ${e[1]}%, ${e[2]}%)`},ot=/^\s*hsl\(\s*(\d+)(?:deg|)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)\s*$/,st=(t,e)=>(t%e+e)%e;const rt=t=>{const[e,n,i]=function([t,e,n]){const i=Math.max(t,e,n),o=Math.min(t,e,n),s=.5*(o+i),r=i-o;let a=0,l=0;if(0!==r)switch(l=0===s||1===s?0:(i-s)/Math.min(s,1-s),i){case t:a=(e-n)/r+(et/255)));return[360*e,100*n,100*i]};function at([t,e,n]){return e=W(e,0,1),n=W(n,0,1),[t,t+2/3,t+1/3].map((t=>{return i=1,o=W(Math.abs(6*(t=>t>=0?t%1:1-t%1)(t)-3)-1,0,1),(i+(o-i)*e)*n;var i,o}))}const lt=t=>Math.round(1e3*t)/1e3;function ut([t,e,n]){const i=n>e?[n,e,-1,2/3]:[e,n,0,-1/3],o=i[0]>t?[i[0],i[1],i[3],t]:[t,i[1],i[2],i[0]],s=o[0]-Math.min(o[3],o[1]);return[Math.abs(o[2]+(o[3]-o[1])/(6*s+Number.EPSILON)),s/(o[0]+Number.EPSILON),o[0]].map(lt)}window.hsv01ToRGBFloat=at,window.rgbFloatToHSV01=ut;const ct=[{re:/^#(?:[0-9a-f]){6}$/i,format:"hex6"},{re:/^(?:[0-9a-f]){6}$/i,format:"hex6-no-hash"},{re:/^#(?:[0-9a-f]){3}$/i,format:"hex3"},{re:/^(?:[0-9a-f]){3}$/i,format:"hex3-no-hash"},{re:nt,format:"css-rgb"},{re:ot,format:"css-hsl"}];function ht(t){switch(typeof t){case"number":return"uint32-rgb";case"string":{const e=function(t){for(const e of ct)if(e.re.test(t))return e}(t.trim());if(e)return e.format;break}case"object":if(t instanceof Uint8Array||t instanceof Uint8ClampedArray){if(3===t.length)return"uint8-rgb"}else if(t instanceof Float32Array){if(3===t.length)return"float-rgb"}else if(Array.isArray(t)){if(3===t.length)return"float-rgb"}else if("r"in t&&"g"in t&&"b"in t)return"object-rgb"}throw new Error(`unknown color format: ${t}`)}function dt(t){return t.trim(t)}function pt(t){return t[1]===t[2]&&t[3]===t[4]&&t[5]===t[6]?`#${t[1]}${t[3]}${t[5]}`:t}const mt=/^(#|)([0-9a-f]{3})$/i;function gt(t){const e=mt.exec(t);if(e){const[,,t]=e;return"#"+`${(n=t)[0]}${n[0]}${n[1]}${n[1]}${n[2]}${n[2]}`}var n;return t}function ft(t){return pt(dt(t))}const bt=t=>{const e=nt.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),`rgb(${n.join(", ")})`]},vt=t=>{const e=ot.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseFloat(t)));return[!n.find((t=>Number.isNaN(t))),`hsl(${n[0]}, ${n[1]}%, ${n[2]}%)`]},xt=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$/,wt=/^\s*(?:0x){0,1}([0-9a-z]{1,6})\s*$/i,yt=/^\s*#[a-f0-9]{6}\s*$|^\s*#[a-f0-9]{3}\s*$/i,kt=/^\s*[a-f0-9]{6}\s*$/i,Et={hex6:{color:{from:t=>[!0,t],to:dt},text:{from:t=>[yt.test(t),t.trim()],to:t=>t}},hex3:{color:{from:t=>[!0,ft(t)],to:gt},text:{from:t=>[yt.test(t),pt(t.trim())],to:t=>t}},"hex6-no-hash":{color:{from:t=>[!0,t.substring(1)],to:t=>`#${dt(t)}`},text:{from:t=>[kt.test(t),t.trim()],to:t=>t}},"hex3-no-hash":{color:{from:t=>[!0,ft(t).substring(1)],to:gt},text:{from:t=>[kt.test(t),pt(t.trim())],to:t=>t}},"uint32-rgb":{color:{from:t=>[!0,_(t)],to:t=>`#${Math.round(t).toString(16).padStart(6,"0")}`},text:{from:t=>(t=>{const e=wt.exec(t);return e?[!0,parseInt(e[1],16)]:[!1]})(t),to:t=>`0x${t.toString(16).padStart(6,"0")}`}},"uint8-rgb":{color:{from:t=>[!0,J(t)],to:K},text:{from:t=>{const e=xt.exec(t);if(!e)return[!1];const n=[e[1],e[2],e[3]].map((t=>parseInt(t)));return[!n.find((t=>t>255)),n]},to:t=>t.join(", ")}},"float-rgb":{color:{from:t=>[!0,X(t)],to:Z},text:{from:t=>{const e=t.split(",").map((t=>t.trim())),n=e.map((t=>parseFloat(t)));if(3!==n.length)return[!1];const i=e.findIndex((t=>isNaN(t)));return[i<0,n.map((t=>q(t)))]},to:t=>Array.from(t).map((t=>q(t))).join(", ")}},"object-rgb":{color:{from:t=>[!0,Q(t)],to:t=>`#${tt(t.r)}${tt(t.g)}${tt(t.b)}`},text:{from:t=>{try{const e=t.replace(/([a-z])/g,'"$1"'),n=JSON.parse(e);if(Number.isNaN(n.r)||Number.isNaN(n.g)||Number.isNaN(n.b))throw new Error("not {r, g, b}");return[!0,n]}catch(t){return[!1]}},to:t=>`{r:${q(t.r)}, g:${q(t.g)}, b:${q(t.b)}}`}},"css-rgb":{color:{from:t=>[!0,et(t)],to:t=>{const e=nt.exec(t);return K([e[1],e[2],e[3]].map((t=>parseInt(t))))}},text:{from:bt,to:t=>bt(t)[1]}},"css-hsl":{color:{from:t=>[!0,it(t)],to:t=>{const e=ot.exec(t),n=function([t,e,n]){t=st(t,360),e=W(e/100,0,1),n=W(n/100,0,1);const i=e*Math.min(n,1-n);function o(e){const o=(e+t/30)%12;return n-i*Math.max(-1,Math.min(o-3,9-o,1))}return[o(0),o(8),o(4)].map((t=>Math.round(255*t)))}([e[1],e[2],e[3]].map((t=>parseFloat(t))));return K(n)}},text:{from:vt,to:t=>vt(t)[1]}}};class $t extends b{#E;#$;#F;#M;#u={converters:F};constructor(t,n){const i=e("input",{type:"color",onInput:()=>{const[e,n]=this.#$(i.value);e&&(this.#M=!0,t.setValue(n))},onChange:()=>{const[e,n]=this.#$(i.value);e&&(this.#M=!0,t.setFinalValue(n))}});super(e("div",{},[i])),this.setOptions(n),this.#F=i}updateDisplay(t){this.#M||(this.#F.value=this.#E(t)),this.#M=!1}setOptions(t){a(this.#u,t);const{converters:{to:e,from:n}}=this.#u;return this.#E=e,this.#$=n,this}}class Ct extends I{#L;#S;constructor(t,e,n={}){super(t,e,"muigui-color");const i=n.format||ht(this.getValue()),{color:o,text:s}=Et[i];this.#L=this.add(new $t(this,{converters:o})),this.#S=this.add(new G(this,{converters:s})),this.updateDisplay()}setOptions(t){const{format:e}=t;if(e){const{color:t,text:n}=Et[e];this.#L.setOptions({converters:t}),this.#S.setOptions({converters:n})}return super.setOptions(t),this}}class Mt extends m{constructor(){super("muigui-divider")}}class Vt extends m{#N;#A;constructor(t){super(t),this.#N=[],this.#A=this}get children(){return this.#N}get controllers(){return this.#N.filter((t=>!(t instanceof Vt)))}get folders(){return this.#N.filter((t=>t instanceof Vt))}reset(t=!0){for(const e of this.#N)e instanceof Vt&&!t||e.reset(t);return this}remove(t){const e=this.#N.indexOf(t);if(e>=0){const t=this.#N.splice(e,1)[0];t.domElement.remove(),t.setParent(null)}return this}_addControllerImpl(t){return this.domElement.appendChild(t.domElement),this.#N.push(t),t.setParent(this),t}addController(t){return this.#A._addControllerImpl(t)}pushContainer(t){return this.addController(t),this.#A=t,t}popContainer(){return this.#A=this.#A.parent,this}}class St extends Vt{#U;constructor(t="Controls",n="muigui-menu"){super(n),this.#U=e("label"),this.addElem(e("button",{type:"button",onClick:()=>this.toggleOpen()},[this.#U])),this.pushContainer(new Vt),this.name(t),this.open()}open(t=!0){return this.domElement.classList.toggle("muigui-closed",!t),this.domElement.classList.toggle("muigui-open",t),this}close(){return this.open(!1)}name(t){return this.#U.textContent=t,this}title(t){return this.name(t)}toggleOpen(){return this.open(!this.domElement.classList.contains("muigui-open")),this}}class It extends m{constructor(t){super("muigui-label"),this.text(t)}text(t){return this.domElement.textContent=t,this}}class Dt extends St{add(t,e,...n){const i=t instanceof m?t:function(t,e,...n){const[i]=n;if(Array.isArray(i))return new P(t,e,{keyValues:i});const o=typeof t[e];switch(o){case"number":if("number"==typeof n[0]&&"number"==typeof n[1]){const i=n[0],o=n[1],s=n[2];return new B(t,e,{min:i,max:o,...s&&{step:s}})}return 0===n.length?new O(t,e,...n):new B(t,e,...n);case"boolean":return new D(t,e,...n);case"function":return new g(t,e,...n);case"string":return new H(t,e,...n);case"undefined":throw new Error(`no property named ${e}`);default:throw new Error(`unhandled type ${o} for property ${e}`)}}(t,e,...n);return this.addController(i)}addCanvas(t){return this.addController(new Y(t))}addColor(t,e,...n){return this.addController(new Ct(t,e,...n))}addDivider(){return this.addController(new Mt)}addFolder(t){return this.addController(new Dt(t))}addLabel(t){return this.addController(new It(t))}}class Ft extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"})}}customElements.define("muigui-element",Ft);const Lt=new CSSStyleSheet;Lt.replaceSync(t.default);const Nt=new CSSStyleSheet;function At(t){let e,n;function i(){if(e&&!n){const o=e;e=void 0,n=t.replace(o).then((()=>{console.log(o),n=void 0,i()}))}}return function(t){e=t,i()}}const Ut=At(Lt),Ot=At(Nt);class jt extends Dt{static converters=N;static mapRange=l;static makeRangeConverters=u;static makeRangeOptions=c;static makeMinMaxPair=d;#O=new CSSStyleSheet;constructor(t={}){super("Controls","muigui-root"),t instanceof HTMLElement&&(t={parent:t});const{autoPlace:n=!0,width:i,title:o="Controls"}=t;let{parent:s}=t;if(i&&(this.domElement.style.width=/^\d+$/.test(i)?`${i}px`:i),void 0===s&&n&&(s=document.body,this.domElement.classList.add("muigui-auto-place")),s){const t=e("muigui-element");t.shadowRoot.adoptedStyleSheets=[Lt,Nt,this.#O],t.shadow.appendChild(this.domElement),s.appendChild(t)}o&&this.title(o),this.domElement.classList.add("muigui","muigui-colors")}setStyle(t){this.#O.replace(t)}static setBaseStyles(t){Ut(t)}static getBaseStyleSheet(){return Lt}static setUserStyles(t){Ot(t)}static getUserStyleSheet(){return Nt}static setTheme(e){jt.setBaseStyles(`${t.default}\n${t.themes[e]||""}`)}}function Tt(){}function Pt(t,e,n){const i=t.getBoundingClientRect(),o=e.clientX-i.left,s=e.clientY-i.top,r=o/i.width,a=s/i.height,l=o-(n=n||[o,s])[0],u=s-n[1];return{x:o,y:s,nx:r,ny:a,dx:l,dy:u,ndx:l/i.width,ndy:u/i.width}}function zt(t,{onDown:e=Tt,onMove:n=Tt,onUp:i=Tt}){let o;const s=function(e){const i={type:"move",...Pt(t,e,o)};n(i)},r=function(e){t.releasePointerCapture(e.pointerId),t.removeEventListener("pointermove",s),t.removeEventListener("pointerup",r),document.body.style.backgroundColor="",i("up")},a=function(n){t.addEventListener("pointermove",s),t.addEventListener("pointerup",r),t.setPointerCapture(n.pointerId);const i=Pt(t,n);o=[i.x,i.y],e({type:"down",...i})};return t.addEventListener("pointerdown",a),function(){t.removeEventListener("pointerdown",a)}}class Bt extends b{#j;#T;#P;#z;#B;#G;#H;#R;constructor(t){super(e("div",{innerHTML:'\n\n\n \n \n \n \n \n \n \n \n\n \n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n',className:"muigui-no-scroll"})),this.#j=this.domElement.children[0],this.#T=this.domElement.children[1],this.#P=this.$(".muigui-color-chooser-circle"),this.#z=this.$("#muigui-color-chooser-hue"),this.#B=this.$(".muigui-color-chooser-cursor");const n=e=>{const n=i(e.nx,0,1),o=i(e.ny,0,1);this.#G[1]=n,this.#G[2]=1-o,this.#H=!0,t.setValue(Z(at(this.#G)))},o=e=>{const n=i(e.nx,0,1);this.#G[0]=n,this.#R=!0,t.setValue(Z(at(this.#G)))};zt(this.#j,{onDown:n,onMove:n}),zt(this.#T,{onDown:o,onMove:o})}updateDisplay(t){this.#G||(this.#G=ut(X(t)));{const[e,n,i]=ut(X(t));this.#H||(this.#G[0]=n>.001&&i>.001?e:this.#G[0]),this.#R||(this.#G[1]=n,this.#G[2]=i)}{const[t,e,n]=this.#G;this.#H||(this.#B.setAttribute("transform",`translate(${64*t}, 0)`),this.#z.children[0].setAttribute("stop-color",`hsl(${360*t}, 0%, 100%)`),this.#z.children[1].setAttribute("stop-color",`hsl(${360*t}, 100%, 50%)`)),this.#R||(this.#P.setAttribute("cx",""+64*e),this.#P.setAttribute("cy",""+48*(1-n)))}this.#H=!1,this.#R=!1}}class Gt extends I{#Y;#W;#q;#u={open:!1};constructor(t,n,i={}){super(t,n,"muigui-pop-down-controller"),this.#Y=this.add(new R("div","muigui-pop-down-top"));const o=this.#Y.addElem(e("input",{type:"checkbox",onChange:()=>{this.#u.open=o.checked}}));this.#W=this.#Y.add(new R("div","muigui-pop-down-values")),this.#q=this.add(new R("div","muigui-pop-down-bottom")),this.setOptions(i)}updateDisplay(){super.updateDisplay();const{open:t}=this.#u;this.domElement.children[1].classList.toggle("muigui-open",t),this.domElement.children[1].classList.toggle("muigui-closed",!t)}setOptions(t){a(this.#u,t),super.setOptions(t),this.updateDisplay()}addTop(t){return this.#W.add(t)}addBottom(t){return this.#q.add(t)}}class Ht extends Gt{constructor(t,e){super(t,e,"muigui-color-chooser"),this.addTop(new G(this)),this.addBottom(new Bt(this)),this.updateDisplay()}}function Rt(){}const Yt={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]};function Wt(t,{onDown:e=Rt,onUp:n=Rt}){const i=function(t){const i=t.shiftKey?10:1,[o,s]=(Yt[t.key]||[0,0]).map((t=>t*i));("keydown"===t.type?e:n)({type:t.type.substring(3),dx:o,dy:s,event:t})};return t.addEventListener("keydown",i),t.addEventListener("keyup",i),function(){t.removeEventListener("keydown",i),t.removeEventListener("keyup",i)}}function qt(t,e=""){if(!t)throw new Error(e)}function _t(t,e,n,i,o,s){const r=Math.abs(n)*Math.cos(s),a=Math.abs(i)*Math.sin(s);return[t+Math.cos(o)*r-Math.sin(o)*a,e+Math.sin(o)*r+Math.cos(o)*a]}function Jt(t,e,n,i,o){qt(Math.abs(i-o)<=2*Math.PI),qt(i>=-Math.PI&&i<=2*Math.PI),qt(i<=o),qt(o>=-Math.PI&&o<=4*Math.PI);const{x1:s,y1:r,x2:a,y2:l,fa:u,fs:c}=function(t,e,n,i,o,s,r){const[a,l]=_t(t,e,n,i,o,s),[u,c]=_t(t,e,n,i,o,s+r);return{x1:a,y1:l,x2:u,y2:c,fa:Math.abs(r)>Math.PI?1:0,fs:r>0?1:0}}(t,e,n,n,0,i,o-i);return Math.abs(Math.abs(i-o)-2*Math.PI)>Number.EPSILON?`M${t} ${e} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l} L${t} ${e}`:`M${s} ${r} L${s} ${r} A ${n} ${n} 0 ${u} ${c} ${a} ${l}`}const Kt=t=>r(t+Math.PI,2*Math.PI)-Math.PI;class Xt extends b{#_;#J;#K;#X;#u={step:1,min:-180,max:180,dirMin:-Math.PI,dirMax:Math.PI,wrap:void 0,converters:F};constructor(t,n={}){const o=A();super(e("div",{className:"muigui-direction muigui-no-scroll",innerHTML:'\n\n \x3c!----\x3e\n \n \n \n \n \n \n\n',onWheel:e=>{e.preventDefault();const{min:n,max:a,step:l}=this.#u,u=o(e,l);let c=this.#K+u;this.#X&&(c=r(c-n,a-n)+n);const h=i(s(c,(t=>t),l),n,a);t.setValue(h)}}));const a=e=>{const{min:n,max:o,step:r,dirMin:a,dirMax:l}=this.#u,u=2*e.nx-1,c=2*e.ny-1,h=Math.atan2(c,u),d=(a+l)/2,p=i((Kt(h-d)-Kt(a-d))/(l-a),0,1),m=s(n+(o-n)*p,(t=>t),r);t.setValue(m)};zt(this.domElement,{onDown:a,onMove:a}),Wt(this.domElement,{onDown:e=>{const{min:n,max:o,step:r}=this.#u,a=i(s(this.#K+e.dx*r,(t=>t),r),n,o);t.setValue(a)}}),this.#_=this.$("#muigui-arrow"),this.#J=this.$("#muigui-range"),this.setOptions(n)}updateDisplay(t){this.#K=t;const{min:e,max:n}=this.#u,i=(t-e)/(n-e),o=(s=this.#u.dirMin,r=this.#u.dirMax,s+(r-s)*i);var s,r;this.#_.style.transform=`rotate(${o}rad)`}setOptions(t){a(this.#u,t);const{dirMin:e,dirMax:n,wrap:i}=this.#u;this.#X=void 0!==i?i:Math.abs(e-n)>=2*Math.PI-Number.EPSILON;const[o,s]=e(o.push(i),e("label",{},[e("input",{type:"radio",name:s,value:a,onChange:function(){this.checked&&t.setFinalValue(r.#I[this.value])}}),e("button",{type:"button",textContent:n,onClick:function(){this.previousElementSibling.click()}})]))))));const r=this;this.#I=o,this.cols(i)}updateDisplay(t){const e=this.#I.indexOf(t);for(let t=0;t{e({rect:t.getBoundingClientRect(),elem:t})})).observe(t)}function ne(t,e,n,i){ee(t,(({rect:o})=>{const{width:s,height:r}=o;t.setAttribute("viewBox",`-${s*e} -${r*n} ${s} ${r}`),i({elem:t,rect:o})}))}function ie(t,e,n,i,o,r){const a=[];tt),n)),e=Math.min(e,o);for(let i=t;i<=e;i+=n)a.push(`M${i} 0 l0 ${r}`);return a.join(" ")}class oe extends b{#Z;#Q;#tt;#et;#nt;#it;#ot;#st;#rt;#K;#at;#u={min:-100,max:100,step:1,unit:10,unitSize:10,ticksPerUnit:5,labelFn:t=>t,tickHeight:1,limits:!0,thicksColor:void 0,orientation:void 0};constructor(t,n){const o=A();let r;super(e("div",{innerHTML:'\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \x3c!----\x3e\n \x3c!----\x3e\n \n \n \n \n\n',className:"muigui-no-v-scroll",onWheel:e=>{e.preventDefault();const{min:n,max:r,step:a}=this.#u,l=o(e,a),u=i(s(this.#K+l,(t=>t),a),n,r);t.setValue(u)}})),this.#Z=this.$("svg"),this.#Q=this.$("#muigui-origin"),this.#tt=this.$("#muigui-ticks"),this.#et=this.$("#muigui-thicks"),this.#nt=this.$("#muigui-numbers"),this.#it=this.$("#muigui-left-grad"),this.#ot=this.$("#muigui-right-grad"),this.setOptions(n),zt(this.domElement,{onDown:()=>{r=this.#K},onMove:e=>{const{min:n,max:o,unitSize:a,unit:l,step:u}=this.#u,c=i(s(r-e.dx/a*l,(t=>t),u),n,o);t.setValue(c)}}),Wt(this.domElement,{onDown:e=>{const{min:n,max:o,step:r}=this.#u,a=i(s(this.#K+e.dx*r,(t=>t),r),n,o);t.setValue(a)}}),ne(this.#Z,.5,0,(({rect:{width:t}})=>{this.#it.setAttribute("x",-t/2),this.#ot.setAttribute("x",t/2-20),this.#at=function(t){const e=t.innerHTML;t.innerHTML="- ";const n=t.querySelector("text").getComputedTextLength();return t.innerHTML=e,n}(this.#nt),this.#st=t,this.#lt()}))}#lt(){if(!this.#st||void 0===this.#K)return;const{labelFn:t,limits:e,min:n,max:i,orientation:o,tickHeight:r,ticksPerUnit:a,unit:l,unitSize:u,thicksColor:c}=this.#u,h=Math.ceil(this.#st/u),d=this.#K/l,p=Math.round(d-h),m=p*u,g=(p+2*h)*u,f=e?n*u/l:m,b=e?i*u/l:g,v=""===t(1)?10:5;a>1&&this.#tt.setAttribute("d",ie(m,g,u/a,f,b,v*r)),this.#et.style.stroke=c,this.#et.setAttribute("d",ie(m,g,u,f,b,v)),this.#nt.innerHTML=function(t,e,n,i,o,r,a,l){const u=[];tt),n)),e=Math.min(e,a);const c=Math.max(0,-Math.log10(i));for(let s=t;s<=e;s+=n)u.push(`${h=s/n*i,l(h.toFixed(c))}`);var h;return u.join("\n")}(m,g,u,l,this.#at,f,b,t),this.#Q.setAttribute("transform",`translate(${-this.#K*u/l} 0)`),this.#Z.classList.toggle("muigui-slider-up","up"===o)}updateDisplay(t){this.#K=t,this.#lt()}setOptions(t){return a(this.#u,t),this}}class se extends I{constructor(t,e,n={}){super(t,e,"muigui-slider"),this.add(new oe(this,n)),this.add(new U(this,n)),this.updateDisplay()}}class re extends b{#Z;#_;#P;#K=[];constructor(t){super(e("div",{innerHTML:'\n\n \n \n \n \n \n\n',className:"muigui-no-scroll"}));const n=e=>{const{width:n,height:i}=this.#Z.getBoundingClientRect(),o=2*e.nx-1,s=2*e.ny-1;t.setValue([o*n*.5,s*i*.5])};zt(this.domElement,{onDown:n,onMove:n}),this.#Z=this.$("svg"),this.#_=this.$("#muigui-arrow"),this.#P=this.$("#muigui-circle"),ne(this.#Z,.5,.5,(()=>this.#ut))}#ut(){const[t,e]=this.#K;this.#_.setAttribute("d",`M0,0L${t},${e}`),this.#P.setAttribute("transform",`translate(${t}, ${e})`)}updateDisplay(t){this.#K[0]=t[0],this.#K[1]=t[1],this.#ut()}}class ae extends Gt{constructor(t,e){super(t,e,"muigui-vec2");const n=t=>({setValue:e=>{const n=this.getValue();n[t]=e,this.setValue(n)},setFinalValue:e=>{const n=this.getValue();n[t]=e,this.setFinalValue(n)}});this.addTop(new U(n(0),{converters:{to:t=>t[0],from:L.from}})),this.addTop(new U(n(1),{converters:{to:t=>t[1],from:L.from}})),this.addBottom(new re(this)),this.updateDisplay()}}export{Ht as ColorChooser,Zt as Direction,te as RadioGrid,B as Range,P as Select,se as Slider,O as TextNumber,ae as Vec2,jt as default}; diff --git a/examples/js/index.js b/examples/js/index.js index 8f7678e..a1e1bc9 100644 --- a/examples/js/index.js +++ b/examples/js/index.js @@ -739,17 +739,22 @@ if (showUI) { // --------------- [ make a GUI for each CSS variable that affects GUI ] ----------------- const obj = {}; - for (const {name: key, rule} of varNames) { - const value = rule.style.getPropertyValue(key).trim(); - if (value.startsWith('#')) { - obj[key] = cssStringToHexColor(value); - controllersByKey[key] = folder.addColor(obj, key).onChange(updateStyles); - } else if (!value.startsWith('var')){ - obj[key] = value; - controllersByKey[key] = folder.add(obj, key).onChange(v => { - const fn = fns[key]; - if (fn) { - fn(v); + const folder = gui.addFolder('Style'); + for (const {vars} of varNamesBySelector) { + for (const {key, rule} of vars) { + const value = rule.style.getPropertyValue(key).trim(); + if (looksLikeCSSColor(value)) { + obj[key] = cssStringToHexColor(value); + controllersByKey[key] = folder.addColor(obj, key).onChange(updateMuiguiCSSStyles); + } else if (!value.startsWith('var')){ + obj[key] = value; + controllersByKey[key] = folder.add(obj, key).onChange(v => { + const fn = fns[key]; + if (fn) { + fn(v); + } + updateMuiguiCSSStyles(); + }); } } } diff --git a/src/muigui.js b/src/muigui.js index 27b7d39..c82a546 100644 --- a/src/muigui.js +++ b/src/muigui.js @@ -63,7 +63,7 @@ class MuiguiElement extends HTMLElement { customElements.define('muigui-element', MuiguiElement); const baseStyleSheet = new CSSStyleSheet(); -baseStyleSheet.replaceSync(css); +baseStyleSheet.replaceSync(css.default); const userStyleSheet = new CSSStyleSheet(); function makeStyleSheetUpdater(styleSheet) { @@ -146,6 +146,9 @@ export class GUI extends GUIFolder { static getUserStyleSheet() { return userStyleSheet; } + static setTheme(name) { + GUI.setBaseStyles(`${css.default}\n${css.themes[name] || ''}`); + } } export default GUI; diff --git a/src/styles/muigui.css.js b/src/styles/muigui.css.js index 9fb8958..b54e552 100644 --- a/src/styles/muigui.css.js +++ b/src/styles/muigui.css.js @@ -1,7 +1,9 @@ -export default ` +export default { + default: ` .muigui { --bg-color: #ddd; --color: #222; + --contrast-color: #eee; --value-color: #145 ; --value-bg-color: #eeee; --disabled-color: #999; @@ -27,6 +29,7 @@ export default ` .muigui { --bg-color: #222222; --color: #dddddd; + --contrast-color: #000; --value-color: #43e5f7; --value-bg-color: #444444; --disabled-color: #666666; @@ -678,5 +681,64 @@ export default ` z-index: 100001; } -`; +`, +themes: { + default: '', + float: ` + :root { + color-scheme: light dark, + } + .muigui { + --width: 400px; + --bg-color: initial; + --label-width: 25%; + } + + input, + .muigui-label-controller>label { + text-shadow: + -1px -1px 0 var(--contrast-color), + 1px -1px 0 var(--contrast-color), + -1px 1px 0 var(--contrast-color), + 1px 1px 0 var(--contrast-color); + } + + .muigui-controller > label:nth-child(1) { + place-content: center end; + margin-right: 1em; + } + + .muigui-value > :nth-child(2) { + margin-left: 1em; + } + + .muigui-root>*:nth-child(1) { + display: none; + } + + .muigui-range input[type=range]::-webkit-slider-thumb { + border-radius: 1em; + } + + .muigui-range input[type=range]::-webkit-slider-runnable-track { + -webkit-appearance: initial; + appearance: none; + border: 1px solid rgba(0, 0, 0, 0.25); + height: 2px; + } + + .muigui-colors { + --value-color: var(--color ); + --value-bg-color: rgba(0, 0, 0, 0.1); + --disabled-color: #cccccc; + --menu-bg-color: rgba(0, 0, 0, 0.1); + --menu-sep-color: #bbbbbb; + --hover-bg-color: rgba(0, 0, 0, 0); + --invalid-color: #FF0000; + --selected-color: rgba(0, 0, 0, 0.3); + --range-color: rgba(0, 0, 0, 0.125); + } +`, +}, +};