kempo-ui 0.0.34 → 0.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,21 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";export default class ColorPicker extends ShadowComponent{static formAssociated=!0;static properties={name:{type:String,reflect:!0,attribute:"name"},format:{type:String,reflect:!0,attribute:"format"},value:{type:String,reflect:!0,attribute:"value"},red:{type:Number},green:{type:Number},blue:{type:Number},alpha:{type:Number}};constructor(){super(),this.internals=this.attachInternals(),this.format="hex",this.red=0,this.green=0,this.blue=0,this.alpha=1}connectedCallback(){super.connectedCallback(),this.originalHadFormat=this.hasAttribute("format"),this.originalValue=this.getAttribute("value")}firstUpdated(t){if(super.firstUpdated(t),this.originalValue&&!this.originalHadFormat)for(const[t,a]of Object.entries(this.constructor.formats))if(a.detect(this.originalValue)){this.format=t;break}}updated(t){super.updated(t),t.has("format")&&this.requestUpdate(),(t.has("red")||t.has("green")||t.has("blue")||t.has("alpha")||t.has("format"))&&this.updateFormValue()}get value(){if(void 0===this.red||void 0===this.green||void 0===this.blue){const t=this.constructor.formats[this.format];return t&&t.toString?t.toString(0,0,0,1):"#000000"}const t=this.constructor.formats[this.format];return t&&t.toString?t.toString(this.red,this.green,this.blue,this.alpha||1):"#000000"}set value(t){if(t&&"string"==typeof t){for(const[a,s]of Object.entries(this.constructor.formats))if(s.detect(t)){const a=s.parse(t);if(a)return this.red=a.r,this.green=a.g,this.blue=a.b,a.hasAlpha&&(this.alpha=a.a),void this.updateFormValue()}this.red=0,this.green=0,this.blue=0,this.alpha=1,this.updateFormValue()}}updateFormValue(){const t=this.value;this.internals.setFormValue(t)}onColorInputChange(t){const a=this.constructor.formats.hex.parse(t.target.value);a&&(this.red=a.r,this.green=a.g,this.blue=a.b,this.alpha=1)}onTextInputChange(t){this.value=t.target.value}render(){return html`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";export default class ColorPicker extends ShadowComponent{static formAssociated=!0;static properties={name:{type:String,reflect:!0,attribute:"name"},format:{type:String,reflect:!0,attribute:"format"},value:{type:String,reflect:!0,attribute:"value"},red:{type:Number},green:{type:Number},blue:{type:Number},alpha:{type:Number}};constructor(){super(),this.internals=this.attachInternals(),this.format="hex",this.red=0,this.green=0,this.blue=0,this.alpha=1}connectedCallback(){super.connectedCallback(),this.originalHadFormat=this.hasAttribute("format"),this.originalValue=this.getAttribute("value")}firstUpdated(t){if(super.firstUpdated(t),this.originalValue&&!this.originalHadFormat)for(const[t,a]of Object.entries(this.constructor.formats))if(a.detect(this.originalValue)){this.format=t;break}}updated(t){super.updated(t),t.has("format")&&this.requestUpdate(),(t.has("red")||t.has("green")||t.has("blue")||t.has("alpha")||t.has("format"))&&(this.updateFormValue(),this.syncInputs(t.has("format")))}syncInputs(t=!1){const a=this.shadowRoot?.querySelector("#text"),s=this.shadowRoot?.querySelector("#color"),r=this.shadowRoot?.querySelector("#format"),e=this.shadowRoot?.activeElement;a&&(t||e!==a)&&(a.value=this.value),s&&e!==s&&(s.value=this.constructor.formats.hex.toString(this.red||0,this.green||0,this.blue||0,1)),r&&e!==r&&(r.value=this.format)}get value(){if(void 0===this.red||void 0===this.green||void 0===this.blue){const t=this.constructor.formats[this.format];return t&&t.toString?t.toString(0,0,0,1):"#000000"}const t=this.constructor.formats[this.format];return t&&t.toString?t.toString(this.red,this.green,this.blue,this.alpha||1):"#000000"}set value(t){if(t&&"string"==typeof t){for(const[a,s]of Object.entries(this.constructor.formats))if(s.detect(t)){const a=s.parse(t);if(a)return this.red=a.r,this.green=a.g,this.blue=a.b,a.hasAlpha&&(this.alpha=a.a),void this.updateFormValue()}this.red=0,this.green=0,this.blue=0,this.alpha=1,this.updateFormValue()}}updateFormValue(){const t=this.value;this.internals.setFormValue(t)}onColorInputChange(t){const a=this.constructor.formats.hex.parse(t.target.value);a&&(this.red=a.r,this.green=a.g,this.blue=a.b,this.alpha=1),this.forwardEvent(t)}onTextInputChange(t){this.value=t.target.value,this.forwardEvent(t)}onTextInput(t){this.value=t.target.value,this.forwardEvent(t)}onColorInput(t){const a=this.constructor.formats.hex.parse(t.target.value);a&&(this.red=a.r,this.green=a.g,this.blue=a.b,this.alpha=1),this.forwardEvent(t)}onFormatChange(t){this.format=t.target.value,this.forwardEvent(t)}onFormatInput(t){this.format=t.target.value,this.forwardEvent(t)}forwardEvent=t=>{this.dispatchEvent(new t.constructor(t.type,t))};render(){return html`
2
2
  <div id="container">
3
3
  <select
4
4
  id="format"
5
5
  value="${this.format}"
6
- @change=${t=>this.format=t.target.value}
6
+ @change=${this.onFormatChange}
7
+ @input=${this.onFormatInput}
8
+ @focus=${this.forwardEvent}
9
+ @blur=${this.forwardEvent}
7
10
  >${this.constructor.formats?Object.keys(this.constructor.formats).map(t=>html`<option value="${t}" ?selected=${this.format===t}>${t.toUpperCase()}</option>`):null}</select>
8
11
  <input
9
12
  id="text"
10
13
  type="text"
11
14
  value="${this.value}"
12
15
  @change=${this.onTextInputChange}
16
+ @input=${this.onTextInput}
17
+ @focus=${this.forwardEvent}
18
+ @blur=${this.forwardEvent}
13
19
  />
14
20
  <div id="color-wrapper">
15
21
  <input
@@ -17,6 +23,9 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
17
23
  type="color"
18
24
  value="${this.constructor.formats.hex.toString(this.red||0,this.green||0,this.blue||0,1)}"
19
25
  @change=${this.onColorInputChange}
26
+ @input=${this.onColorInput}
27
+ @focus=${this.forwardEvent}
28
+ @blur=${this.forwardEvent}
20
29
  />
21
30
  </div>
22
31
  </div>
@@ -42,4 +51,4 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
42
51
  aspect-ratio: 1;
43
52
  height: 100%;
44
53
  }
45
- `;static formats={hex:{detect:t=>/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/.test(t),parse:t=>{let a,s,e,r=t.slice(1),o=r.length,h=1,n=!1;return 3===o||4===o?(a=parseInt(r[0]+r[0],16),s=parseInt(r[1]+r[1],16),e=parseInt(r[2]+r[2],16),4===o&&(h=parseInt(r[3]+r[3],16)/255,n=!0)):6!==o&&8!==o||(a=parseInt(r.slice(0,2),16),s=parseInt(r.slice(2,4),16),e=parseInt(r.slice(4,6),16),8===o&&(h=parseInt(r.slice(6,8),16)/255,n=!0)),{r:a,g:s,b:e,a:h,hasAlpha:n}},toString:(t,a,s,e)=>{let r=((t=Math.round(t))<<16|(a=Math.round(a))<<8|(s=Math.round(s))).toString(16).padStart(6,"0");if(e<1){r+=Math.round(255*e).toString(16).padStart(2,"0")}return"#"+r}},rgb:{detect:t=>/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(?:,\s*(?:0?\.\d+|1(?:\.0*)?|\d+(?:\.\d*)?))?\s*\)$/.test(t),parse:t=>{const a=t.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)$/);if(!a)return null;return{r:parseInt(a[1],10),g:parseInt(a[2],10),b:parseInt(a[3],10),a:a[4]?parseFloat(a[4]):1,hasAlpha:!!a[4]}},toString:(t,a,s,e)=>(t=Math.round(t),a=Math.round(a),s=Math.round(s),e<1?`rgba(${t}, ${a}, ${s}, ${e})`:`rgb(${t}, ${a}, ${s})`)},hsl:{detect:t=>/^hsla?\(\s*\d+(?:\.\d+)?\s*,\s*\d+(?:\.\d+)?%\s*,\s*\d+(?:\.\d+)?%\s*(?:,\s*(?:0?\.\d+|1(?:\.0*)?|\d+(?:\.\d*)?))?\s*\)$/.test(t),parse:t=>{const a=t.match(/^hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*(?:,\s*([\d.]+))?\s*\)$/);if(!a)return null;let s=parseFloat(a[1])/360,e=parseFloat(a[2])/100,r=parseFloat(a[3])/100,o=a[4]?parseFloat(a[4]):1;const h=!!a[4];let n,d,i;if(0===e)n=d=i=r;else{const t=(t,a,s)=>(s<0&&(s+=1),s>1&&(s-=1),s<1/6?t+6*(a-t)*s:s<.5?a:s<2/3?t+(a-t)*(2/3-s)*6:t),a=r<.5?r*(1+e):r+e-r*e,o=2*r-a;n=t(o,a,s+1/3),d=t(o,a,s),i=t(o,a,s-1/3)}return{r:Math.round(255*n),g:Math.round(255*d),b:Math.round(255*i),a:o,hasAlpha:h}},toString:(t,a,s,e)=>{t/=255,a/=255,s/=255;const r=Math.max(t,a,s),o=Math.min(t,a,s);let h,n,d=(r+o)/2;if(r===o)h=n=0;else{const e=r-o;switch(n=d>.5?e/(2-r-o):e/(r+o),r){case t:h=(a-s)/e+(a<s?6:0);break;case a:h=(s-t)/e+2;break;case s:h=(t-a)/e+4}h/=6}return h=Math.round(360*h),n=Math.round(100*n),d=Math.round(100*d),e<1?`hsla(${h}, ${n}%, ${d}%, ${e})`:`hsl(${h}, ${n}%, ${d}%)`}},hwb:{detect:t=>/^hwb\(\s*(\d+(?:\.\d+)?)(?:deg)?\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^hwb\(\s*(\d+(?:\.\d+)?)(?:deg)?\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s,e,r,o=parseFloat(a[1]),h=parseFloat(a[2])/100,n=parseFloat(a[3])/100,d=a[4]?parseFloat(a[4]):1,i=1-h-n;if(i>0){let t=o/360,a=1-Math.abs(6*t%2-1),n=h+i*(1-a),d=h+i*a;t<1/6?(s=h+i,e=d,r=h):t<2/6?(s=n,e=h+i,r=h):t<.5?(s=h,e=h+i,r=d):t<4/6?(s=h,e=n,r=h+i):t<5/6?(s=d,e=h,r=h+i):(s=h+i,e=h,r=n)}else s=e=r=h;const l=!!a[4];return{r:Math.round(255*s),g:Math.round(255*e),b:Math.round(255*r),a:d,hasAlpha:l}},toString:(t,a,s,e)=>{t/=255,a/=255,s/=255;const r=Math.max(t,a,s),o=Math.min(t,a,s),h=r-o;let n=0;if(0!==h){switch(r){case t:n=(a-s)/h%6;break;case a:n=(s-t)/h+2;break;case s:n=(t-a)/h+4}n=Math.round(60*n),n<0&&(n+=360)}const d=Math.round(100*o),i=Math.round(100*(1-r));return e<1?`hwb(${n} ${d}% ${i}% / ${e})`:`hwb(${n} ${d}% ${i}%)`}},lab:{detect:t=>/^lab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^lab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1])/100,e=parseFloat(a[2]),r=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=(100*s+16)/116,n=h+e/500,d=h-r/200,i=.95047*(n>.206893034?n*n*n:(n-16/116)/7.787),l=1*(h>.206893034?h*h*h:(h-16/116)/7.787),p=1.08883*(d>.206893034?d*d*d:(d-16/116)/7.787),u=3.2404542*i-1.5371385*l-.4985314*p,c=-.969266*i+1.8760108*l+.041556*p,M=.0556434*i-.2040259*l+1.0572252*p,m=u<=.0031308?12.92*u:1.055*Math.pow(u,1/2.4)-.055,$=c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055,g=M<=.0031308?12.92*M:1.055*Math.pow(M,1/2.4)-.055;const f=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,m))),g:Math.round(255*Math.max(0,Math.min(1,$))),b:Math.round(255*Math.max(0,Math.min(1,g))),a:o,hasAlpha:f}},toString:(t,a,s,e)=>{a/=255,s/=255;const r=(.4124564*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.3575761*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.1804375*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)))/.95047,o=(.2126729*t+.7151522*a+.072175*s)/1,h=(.0193339*t+.119192*a+.9503041*s)/1.08883,n=r>.008856?Math.pow(r,1/3):7.787*r+16/116,d=o>.008856?Math.pow(o,1/3):7.787*o+16/116,i=h>.008856?Math.pow(h,1/3):7.787*h+16/116,l=Math.round(100*(116*d-16))/100,p=Math.round(500*(n-d)*100)/100,u=Math.round(200*(d-i)*100)/100;return e<1?`lab(${l}% ${p} ${u} / ${e})`:`lab(${l}% ${p} ${u})`}},lch:{detect:t=>/^lch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^lch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1]),e=parseFloat(a[2]),r=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=(100*(s/100)+16)/116,n=h+e*Math.cos(r*Math.PI/180)/500,d=h-e*Math.sin(r*Math.PI/180)/200,i=.95047*(n>.206893034?n*n*n:(n-16/116)/7.787),l=1*(h>.206893034?h*h*h:(h-16/116)/7.787),p=1.08883*(d>.206893034?d*d*d:(d-16/116)/7.787),u=3.2404542*i-1.5371385*l-.4985314*p,c=-.969266*i+1.8760108*l+.041556*p,M=.0556434*i-.2040259*l+1.0572252*p,m=u<=.0031308?12.92*u:1.055*Math.pow(u,1/2.4)-.055,$=c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055,g=M<=.0031308?12.92*M:1.055*Math.pow(M,1/2.4)-.055;const f=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,m))),g:Math.round(255*Math.max(0,Math.min(1,$))),b:Math.round(255*Math.max(0,Math.min(1,g))),a:o,hasAlpha:f}},toString:(t,a,s,e)=>{a/=255,s/=255;const r=(.4124564*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.3575761*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.1804375*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)))/.95047,o=(.2126729*t+.7151522*a+.072175*s)/1,h=(.0193339*t+.119192*a+.9503041*s)/1.08883,n=r>.008856?Math.pow(r,1/3):7.787*r+16/116,d=o>.008856?Math.pow(o,1/3):7.787*o+16/116,i=(116*d-16)/100,l=500*(n-d),p=200*(d-(h>.008856?Math.pow(h,1/3):7.787*h+16/116)),u=Math.sqrt(l*l+p*p);let c=180*Math.atan2(p,l)/Math.PI;c<0&&(c+=360);const M=Math.round(100*i*100)/100,m=Math.round(100*u)/100,$=Math.round(100*c)/100;return e<1?`lch(${M}% ${m} ${$} / ${e})`:`lch(${M}% ${m} ${$})`}},oklab:{detect:t=>/^oklab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^oklab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1])/100,e=parseFloat(a[2]),r=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=s+.3963377774*e+.2158037573*r,n=s-.1055613458*e-.0638541728*r,d=s-.0894841775*e-1.291485548*r,i=4.0767416621*h-3.3077115913*n+.2309699292*d,l=-1.2684380046*h+2.6097574011*n-.3413193965*d,p=-.0041960863*h-.7034186147*n+1.707614701*d,u=i<=.0031308?12.92*i:1.055*Math.pow(i,1/2.4)-.055,c=l<=.0031308?12.92*l:1.055*Math.pow(l,1/2.4)-.055,M=p<=.0031308?12.92*p:1.055*Math.pow(p,1/2.4)-.055;const m=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,u))),g:Math.round(255*Math.max(0,Math.min(1,c))),b:Math.round(255*Math.max(0,Math.min(1,M))),a:o,hasAlpha:m}},toString:(t,a,s,e)=>{a/=255,s/=255;const r=.4122214708*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.5363325363*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.0514459929*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)),o=.2119034982*t+.6806995451*a+.1073969566*s,h=.0883024619*t+.2817188376*a+.6299787005*s,n=Math.pow(r,1/3),d=Math.pow(o,1/3),i=Math.pow(h,1/3),l=.2104542553*n+.793617785*d-.0040720468*i,p=1.9779984951*n-2.428592205*d+.4505937099*i,u=.0259040371*n+.7827717662*d-.808675766*i,c=Math.round(100*l*100)/100,M=Math.round(100*p)/100,m=Math.round(100*u)/100;return e<1?`oklab(${c}% ${M} ${m} / ${e})`:`oklab(${c}% ${M} ${m})`}},oklch:{detect:t=>/^oklch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^oklch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1])/100,e=parseFloat(a[2]),r=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=e*Math.cos(r*Math.PI/180),n=e*Math.sin(r*Math.PI/180),d=s+.3963377774*h+.2158037573*n,i=s-.1055613458*h-.0638541728*n,l=s-.0894841775*h-1.291485548*n,p=4.0767416621*d-3.3077115913*i+.2309699292*l,u=-1.2684380046*d+2.6097574011*i-.3413193965*l,c=-.0041960863*d-.7034186147*i+1.707614701*l,M=p<=.0031308?12.92*p:1.055*Math.pow(p,1/2.4)-.055,m=u<=.0031308?12.92*u:1.055*Math.pow(u,1/2.4)-.055,$=c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055;const g=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,M))),g:Math.round(255*Math.max(0,Math.min(1,m))),b:Math.round(255*Math.max(0,Math.min(1,$))),a:o,hasAlpha:g}},toString:(t,a,s,e)=>{a/=255,s/=255;const r=.4122214708*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.5363325363*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.0514459929*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)),o=.2119034982*t+.6806995451*a+.1073969566*s,h=.0883024619*t+.2817188376*a+.6299787005*s,n=Math.pow(r,1/3),d=Math.pow(o,1/3),i=Math.pow(h,1/3),l=.2104542553*n+.793617785*d-.0040720468*i,p=1.9779984951*n-2.428592205*d+.4505937099*i,u=.0259040371*n+.7827717662*d-.808675766*i,c=Math.sqrt(p*p+u*u);let M=180*Math.atan2(u,p)/Math.PI;M<0&&(M+=360);const m=Math.round(100*l*100)/100,$=Math.round(100*c)/100,g=Math.round(100*M)/100;return e<1?`oklch(${m}% ${$} ${g} / ${e})`:`oklch(${m}% ${$} ${g})`}}}}window.customElements.define("k-color-picker",ColorPicker);
54
+ `;static formats={hex:{detect:t=>/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/.test(t),parse:t=>{let a,s,r,e=t.slice(1),o=e.length,h=1,n=!1;return 3===o||4===o?(a=parseInt(e[0]+e[0],16),s=parseInt(e[1]+e[1],16),r=parseInt(e[2]+e[2],16),4===o&&(h=parseInt(e[3]+e[3],16)/255,n=!0)):6!==o&&8!==o||(a=parseInt(e.slice(0,2),16),s=parseInt(e.slice(2,4),16),r=parseInt(e.slice(4,6),16),8===o&&(h=parseInt(e.slice(6,8),16)/255,n=!0)),{r:a,g:s,b:r,a:h,hasAlpha:n}},toString:(t,a,s,r)=>{let e=((t=Math.round(t))<<16|(a=Math.round(a))<<8|(s=Math.round(s))).toString(16).padStart(6,"0");if(r<1){e+=Math.round(255*r).toString(16).padStart(2,"0")}return"#"+e}},rgb:{detect:t=>/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(?:,\s*(?:0?\.\d+|1(?:\.0*)?|\d+(?:\.\d*)?))?\s*\)$/.test(t),parse:t=>{const a=t.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)$/);if(!a)return null;return{r:parseInt(a[1],10),g:parseInt(a[2],10),b:parseInt(a[3],10),a:a[4]?parseFloat(a[4]):1,hasAlpha:!!a[4]}},toString:(t,a,s,r)=>(t=Math.round(t),a=Math.round(a),s=Math.round(s),r<1?`rgba(${t}, ${a}, ${s}, ${r})`:`rgb(${t}, ${a}, ${s})`)},hsl:{detect:t=>/^hsla?\(\s*\d+(?:\.\d+)?\s*,\s*\d+(?:\.\d+)?%\s*,\s*\d+(?:\.\d+)?%\s*(?:,\s*(?:0?\.\d+|1(?:\.0*)?|\d+(?:\.\d*)?))?\s*\)$/.test(t),parse:t=>{const a=t.match(/^hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*(?:,\s*([\d.]+))?\s*\)$/);if(!a)return null;let s=parseFloat(a[1])/360,r=parseFloat(a[2])/100,e=parseFloat(a[3])/100,o=a[4]?parseFloat(a[4]):1;const h=!!a[4];let n,i,d;if(0===r)n=i=d=e;else{const t=(t,a,s)=>(s<0&&(s+=1),s>1&&(s-=1),s<1/6?t+6*(a-t)*s:s<.5?a:s<2/3?t+(a-t)*(2/3-s)*6:t),a=e<.5?e*(1+r):e+r-e*r,o=2*e-a;n=t(o,a,s+1/3),i=t(o,a,s),d=t(o,a,s-1/3)}return{r:Math.round(255*n),g:Math.round(255*i),b:Math.round(255*d),a:o,hasAlpha:h}},toString:(t,a,s,r)=>{t/=255,a/=255,s/=255;const e=Math.max(t,a,s),o=Math.min(t,a,s);let h,n,i=(e+o)/2;if(e===o)h=n=0;else{const r=e-o;switch(n=i>.5?r/(2-e-o):r/(e+o),e){case t:h=(a-s)/r+(a<s?6:0);break;case a:h=(s-t)/r+2;break;case s:h=(t-a)/r+4}h/=6}return h=Math.round(360*h),n=Math.round(100*n),i=Math.round(100*i),r<1?`hsla(${h}, ${n}%, ${i}%, ${r})`:`hsl(${h}, ${n}%, ${i}%)`}},hwb:{detect:t=>/^hwb\(\s*(\d+(?:\.\d+)?)(?:deg)?\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^hwb\(\s*(\d+(?:\.\d+)?)(?:deg)?\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s,r,e,o=parseFloat(a[1]),h=parseFloat(a[2])/100,n=parseFloat(a[3])/100,i=a[4]?parseFloat(a[4]):1,d=1-h-n;if(d>0){let t=o/360,a=1-Math.abs(6*t%2-1),n=h+d*(1-a),i=h+d*a;t<1/6?(s=h+d,r=i,e=h):t<2/6?(s=n,r=h+d,e=h):t<.5?(s=h,r=h+d,e=i):t<4/6?(s=h,r=n,e=h+d):t<5/6?(s=i,r=h,e=h+d):(s=h+d,r=h,e=n)}else s=r=e=h;const l=!!a[4];return{r:Math.round(255*s),g:Math.round(255*r),b:Math.round(255*e),a:i,hasAlpha:l}},toString:(t,a,s,r)=>{t/=255,a/=255,s/=255;const e=Math.max(t,a,s),o=Math.min(t,a,s),h=e-o;let n=0;if(0!==h){switch(e){case t:n=(a-s)/h%6;break;case a:n=(s-t)/h+2;break;case s:n=(t-a)/h+4}n=Math.round(60*n),n<0&&(n+=360)}const i=Math.round(100*o),d=Math.round(100*(1-e));return r<1?`hwb(${n} ${i}% ${d}% / ${r})`:`hwb(${n} ${i}% ${d}%)`}},lab:{detect:t=>/^lab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^lab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1])/100,r=parseFloat(a[2]),e=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=(100*s+16)/116,n=h+r/500,i=h-e/200,d=.95047*(n>.206893034?n*n*n:(n-16/116)/7.787),l=1*(h>.206893034?h*h*h:(h-16/116)/7.787),u=1.08883*(i>.206893034?i*i*i:(i-16/116)/7.787),p=3.2404542*d-1.5371385*l-.4985314*u,c=-.969266*d+1.8760108*l+.041556*u,M=.0556434*d-.2040259*l+1.0572252*u,m=p<=.0031308?12.92*p:1.055*Math.pow(p,1/2.4)-.055,f=c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055,$=M<=.0031308?12.92*M:1.055*Math.pow(M,1/2.4)-.055;const g=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,m))),g:Math.round(255*Math.max(0,Math.min(1,f))),b:Math.round(255*Math.max(0,Math.min(1,$))),a:o,hasAlpha:g}},toString:(t,a,s,r)=>{a/=255,s/=255;const e=(.4124564*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.3575761*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.1804375*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)))/.95047,o=(.2126729*t+.7151522*a+.072175*s)/1,h=(.0193339*t+.119192*a+.9503041*s)/1.08883,n=e>.008856?Math.pow(e,1/3):7.787*e+16/116,i=o>.008856?Math.pow(o,1/3):7.787*o+16/116,d=h>.008856?Math.pow(h,1/3):7.787*h+16/116,l=Math.round(100*(116*i-16))/100,u=Math.round(500*(n-i)*100)/100,p=Math.round(200*(i-d)*100)/100;return r<1?`lab(${l}% ${u} ${p} / ${r})`:`lab(${l}% ${u} ${p})`}},lch:{detect:t=>/^lch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^lch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1]),r=parseFloat(a[2]),e=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=(100*(s/100)+16)/116,n=h+r*Math.cos(e*Math.PI/180)/500,i=h-r*Math.sin(e*Math.PI/180)/200,d=.95047*(n>.206893034?n*n*n:(n-16/116)/7.787),l=1*(h>.206893034?h*h*h:(h-16/116)/7.787),u=1.08883*(i>.206893034?i*i*i:(i-16/116)/7.787),p=3.2404542*d-1.5371385*l-.4985314*u,c=-.969266*d+1.8760108*l+.041556*u,M=.0556434*d-.2040259*l+1.0572252*u,m=p<=.0031308?12.92*p:1.055*Math.pow(p,1/2.4)-.055,f=c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055,$=M<=.0031308?12.92*M:1.055*Math.pow(M,1/2.4)-.055;const g=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,m))),g:Math.round(255*Math.max(0,Math.min(1,f))),b:Math.round(255*Math.max(0,Math.min(1,$))),a:o,hasAlpha:g}},toString:(t,a,s,r)=>{a/=255,s/=255;const e=(.4124564*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.3575761*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.1804375*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)))/.95047,o=(.2126729*t+.7151522*a+.072175*s)/1,h=(.0193339*t+.119192*a+.9503041*s)/1.08883,n=e>.008856?Math.pow(e,1/3):7.787*e+16/116,i=o>.008856?Math.pow(o,1/3):7.787*o+16/116,d=(116*i-16)/100,l=500*(n-i),u=200*(i-(h>.008856?Math.pow(h,1/3):7.787*h+16/116)),p=Math.sqrt(l*l+u*u);let c=180*Math.atan2(u,l)/Math.PI;c<0&&(c+=360);const M=Math.round(100*d*100)/100,m=Math.round(100*p)/100,f=Math.round(100*c)/100;return r<1?`lch(${M}% ${m} ${f} / ${r})`:`lch(${M}% ${m} ${f})`}},oklab:{detect:t=>/^oklab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^oklab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1])/100,r=parseFloat(a[2]),e=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=s+.3963377774*r+.2158037573*e,n=s-.1055613458*r-.0638541728*e,i=s-.0894841775*r-1.291485548*e,d=4.0767416621*h-3.3077115913*n+.2309699292*i,l=-1.2684380046*h+2.6097574011*n-.3413193965*i,u=-.0041960863*h-.7034186147*n+1.707614701*i,p=d<=.0031308?12.92*d:1.055*Math.pow(d,1/2.4)-.055,c=l<=.0031308?12.92*l:1.055*Math.pow(l,1/2.4)-.055,M=u<=.0031308?12.92*u:1.055*Math.pow(u,1/2.4)-.055;const m=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,p))),g:Math.round(255*Math.max(0,Math.min(1,c))),b:Math.round(255*Math.max(0,Math.min(1,M))),a:o,hasAlpha:m}},toString:(t,a,s,r)=>{a/=255,s/=255;const e=.4122214708*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.5363325363*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.0514459929*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)),o=.2119034982*t+.6806995451*a+.1073969566*s,h=.0883024619*t+.2817188376*a+.6299787005*s,n=Math.pow(e,1/3),i=Math.pow(o,1/3),d=Math.pow(h,1/3),l=.2104542553*n+.793617785*i-.0040720468*d,u=1.9779984951*n-2.428592205*i+.4505937099*d,p=.0259040371*n+.7827717662*i-.808675766*d,c=Math.round(100*l*100)/100,M=Math.round(100*u)/100,m=Math.round(100*p)/100;return r<1?`oklab(${c}% ${M} ${m} / ${r})`:`oklab(${c}% ${M} ${m})`}},oklch:{detect:t=>/^oklch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(t),parse:t=>{const a=t.match(/^oklch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i);if(!a)return null;let s=parseFloat(a[1])/100,r=parseFloat(a[2]),e=parseFloat(a[3]),o=a[4]?parseFloat(a[4]):1,h=r*Math.cos(e*Math.PI/180),n=r*Math.sin(e*Math.PI/180),i=s+.3963377774*h+.2158037573*n,d=s-.1055613458*h-.0638541728*n,l=s-.0894841775*h-1.291485548*n,u=4.0767416621*i-3.3077115913*d+.2309699292*l,p=-1.2684380046*i+2.6097574011*d-.3413193965*l,c=-.0041960863*i-.7034186147*d+1.707614701*l,M=u<=.0031308?12.92*u:1.055*Math.pow(u,1/2.4)-.055,m=p<=.0031308?12.92*p:1.055*Math.pow(p,1/2.4)-.055,f=c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055;const $=!!a[4];return{r:Math.round(255*Math.max(0,Math.min(1,M))),g:Math.round(255*Math.max(0,Math.min(1,m))),b:Math.round(255*Math.max(0,Math.min(1,f))),a:o,hasAlpha:$}},toString:(t,a,s,r)=>{a/=255,s/=255;const e=.4122214708*(t=(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4))+.5363325363*(a=a<=.04045?a/12.92:Math.pow((a+.055)/1.055,2.4))+.0514459929*(s=s<=.04045?s/12.92:Math.pow((s+.055)/1.055,2.4)),o=.2119034982*t+.6806995451*a+.1073969566*s,h=.0883024619*t+.2817188376*a+.6299787005*s,n=Math.pow(e,1/3),i=Math.pow(o,1/3),d=Math.pow(h,1/3),l=.2104542553*n+.793617785*i-.0040720468*d,u=1.9779984951*n-2.428592205*i+.4505937099*d,p=.0259040371*n+.7827717662*i-.808675766*d,c=Math.sqrt(u*u+p*p);let M=180*Math.atan2(p,u)/Math.PI;M<0&&(M+=360);const m=Math.round(100*l*100)/100,f=Math.round(100*c)/100,$=Math.round(100*M)/100;return r<1?`oklch(${m}% ${f} ${$} / ${r})`:`oklch(${m}% ${f} ${$})`}}}}window.customElements.define("k-color-picker",ColorPicker);
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import"./Icon.js";export default class ThemeSwitcher extends ShadowComponent{static properties={currentTheme:{type:String,reflect:!0,attribute:"current-theme"}};constructor(){super(),this.currentTheme=ThemeSwitcher.getCurrentTheme()}handleClick=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")};handleStorageChange=e=>{"theme"===e.key&&(this.currentTheme=e.newValue||"auto",document.documentElement.setAttribute("theme",this.currentTheme))};connectedCallback(){super.connectedCallback(),window.addEventListener("storage",this.handleStorageChange)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("storage",this.handleStorageChange)}static styles=css`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import theme from"../utils/theme.js";import"./Icon.js";export default class ThemeSwitcher extends ShadowComponent{static properties={currentTheme:{type:String,reflect:!0,attribute:"current-theme"}};constructor(){super(),this.currentTheme=theme.get()}handleClick=()=>{const e=theme.get();"auto"===e&&theme.set("light"),"light"===e&&theme.set("dark"),"dark"===e&&theme.set("auto")};connectedCallback(){super.connectedCallback(),this.unsubscribe=theme.subscribe(e=>{this.currentTheme=e})}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribe&&this.unsubscribe()}static styles=css`
2
2
  :host {
3
3
  --padding: var(--spacer);
4
4
  display: flex;
@@ -20,4 +20,4 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
20
20
  button.no-btn {
21
21
  padding: var(--padding);
22
22
  }
23
- `;static setTheme(e){localStorage.setItem("theme",e),document.documentElement.setAttribute("theme",e),window.dispatchEvent(new StorageEvent("storage",{key:"theme",newValue:e}))}static getCurrentTheme(){let e=document.documentElement.getAttribute("theme");return e||(e=localStorage.getItem("theme")),e||"auto"}}const colorSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),colorSchemeChangeHandler=e=>document.documentElement.setAttribute("auto-theme",e.matches?"dark":"light");colorSchemeQuery.addEventListener("change",colorSchemeChangeHandler),colorSchemeChangeHandler(colorSchemeQuery),ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()),customElements.define("k-theme-switcher",ThemeSwitcher);
23
+ `;static setTheme(e){theme.set(e)}static getCurrentTheme(){return theme.get()}static getCalculatedCurrentTheme(){return theme.getCalculated()}}customElements.define("k-theme-switcher",ThemeSwitcher);
@@ -0,0 +1 @@
1
+ const contexts={},getContext=e=>(contexts[e]||(contexts[e]={value:void 0,subscribers:new Set}),contexts[e]);export const createContext=(e="global",t)=>{const s=getContext(e);return void 0!==t&&void 0===s.value&&(s.value=t),{get:()=>s.value,set:e=>{s.value=e,s.subscribers.forEach(t=>t(e))},subscribe:e=>(s.subscribers.add(e),e(s.value),()=>s.subscribers.delete(e)),unsubscribe:e=>s.subscribers.delete(e)}};export default createContext;
@@ -0,0 +1 @@
1
+ import createContext from"./context.js";const getInitialTheme=()=>{let e=document.documentElement.getAttribute("theme");return e||(e=localStorage.getItem("theme")),e||"auto"},themeContext=createContext("theme",getInitialTheme());themeContext.subscribe(e=>{localStorage.setItem("theme",e),document.documentElement.setAttribute("theme",e)});export const setTheme=e=>themeContext.set(e);export const getTheme=()=>themeContext.get();export const subscribeToTheme=e=>themeContext.subscribe(e);export const getCalculatedTheme=()=>{const e=getTheme();return"auto"===e?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e};const colorSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),colorSchemeChangeHandler=e=>document.documentElement.setAttribute("auto-theme",e.matches?"dark":"light");colorSchemeQuery.addEventListener("change",colorSchemeChangeHandler),colorSchemeChangeHandler(colorSchemeQuery);export default{get:getTheme,set:setTheme,subscribe:subscribeToTheme,getCalculated:getCalculatedTheme};
@@ -30,12 +30,14 @@
30
30
  <a href="#formatSelection">Format Selection</a><br />
31
31
  <a href="#formUsage">Form Integration</a><br />
32
32
  <a href="#javascriptUsage">JavaScript Usage</a><br />
33
+ <a href="#eventHandling">Event Handling</a><br />
33
34
 
34
35
  <h6 class="mt"><a href="#jsRef" class="no-link">JavaScript Reference</a></h6>
35
36
  <a href="#constructor">Constructor</a><br />
36
37
  <a href="#requirements">Requirements</a><br />
37
38
  <a href="#properties">Properties</a><br />
38
39
  <a href="#methods">Methods</a><br />
40
+ <a href="#events">Events</a><br />
39
41
  <a href="#staticMembers">Static Members</a><br />
40
42
  </div>
41
43
  </k-accordion-panel>
@@ -336,6 +338,161 @@
336
338
  </div>
337
339
  </div>
338
340
 
341
+ <h2 id="eventHandling"><a href="#eventHandling" class="no-link">Event Handling</a></h2>
342
+ <p>The ColorPicker component forwards DOM events from its internal form elements (select, text input, and color
343
+ input), allowing you to listen for user interactions. The following events are forwarded: <code>change</code>,
344
+ <code>input</code>, <code>focus</code>, and <code>blur</code>.</p>
345
+
346
+ <h3>Change Event</h3>
347
+ <p>Fired when the user commits a color change through any of the internal inputs.</p>
348
+ <div class="row -mx">
349
+ <div class="col m-span-12 px">
350
+ <k-card label="HTML">
351
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-color-picker</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"changeEventPicker"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"#3498db"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-color-picker</span>&gt;</span>
352
+ <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"changeOutput"</span>&gt;</span>Change the color to see the event<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
353
+ <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
354
+ <span class="hljs-keyword">const</span> picker = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'changeEventPicker'</span>);
355
+ picker.addEventListener(<span class="hljs-string">'change'</span>, (e) =&gt; {
356
+ <span class="hljs-keyword">const</span> output = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'changeOutput'</span>);
357
+ output.textContent = <span class="hljs-string">`Changed to: <span class="hljs-subst">${picker.value}</span>`</span>;
358
+ });
359
+ </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
360
+ </k-card>
361
+ </div>
362
+ <div class="col m-span-12 px">
363
+ <k-card label="Output">
364
+ <k-color-picker id="changeEventPicker" value="#3498db" class="mb"></k-color-picker>
365
+ <p id="changeOutput">Change the color to see the event</p>
366
+ <script>
367
+ const changeEventPicker = document.getElementById('changeEventPicker');
368
+ changeEventPicker.addEventListener('change', (e) => {
369
+ const output = document.getElementById('changeOutput');
370
+ output.textContent = `Changed to: ${changeEventPicker.value}`;
371
+ });
372
+ </script>
373
+ </k-card>
374
+ </div>
375
+ </div>
376
+
377
+ <h3>Input Event</h3>
378
+ <p>Fired as the user types or modifies the color value, providing real-time updates.</p>
379
+ <div class="row -mx">
380
+ <div class="col m-span-12 px">
381
+ <k-card label="HTML">
382
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-color-picker</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"inputEventPicker"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"#e74c3c"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-color-picker</span>&gt;</span>
383
+ <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"colorPreview"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width:100%; height:50px; background:#e74c3c; border-radius:4px;"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
384
+ <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
385
+ <span class="hljs-keyword">const</span> picker = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'inputEventPicker'</span>);
386
+ <span class="hljs-keyword">const</span> preview = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'colorPreview'</span>);
387
+ picker.addEventListener(<span class="hljs-string">'input'</span>, (e) =&gt; {
388
+ preview.style.backgroundColor = picker.value;
389
+ });
390
+ </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
391
+ </k-card>
392
+ </div>
393
+ <div class="col m-span-12 px">
394
+ <k-card label="Output">
395
+ <k-color-picker id="inputEventPicker" value="#e74c3c" class="mb"></k-color-picker>
396
+ <div id="colorPreview" style="width:100%; height:50px; background:#e74c3c; border-radius:4px;"></div>
397
+ <script>
398
+ const inputEventPicker = document.getElementById('inputEventPicker');
399
+ const colorPreview = document.getElementById('colorPreview');
400
+ inputEventPicker.addEventListener('input', (e) => {
401
+ colorPreview.style.backgroundColor = inputEventPicker.value;
402
+ });
403
+ </script>
404
+ </k-card>
405
+ </div>
406
+ </div>
407
+
408
+ <h3>Focus and Blur Events</h3>
409
+ <p>Track when the user focuses on or leaves any of the color picker's input elements.</p>
410
+ <div class="row -mx">
411
+ <div class="col m-span-12 px">
412
+ <k-card label="HTML">
413
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-color-picker</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"focusEventPicker"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"#2ecc71"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-color-picker</span>&gt;</span>
414
+ <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"focusOutput"</span>&gt;</span>Click on the color picker to see focus/blur events<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
415
+ <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
416
+ <span class="hljs-keyword">const</span> picker = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'focusEventPicker'</span>);
417
+ <span class="hljs-keyword">const</span> output = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'focusOutput'</span>);
418
+ picker.addEventListener(<span class="hljs-string">'focus'</span>, (e) =&gt; {
419
+ output.textContent = <span class="hljs-string">'Color picker focused'</span>;
420
+ output.style.color = <span class="hljs-string">'#2ecc71'</span>;
421
+ });
422
+ picker.addEventListener(<span class="hljs-string">'blur'</span>, (e) =&gt; {
423
+ output.textContent = <span class="hljs-string">'Color picker blurred'</span>;
424
+ output.style.color = <span class="hljs-string">'#95a5a6'</span>;
425
+ });
426
+ </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
427
+ </k-card>
428
+ </div>
429
+ <div class="col m-span-12 px">
430
+ <k-card label="Output">
431
+ <k-color-picker id="focusEventPicker" value="#2ecc71" class="mb"></k-color-picker>
432
+ <p id="focusOutput">Click on the color picker to see focus/blur events</p>
433
+ <script>
434
+ const focusEventPicker = document.getElementById('focusEventPicker');
435
+ const focusOutput = document.getElementById('focusOutput');
436
+ focusEventPicker.addEventListener('focus', (e) => {
437
+ focusOutput.textContent = 'Color picker focused';
438
+ focusOutput.style.color = '#2ecc71';
439
+ });
440
+ focusEventPicker.addEventListener('blur', (e) => {
441
+ focusOutput.textContent = 'Color picker blurred';
442
+ focusOutput.style.color = '#95a5a6';
443
+ });
444
+ </script>
445
+ </k-card>
446
+ </div>
447
+ </div>
448
+
449
+ <h3>Multiple Events Example</h3>
450
+ <p>Combining multiple event listeners to create an interactive color picking experience with event logging.</p>
451
+ <div class="row -mx">
452
+ <div class="col m-span-12 px">
453
+ <k-card label="HTML">
454
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-color-picker</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"multiEventPicker"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"#9b59b6"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-color-picker</span>&gt;</span>
455
+ <span class="hljs-tag">&lt;<span class="hljs-name">pre</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"eventLog"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span>
456
+ <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
457
+ <span class="hljs-keyword">const</span> picker = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'multiEventPicker'</span>);
458
+ <span class="hljs-keyword">const</span> log = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'eventLog'</span>);
459
+ <span class="hljs-keyword">const</span> logEvent = <span class="hljs-function">(<span class="hljs-params">type, value</span>) =&gt;</span> {
460
+ <span class="hljs-keyword">const</span> time = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleTimeString();
461
+ <span class="hljs-keyword">const</span> entry = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'div'</span>);
462
+ entry.textContent = <span class="hljs-string">`<span class="hljs-subst">${time}</span> - <span class="hljs-subst">${type}</span>: <span class="hljs-subst">${value}</span>`</span>;
463
+ log.insertBefore(entry, log.firstChild);
464
+ <span class="hljs-keyword">if</span> (log.children.length &gt; <span class="hljs-number">10</span>) log.lastChild.remove();
465
+ };
466
+ picker.addEventListener(<span class="hljs-string">'change'</span>, () =&gt; logEvent(<span class="hljs-string">'change'</span>, picker.value));
467
+ picker.addEventListener(<span class="hljs-string">'input'</span>, () =&gt; logEvent(<span class="hljs-string">'input'</span>, picker.value));
468
+ picker.addEventListener(<span class="hljs-string">'focus'</span>, () =&gt; logEvent(<span class="hljs-string">'focus'</span>, <span class="hljs-string">'focused'</span>));
469
+ picker.addEventListener(<span class="hljs-string">'blur'</span>, () =&gt; logEvent(<span class="hljs-string">'blur'</span>, <span class="hljs-string">'blurred'</span>));
470
+ </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
471
+ </k-card>
472
+ </div>
473
+ <div class="col m-span-12 px">
474
+ <k-card label="Output">
475
+ <k-color-picker id="multiEventPicker" value="#9b59b6" class="mb"></k-color-picker>
476
+ <pre id="eventLog"></pre>
477
+ <script>
478
+ const multiEventPicker = document.getElementById('multiEventPicker');
479
+ const eventLog = document.getElementById('eventLog');
480
+ const logEvent = (type, value) => {
481
+ const time = new Date().toLocaleTimeString();
482
+ const entry = document.createElement('div');
483
+ entry.textContent = `${time} - ${type}: ${value}`;
484
+ eventLog.insertBefore(entry, eventLog.firstChild);
485
+ if (eventLog.children.length > 10) eventLog.lastChild.remove();
486
+ };
487
+ multiEventPicker.addEventListener('change', () => logEvent('change', multiEventPicker.value));
488
+ multiEventPicker.addEventListener('input', () => logEvent('input', multiEventPicker.value));
489
+ multiEventPicker.addEventListener('focus', () => logEvent('focus', 'focused'));
490
+ multiEventPicker.addEventListener('blur', () => logEvent('blur', 'blurred'));
491
+ </script>
492
+ </k-card>
493
+ </div>
494
+ </div>
495
+
339
496
  <h2 id="jsRef"><a href="jsRef" class="no-link">JavaScript Reference</a></h2>
340
497
 
341
498
  <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
@@ -381,6 +538,23 @@
381
538
  <h5><code>toHexColor(red, green, blue)<i>: string</i></code></h5>
382
539
  <p>Converts RGB values to a hex color string for the native color input.</p>
383
540
 
541
+ <h3 id="events"><a href="#events" class="no-link">Events</a></h3>
542
+ <h5><code>change</code></h5>
543
+ <p>Fired when the user commits a color change through any of the internal inputs (select, text input, or color
544
+ input). This event is forwarded from the native DOM elements.</p>
545
+
546
+ <h5><code>input</code></h5>
547
+ <p>Fired when the user types or modifies values in the text input or interacts with the format selector. This event
548
+ is forwarded from the native DOM elements and provides real-time updates.</p>
549
+
550
+ <h5><code>focus</code></h5>
551
+ <p>Fired when any of the internal form elements (select, text input, or color input) receives focus. This event is
552
+ forwarded from the native DOM elements.</p>
553
+
554
+ <h5><code>blur</code></h5>
555
+ <p>Fired when any of the internal form elements (select, text input, or color input) loses focus. This event is
556
+ forwarded from the native DOM elements.</p>
557
+
384
558
  <h3 id="staticMembers"><a href="#staticMembers" class="no-link">Static Members</a></h3>
385
559
  <h5><code>namedColors<i>: object</i></code></h5>
386
560
  <p>An object containing 147 named CSS colors mapped to their hex values.</p>
@@ -37,7 +37,8 @@
37
37
  </k-accordion>
38
38
 
39
39
  <h3>Description</h3>
40
- <p>The <code>ThemeSwitcher</code> component allows users to switch between different themes (auto, light, dark). It extends the <a href="./shadow-component.html">ShadowComponent</a> class and automatically saves the selected theme to local storage, applies it to the document, and synchronizes across browser tabs.</p>
40
+ <p>The <code>ThemeSwitcher</code> component provides a UI control for users to switch between different themes (auto, light, dark). It extends the <a href="./shadow-component.html">ShadowComponent</a> class and uses the <a href="../utils/theme.html">theme utility</a> internally for state management, persistence, and synchronization.</p>
41
+ <p><strong>Note:</strong> You can manage theme state without this component by directly importing the <a href="../utils/theme.html">theme utility</a>.</p>
41
42
 
42
43
  <h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
43
44
  <p>Use the <code>ThemeSwitcher</code> component to allow users to cycle through themes. Clicking the button cycles through auto → light → dark → auto. The component automatically detects the user's system preference when in auto mode.</p>
@@ -84,6 +85,7 @@
84
85
  <ul>
85
86
  <li><a href="./shadow-component.html">ShadowComponent</a></li>
86
87
  <li><a href="./icon.html">Icon</a></li>
88
+ <li><a href="../utils/theme.html">theme</a> utility</li>
87
89
  </ul>
88
90
 
89
91
  <h3 id="properties"><a href="#properties" class="no-link">Properties</a></h3>
@@ -101,8 +103,9 @@
101
103
  <p>The <code>ThemeSwitcher</code> class does not introduce any new public methods beyond those provided by the <a href="./shadow-component.html">ShadowComponent</a> class.</p>
102
104
 
103
105
  <h3 id="staticMethods"><a href="#staticMethods" class="no-link">Static Methods</a></h3>
106
+ <p><strong>Note:</strong> These static methods are convenience wrappers around the <a href="../utils/theme.html">theme utility</a>. For direct theme management without the component, use the theme utility directly.</p>
104
107
  <h5><code>static setTheme(theme)<i>: void</i></code></h5>
105
- <p>Sets the specified theme and saves it to local storage. Also applies the theme to the document element and dispatches a storage event for cross-tab synchronization.</p>
108
+ <p>Sets the specified theme. Internally calls the <a href="../utils/theme.html">theme utility</a> which handles persistence and DOM updates.</p>
106
109
  <ul>
107
110
  <li><strong>theme</strong> <code>string</code> - The theme to set. Must be one of: <code>"auto"</code>, <code>"light"</code>, or <code>"dark"</code></li>
108
111
  </ul>
@@ -110,20 +113,29 @@
110
113
  <span class="hljs-title class_">ThemeSwitcher</span>.<span class="hljs-title function_">setTheme</span>(<span class="hljs-string">'dark'</span>);</code></pre>
111
114
 
112
115
  <h5><code>static getCurrentTheme()<i>: string</i></code></h5>
113
- <p>Gets the current theme from the document attribute or local storage. Returns <code>"auto"</code> if no theme is set.</p>
116
+ <p>Gets the current theme. Returns <code>"auto"</code> if no theme is set. Internally calls the <a href="../utils/theme.html">theme utility</a>.</p>
114
117
  <pre><code class="hljs javascript"><span class="hljs-comment">// Get the current theme</span>
115
118
  <span class="hljs-keyword">const</span> currentTheme = <span class="hljs-title class_">ThemeSwitcher</span>.<span class="hljs-title function_">getCurrentTheme</span>();
116
119
  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(currentTheme); <span class="hljs-comment">// "auto", "light", or "dark"</span></code></pre>
120
+
121
+ <h5><code>static getCalculatedCurrentTheme()<i>: string</i></code></h5>
122
+ <p>Returns the effective theme, always <code>"dark"</code> or <code>"light"</code>. If the current theme is <code>"auto"</code>, this method uses the user's system preference (<code>prefers-color-scheme</code> media query) to determine the theme. Internally calls the <a href="../utils/theme.html">theme utility</a>.</p>
123
+ <pre><code class="hljs javascript"><span class="hljs-comment">// Get the calculated current theme</span>
124
+ <span class="hljs-keyword">const</span> effectiveTheme = <span class="hljs-title class_">ThemeSwitcher</span>.<span class="hljs-title function_">getCalculatedCurrentTheme</span>();
125
+ <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(effectiveTheme); <span class="hljs.comment">// "dark" or "light"</span></code></pre>
117
126
 
118
127
  <h3 id="themeDetection"><a href="#themeDetection" class="no-link">Automatic Theme Detection</a></h3>
119
- <p>When the theme is set to <code>"auto"</code>, the component automatically detects the user's system preference using <code>prefers-color-scheme</code> media query. The detected theme is applied to the document element as an <code>auto-theme</code> attribute.</p>
120
- <p>The component also synchronizes theme changes across browser tabs using the storage event, ensuring a consistent user experience.</p>
128
+ <p>When the theme is set to <code>"auto"</code>, the <a href="../utils/theme.html">theme utility</a> automatically detects the user's system preference using <code>prefers-color-scheme</code> media query. The detected theme is applied to the document element as an <code>auto-theme</code> attribute.</p>
129
+ <p>The theme utility handles persistence via localStorage and ensures theme changes are reflected in the DOM, providing a consistent user experience.</p>
130
+
131
+ <h3>Related</h3>
132
+ <p>See the <a href="../utils/theme.html">theme utility</a> documentation for programmatic theme management without using this component.</p>
121
133
 
122
134
  </main>
135
+ <div style="height:33vh"></div>
123
136
  <script type="module" src="../src/components/Import.js"></script>
124
137
  <script type="module" src="../src/components/ThemeSwitcher.js"></script>
125
138
  <script type="module" src="../src/components/Accordion.js"></script>
126
139
  <script type="module" src="../src/components/Card.js"></script>
127
-
128
140
  </body>
129
141
  </html>
package/docs/index.html CHANGED
@@ -207,6 +207,18 @@
207
207
 
208
208
  <h2>Utils</h2>
209
209
  <div class="row -mx">
210
+ <div class="span-12 t-span-6 d-span-4 px">
211
+ <a href="./utils/cookie.html" class="card mb no-link d-b">
212
+ <h3 class="tc-primary">cookie</h3>
213
+ <p class="tc-muted">Functions for managing browser cookies.</p>
214
+ </a>
215
+ </div>
216
+ <div class="span-12 t-span-6 d-span-4 px">
217
+ <a href="./utils/context.html" class="card mb no-link d-b">
218
+ <h3 class="tc-primary">context</h3>
219
+ <p class="tc-muted">Global or named shared state for vanilla JS components.</p>
220
+ </a>
221
+ </div>
210
222
  <div class="span-12 t-span-6 d-span-4 px">
211
223
  <a href="./utils/debounce.html" class="card mb no-link d-b">
212
224
  <h3 class="tc-primary">debounce</h3>
@@ -237,6 +249,12 @@
237
249
  <p class="tc-muted">Collection of functions for string manipulation and conversion.</p>
238
250
  </a>
239
251
  </div>
252
+ <div class="span-12 t-span-6 d-span-4 px">
253
+ <a href="./utils/theme.html" class="card mb no-link d-b">
254
+ <h3 class="tc-primary">theme</h3>
255
+ <p class="tc-muted">Centralized theme management with persistence and reactive updates.</p>
256
+ </a>
257
+ </div>
240
258
  <div class="span-12 t-span-6 d-span-4 px">
241
259
  <a href="./utils/type.html" class="card mb no-link d-b">
242
260
  <h3 class="tc-primary">type</h3>
@@ -249,12 +267,6 @@
249
267
  <p class="tc-muted">Functions for manipulating and analyzing JavaScript objects.</p>
250
268
  </a>
251
269
  </div>
252
- <div class="span-12 t-span-6 d-span-4 px">
253
- <a href="./utils/cookie.html" class="card mb no-link d-b">
254
- <h3 class="tc-primary">cookie</h3>
255
- <p class="tc-muted">Functions for managing browser cookies.</p>
256
- </a>
257
- </div>
258
270
  <div class="span-12 t-span-6 d-span-4 px">
259
271
  <a href="./utils/wait.html" class="card mb no-link d-b">
260
272
  <h3 class="tc-primary">wait</h3>
@@ -65,12 +65,14 @@
65
65
  <h5 class="mb0">Utils</h5>
66
66
  <div class="pl mb">
67
67
  <a href="../utils/cookie.html">cookie</a>
68
+ <a href="../utils/context.html">context</a>
68
69
  <a href="../utils/debounce.html">debounce</a>
69
70
  <a href="../utils/drag.html">drag</a>
70
71
  <a href="../utils/formatTimestamp.html">formatTimestamp</a>
71
72
  <a href="../utils/object.html">object</a>
72
73
  <a href="../utils/propConverters.html">propConverters</a>
73
74
  <a href="../utils/string.html">string</a>
75
+ <a href="../utils/theme.html">theme</a>
74
76
  <a href="../utils/type.html">type</a>
75
77
  <a href="../utils/wait.html">wait</a>
76
78
  </div>
package/docs/nav.inc.html CHANGED
@@ -54,6 +54,7 @@
54
54
  <a href="./components/timestamp.html">Timestamp</a>
55
55
  <a href="./components/toggle.html">Toggle</a>
56
56
  <a href="./components/tree.html">Tree</a>
57
+ <a href="./utils/context.html">Context Utility</a>
57
58
  </div>
58
59
 
59
60
  <h5 class="mb0">Base Components</h5>
@@ -66,6 +67,7 @@
66
67
  <h5 class="mb0">Utils</h5>
67
68
  <div class="pl mb">
68
69
  <a href="./utils/cookie.html">cookie</a>
70
+ <a href="./utils/context.html">context</a>
69
71
  <a href="./utils/debounce.html">debounce</a>
70
72
  <a href="./utils/drag.html">drag</a>
71
73
  <a href="./utils/formatTimestamp.html">formatTimestamp</a>