kempo-ui 0.0.28 → 0.0.30

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.
Files changed (57) hide show
  1. package/.github/copilot-instructions.md +16 -0
  2. package/color-picker-fixed.png +0 -0
  3. package/dist/components/Accordion.js +1 -1
  4. package/dist/components/ColorPicker.js +34 -0
  5. package/dist/components/Table.js +1 -1
  6. package/dist/utils/cookie.js +1 -0
  7. package/dist/utils/object.js +1 -0
  8. package/dist/utils/string.js +1 -0
  9. package/dist/utils/type.js +1 -0
  10. package/dist/utils/wait.js +1 -0
  11. package/docs/components/color-picker.html +369 -0
  12. package/docs/components/content-slider.html +2 -2
  13. package/docs/components/theme-switcher.html +4 -4
  14. package/docs/index.html +33 -3
  15. package/docs/init-1.js +1 -1
  16. package/docs/nav-1.inc.html +6 -1
  17. package/docs/nav.inc.html +6 -1
  18. package/docs/src/components/Accordion.js +1 -1
  19. package/docs/src/components/ColorPicker.js +34 -0
  20. package/docs/src/components/Table.js +1 -1
  21. package/docs/src/utils/cookie.js +1 -0
  22. package/docs/src/utils/object.js +1 -0
  23. package/docs/src/utils/string.js +1 -0
  24. package/docs/src/utils/type.js +1 -0
  25. package/docs/src/utils/wait.js +1 -0
  26. package/docs/utils/cookie.html +145 -0
  27. package/docs/utils/object.html +93 -0
  28. package/docs/utils/string.html +83 -0
  29. package/docs/utils/toTitleCase.html +2 -1
  30. package/docs/utils/type.html +48 -0
  31. package/docs/utils/wait.html +48 -0
  32. package/package.json +1 -1
  33. package/src/components/Accordion.js +5 -13
  34. package/src/components/Card.js +1 -3
  35. package/src/components/ColorPicker.js +578 -0
  36. package/src/components/ContentSlider.js +1 -3
  37. package/src/components/Dialog.js +1 -3
  38. package/src/components/Icon.js +1 -3
  39. package/src/components/Import.js +1 -3
  40. package/src/components/PhotoViewer.js +1 -3
  41. package/src/components/Resize.js +1 -3
  42. package/src/components/ShowMore.js +1 -3
  43. package/src/components/SideMenu.js +1 -3
  44. package/src/components/Table.js +1 -1
  45. package/src/components/ThemeSwitcher.js +1 -3
  46. package/src/components/tableControls/Edit.js +1 -3
  47. package/src/components/tableControls/HiddenCount.js +1 -3
  48. package/src/components/tableControls/Search.js +1 -3
  49. package/src/components/tableControls/TableControl.js +1 -3
  50. package/src/utils/cookie.js +20 -0
  51. package/src/utils/object.js +198 -0
  52. package/src/utils/string.js +74 -0
  53. package/src/utils/type.js +13 -0
  54. package/src/utils/wait.js +18 -0
  55. package/dist/utils/toTitleCase.js +0 -1
  56. package/docs/src/utils/toTitleCase.js +0 -1
  57. package/src/utils/toTitleCase.js +0 -9
@@ -0,0 +1,578 @@
1
+ import ShadowComponent from './ShadowComponent.js';
2
+ import { html, css } from '../lit-all.min.js';
3
+
4
+ export default class ColorPicker extends ShadowComponent {
5
+ /* Properties */
6
+ static properties = {
7
+ format: {
8
+ type: String,
9
+ reflect: true,
10
+ attribute: 'format'
11
+ },
12
+ value: {
13
+ type: String,
14
+ reflect: true,
15
+ attribute: 'value'
16
+ },
17
+ red: {
18
+ type: Number
19
+ },
20
+ green: {
21
+ type: Number
22
+ },
23
+ blue: {
24
+ type: Number
25
+ },
26
+ alpha: {
27
+ type: Number
28
+ }
29
+ };
30
+ constructor(){
31
+ super();
32
+ this.format = "hex";
33
+ this.red = 0;
34
+ this.green = 0;
35
+ this.blue = 0;
36
+ this.alpha = 1;
37
+ }
38
+
39
+ /* Lifecycle */
40
+ updated(changedProperties){
41
+ super.updated(changedProperties);
42
+ if (changedProperties.has('format')) {
43
+ this.requestUpdate();
44
+ }
45
+ }
46
+
47
+ /* Members */
48
+ get value(){
49
+ if (this.red === undefined || this.green === undefined || this.blue === undefined) {
50
+ // Default to black in current format
51
+ const format = this.constructor.formats[this.format];
52
+ if (format && format.toString) {
53
+ return format.toString(0, 0, 0, 1);
54
+ }
55
+ return "#000000";
56
+ }
57
+ const format = this.constructor.formats[this.format];
58
+ if (!format || !format.toString) {
59
+ return "#000000";
60
+ }
61
+ return format.toString(this.red, this.green, this.blue, this.alpha || 1);
62
+ }
63
+ set value(val){
64
+ if (!val || typeof val !== 'string') return;
65
+
66
+ // Try to detect and parse the format
67
+ for (const [formatName, format] of Object.entries(this.constructor.formats)) {
68
+ if (format.detect(val)) {
69
+ const parsed = format.parse(val);
70
+ if (parsed) {
71
+ this.red = parsed.r;
72
+ this.green = parsed.g;
73
+ this.blue = parsed.b;
74
+ // Only update alpha if the input actually specified an alpha value
75
+ if (parsed.hasAlpha) {
76
+ this.alpha = parsed.a;
77
+ }
78
+ return;
79
+ }
80
+ }
81
+ }
82
+
83
+ // If no format matched, default to black
84
+ this.red = 0;
85
+ this.green = 0;
86
+ this.blue = 0;
87
+ this.alpha = 1;
88
+ }
89
+
90
+ /* Methods */
91
+ onColorInputChange(event){
92
+ const parsed = this.constructor.formats.hex.parse(event.target.value);
93
+ if (parsed) {
94
+ this.red = parsed.r;
95
+ this.green = parsed.g;
96
+ this.blue = parsed.b;
97
+ this.alpha = 1;
98
+ }
99
+ }
100
+ onTextInputChange(event){
101
+ this.value = event.target.value;
102
+ }
103
+
104
+ /* Rendering */
105
+ render(){
106
+ return html`
107
+ <div id="container">
108
+ <select
109
+ id="format"
110
+ value="${this.format}"
111
+ @change=${(e) => this.format = e.target.value}
112
+ >${
113
+ this.constructor.formats ? Object.keys(this.constructor.formats).map(formatName => html`<option value="${formatName}" ?selected=${this.format === formatName}>${formatName.toUpperCase()}</option>`) : null
114
+ }</select>
115
+ <input
116
+ id="text"
117
+ type="text"
118
+ value="${this.value}"
119
+ @change=${this.onTextInputChange}
120
+ />
121
+ <input
122
+ id="color"
123
+ type="color"
124
+ value="${this.constructor.formats.hex.toString(this.red || 0, this.green || 0, this.blue || 0, 1)}"
125
+ @change=${this.onColorInputChange}
126
+ />
127
+ </div>
128
+ `;
129
+ }
130
+ static styles = css`
131
+ :host {
132
+ display: block;
133
+ }
134
+ #container {
135
+ display: flex;
136
+ align-items: stretch;
137
+ }
138
+ #format {
139
+ width: 7rem;
140
+ }
141
+ #text {
142
+ flex: 1 1 auto;
143
+ }
144
+ #color {
145
+ width: 3rem;
146
+ height: auto !important;
147
+ align-self: stretch !important;
148
+ }
149
+ `;
150
+
151
+ /* Static Members */
152
+ static formats = {
153
+ hex: {
154
+ detect: (value) => /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/.test(value),
155
+ parse: (value) => {
156
+ let hex = value.slice(1);
157
+ let len = hex.length;
158
+ let r, g, b, a = 1, hasAlpha = false;
159
+ if (len === 3 || len === 4) {
160
+ r = parseInt(hex[0] + hex[0], 16);
161
+ g = parseInt(hex[1] + hex[1], 16);
162
+ b = parseInt(hex[2] + hex[2], 16);
163
+ if (len === 4) {
164
+ a = parseInt(hex[3] + hex[3], 16) / 255;
165
+ hasAlpha = true;
166
+ }
167
+ } else if (len === 6 || len === 8) {
168
+ r = parseInt(hex.slice(0, 2), 16);
169
+ g = parseInt(hex.slice(2, 4), 16);
170
+ b = parseInt(hex.slice(4, 6), 16);
171
+ if (len === 8) {
172
+ a = parseInt(hex.slice(6, 8), 16) / 255;
173
+ hasAlpha = true;
174
+ }
175
+ }
176
+ return { r, g, b, a, hasAlpha };
177
+ },
178
+ toString: (r,g,b,a) => {
179
+ r = Math.round(r);
180
+ g = Math.round(g);
181
+ b = Math.round(b);
182
+ let hex = ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
183
+ if (a < 1) {
184
+ let alphaHex = Math.round(a * 255).toString(16).padStart(2, '0');
185
+ hex += alphaHex;
186
+ }
187
+ return '#' + hex;
188
+ }
189
+ },
190
+ rgba: {
191
+ detect: (value) => /^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(?:,\s*(?:0?\.\d+|1(?:\.0*)?|\d+(?:\.\d*)?))?\s*\)$/.test(value),
192
+ parse: (value) => {
193
+ const match = value.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)$/);
194
+ if (!match) return null;
195
+ const r = parseInt(match[1], 10);
196
+ const g = parseInt(match[2], 10);
197
+ const b = parseInt(match[3], 10);
198
+ const a = match[4] ? parseFloat(match[4]) : 1;
199
+ const hasAlpha = !!match[4];
200
+ return { r, g, b, a, hasAlpha };
201
+ },
202
+ toString: (r,g,b,a) => {
203
+ r = Math.round(r);
204
+ g = Math.round(g);
205
+ b = Math.round(b);
206
+ if (a < 1) {
207
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
208
+ } else {
209
+ return `rgb(${r}, ${g}, ${b})`;
210
+ }
211
+ }
212
+ },
213
+ hsla: {
214
+ detect: (value) => /^hsla?\(\s*\d+(?:\.\d+)?\s*,\s*\d+(?:\.\d+)?%\s*,\s*\d+(?:\.\d+)?%\s*(?:,\s*(?:0?\.\d+|1(?:\.0*)?|\d+(?:\.\d*)?))?\s*\)$/.test(value),
215
+ parse: (value) => {
216
+ const match = value.match(/^hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*(?:,\s*([\d.]+))?\s*\)$/);
217
+ if (!match) return null;
218
+ let h = parseFloat(match[1]) / 360;
219
+ let s = parseFloat(match[2]) / 100;
220
+ let l = parseFloat(match[3]) / 100;
221
+ let a = match[4] ? parseFloat(match[4]) : 1;
222
+ const hasAlpha = !!match[4];
223
+ let r, g, b;
224
+ if (s === 0) {
225
+ r = g = b = l;
226
+ } else {
227
+ const hue2rgb = (p, q, t) => {
228
+ if (t < 0) t += 1;
229
+ if (t > 1) t -= 1;
230
+ if (t < 1/6) return p + (q - p) * 6 * t;
231
+ if (t < 1/2) return q;
232
+ if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
233
+ return p;
234
+ };
235
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
236
+ const p = 2 * l - q;
237
+ r = hue2rgb(p, q, h + 1/3);
238
+ g = hue2rgb(p, q, h);
239
+ b = hue2rgb(p, q, h - 1/3);
240
+ }
241
+ return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255), a, hasAlpha };
242
+ },
243
+ toString: (r,g,b,a) => {
244
+ r /= 255; g /= 255; b /= 255;
245
+ const max = Math.max(r, g, b);
246
+ const min = Math.min(r, g, b);
247
+ let h, s, l = (max + min) / 2;
248
+
249
+ if (max === min) {
250
+ h = s = 0; // achromatic
251
+ } else {
252
+ const d = max - min;
253
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
254
+ switch (max) {
255
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
256
+ case g: h = (b - r) / d + 2; break;
257
+ case b: h = (r - g) / d + 4; break;
258
+ }
259
+ h /= 6;
260
+ }
261
+
262
+ h = Math.round(h * 360);
263
+ s = Math.round(s * 100);
264
+ l = Math.round(l * 100);
265
+
266
+ if (a < 1) {
267
+ return `hsla(${h}, ${s}%, ${l}%, ${a})`;
268
+ } else {
269
+ return `hsl(${h}, ${s}%, ${l}%)`;
270
+ }
271
+ }
272
+ },
273
+ hwb: {
274
+ detect: (value) => /^hwb\(\s*(\d+(?:\.\d+)?)(?:deg)?\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(value),
275
+ parse: (value) => {
276
+ const match = value.match(/^hwb\(\s*(\d+(?:\.\d+)?)(?:deg)?\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*(?:\/\s*([\d.]+))?\s*\)$/i);
277
+ if (!match) return null;
278
+ let h = parseFloat(match[1]);
279
+ let w = parseFloat(match[2]) / 100;
280
+ let b = parseFloat(match[3]) / 100;
281
+ let a = match[4] ? parseFloat(match[4]) : 1;
282
+ let ratio = 1 - w - b;
283
+ let r, g, b_val;
284
+ if (ratio > 0) {
285
+ let hue = h / 360;
286
+ let x = 1 - Math.abs((hue * 6) % 2 - 1);
287
+ let m = w + ratio * (1 - x);
288
+ let n = w + ratio * x;
289
+ if (hue < 1/6) {
290
+ r = w + ratio;
291
+ g = n;
292
+ b_val = w;
293
+ } else if (hue < 2/6) {
294
+ r = m;
295
+ g = w + ratio;
296
+ b_val = w;
297
+ } else if (hue < 3/6) {
298
+ r = w;
299
+ g = w + ratio;
300
+ b_val = n;
301
+ } else if (hue < 4/6) {
302
+ r = w;
303
+ g = m;
304
+ b_val = w + ratio;
305
+ } else if (hue < 5/6) {
306
+ r = n;
307
+ g = w;
308
+ b_val = w + ratio;
309
+ } else {
310
+ r = w + ratio;
311
+ g = w;
312
+ b_val = m;
313
+ }
314
+ } else {
315
+ r = g = b_val = w;
316
+ }
317
+ const hasAlpha = !!match[4];
318
+ return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b_val * 255), a, hasAlpha };
319
+ },
320
+ toString: (r,g,b,a) => {
321
+ r /= 255; g /= 255; b /= 255;
322
+ const max = Math.max(r, g, b);
323
+ const min = Math.min(r, g, b);
324
+ const delta = max - min;
325
+
326
+ let h = 0;
327
+ if (delta !== 0) {
328
+ switch (max) {
329
+ case r: h = ((g - b) / delta) % 6; break;
330
+ case g: h = (b - r) / delta + 2; break;
331
+ case b: h = (r - g) / delta + 4; break;
332
+ }
333
+ h = Math.round(h * 60);
334
+ if (h < 0) h += 360;
335
+ }
336
+
337
+ const w = Math.round(min * 100);
338
+ const bl = Math.round((1 - max) * 100);
339
+
340
+ if (a < 1) {
341
+ return `hwb(${h} ${w}% ${bl}% / ${a})`;
342
+ } else {
343
+ return `hwb(${h} ${w}% ${bl}%)`;
344
+ }
345
+ }
346
+ },
347
+ lab: {
348
+ detect: (value) => /^lab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(value),
349
+ parse: (value) => {
350
+ const match = value.match(/^lab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i);
351
+ if (!match) return null;
352
+ let l = parseFloat(match[1]) / 100;
353
+ let a = parseFloat(match[2]);
354
+ let b = parseFloat(match[3]);
355
+ let alpha = match[4] ? parseFloat(match[4]) : 1;
356
+ // Lab to XYZ
357
+ let fy = (l * 100 + 16) / 116;
358
+ let fx = fy + a / 500;
359
+ let fz = fy - b / 200;
360
+ let xr = fx > 0.206893034 ? fx * fx * fx : (fx - 16/116) / 7.787;
361
+ let yr = fy > 0.206893034 ? fy * fy * fy : (fy - 16/116) / 7.787;
362
+ let zr = fz > 0.206893034 ? fz * fz * fz : (fz - 16/116) / 7.787;
363
+ let x = xr * 0.95047;
364
+ let y = yr * 1.0;
365
+ let z = zr * 1.08883;
366
+ // XYZ to linear RGB
367
+ let r_linear = x * 3.2404542 - y * 1.5371385 - z * 0.4985314;
368
+ let g_linear = x * -0.9692660 + y * 1.8760108 + z * 0.0415560;
369
+ let b_linear = x * 0.0556434 - y * 0.2040259 + z * 1.0572252;
370
+ // Linear to sRGB
371
+ let r = r_linear <= 0.0031308 ? r_linear * 12.92 : 1.055 * Math.pow(r_linear, 1/2.4) - 0.055;
372
+ let g = g_linear <= 0.0031308 ? g_linear * 12.92 : 1.055 * Math.pow(g_linear, 1/2.4) - 0.055;
373
+ let b_val = b_linear <= 0.0031308 ? b_linear * 12.92 : 1.055 * Math.pow(b_linear, 1/2.4) - 0.055;
374
+ const hasAlpha = !!match[4];
375
+ return { r: Math.round(Math.max(0, Math.min(1, r)) * 255), g: Math.round(Math.max(0, Math.min(1, g)) * 255), b: Math.round(Math.max(0, Math.min(1, b_val)) * 255), a: alpha, hasAlpha };
376
+ },
377
+ toString: (r,g,b,a) => {
378
+ r /= 255; g /= 255; b /= 255;
379
+ // sRGB to linear RGB
380
+ r = r <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
381
+ g = g <= 0.04045 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
382
+ b = b <= 0.04045 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
383
+ // Linear RGB to XYZ
384
+ const x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375;
385
+ const y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750;
386
+ const z = r * 0.0193339 + g * 0.1191920 + b * 0.9503041;
387
+ // XYZ to Lab
388
+ const xr = x / 0.95047;
389
+ const yr = y / 1.0;
390
+ const zr = z / 1.08883;
391
+ const fx = xr > 0.008856 ? Math.pow(xr, 1/3) : (7.787 * xr + 16/116);
392
+ const fy = yr > 0.008856 ? Math.pow(yr, 1/3) : (7.787 * yr + 16/116);
393
+ const fz = zr > 0.008856 ? Math.pow(zr, 1/3) : (7.787 * zr + 16/116);
394
+ const l = Math.round((116 * fy - 16) * 100) / 100;
395
+ const aa = Math.round((500 * (fx - fy)) * 100) / 100;
396
+ const bb = Math.round((200 * (fy - fz)) * 100) / 100;
397
+
398
+ if (a < 1) {
399
+ return `lab(${l}% ${aa} ${bb} / ${a})`;
400
+ } else {
401
+ return `lab(${l}% ${aa} ${bb})`;
402
+ }
403
+ }
404
+ },
405
+ lch: {
406
+ detect: (value) => /^lch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(value),
407
+ parse: (value) => {
408
+ const match = value.match(/^lch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i);
409
+ if (!match) return null;
410
+ let l = parseFloat(match[1]);
411
+ let c = parseFloat(match[2]);
412
+ let h = parseFloat(match[3]);
413
+ let alpha = match[4] ? parseFloat(match[4]) : 1;
414
+ let a = c * Math.cos(h * Math.PI / 180);
415
+ let b = c * Math.sin(h * Math.PI / 180);
416
+ // Now use lab conversion
417
+ let l_norm = l / 100;
418
+ let fy = (l_norm * 100 + 16) / 116;
419
+ let fx = fy + a / 500;
420
+ let fz = fy - b / 200;
421
+ let xr = fx > 0.206893034 ? fx * fx * fx : (fx - 16/116) / 7.787;
422
+ let yr = fy > 0.206893034 ? fy * fy * fy : (fy - 16/116) / 7.787;
423
+ let zr = fz > 0.206893034 ? fz * fz * fz : (fz - 16/116) / 7.787;
424
+ let x = xr * 0.95047;
425
+ let y = yr * 1.0;
426
+ let z = zr * 1.08883;
427
+ let r_linear = x * 3.2404542 - y * 1.5371385 - z * 0.4985314;
428
+ let g_linear = x * -0.9692660 + y * 1.8760108 + z * 0.0415560;
429
+ let b_linear = x * 0.0556434 - y * 0.2040259 + z * 1.0572252;
430
+ let r = r_linear <= 0.0031308 ? r_linear * 12.92 : 1.055 * Math.pow(r_linear, 1/2.4) - 0.055;
431
+ let g = g_linear <= 0.0031308 ? g_linear * 12.92 : 1.055 * Math.pow(g_linear, 1/2.4) - 0.055;
432
+ let b_val = b_linear <= 0.0031308 ? b_linear * 12.92 : 1.055 * Math.pow(b_linear, 1/2.4) - 0.055;
433
+ const hasAlpha = !!match[4];
434
+ return { r: Math.round(Math.max(0, Math.min(1, r)) * 255), g: Math.round(Math.max(0, Math.min(1, g)) * 255), b: Math.round(Math.max(0, Math.min(1, b_val)) * 255), a: alpha, hasAlpha };
435
+ },
436
+ toString: (r,g,b,a) => {
437
+ // First convert RGB to Lab
438
+ r /= 255; g /= 255; b /= 255;
439
+ r = r <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
440
+ g = g <= 0.04045 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
441
+ b = b <= 0.04045 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
442
+ const x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375;
443
+ const y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750;
444
+ const z = r * 0.0193339 + g * 0.1191920 + b * 0.9503041;
445
+ const xr = x / 0.95047;
446
+ const yr = y / 1.0;
447
+ const zr = z / 1.08883;
448
+ const fx = xr > 0.008856 ? Math.pow(xr, 1/3) : (7.787 * xr + 16/116);
449
+ const fy = yr > 0.008856 ? Math.pow(yr, 1/3) : (7.787 * yr + 16/116);
450
+ const fz = zr > 0.008856 ? Math.pow(zr, 1/3) : (7.787 * zr + 16/116);
451
+ const l_val = (116 * fy - 16) / 100;
452
+ const aa = 500 * (fx - fy);
453
+ const bb = 200 * (fy - fz);
454
+ // Now convert Lab to LCH
455
+ const c = Math.sqrt(aa * aa + bb * bb);
456
+ let h = Math.atan2(bb, aa) * 180 / Math.PI;
457
+ if (h < 0) h += 360;
458
+
459
+ const l = Math.round(l_val * 100 * 100) / 100;
460
+ const chroma = Math.round(c * 100) / 100;
461
+ const hue = Math.round(h * 100) / 100;
462
+
463
+ if (a < 1) {
464
+ return `lch(${l}% ${chroma} ${hue} / ${a})`;
465
+ } else {
466
+ return `lch(${l}% ${chroma} ${hue})`;
467
+ }
468
+ }
469
+ },
470
+ oklab: {
471
+ detect: (value) => /^oklab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(value),
472
+ parse: (value) => {
473
+ const match = value.match(/^oklab\(\s*(\d+(?:\.\d+)?)%\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*(?:\/\s*([\d.]+))?\s*\)$/i);
474
+ if (!match) return null;
475
+ let l = parseFloat(match[1]) / 100;
476
+ let a = parseFloat(match[2]);
477
+ let b = parseFloat(match[3]);
478
+ let alpha = match[4] ? parseFloat(match[4]) : 1;
479
+ // Oklab to linear RGB
480
+ let l_ = l + 0.3963377774 * a + 0.2158037573 * b;
481
+ let m_ = l - 0.1055613458 * a - 0.0638541728 * b;
482
+ let s_ = l - 0.0894841775 * a - 1.2914855480 * b;
483
+ let r_linear = l_ * 4.0767416621 - m_ * 3.3077115913 + s_ * 0.2309699292;
484
+ let g_linear = l_ * -1.2684380046 + m_ * 2.6097574011 - s_ * 0.3413193965;
485
+ let b_linear = l_ * -0.0041960863 - m_ * 0.7034186147 + s_ * 1.7076147010;
486
+ // Linear to sRGB
487
+ let r = r_linear <= 0.0031308 ? r_linear * 12.92 : 1.055 * Math.pow(r_linear, 1/2.4) - 0.055;
488
+ let g = g_linear <= 0.0031308 ? g_linear * 12.92 : 1.055 * Math.pow(g_linear, 1/2.4) - 0.055;
489
+ let b_val = b_linear <= 0.0031308 ? b_linear * 12.92 : 1.055 * Math.pow(b_linear, 1/2.4) - 0.055;
490
+ const hasAlpha = !!match[4];
491
+ return { r: Math.round(Math.max(0, Math.min(1, r)) * 255), g: Math.round(Math.max(0, Math.min(1, g)) * 255), b: Math.round(Math.max(0, Math.min(1, b_val)) * 255), a: alpha, hasAlpha };
492
+ },
493
+ toString: (r,g,b,a) => {
494
+ r /= 255; g /= 255; b /= 255;
495
+ // sRGB to linear RGB
496
+ r = r <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
497
+ g = g <= 0.04045 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
498
+ b = b <= 0.04045 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
499
+ // Linear RGB to Oklab
500
+ const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
501
+ const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
502
+ const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
503
+ const l_root = Math.pow(l_, 1/3);
504
+ const m_root = Math.pow(m_, 1/3);
505
+ const s_root = Math.pow(s_, 1/3);
506
+ const l_val = 0.2104542553 * l_root + 0.7936177850 * m_root - 0.0040720468 * s_root;
507
+ const a_val = 1.9779984951 * l_root - 2.4285922050 * m_root + 0.4505937099 * s_root;
508
+ const b_val = 0.0259040371 * l_root + 0.7827717662 * m_root - 0.8086757660 * s_root;
509
+
510
+ const l = Math.round(l_val * 100 * 100) / 100;
511
+ const aa = Math.round(a_val * 100) / 100;
512
+ const bb = Math.round(b_val * 100) / 100;
513
+
514
+ if (a < 1) {
515
+ return `oklab(${l}% ${aa} ${bb} / ${a})`;
516
+ } else {
517
+ return `oklab(${l}% ${aa} ${bb})`;
518
+ }
519
+ }
520
+ },
521
+ oklch: {
522
+ detect: (value) => /^oklch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i.test(value),
523
+ parse: (value) => {
524
+ const match = value.match(/^oklch\(\s*(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)(?:deg)?\s*(?:\/\s*([\d.]+))?\s*\)$/i);
525
+ if (!match) return null;
526
+ let l = parseFloat(match[1]) / 100;
527
+ let c = parseFloat(match[2]);
528
+ let h = parseFloat(match[3]);
529
+ let alpha = match[4] ? parseFloat(match[4]) : 1;
530
+ let a = c * Math.cos(h * Math.PI / 180);
531
+ let b = c * Math.sin(h * Math.PI / 180);
532
+ // Now use oklab conversion
533
+ let l_ = l + 0.3963377774 * a + 0.2158037573 * b;
534
+ let m_ = l - 0.1055613458 * a - 0.0638541728 * b;
535
+ let s_ = l - 0.0894841775 * a - 1.2914855480 * b;
536
+ let r_linear = l_ * 4.0767416621 - m_ * 3.3077115913 + s_ * 0.2309699292;
537
+ let g_linear = l_ * -1.2684380046 + m_ * 2.6097574011 - s_ * 0.3413193965;
538
+ let b_linear = l_ * -0.0041960863 - m_ * 0.7034186147 + s_ * 1.7076147010;
539
+ let r = r_linear <= 0.0031308 ? r_linear * 12.92 : 1.055 * Math.pow(r_linear, 1/2.4) - 0.055;
540
+ let g = g_linear <= 0.0031308 ? g_linear * 12.92 : 1.055 * Math.pow(g_linear, 1/2.4) - 0.055;
541
+ let b_val = b_linear <= 0.0031308 ? b_linear * 12.92 : 1.055 * Math.pow(b_linear, 1/2.4) - 0.055;
542
+ const hasAlpha = !!match[4];
543
+ return { r: Math.round(Math.max(0, Math.min(1, r)) * 255), g: Math.round(Math.max(0, Math.min(1, g)) * 255), b: Math.round(Math.max(0, Math.min(1, b_val)) * 255), a: alpha, hasAlpha };
544
+ },
545
+ toString: (r,g,b,a) => {
546
+ // First convert RGB to Oklab
547
+ r /= 255; g /= 255; b /= 255;
548
+ r = r <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
549
+ g = g <= 0.04045 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
550
+ b = b <= 0.04045 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
551
+ const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
552
+ const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
553
+ const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
554
+ const l_root = Math.pow(l_, 1/3);
555
+ const m_root = Math.pow(m_, 1/3);
556
+ const s_root = Math.pow(s_, 1/3);
557
+ const l_val = 0.2104542553 * l_root + 0.7936177850 * m_root - 0.0040720468 * s_root;
558
+ const a_val = 1.9779984951 * l_root - 2.4285922050 * m_root + 0.4505937099 * s_root;
559
+ const b_val = 0.0259040371 * l_root + 0.7827717662 * m_root - 0.8086757660 * s_root;
560
+ // Now convert Oklab to OKLCH
561
+ const c = Math.sqrt(a_val * a_val + b_val * b_val);
562
+ let h = Math.atan2(b_val, a_val) * 180 / Math.PI;
563
+ if (h < 0) h += 360;
564
+
565
+ const l = Math.round(l_val * 100 * 100) / 100;
566
+ const chroma = Math.round(c * 100) / 100;
567
+ const hue = Math.round(h * 100) / 100;
568
+
569
+ if (a < 1) {
570
+ return `oklch(${l}% ${chroma} ${hue} / ${a})`;
571
+ } else {
572
+ return `oklch(${l}% ${chroma} ${hue})`;
573
+ }
574
+ }
575
+ }
576
+ }
577
+ }
578
+ window.customElements.define('k-color-picker', ColorPicker);
@@ -4,9 +4,7 @@ import { boolTrueFalse } from '../utils/propConverters.js';
4
4
  import './Icon.js';
5
5
 
6
6
  export default class ContentSlider extends ShadowComponent {
7
- /*
8
- Properties
9
- */
7
+ /* Properties */
10
8
  static properties = {
11
9
  index: { type: Number, reflect: true },
12
10
  controls: { type: Boolean, reflect: true, converter: boolTrueFalse },
@@ -12,9 +12,7 @@ const firstFocusable = element => {
12
12
  };
13
13
 
14
14
  export default class Dialog extends ShadowComponent {
15
- /*
16
- Properties
17
- */
15
+ /* Properties */
18
16
  static properties = {
19
17
  opened: { type: Boolean, reflect: true, converter: boolExists },
20
18
  closeBtn: { type: Boolean, reflect: true, attribute: 'close-btn', converter: boolExists },
@@ -45,9 +45,7 @@ const getIconByName = (name) => {
45
45
  };
46
46
 
47
47
  export default class Icon extends ShadowComponent {
48
- /*
49
- Properties
50
- */
48
+ /* Properties */
51
49
  static properties = {
52
50
  src: { type: String, reflect: true },
53
51
  name: { type: String, reflect: true },
@@ -2,9 +2,7 @@ import LightComponent from './LightComponent.js';
2
2
  import { html, render, unsafeHTML } from '../lit-all.min.js';
3
3
 
4
4
  export default class Import extends LightComponent {
5
- /*
6
- Properties
7
- */
5
+ /* Properties */
8
6
  static properties = {
9
7
  src: {
10
8
  type: String,
@@ -4,9 +4,7 @@ import { boolExists } from '../utils/propConverters.js';
4
4
  import './Icon.js';
5
5
 
6
6
  export default class PhotoViewer extends ShadowComponent {
7
- /*
8
- Properties
9
- */
7
+ /* Properties */
10
8
  static properties = {
11
9
  src: { type: String, reflect: true },
12
10
  alt: { type: String, reflect: true },
@@ -4,9 +4,7 @@ import Icon from './Icon.js';
4
4
  import drag from '../utils/drag.js';
5
5
 
6
6
  export default class Resize extends ShadowComponent {
7
- /*
8
- Properties
9
- */
7
+ /* Properties */
10
8
  static properties = {
11
9
  resizing: { type: String, reflect: true },
12
10
  dimention: { type: String, reflect: true }
@@ -4,9 +4,7 @@ import Icon from './Icon.js';
4
4
  import { boolExists } from '../utils/propConverters.js';
5
5
 
6
6
  export default class ShowMore extends ShadowComponent {
7
- /*
8
- Properties
9
- */
7
+ /* Properties */
10
8
  static properties = {
11
9
  opened: { type: Boolean, converter: boolExists, reflect: true }
12
10
  };
@@ -5,9 +5,7 @@ import './FocusCapture.js';
5
5
  import './Icon.js';
6
6
 
7
7
  export default class SideMenu extends ShadowComponent {
8
- /*
9
- Properties
10
- */
8
+ /* Properties */
11
9
  static properties = {
12
10
  opened: { type: Boolean, reflect: true },
13
11
  overlayClose: { type: Boolean, reflect: true, attribute: 'overlay-close', converter: boolTrueFalse },
@@ -1,6 +1,6 @@
1
1
  import { html, css, unsafeStatic, literal } from '../lit-all.min.js';
2
2
  import ShadowComponent from './ShadowComponent.js';
3
- import toTitleCase from '../utils/toTitleCase.js';
3
+ import { toTitleCase } from '../utils/string.js';
4
4
  import { boolExists } from '../utils/propConverters.js';
5
5
 
6
6
  const selected = Symbol('selected');
@@ -3,9 +3,7 @@ import { html, css } from '../lit-all.min.js';
3
3
  import './Icon.js';
4
4
 
5
5
  export default class ThemeSwitcher extends ShadowComponent {
6
- /*
7
- Properties
8
- */
6
+ /* Properties */
9
7
  static properties = {
10
8
  currentTheme: { type: String, reflect: true, attribute: 'current-theme' }
11
9
  };