lexgui 0.5.5 → 0.5.7
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.
- package/build/lexgui.css +177 -69
- package/build/lexgui.js +1119 -192
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1119 -192
- package/build/lexgui.module.min.js +1 -1
- package/build/utilities.css +74 -8
- package/changelog.md +23 -3
- package/demo.js +17 -10
- package/examples/all_widgets.html +13 -3
- package/examples/area_tabs.html +1 -1
- package/examples/dialogs.html +3 -3
- package/examples/timeline.html +1 -1
- package/package.json +1 -1
package/build/lexgui.module.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
var LX = {
|
|
9
|
-
version: "0.5.
|
|
9
|
+
version: "0.5.7",
|
|
10
10
|
ready: false,
|
|
11
11
|
components: [], // Specific pre-build components
|
|
12
12
|
signals: {}, // Events and triggers
|
|
@@ -216,37 +216,141 @@ LX.getBase64Image = getBase64Image;
|
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
218
|
* @method hexToRgb
|
|
219
|
-
* @description Convert a hexadecimal string to a valid RGB color
|
|
220
|
-
* @param {String}
|
|
219
|
+
* @description Convert a hexadecimal string to a valid RGB color
|
|
220
|
+
* @param {String} hex Hexadecimal color
|
|
221
221
|
*/
|
|
222
|
-
function hexToRgb(
|
|
222
|
+
function hexToRgb( hex )
|
|
223
223
|
{
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
224
|
+
const hexPattern = /^#(?:[A-Fa-f0-9]{3,4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/;
|
|
225
|
+
if( !hexPattern.test( hex ) )
|
|
226
|
+
{
|
|
227
|
+
throw( `Invalid Hex Color: ${ hex }` );
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
hex = hex.replace( /^#/, '' );
|
|
231
|
+
|
|
232
|
+
// Expand shorthand form (#RGB or #RGBA)
|
|
233
|
+
if( hex.length === 3 || hex.length === 4 )
|
|
234
|
+
{
|
|
235
|
+
hex = hex.split( '' ).map( c => c + c ).join( '' );
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const bigint = parseInt( hex, 16 );
|
|
239
|
+
|
|
240
|
+
const r = ( ( bigint >> ( hex.length === 8 ? 24 : 16 ) ) & 255 ) / 255;
|
|
241
|
+
const g = ( ( bigint >> ( hex.length === 8 ? 16 : 8 ) ) & 255 ) / 255;
|
|
242
|
+
const b = ( ( bigint >> ( hex.length === 8 ? 8 : 0 ) ) & 255 ) / 255;
|
|
243
|
+
const a = ( hex.length === 8 ? ( bigint & 255 ) : ( hex.length === 4 ? parseInt( hex.slice( -2 ), 16 ) : 255 ) ) / 255;
|
|
244
|
+
|
|
245
|
+
return { r, g, b, a };
|
|
228
246
|
}
|
|
229
247
|
|
|
230
248
|
LX.hexToRgb = hexToRgb;
|
|
231
249
|
|
|
250
|
+
/**
|
|
251
|
+
* @method hexToHsv
|
|
252
|
+
* @description Convert a hexadecimal string to HSV (0..360|0..1|0..1)
|
|
253
|
+
* @param {String} hexStr Hexadecimal color
|
|
254
|
+
*/
|
|
255
|
+
function hexToHsv( hexStr )
|
|
256
|
+
{
|
|
257
|
+
const rgb = hexToRgb( hexStr );
|
|
258
|
+
return rgbToHsv( rgb );
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
LX.hexToHsv = hexToHsv;
|
|
262
|
+
|
|
232
263
|
/**
|
|
233
264
|
* @method rgbToHex
|
|
234
|
-
* @description Convert a RGB color
|
|
235
|
-
* @param {
|
|
265
|
+
* @description Convert a RGB color to a hexadecimal string
|
|
266
|
+
* @param {Object} rgb Object containing RGB color
|
|
267
|
+
* @param {Number} scale Use 255 for 0..255 range or 1 for 0..1 range
|
|
236
268
|
*/
|
|
237
|
-
function rgbToHex( rgb )
|
|
269
|
+
function rgbToHex( rgb, scale = 255 )
|
|
238
270
|
{
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
271
|
+
const rgbArray = [ rgb.r, rgb.g, rgb.b ];
|
|
272
|
+
if( rgb.a != undefined ) rgbArray.push( rgb.a );
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
"#" +
|
|
276
|
+
rgbArray.map( c => {
|
|
277
|
+
c = Math.floor( c * scale );
|
|
278
|
+
const hex = c.toString(16);
|
|
279
|
+
return hex.length === 1 ? ( '0' + hex ) : hex;
|
|
280
|
+
}).join("")
|
|
281
|
+
);
|
|
246
282
|
}
|
|
247
283
|
|
|
248
284
|
LX.rgbToHex = rgbToHex;
|
|
249
285
|
|
|
286
|
+
/**
|
|
287
|
+
* @method rgbToCss
|
|
288
|
+
* @description Convert a RGB color (0..1) to a CSS color format
|
|
289
|
+
* @param {Object} rgb Object containing RGB color
|
|
290
|
+
*/
|
|
291
|
+
function rgbToCss( rgb )
|
|
292
|
+
{
|
|
293
|
+
return { r: Math.floor( rgb.r * 255 ), g: Math.floor( rgb.g * 255 ), b: Math.floor( rgb.b * 255 ), a: rgb.a };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
LX.rgbToCss = rgbToCss;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @method rgbToHsv
|
|
300
|
+
* @description Convert a RGB color (0..1) array to HSV (0..360|0..1|0..1)
|
|
301
|
+
* @param {Object} rgb Array containing R, G, B
|
|
302
|
+
*/
|
|
303
|
+
function rgbToHsv( rgb )
|
|
304
|
+
{
|
|
305
|
+
let { r, g, b, a } = rgb;
|
|
306
|
+
a = a ?? 1;
|
|
307
|
+
|
|
308
|
+
const max = Math.max(r, g, b);
|
|
309
|
+
const min = Math.min(r, g, b);
|
|
310
|
+
const d = max - min;
|
|
311
|
+
let h = 0;
|
|
312
|
+
|
|
313
|
+
if (d !== 0) {
|
|
314
|
+
if (max === r) { h = ((g - b) / d) % 6 }
|
|
315
|
+
else if (max === g) { h = (b - r) / d + 2 }
|
|
316
|
+
else { h = (r - g) / d + 4 }
|
|
317
|
+
h *= 60
|
|
318
|
+
if (h < 0) { h += 360 }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const s = max === 0 ? 0 : (d / max);
|
|
322
|
+
const v = max;
|
|
323
|
+
|
|
324
|
+
return { h, s, v, a };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
LX.rgbToHsv = rgbToHsv;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @method hsvToRgb
|
|
331
|
+
* @description Convert an HSV color (0..360|0..1|0..1) array to RGB (0..1|0..255)
|
|
332
|
+
* @param {Array} hsv Array containing H, S, V
|
|
333
|
+
*/
|
|
334
|
+
function hsvToRgb( hsv )
|
|
335
|
+
{
|
|
336
|
+
const { h, s, v, a } = hsv;
|
|
337
|
+
const c = v * s;
|
|
338
|
+
const x = c * (1 - Math.abs( ( (h / 60) % 2 ) - 1) )
|
|
339
|
+
const m = v - c;
|
|
340
|
+
let r = 0, g = 0, b = 0;
|
|
341
|
+
|
|
342
|
+
if( h < 60 ) { r = c; g = x; b = 0; }
|
|
343
|
+
else if ( h < 120 ) { r = x; g = c; b = 0; }
|
|
344
|
+
else if ( h < 180 ) { r = 0; g = c; b = x; }
|
|
345
|
+
else if ( h < 240 ) { r = 0; g = x; b = c; }
|
|
346
|
+
else if ( h < 300 ) { r = x; g = 0; b = c; }
|
|
347
|
+
else { r = c; g = 0; b = x; }
|
|
348
|
+
|
|
349
|
+
return { r: ( r + m ), g: ( g + m ), b: ( b + m ), a };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
LX.hsvToRgb = hsvToRgb;
|
|
353
|
+
|
|
250
354
|
/**
|
|
251
355
|
* @method measureRealWidth
|
|
252
356
|
* @description Measure the pixel width of a text
|
|
@@ -578,18 +682,60 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
578
682
|
|
|
579
683
|
LX.makeCodeSnippet = makeCodeSnippet;
|
|
580
684
|
|
|
685
|
+
/**
|
|
686
|
+
* @method makeKbd
|
|
687
|
+
* @description Kbd element to display a keyboard key.
|
|
688
|
+
* @param {Array} keys
|
|
689
|
+
* @param {String} extraClass
|
|
690
|
+
*/
|
|
691
|
+
function makeKbd( keys, extraClass = "" )
|
|
692
|
+
{
|
|
693
|
+
const specialKeys = {
|
|
694
|
+
"Ctrl": '⌃',
|
|
695
|
+
"Enter": '↩',
|
|
696
|
+
"Shift": '⇧',
|
|
697
|
+
"CapsLock": '⇪',
|
|
698
|
+
"Meta": '⌘',
|
|
699
|
+
"Option": '⌥',
|
|
700
|
+
"Alt": '⌥',
|
|
701
|
+
"Tab": '⇥',
|
|
702
|
+
"ArrowUp": '↑',
|
|
703
|
+
"ArrowDown": '↓',
|
|
704
|
+
"ArrowLeft": '←',
|
|
705
|
+
"ArrowRight": '→',
|
|
706
|
+
"Space": '␣'
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
const kbd = LX.makeContainer( ["auto", "auto"], "flex flex-row ml-auto" );
|
|
710
|
+
|
|
711
|
+
for( const k of keys )
|
|
712
|
+
{
|
|
713
|
+
LX.makeContainer( ["auto", "auto"], "self-center text-xs fg-secondary select-none", specialKeys[ k ] ?? k, kbd );
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
return kbd;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
LX.makeKbd = makeKbd;
|
|
720
|
+
|
|
581
721
|
/**
|
|
582
722
|
* @method makeIcon
|
|
583
723
|
* @description Gets an SVG element using one of LX.ICONS
|
|
584
724
|
* @param {String} iconName
|
|
585
|
-
* @param {
|
|
586
|
-
*
|
|
725
|
+
* @param {Object} options
|
|
726
|
+
* iconTitle
|
|
727
|
+
* extraClass
|
|
728
|
+
* svgClass
|
|
587
729
|
*/
|
|
588
|
-
function makeIcon( iconName,
|
|
730
|
+
function makeIcon( iconName, options = { } )
|
|
589
731
|
{
|
|
590
732
|
let data = LX.ICONS[ iconName ];
|
|
591
733
|
console.assert( data, `No icon named _${ iconName }_` );
|
|
592
734
|
|
|
735
|
+
const iconTitle = options.iconTitle;
|
|
736
|
+
const iconClass = options.iconClass;
|
|
737
|
+
const svgClass = options.svgClass;
|
|
738
|
+
|
|
593
739
|
// Just another name for the same icon..
|
|
594
740
|
if( data.constructor == String )
|
|
595
741
|
{
|
|
@@ -599,9 +745,9 @@ function makeIcon( iconName, iconTitle, extraClass = "" )
|
|
|
599
745
|
const svg = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
|
|
600
746
|
svg.setAttribute( "viewBox", `0 0 ${ data[ 0 ] } ${ data[ 1 ] }` );
|
|
601
747
|
|
|
602
|
-
if(
|
|
748
|
+
if( svgClass )
|
|
603
749
|
{
|
|
604
|
-
svg.classList.add(
|
|
750
|
+
svg.classList.add( svgClass );
|
|
605
751
|
}
|
|
606
752
|
|
|
607
753
|
if( data[ 5 ] )
|
|
@@ -629,7 +775,7 @@ function makeIcon( iconName, iconTitle, extraClass = "" )
|
|
|
629
775
|
|
|
630
776
|
const icon = document.createElement( "a" );
|
|
631
777
|
icon.title = iconTitle ?? "";
|
|
632
|
-
icon.className = "lexicon " +
|
|
778
|
+
icon.className = "lexicon " + ( iconClass ?? "" );
|
|
633
779
|
icon.appendChild( svg );
|
|
634
780
|
|
|
635
781
|
return icon;
|
|
@@ -716,7 +862,7 @@ function registerCommandbarEntry( name, callback )
|
|
|
716
862
|
|
|
717
863
|
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
718
864
|
|
|
719
|
-
//
|
|
865
|
+
// Utils classes
|
|
720
866
|
|
|
721
867
|
class vec2 {
|
|
722
868
|
|
|
@@ -744,6 +890,77 @@ class vec2 {
|
|
|
744
890
|
|
|
745
891
|
LX.vec2 = vec2;
|
|
746
892
|
|
|
893
|
+
class Color {
|
|
894
|
+
|
|
895
|
+
constructor( value ) {
|
|
896
|
+
|
|
897
|
+
Object.defineProperty( Color.prototype, "rgb", {
|
|
898
|
+
get: function() { return this._rgb; },
|
|
899
|
+
set: function( v ) { this._fromRGB( v ) }, enumerable: true, configurable: true
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
Object.defineProperty( Color.prototype, "hex", {
|
|
903
|
+
get: function() { return this._hex; },
|
|
904
|
+
set: function( v ) { this._fromHex( v ) }, enumerable: true, configurable: true
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
Object.defineProperty( Color.prototype, "hsv", {
|
|
908
|
+
get: function() { return this._hsv; },
|
|
909
|
+
set: function( v ) { this._fromHSV( v ) }, enumerable: true, configurable: true
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
this.set( value );
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
set( value ) {
|
|
916
|
+
|
|
917
|
+
if ( typeof value === 'string' && value.startsWith( '#' ) )
|
|
918
|
+
{
|
|
919
|
+
this._fromHex( value );
|
|
920
|
+
}
|
|
921
|
+
else if( 'r' in value && 'g' in value && 'b' in value)
|
|
922
|
+
{
|
|
923
|
+
value.a = value.a ?? 1.0;
|
|
924
|
+
this._fromRGB( value );
|
|
925
|
+
}
|
|
926
|
+
else if( 'h' in value && 's' in value && 'v' in value )
|
|
927
|
+
{
|
|
928
|
+
value.a = value.a ?? 1.0;
|
|
929
|
+
this._fromHSV( value );
|
|
930
|
+
}
|
|
931
|
+
else
|
|
932
|
+
{
|
|
933
|
+
throw( "Bad color model!", value );
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
setHSV( hsv ) { this._fromHSV( hsv ); }
|
|
938
|
+
setRGB( rgb ) { this._fromRGB( rgb ); }
|
|
939
|
+
setHex( hex ) { this._fromHex( hex ); }
|
|
940
|
+
|
|
941
|
+
_fromHex( hex ) {
|
|
942
|
+
this._fromRGB( hexToRgb( hex ) );
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
_fromRGB( rgb ) {
|
|
946
|
+
this._rgb = rgb;
|
|
947
|
+
this._hsv = rgbToHsv( rgb );
|
|
948
|
+
this._hex = rgbToHex( rgb );
|
|
949
|
+
this.css = rgbToCss( this._rgb );
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
_fromHSV( hsv ) {
|
|
953
|
+
this._hsv = hsv;
|
|
954
|
+
this._rgb = hsvToRgb( hsv );
|
|
955
|
+
this._hex = rgbToHex( this._rgb );
|
|
956
|
+
this.css = rgbToCss( this._rgb );
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
LX.Color = Color;
|
|
961
|
+
|
|
962
|
+
// Command bar creation
|
|
963
|
+
|
|
747
964
|
function _createCommandbar( root )
|
|
748
965
|
{
|
|
749
966
|
let commandbar = document.createElement( "dialog" );
|
|
@@ -1157,6 +1374,19 @@ function init( options = { } )
|
|
|
1157
1374
|
|
|
1158
1375
|
LX.init = init;
|
|
1159
1376
|
|
|
1377
|
+
/**
|
|
1378
|
+
* @method setStrictViewport
|
|
1379
|
+
* @param {Boolean} value
|
|
1380
|
+
*/
|
|
1381
|
+
|
|
1382
|
+
function setStrictViewport( value )
|
|
1383
|
+
{
|
|
1384
|
+
this.usingStrictViewport = value ?? true;
|
|
1385
|
+
document.documentElement.setAttribute( "data-strictVP", ( this.usingStrictViewport ) ? "true" : "false" );
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
LX.setStrictViewport = setStrictViewport;
|
|
1389
|
+
|
|
1160
1390
|
/**
|
|
1161
1391
|
* @method setCommandbarState
|
|
1162
1392
|
* @param {Boolean} value
|
|
@@ -1801,6 +2031,13 @@ class DropdownMenu {
|
|
|
1801
2031
|
submenuIcon.className = "fa-solid fa-angle-right fa-xs";
|
|
1802
2032
|
menuItem.appendChild( submenuIcon );
|
|
1803
2033
|
}
|
|
2034
|
+
else if( item.kbd )
|
|
2035
|
+
{
|
|
2036
|
+
item.kbd = [].concat( item.kbd );
|
|
2037
|
+
|
|
2038
|
+
const kbd = LX.makeKbd( item.kbd );
|
|
2039
|
+
menuItem.appendChild( kbd );
|
|
2040
|
+
}
|
|
1804
2041
|
|
|
1805
2042
|
if( item.icon )
|
|
1806
2043
|
{
|
|
@@ -1838,39 +2075,504 @@ class DropdownMenu {
|
|
|
1838
2075
|
} );
|
|
1839
2076
|
}
|
|
1840
2077
|
|
|
1841
|
-
menuItem.addEventListener("mouseover", e => {
|
|
2078
|
+
menuItem.addEventListener("mouseover", e => {
|
|
2079
|
+
|
|
2080
|
+
let path = menuItem.id;
|
|
2081
|
+
let p = parentDom;
|
|
2082
|
+
|
|
2083
|
+
while( p )
|
|
2084
|
+
{
|
|
2085
|
+
path += "/" + p.id;
|
|
2086
|
+
p = p.currentParent?.parentElement;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => {
|
|
2090
|
+
if( !path.includes( m.id ) )
|
|
2091
|
+
{
|
|
2092
|
+
m.currentParent.built = false;
|
|
2093
|
+
m.remove();
|
|
2094
|
+
}
|
|
2095
|
+
} );
|
|
2096
|
+
|
|
2097
|
+
if( item.submenu )
|
|
2098
|
+
{
|
|
2099
|
+
if( menuItem.built )
|
|
2100
|
+
{
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
menuItem.built = true;
|
|
2104
|
+
this._create( item.submenu, menuItem );
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
e.stopPropagation();
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
_adjustPosition() {
|
|
2113
|
+
|
|
2114
|
+
const position = [ 0, 0 ];
|
|
2115
|
+
|
|
2116
|
+
// Place menu using trigger position and user options
|
|
2117
|
+
{
|
|
2118
|
+
const rect = this._trigger.getBoundingClientRect();
|
|
2119
|
+
|
|
2120
|
+
let alignWidth = true;
|
|
2121
|
+
|
|
2122
|
+
switch( this.side )
|
|
2123
|
+
{
|
|
2124
|
+
case "left":
|
|
2125
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
2126
|
+
alignWidth = false;
|
|
2127
|
+
break;
|
|
2128
|
+
case "right":
|
|
2129
|
+
position[ 0 ] += ( rect.x + rect.width );
|
|
2130
|
+
alignWidth = false;
|
|
2131
|
+
break;
|
|
2132
|
+
case "top":
|
|
2133
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
2134
|
+
alignWidth = true;
|
|
2135
|
+
break;
|
|
2136
|
+
case "bottom":
|
|
2137
|
+
position[ 1 ] += ( rect.y + rect.height );
|
|
2138
|
+
alignWidth = true;
|
|
2139
|
+
break;
|
|
2140
|
+
default:
|
|
2141
|
+
break;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
switch( this.align )
|
|
2145
|
+
{
|
|
2146
|
+
case "start":
|
|
2147
|
+
if( alignWidth ) { position[ 0 ] += rect.x; }
|
|
2148
|
+
else { position[ 1 ] += rect.y; }
|
|
2149
|
+
break;
|
|
2150
|
+
case "center":
|
|
2151
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - this.root.offsetWidth * 0.5; }
|
|
2152
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - this.root.offsetHeight * 0.5; }
|
|
2153
|
+
break;
|
|
2154
|
+
case "end":
|
|
2155
|
+
if( alignWidth ) { position[ 0 ] += rect.x - this.root.offsetWidth + rect.width; }
|
|
2156
|
+
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
2157
|
+
break;
|
|
2158
|
+
default:
|
|
2159
|
+
break;
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
if( this.avoidCollisions )
|
|
2164
|
+
{
|
|
2165
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - this.root.offsetWidth - this._windowPadding );
|
|
2166
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - this.root.offsetHeight - this._windowPadding );
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
this.root.style.left = `${ position[ 0 ] }px`;
|
|
2170
|
+
this.root.style.top = `${ position[ 1 ] }px`;
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
_addSeparator( parent ) {
|
|
2174
|
+
const separator = document.createElement('div');
|
|
2175
|
+
separator.className = "separator";
|
|
2176
|
+
parent = parent ?? this.root;
|
|
2177
|
+
parent.appendChild( separator );
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
|
|
2181
|
+
LX.DropdownMenu = DropdownMenu;
|
|
2182
|
+
|
|
2183
|
+
/**
|
|
2184
|
+
* @class ColorPicker
|
|
2185
|
+
*/
|
|
2186
|
+
|
|
2187
|
+
class ColorPicker {
|
|
2188
|
+
|
|
2189
|
+
static currentPicker = false;
|
|
2190
|
+
|
|
2191
|
+
constructor( hexValue, trigger, options = {} ) {
|
|
2192
|
+
|
|
2193
|
+
console.assert( trigger, "ColorPicker needs a DOM element as trigger!" );
|
|
2194
|
+
|
|
2195
|
+
this._windowPadding = 4;
|
|
2196
|
+
this.side = options.side ?? "bottom";
|
|
2197
|
+
this.align = options.align ?? "center";
|
|
2198
|
+
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
2199
|
+
this.colorModel = options.colorModel ?? "Hex";
|
|
2200
|
+
this.useAlpha = options.useAlpha ?? false;
|
|
2201
|
+
this.callback = options.onChange;
|
|
2202
|
+
|
|
2203
|
+
if( !this.callback )
|
|
2204
|
+
{
|
|
2205
|
+
console.warn( "Define a callback in _options.onChange_ to allow getting new Color values!" );
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
if( ColorPicker.currentPicker )
|
|
2209
|
+
{
|
|
2210
|
+
ColorPicker.currentPicker.destroy();
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
this._trigger = trigger;
|
|
2215
|
+
trigger.classList.add( "triggered" );
|
|
2216
|
+
trigger.picker = this;
|
|
2217
|
+
|
|
2218
|
+
this.root = document.createElement( "div" );
|
|
2219
|
+
this.root.tabIndex = "1";
|
|
2220
|
+
this.root.className = "lexcolorpicker";
|
|
2221
|
+
this.root.dataset["side"] = this.side;
|
|
2222
|
+
LX.root.appendChild( this.root );
|
|
2223
|
+
|
|
2224
|
+
this.root.addEventListener( "keydown", (e) => {
|
|
2225
|
+
if( e.key == "Escape" )
|
|
2226
|
+
{
|
|
2227
|
+
e.preventDefault();
|
|
2228
|
+
e.stopPropagation();
|
|
2229
|
+
this.destroy();
|
|
2230
|
+
}
|
|
2231
|
+
} )
|
|
2232
|
+
|
|
2233
|
+
ColorPicker.currentPicker = this;
|
|
2234
|
+
|
|
2235
|
+
this.markerHalfSize = 8;
|
|
2236
|
+
this.markerSize = this.markerHalfSize * 2;
|
|
2237
|
+
this.currentColor = new Color( hexValue );
|
|
2238
|
+
|
|
2239
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2240
|
+
|
|
2241
|
+
// Intensity, Sat
|
|
2242
|
+
this.colorPickerBackground = document.createElement( 'div' );
|
|
2243
|
+
this.colorPickerBackground.className = "lexcolorpickerbg";
|
|
2244
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2245
|
+
this.root.appendChild( this.colorPickerBackground );
|
|
2246
|
+
|
|
2247
|
+
this.intSatMarker = document.createElement( 'div' );
|
|
2248
|
+
this.intSatMarker.className = "lexcolormarker";
|
|
2249
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
2250
|
+
this.colorPickerBackground.appendChild( this.intSatMarker );
|
|
2251
|
+
|
|
2252
|
+
doAsync( this._svToPosition.bind( this, this.currentColor.hsv.s, this.currentColor.hsv.v ) );
|
|
2253
|
+
|
|
2254
|
+
let innerMouseDown = e => {
|
|
2255
|
+
var doc = this.root.ownerDocument;
|
|
2256
|
+
doc.addEventListener( 'mousemove', innerMouseMove );
|
|
2257
|
+
doc.addEventListener( 'mouseup', innerMouseUp );
|
|
2258
|
+
document.body.classList.add( 'noevents' );
|
|
2259
|
+
e.stopImmediatePropagation();
|
|
2260
|
+
e.stopPropagation();
|
|
2261
|
+
|
|
2262
|
+
const currentLeft = ( e.offsetX - this.markerHalfSize );
|
|
2263
|
+
this.intSatMarker.style.left = currentLeft + "px";
|
|
2264
|
+
const currentTop = ( e.offsetY - this.markerHalfSize );
|
|
2265
|
+
this.intSatMarker.style.top = currentTop + "px";
|
|
2266
|
+
this._positionToSv( currentLeft, currentTop );
|
|
2267
|
+
this._updateColorValue();
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
let innerMouseMove = e => {
|
|
2271
|
+
const dX = e.movementX;
|
|
2272
|
+
const dY = e.movementY;
|
|
2273
|
+
|
|
2274
|
+
const rect = this.colorPickerBackground.getBoundingClientRect();
|
|
2275
|
+
const mouseX = e.offsetX - rect.x;
|
|
2276
|
+
const mouseY = e.offsetY - rect.y;
|
|
2277
|
+
|
|
2278
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerBackground.offsetWidth || dX > 0 ) )
|
|
2279
|
+
{
|
|
2280
|
+
this.intSatMarker.style.left = LX.clamp( parseInt( this.intSatMarker.style.left ) + dX, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) + "px";
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
if ( dY != 0 && ( mouseY >= 0 || dY < 0 ) && ( mouseY < this.colorPickerBackground.offsetHeight || dY > 0 ) )
|
|
2284
|
+
{
|
|
2285
|
+
this.intSatMarker.style.top = LX.clamp( parseInt( this.intSatMarker.style.top ) + dY, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) + "px";
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
this._positionToSv( parseInt( this.intSatMarker.style.left ), parseInt( this.intSatMarker.style.top ) );
|
|
2289
|
+
this._updateColorValue();
|
|
2290
|
+
|
|
2291
|
+
e.stopPropagation();
|
|
2292
|
+
e.preventDefault();
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
let innerMouseUp = e => {
|
|
2296
|
+
var doc = this.root.ownerDocument;
|
|
2297
|
+
doc.removeEventListener( 'mousemove', innerMouseMove );
|
|
2298
|
+
doc.removeEventListener( 'mouseup', innerMouseUp );
|
|
2299
|
+
document.body.classList.remove( 'noevents' );
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
this.colorPickerBackground.addEventListener( "mousedown", innerMouseDown );
|
|
2303
|
+
|
|
2304
|
+
const hueAlphaContainer = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1 items-center", "", this.root );
|
|
2305
|
+
|
|
2306
|
+
if( window.EyeDropper )
|
|
2307
|
+
{
|
|
2308
|
+
hueAlphaContainer.appendChild( new Button(null, "eyedrop", async () => {
|
|
2309
|
+
const eyeDropper = new EyeDropper()
|
|
2310
|
+
try {
|
|
2311
|
+
const result = await eyeDropper.open();
|
|
2312
|
+
this.fromHexColor( result.sRGBHex );
|
|
2313
|
+
} catch ( err ) {
|
|
2314
|
+
// console.error("EyeDropper cancelled or failed: ", err)
|
|
2315
|
+
}
|
|
2316
|
+
}, { icon: "eye-dropper", buttonClass: "bg-none", title: "Sample Color" }).root );
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
const innerHueAlpha = LX.makeContainer( ["100%", "100%"], "flex flex-col gap-2", "", hueAlphaContainer );
|
|
2320
|
+
|
|
2321
|
+
// Hue
|
|
2322
|
+
this.colorPickerTracker = document.createElement( 'div' );
|
|
2323
|
+
this.colorPickerTracker.className = "lexhuetracker";
|
|
2324
|
+
innerHueAlpha.appendChild( this.colorPickerTracker );
|
|
2325
|
+
|
|
2326
|
+
this.hueMarker = document.createElement( 'div' );
|
|
2327
|
+
this.hueMarker.className = "lexcolormarker";
|
|
2328
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2329
|
+
this.colorPickerTracker.appendChild( this.hueMarker );
|
|
2330
|
+
|
|
2331
|
+
doAsync( () => {
|
|
2332
|
+
const hueLeft = LX.remapRange( this.currentColor.hsv.h, 0, 360, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2333
|
+
this.hueMarker.style.left = hueLeft + "px";
|
|
2334
|
+
} );
|
|
2335
|
+
|
|
2336
|
+
const _fromHueX = ( hueX ) => {
|
|
2337
|
+
this.hueMarker.style.left = hueX + "px";
|
|
2338
|
+
this.currentColor.hsv.h = LX.remapRange( hueX, 0, this.colorPickerTracker.offsetWidth - this.markerSize, 0, 360 );
|
|
2339
|
+
|
|
2340
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2341
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2342
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2343
|
+
this._updateColorValue();
|
|
2344
|
+
};
|
|
2345
|
+
|
|
2346
|
+
let innerMouseDownHue = e => {
|
|
2347
|
+
const doc = this.root.ownerDocument;
|
|
2348
|
+
doc.addEventListener( 'mousemove', innerMouseMoveHue );
|
|
2349
|
+
doc.addEventListener( 'mouseup', innerMouseUpHue );
|
|
2350
|
+
document.body.classList.add( 'noevents' );
|
|
2351
|
+
e.stopImmediatePropagation();
|
|
2352
|
+
e.stopPropagation();
|
|
2353
|
+
|
|
2354
|
+
const hueX = clamp( e.offsetX - this.markerHalfSize, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2355
|
+
_fromHueX( hueX );
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
let innerMouseMoveHue = e => {
|
|
2359
|
+
let dX = e.movementX;
|
|
2360
|
+
|
|
2361
|
+
const rect = this.colorPickerTracker.getBoundingClientRect();
|
|
2362
|
+
const mouseX = e.offsetX - rect.x;
|
|
2363
|
+
|
|
2364
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerTracker.offsetWidth || dX > 0 ) )
|
|
2365
|
+
{
|
|
2366
|
+
const hueX = LX.clamp( parseInt( this.hueMarker.style.left ) + dX, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2367
|
+
_fromHueX( hueX )
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
e.stopPropagation();
|
|
2371
|
+
e.preventDefault();
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
let innerMouseUpHue = e => {
|
|
2375
|
+
var doc = this.root.ownerDocument;
|
|
2376
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveHue );
|
|
2377
|
+
doc.removeEventListener( 'mouseup', innerMouseUpHue );
|
|
2378
|
+
document.body.classList.remove( 'noevents' );
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
this.colorPickerTracker.addEventListener( "mousedown", innerMouseDownHue );
|
|
2382
|
+
|
|
2383
|
+
// Alpha
|
|
2384
|
+
if( this.useAlpha )
|
|
2385
|
+
{
|
|
2386
|
+
this.alphaTracker = document.createElement( 'div' );
|
|
2387
|
+
this.alphaTracker.className = "lexalphatracker";
|
|
2388
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b })`;
|
|
2389
|
+
innerHueAlpha.appendChild( this.alphaTracker );
|
|
2390
|
+
|
|
2391
|
+
this.alphaMarker = document.createElement( 'div' );
|
|
2392
|
+
this.alphaMarker.className = "lexcolormarker";
|
|
2393
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2394
|
+
this.alphaTracker.appendChild( this.alphaMarker );
|
|
2395
|
+
|
|
2396
|
+
doAsync( () => {
|
|
2397
|
+
const alphaLeft = LX.remapRange( this.currentColor.hsv.a, 0, 1, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2398
|
+
this.alphaMarker.style.left = alphaLeft + "px";
|
|
2399
|
+
} );
|
|
2400
|
+
|
|
2401
|
+
const _fromAlphaX = ( alphaX ) => {
|
|
2402
|
+
this.alphaMarker.style.left = alphaX + "px";
|
|
2403
|
+
this.currentColor.hsv.a = LX.remapRange( alphaX, 0, this.alphaTracker.offsetWidth - this.markerSize, 0, 1 );
|
|
2404
|
+
this._updateColorValue();
|
|
2405
|
+
// Update alpha marker once the color is updated
|
|
2406
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2407
|
+
};
|
|
2408
|
+
|
|
2409
|
+
let innerMouseDownAlpha = e => {
|
|
2410
|
+
const doc = this.root.ownerDocument;
|
|
2411
|
+
doc.addEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2412
|
+
doc.addEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2413
|
+
document.body.classList.add( 'noevents' );
|
|
2414
|
+
e.stopImmediatePropagation();
|
|
2415
|
+
e.stopPropagation();
|
|
2416
|
+
const alphaX = clamp( e.offsetX - this.markerHalfSize, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2417
|
+
_fromAlphaX( alphaX );
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
let innerMouseMoveAlpha = e => {
|
|
2421
|
+
let dX = e.movementX;
|
|
2422
|
+
|
|
2423
|
+
const rect = this.alphaTracker.getBoundingClientRect();
|
|
2424
|
+
const mouseX = e.offsetX - rect.x;
|
|
2425
|
+
|
|
2426
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.alphaTracker.offsetWidth || dX > 0 ) )
|
|
2427
|
+
{
|
|
2428
|
+
const alphaX = LX.clamp( parseInt( this.alphaMarker.style.left ) + dX, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2429
|
+
_fromAlphaX( alphaX );
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
e.stopPropagation();
|
|
2433
|
+
e.preventDefault();
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
let innerMouseUpAlpha = e => {
|
|
2437
|
+
var doc = this.root.ownerDocument;
|
|
2438
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2439
|
+
doc.removeEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2440
|
+
document.body.classList.remove( 'noevents' );
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
this.alphaTracker.addEventListener( "mousedown", innerMouseDownAlpha );
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
// Info display
|
|
2447
|
+
const colorLabel = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1", "", this.root );
|
|
2448
|
+
|
|
2449
|
+
colorLabel.appendChild( new Select( null, [ "CSS", "Hex", "HSV", "RGB" ], this.colorModel, v => {
|
|
2450
|
+
this.colorModel = v;
|
|
2451
|
+
this._updateColorValue( null, true );
|
|
2452
|
+
} ).root );
|
|
2453
|
+
|
|
2454
|
+
this.labelWidget = new TextInput( null, "", null, { inputClass: "bg-none", fit: true, disabled: true } );
|
|
2455
|
+
colorLabel.appendChild( this.labelWidget.root );
|
|
2456
|
+
|
|
2457
|
+
// Copy button
|
|
2458
|
+
{
|
|
2459
|
+
const copyButtonWidget = new Button(null, "copy", async () => {
|
|
2460
|
+
navigator.clipboard.writeText( this.labelWidget.value() );
|
|
2461
|
+
copyButtonWidget.root.querySelector( "input[type='checkbox']" ).style.pointerEvents = "none";
|
|
2462
|
+
|
|
2463
|
+
doAsync( () => {
|
|
2464
|
+
copyButtonWidget.root.swap( true );
|
|
2465
|
+
copyButtonWidget.root.querySelector( "input[type='checkbox']" ).style.pointerEvents = "auto";
|
|
2466
|
+
}, 3000 );
|
|
2467
|
+
|
|
2468
|
+
}, { swap: "check", icon: "copy", buttonClass: "bg-none", className: "ml-auto", title: "Copy" })
|
|
2469
|
+
|
|
2470
|
+
copyButtonWidget.root.querySelector( ".swap-on svg path" ).style.fill = "#42d065";
|
|
2471
|
+
|
|
2472
|
+
colorLabel.appendChild( copyButtonWidget.root );
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
this._updateColorValue( hexValue, true );
|
|
2476
|
+
|
|
2477
|
+
doAsync( () => {
|
|
2478
|
+
this._adjustPosition();
|
|
2479
|
+
|
|
2480
|
+
this.root.focus();
|
|
2481
|
+
|
|
2482
|
+
this._onClick = e => {
|
|
2483
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
2484
|
+
{
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
this.destroy();
|
|
2488
|
+
};
|
|
2489
|
+
|
|
2490
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
2491
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
2492
|
+
}, 10 );
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
fromHexColor( hexColor ) {
|
|
2496
|
+
|
|
2497
|
+
this.currentColor.setHex( hexColor );
|
|
2498
|
+
|
|
2499
|
+
// Decompose into HSV
|
|
2500
|
+
const { h, s, v } = this.currentColor.hsv;
|
|
2501
|
+
this._svToPosition( s, v );
|
|
2502
|
+
|
|
2503
|
+
const hueColor = new Color( { h, s: 1, v: 1 } );
|
|
2504
|
+
this.hueMarker.style.backgroundColor = this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2505
|
+
this.hueMarker.style.left = LX.remapRange( h, 0, 360, -this.markerHalfSize, this.colorPickerTracker.offsetWidth - this.markerHalfSize ) + "px";
|
|
2506
|
+
|
|
2507
|
+
this._updateColorValue( hexColor );
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
destroy() {
|
|
2511
|
+
|
|
2512
|
+
this._trigger.classList.remove( "triggered" );
|
|
2513
|
+
|
|
2514
|
+
delete this._trigger.picker;
|
|
1842
2515
|
|
|
1843
|
-
|
|
1844
|
-
|
|
2516
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
2517
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
1845
2518
|
|
|
1846
|
-
|
|
1847
|
-
{
|
|
1848
|
-
path += "/" + p.id;
|
|
1849
|
-
p = p.currentParent?.parentElement;
|
|
1850
|
-
}
|
|
2519
|
+
LX.root.querySelectorAll( ".lexcolorpicker" ).forEach( m => { m.remove(); } );
|
|
1851
2520
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
{
|
|
1855
|
-
m.currentParent.built = false;
|
|
1856
|
-
m.remove();
|
|
1857
|
-
}
|
|
1858
|
-
} );
|
|
2521
|
+
ColorPicker.currentPicker = null;
|
|
2522
|
+
}
|
|
1859
2523
|
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
return;
|
|
1865
|
-
}
|
|
1866
|
-
menuItem.built = true;
|
|
1867
|
-
this._create( item.submenu, menuItem );
|
|
1868
|
-
}
|
|
2524
|
+
_svToPosition( s, v ) {
|
|
2525
|
+
this.intSatMarker.style.left = `${ LX.remapRange( s, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) }px`;
|
|
2526
|
+
this.intSatMarker.style.top = `${ LX.remapRange( 1 - v, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) }px`
|
|
2527
|
+
};
|
|
1869
2528
|
|
|
1870
|
-
|
|
1871
|
-
|
|
2529
|
+
_positionToSv( left, top ) {
|
|
2530
|
+
this.currentColor.hsv.s = LX.remapRange( left, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize, 0, 1 );
|
|
2531
|
+
this.currentColor.hsv.v = 1 - LX.remapRange( top, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize, 0, 1 );
|
|
2532
|
+
};
|
|
2533
|
+
|
|
2534
|
+
_updateColorValue( newHexValue, skipCallback = false ) {
|
|
2535
|
+
|
|
2536
|
+
this.currentColor.set( newHexValue ?? this.currentColor.hsv );
|
|
2537
|
+
|
|
2538
|
+
if( this.callback && !skipCallback )
|
|
2539
|
+
{
|
|
2540
|
+
this.callback( this.currentColor );
|
|
1872
2541
|
}
|
|
1873
|
-
|
|
2542
|
+
|
|
2543
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
2544
|
+
|
|
2545
|
+
if( this.useAlpha )
|
|
2546
|
+
{
|
|
2547
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b })`;
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
const toFixed = ( s, n = 2) => { return s.toFixed( n ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' ) };
|
|
2551
|
+
|
|
2552
|
+
if( this.colorModel == "CSS" )
|
|
2553
|
+
{
|
|
2554
|
+
const { r, g, b, a } = this.currentColor.css;
|
|
2555
|
+
this.labelWidget.set( `rgb${ this.useAlpha ? 'a' : '' }(${ r },${ g },${ b }${ this.useAlpha ? ',' + toFixed( a ) : '' })` );
|
|
2556
|
+
}
|
|
2557
|
+
else if( this.colorModel == "Hex" )
|
|
2558
|
+
{
|
|
2559
|
+
this.labelWidget.set( ( this.useAlpha ? this.currentColor.hex : this.currentColor.hex.substr( 0, 7 ) ).toUpperCase() );
|
|
2560
|
+
}
|
|
2561
|
+
else if( this.colorModel == "HSV" )
|
|
2562
|
+
{
|
|
2563
|
+
const { h, s, v, a } = this.currentColor.hsv;
|
|
2564
|
+
const components = [ Math.floor( h ) + 'º', Math.floor( s * 100 ) + '%', Math.floor( v * 100 ) + '%' ];
|
|
2565
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2566
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2567
|
+
}
|
|
2568
|
+
else // RGB
|
|
2569
|
+
{
|
|
2570
|
+
const { r, g, b, a } = this.currentColor.rgb;
|
|
2571
|
+
const components = [ toFixed( r ), toFixed( g ), toFixed( b ) ];
|
|
2572
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2573
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
1874
2576
|
|
|
1875
2577
|
_adjustPosition() {
|
|
1876
2578
|
|
|
@@ -1932,16 +2634,9 @@ class DropdownMenu {
|
|
|
1932
2634
|
this.root.style.left = `${ position[ 0 ] }px`;
|
|
1933
2635
|
this.root.style.top = `${ position[ 1 ] }px`;
|
|
1934
2636
|
}
|
|
1935
|
-
|
|
1936
|
-
_addSeparator( parent ) {
|
|
1937
|
-
const separator = document.createElement('div');
|
|
1938
|
-
separator.className = "separator";
|
|
1939
|
-
parent = parent ?? this.root;
|
|
1940
|
-
parent.appendChild( separator );
|
|
1941
|
-
}
|
|
1942
2637
|
};
|
|
1943
2638
|
|
|
1944
|
-
LX.
|
|
2639
|
+
LX.ColorPicker = ColorPicker;
|
|
1945
2640
|
|
|
1946
2641
|
class Area {
|
|
1947
2642
|
|
|
@@ -3734,7 +4429,7 @@ class Menubar {
|
|
|
3734
4429
|
// Otherwise, create it
|
|
3735
4430
|
button = document.createElement('div');
|
|
3736
4431
|
const disabled = options.disabled ?? false;
|
|
3737
|
-
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
4432
|
+
button.className = "lexmenubutton main" + (disabled ? " disabled" : "");
|
|
3738
4433
|
button.title = name;
|
|
3739
4434
|
button.innerHTML = "<a><image src='" + src + "' class='lexicon' style='height:32px;'></a>";
|
|
3740
4435
|
|
|
@@ -3804,57 +4499,14 @@ class Menubar {
|
|
|
3804
4499
|
|
|
3805
4500
|
for( let i = 0; i < buttons.length; ++i )
|
|
3806
4501
|
{
|
|
3807
|
-
|
|
3808
|
-
let button = document.createElement( "label" );
|
|
4502
|
+
const data = buttons[ i ];
|
|
3809
4503
|
const title = data.title;
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
button.title = title ?? "";
|
|
3813
|
-
this.buttonContainer.appendChild( button );
|
|
3814
|
-
|
|
3815
|
-
const icon = document.createElement( "a" );
|
|
3816
|
-
icon.className = data.icon + " lexicon";
|
|
3817
|
-
button.appendChild( icon );
|
|
3818
|
-
|
|
3819
|
-
let trigger = icon;
|
|
3820
|
-
|
|
3821
|
-
if( data.swap )
|
|
3822
|
-
{
|
|
3823
|
-
button.classList.add( "swap" );
|
|
3824
|
-
icon.classList.add( "swap-off" );
|
|
3825
|
-
|
|
3826
|
-
const input = document.createElement( "input" );
|
|
3827
|
-
input.type = "checkbox";
|
|
3828
|
-
button.prepend( input );
|
|
3829
|
-
trigger = input;
|
|
3830
|
-
|
|
3831
|
-
const swapIcon = document.createElement( "a" );
|
|
3832
|
-
swapIcon.className = data.swap + " swap-on lexicon";
|
|
3833
|
-
button.appendChild( swapIcon );
|
|
3834
|
-
|
|
3835
|
-
button.swap = function() {
|
|
3836
|
-
const swapInput = this.querySelector( "input" );
|
|
3837
|
-
swapInput.checked = !swapInput.checked;
|
|
3838
|
-
};
|
|
3839
|
-
|
|
3840
|
-
// Set if swap has to be performed
|
|
3841
|
-
button.setState = function( v ) {
|
|
3842
|
-
const swapInput = this.querySelector( "input" );
|
|
3843
|
-
swapInput.checked = v;
|
|
3844
|
-
};
|
|
3845
|
-
}
|
|
3846
|
-
|
|
3847
|
-
trigger.addEventListener("click", e => {
|
|
3848
|
-
if( data.callback && !disabled )
|
|
3849
|
-
{
|
|
3850
|
-
const swapInput = button.querySelector( "input" );
|
|
3851
|
-
data.callback.call( this, e, swapInput?.checked );
|
|
3852
|
-
}
|
|
3853
|
-
});
|
|
4504
|
+
const button = new Button( title, "", data.callback, { title, buttonClass: "bg-none", disabled: data.disabled, icon: data.icon, hideName: true, swap: data.swap } )
|
|
4505
|
+
this.buttonContainer.appendChild( button.root );
|
|
3854
4506
|
|
|
3855
4507
|
if( title )
|
|
3856
4508
|
{
|
|
3857
|
-
this.buttons[ title ] = button;
|
|
4509
|
+
this.buttons[ title ] = button.root;
|
|
3858
4510
|
}
|
|
3859
4511
|
}
|
|
3860
4512
|
}
|
|
@@ -3941,7 +4593,7 @@ class SideBar {
|
|
|
3941
4593
|
|
|
3942
4594
|
if( this.collapsable )
|
|
3943
4595
|
{
|
|
3944
|
-
const icon = LX.makeIcon( "sidebar", "Toggle Sidebar", "toggler" );
|
|
4596
|
+
const icon = LX.makeIcon( "sidebar", { title: "Toggle Sidebar", iconClass: "toggler" } );
|
|
3945
4597
|
this.header.appendChild( icon );
|
|
3946
4598
|
|
|
3947
4599
|
icon.addEventListener( "click", (e) => {
|
|
@@ -4428,7 +5080,7 @@ class SideBar {
|
|
|
4428
5080
|
|
|
4429
5081
|
if( options.action )
|
|
4430
5082
|
{
|
|
4431
|
-
const actionIcon = LX.makeIcon( options.action.icon ?? "more-horizontal", options.action.name );
|
|
5083
|
+
const actionIcon = LX.makeIcon( options.action.icon ?? "more-horizontal", { title: options.action.name } );
|
|
4432
5084
|
itemDom.appendChild( actionIcon );
|
|
4433
5085
|
|
|
4434
5086
|
actionIcon.addEventListener( "click", (e) => {
|
|
@@ -4488,7 +5140,7 @@ class SideBar {
|
|
|
4488
5140
|
|
|
4489
5141
|
if( suboptions.action )
|
|
4490
5142
|
{
|
|
4491
|
-
const actionIcon = LX.makeIcon( suboptions.action.icon ?? "more-horizontal", suboptions.action.name );
|
|
5143
|
+
const actionIcon = LX.makeIcon( suboptions.action.icon ?? "more-horizontal", { title: suboptions.action.name } );
|
|
4492
5144
|
subentry.appendChild( actionIcon );
|
|
4493
5145
|
|
|
4494
5146
|
actionIcon.addEventListener( "click", (e) => {
|
|
@@ -4557,14 +5209,15 @@ class Widget {
|
|
|
4557
5209
|
static SEPARATOR = 26;
|
|
4558
5210
|
static KNOB = 27;
|
|
4559
5211
|
static SIZE = 28;
|
|
4560
|
-
static
|
|
4561
|
-
static
|
|
4562
|
-
static
|
|
4563
|
-
static
|
|
4564
|
-
static
|
|
4565
|
-
static
|
|
4566
|
-
static
|
|
4567
|
-
static
|
|
5212
|
+
static OTP = 29;
|
|
5213
|
+
static PAD = 30;
|
|
5214
|
+
static FORM = 31;
|
|
5215
|
+
static DIAL = 32;
|
|
5216
|
+
static COUNTER = 33;
|
|
5217
|
+
static TABLE = 34;
|
|
5218
|
+
static TABS = 35;
|
|
5219
|
+
static LABEL = 36;
|
|
5220
|
+
static BLANK = 37;
|
|
4568
5221
|
|
|
4569
5222
|
static NO_CONTEXT_TYPES = [
|
|
4570
5223
|
Widget.BUTTON,
|
|
@@ -4679,7 +5332,7 @@ class Widget {
|
|
|
4679
5332
|
|
|
4680
5333
|
_addResetProperty( container, callback ) {
|
|
4681
5334
|
|
|
4682
|
-
const domEl = LX.makeIcon( "rotate-left", "Reset" )
|
|
5335
|
+
const domEl = LX.makeIcon( "rotate-left", { title: "Reset" } )
|
|
4683
5336
|
domEl.style.display = "none";
|
|
4684
5337
|
domEl.style.marginRight = "6px";
|
|
4685
5338
|
domEl.style.marginLeft = "0";
|
|
@@ -5809,40 +6462,17 @@ class Button extends Widget {
|
|
|
5809
6462
|
super( Widget.BUTTON, name, null, options );
|
|
5810
6463
|
|
|
5811
6464
|
this.onGetValue = () => {
|
|
5812
|
-
return wValue.
|
|
6465
|
+
return wValue.querySelector( "input" )?.checked;
|
|
5813
6466
|
};
|
|
5814
6467
|
|
|
5815
6468
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
5816
6469
|
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
if( options.icon )
|
|
5820
|
-
{
|
|
5821
|
-
let icon = null;
|
|
5822
|
-
|
|
5823
|
-
// @legacy
|
|
5824
|
-
if( options.icon.includes( "fa-" ) )
|
|
5825
|
-
{
|
|
5826
|
-
icon = document.createElement( 'a' );
|
|
5827
|
-
icon.className = options.icon;
|
|
5828
|
-
}
|
|
5829
|
-
else
|
|
5830
|
-
{
|
|
5831
|
-
icon = LX.makeIcon( options.icon );
|
|
5832
|
-
}
|
|
5833
|
-
|
|
5834
|
-
wValue.prepend( icon );
|
|
5835
|
-
}
|
|
5836
|
-
else if( options.img )
|
|
5837
|
-
{
|
|
5838
|
-
let img = document.createElement( 'img' );
|
|
5839
|
-
img.src = options.img;
|
|
5840
|
-
wValue.prepend( img );
|
|
5841
|
-
}
|
|
5842
|
-
else
|
|
6470
|
+
if( !( options.swap ?? false ) )
|
|
5843
6471
|
{
|
|
5844
|
-
|
|
6472
|
+
return;
|
|
5845
6473
|
}
|
|
6474
|
+
|
|
6475
|
+
this.root.setState( newValue, skipCallback );
|
|
5846
6476
|
};
|
|
5847
6477
|
|
|
5848
6478
|
this.onResize = ( rect ) => {
|
|
@@ -5866,25 +6496,98 @@ class Button extends Widget {
|
|
|
5866
6496
|
wValue.classList.add( "selected" );
|
|
5867
6497
|
}
|
|
5868
6498
|
|
|
5869
|
-
|
|
6499
|
+
if( options.icon )
|
|
6500
|
+
{
|
|
6501
|
+
let icon = null;
|
|
6502
|
+
|
|
6503
|
+
// @legacy
|
|
6504
|
+
if( options.icon.includes( "fa-" ) )
|
|
6505
|
+
{
|
|
6506
|
+
icon = document.createElement( 'a' );
|
|
6507
|
+
icon.className = options.icon + " lexicon";
|
|
6508
|
+
}
|
|
6509
|
+
else
|
|
6510
|
+
{
|
|
6511
|
+
icon = LX.makeIcon( options.icon );
|
|
6512
|
+
}
|
|
6513
|
+
|
|
6514
|
+
wValue.prepend( icon );
|
|
6515
|
+
}
|
|
6516
|
+
else if( options.img )
|
|
6517
|
+
{
|
|
6518
|
+
let img = document.createElement( 'img' );
|
|
6519
|
+
img.src = options.img;
|
|
6520
|
+
wValue.prepend( img );
|
|
6521
|
+
}
|
|
6522
|
+
else
|
|
6523
|
+
{
|
|
6524
|
+
wValue.innerHTML = `<span>${ ( value || "" ) }</span>`;
|
|
6525
|
+
}
|
|
5870
6526
|
|
|
5871
6527
|
if( options.disabled )
|
|
5872
6528
|
{
|
|
5873
6529
|
wValue.setAttribute( "disabled", true );
|
|
5874
6530
|
}
|
|
5875
6531
|
|
|
5876
|
-
|
|
6532
|
+
let trigger = wValue;
|
|
6533
|
+
|
|
6534
|
+
if( options.swap )
|
|
6535
|
+
{
|
|
6536
|
+
wValue.classList.add( "swap" );
|
|
6537
|
+
wValue.querySelector( "a" ).classList.add( "swap-off" );
|
|
6538
|
+
|
|
6539
|
+
const input = document.createElement( "input" );
|
|
6540
|
+
input.type = "checkbox";
|
|
6541
|
+
wValue.prepend( input );
|
|
6542
|
+
|
|
6543
|
+
let swapIcon = null;
|
|
6544
|
+
|
|
6545
|
+
// @legacy
|
|
6546
|
+
if( options.swap.includes( "fa-" ) )
|
|
6547
|
+
{
|
|
6548
|
+
swapIcon = document.createElement( 'a' );
|
|
6549
|
+
swapIcon.className = options.swap + " swap-on lexicon";
|
|
6550
|
+
}
|
|
6551
|
+
else
|
|
6552
|
+
{
|
|
6553
|
+
swapIcon = LX.makeIcon( options.swap, { iconClass: "swap-on" } );
|
|
6554
|
+
}
|
|
6555
|
+
|
|
6556
|
+
wValue.appendChild( swapIcon );
|
|
6557
|
+
|
|
6558
|
+
this.root.swap = function( skipCallback ) {
|
|
6559
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6560
|
+
swapInput.checked = !swapInput.checked;
|
|
6561
|
+
if( !skipCallback )
|
|
6562
|
+
{
|
|
6563
|
+
trigger.click();
|
|
6564
|
+
}
|
|
6565
|
+
};
|
|
6566
|
+
|
|
6567
|
+
// Set if swap has to be performed
|
|
6568
|
+
this.root.setState = function( v, skipCallback ) {
|
|
6569
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6570
|
+
swapInput.checked = v;
|
|
6571
|
+
if( !skipCallback )
|
|
6572
|
+
{
|
|
6573
|
+
trigger.click();
|
|
6574
|
+
}
|
|
6575
|
+
};
|
|
6576
|
+
}
|
|
6577
|
+
|
|
6578
|
+
trigger.addEventListener( "click", e => {
|
|
5877
6579
|
if( options.selectable )
|
|
5878
6580
|
{
|
|
5879
6581
|
if( options.parent )
|
|
5880
6582
|
{
|
|
5881
|
-
options.parent.querySelectorAll(".lexbutton.selected").forEach(
|
|
6583
|
+
options.parent.querySelectorAll(".lexbutton.selected").forEach( b => { if( b == wValue ) return; b.classList.remove( "selected" ) } );
|
|
5882
6584
|
}
|
|
5883
6585
|
|
|
5884
6586
|
wValue.classList.toggle('selected');
|
|
5885
6587
|
}
|
|
5886
6588
|
|
|
5887
|
-
|
|
6589
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6590
|
+
this._trigger( new IEvent( name, swapInput?.checked ?? value, e ), callback );
|
|
5888
6591
|
});
|
|
5889
6592
|
|
|
5890
6593
|
if( options.tooltip )
|
|
@@ -6279,7 +6982,7 @@ class Select extends Widget {
|
|
|
6279
6982
|
|
|
6280
6983
|
const selectRoot = selectedOption.root;
|
|
6281
6984
|
const rect = selectRoot.getBoundingClientRect();
|
|
6282
|
-
const nestedDialog = parent.parentElement.closest( "dialog" );
|
|
6985
|
+
const nestedDialog = parent.parentElement.closest( "dialog" ) ?? parent.parentElement.closest( ".lexcolorpicker" );
|
|
6283
6986
|
|
|
6284
6987
|
// Manage vertical aspect
|
|
6285
6988
|
{
|
|
@@ -7329,31 +8032,52 @@ class ColorInput extends Widget {
|
|
|
7329
8032
|
|
|
7330
8033
|
constructor( name, value, callback, options = {} ) {
|
|
7331
8034
|
|
|
7332
|
-
|
|
8035
|
+
const useAlpha = options.useAlpha ??
|
|
8036
|
+
( ( value.constructor === Object && 'a' in value ) || ( value.constructor === String && [ 5, 9 ].includes( value.length ) ) );
|
|
8037
|
+
|
|
8038
|
+
const widgetColor = new Color( value );
|
|
8039
|
+
|
|
8040
|
+
// Force always hex internally
|
|
8041
|
+
value = useAlpha ? widgetColor.hex : widgetColor.hex.substr( 0, 7 );
|
|
7333
8042
|
|
|
7334
8043
|
super( Widget.COLOR, name, value, options );
|
|
7335
8044
|
|
|
7336
8045
|
this.onGetValue = () => {
|
|
7337
|
-
|
|
8046
|
+
const currentColor = new Color( value );
|
|
8047
|
+
return options.useRGB ? currentColor.rgb : value;
|
|
7338
8048
|
};
|
|
7339
8049
|
|
|
7340
8050
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
7341
8051
|
|
|
7342
|
-
|
|
8052
|
+
const newColor = new Color( newValue );
|
|
8053
|
+
|
|
8054
|
+
colorSampleRGB.style.color = value = newColor.hex.substr( 0, 7 );
|
|
8055
|
+
|
|
8056
|
+
if( useAlpha )
|
|
7343
8057
|
{
|
|
7344
|
-
|
|
8058
|
+
colorSampleAlpha.style.color = value = newColor.hex;
|
|
7345
8059
|
}
|
|
7346
8060
|
|
|
7347
8061
|
if( !this._skipTextUpdate )
|
|
7348
8062
|
{
|
|
7349
|
-
textWidget.set(
|
|
8063
|
+
textWidget.set( value, true, event );
|
|
7350
8064
|
}
|
|
7351
8065
|
|
|
7352
|
-
color.value = value = newValue;
|
|
7353
|
-
|
|
7354
8066
|
if( !skipCallback )
|
|
7355
8067
|
{
|
|
7356
|
-
|
|
8068
|
+
let retValue = value;
|
|
8069
|
+
|
|
8070
|
+
if( options.useRGB )
|
|
8071
|
+
{
|
|
8072
|
+
retValue = newColor.rgb;
|
|
8073
|
+
|
|
8074
|
+
if( !useAlpha )
|
|
8075
|
+
{
|
|
8076
|
+
delete retValue.a;
|
|
8077
|
+
}
|
|
8078
|
+
}
|
|
8079
|
+
|
|
8080
|
+
this._trigger( new IEvent( name, retValue, event ), callback );
|
|
7357
8081
|
}
|
|
7358
8082
|
};
|
|
7359
8083
|
|
|
@@ -7366,30 +8090,50 @@ class ColorInput extends Widget {
|
|
|
7366
8090
|
container.className = "lexcolor";
|
|
7367
8091
|
this.root.appendChild( container );
|
|
7368
8092
|
|
|
7369
|
-
let
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
8093
|
+
let sampleContainer = LX.makeContainer( ["18px", "18px"], "flex flex-row bg-contrast rounded overflow-hidden", "", container );
|
|
8094
|
+
sampleContainer.tabIndex = "1";
|
|
8095
|
+
sampleContainer.addEventListener( "click", e => {
|
|
8096
|
+
if( ( options.disabled ?? false ) )
|
|
8097
|
+
{
|
|
8098
|
+
return;
|
|
8099
|
+
}
|
|
8100
|
+
new ColorPicker( value, sampleContainer, {
|
|
8101
|
+
colorModel: options.useRGB ? "RGB" : "Hex",
|
|
8102
|
+
useAlpha,
|
|
8103
|
+
onChange: ( color ) => {
|
|
8104
|
+
this._fromColorPicker = true;
|
|
8105
|
+
this.set( color.hex );
|
|
8106
|
+
delete this._fromColorPicker;
|
|
8107
|
+
}
|
|
8108
|
+
} );
|
|
8109
|
+
} );
|
|
8110
|
+
|
|
8111
|
+
let colorSampleRGB = document.createElement( 'div' );
|
|
8112
|
+
colorSampleRGB.className = "lexcolorsample";
|
|
8113
|
+
colorSampleRGB.style.color = value;
|
|
8114
|
+
sampleContainer.appendChild( colorSampleRGB );
|
|
7376
8115
|
|
|
7377
|
-
|
|
8116
|
+
let colorSampleAlpha = null;
|
|
8117
|
+
|
|
8118
|
+
if( useAlpha )
|
|
7378
8119
|
{
|
|
7379
|
-
|
|
8120
|
+
colorSampleAlpha = document.createElement( 'div' );
|
|
8121
|
+
colorSampleAlpha.className = "lexcolorsample";
|
|
8122
|
+
colorSampleAlpha.style.color = value;
|
|
8123
|
+
sampleContainer.appendChild( colorSampleAlpha );
|
|
8124
|
+
}
|
|
8125
|
+
else
|
|
8126
|
+
{
|
|
8127
|
+
colorSampleRGB.style.width = "18px";
|
|
7380
8128
|
}
|
|
7381
8129
|
|
|
7382
|
-
|
|
7383
|
-
this.set( e.target.value, false, e );
|
|
7384
|
-
}, false );
|
|
7385
|
-
|
|
7386
|
-
const textWidget = new TextInput( null, color.value, v => {
|
|
8130
|
+
const textWidget = new TextInput( null, value, v => {
|
|
7387
8131
|
this._skipTextUpdate = true;
|
|
7388
8132
|
this.set( v );
|
|
7389
8133
|
delete this._skipTextUpdate;
|
|
7390
|
-
}, { width: "calc( 100% -
|
|
8134
|
+
}, { width: "calc( 100% - 24px )", disabled: options.disabled });
|
|
7391
8135
|
|
|
7392
|
-
textWidget.root.style.marginLeft = "
|
|
8136
|
+
textWidget.root.style.marginLeft = "6px";
|
|
7393
8137
|
container.appendChild( textWidget.root );
|
|
7394
8138
|
|
|
7395
8139
|
doAsync( this.onResize.bind( this ) );
|
|
@@ -7699,7 +8443,6 @@ class NumberInput extends Widget {
|
|
|
7699
8443
|
else if( e.altKey ) mult *= 0.1;
|
|
7700
8444
|
value = ( +vecinput.valueAsNumber + mult * dt );
|
|
7701
8445
|
this.set( value, false, e );
|
|
7702
|
-
// vecinput.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
|
|
7703
8446
|
}
|
|
7704
8447
|
|
|
7705
8448
|
e.stopPropagation();
|
|
@@ -8097,6 +8840,164 @@ class SizeInput extends Widget {
|
|
|
8097
8840
|
|
|
8098
8841
|
LX.SizeInput = SizeInput;
|
|
8099
8842
|
|
|
8843
|
+
/**
|
|
8844
|
+
* @class OTPInput
|
|
8845
|
+
* @description OTPInput Widget
|
|
8846
|
+
*/
|
|
8847
|
+
|
|
8848
|
+
class OTPInput extends Widget {
|
|
8849
|
+
|
|
8850
|
+
constructor( name, value, callback, options = {} ) {
|
|
8851
|
+
|
|
8852
|
+
const pattern = options.pattern ?? "xxx-xxx";
|
|
8853
|
+
const patternSize = ( pattern.match(/x/g) || [] ).length;
|
|
8854
|
+
|
|
8855
|
+
value = String( value );
|
|
8856
|
+
if( !value.length )
|
|
8857
|
+
{
|
|
8858
|
+
value = "x".repeat( patternSize );
|
|
8859
|
+
}
|
|
8860
|
+
|
|
8861
|
+
super( Widget.OTP, name, value, options );
|
|
8862
|
+
|
|
8863
|
+
this.onGetValue = () => {
|
|
8864
|
+
return +value;
|
|
8865
|
+
};
|
|
8866
|
+
|
|
8867
|
+
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
8868
|
+
|
|
8869
|
+
value = newValue;
|
|
8870
|
+
|
|
8871
|
+
_refreshInput( value );
|
|
8872
|
+
|
|
8873
|
+
if( !skipCallback )
|
|
8874
|
+
{
|
|
8875
|
+
this._trigger( new IEvent( name, +newValue, event ), callback );
|
|
8876
|
+
}
|
|
8877
|
+
};
|
|
8878
|
+
|
|
8879
|
+
this.onResize = ( rect ) => {
|
|
8880
|
+
const realNameWidth = ( this.root.domName?.offsetWidth ?? 0 );
|
|
8881
|
+
container.style.width = `calc( 100% - ${ realNameWidth }px)`;
|
|
8882
|
+
};
|
|
8883
|
+
|
|
8884
|
+
this.disabled = options.disabled ?? false;
|
|
8885
|
+
|
|
8886
|
+
const container = document.createElement( 'div' );
|
|
8887
|
+
container.className = "lexotp flex flex-row items-center";
|
|
8888
|
+
this.root.appendChild( container );
|
|
8889
|
+
|
|
8890
|
+
const groups = pattern.split( '-' );
|
|
8891
|
+
|
|
8892
|
+
const _refreshInput = ( valueString ) => {
|
|
8893
|
+
|
|
8894
|
+
container.innerHTML = "";
|
|
8895
|
+
|
|
8896
|
+
let itemsCount = 0;
|
|
8897
|
+
let activeSlot = 0;
|
|
8898
|
+
|
|
8899
|
+
for( let i = 0; i < groups.length; ++i )
|
|
8900
|
+
{
|
|
8901
|
+
const g = groups[ i ];
|
|
8902
|
+
|
|
8903
|
+
for( let j = 0; j < g.length; ++j )
|
|
8904
|
+
{
|
|
8905
|
+
let number = valueString[ itemsCount++ ];
|
|
8906
|
+
number = ( number == 'x' ? '' : number );
|
|
8907
|
+
|
|
8908
|
+
const slotDom = LX.makeContainer( ["36px", "30px"],
|
|
8909
|
+
"lexotpslot border-top border-bottom border-left px-3 cursor-text select-none font-medium outline-none", number, container );
|
|
8910
|
+
slotDom.tabIndex = "1";
|
|
8911
|
+
|
|
8912
|
+
if( this.disabled )
|
|
8913
|
+
{
|
|
8914
|
+
slotDom.classList.add( "disabled" );
|
|
8915
|
+
}
|
|
8916
|
+
|
|
8917
|
+
const otpIndex = itemsCount;
|
|
8918
|
+
|
|
8919
|
+
if( j == 0 )
|
|
8920
|
+
{
|
|
8921
|
+
slotDom.className += " rounded-l";
|
|
8922
|
+
}
|
|
8923
|
+
else if( j == ( g.length - 1 ) )
|
|
8924
|
+
{
|
|
8925
|
+
slotDom.className += " rounded-r border-right";
|
|
8926
|
+
}
|
|
8927
|
+
|
|
8928
|
+
slotDom.addEventListener( "click", () => {
|
|
8929
|
+
if( this.disabled ) { return; }
|
|
8930
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8931
|
+
const activeDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot ];
|
|
8932
|
+
activeDom.classList.add( "active" );
|
|
8933
|
+
activeDom.focus();
|
|
8934
|
+
} );
|
|
8935
|
+
|
|
8936
|
+
slotDom.addEventListener( "blur", () => {
|
|
8937
|
+
if( this.disabled ) { return; }
|
|
8938
|
+
doAsync( () => {
|
|
8939
|
+
if( container.contains( document.activeElement ) ) { return; }
|
|
8940
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8941
|
+
}, 10 );
|
|
8942
|
+
} );
|
|
8943
|
+
|
|
8944
|
+
slotDom.addEventListener( "keyup", e => {
|
|
8945
|
+
if( this.disabled ) { return; }
|
|
8946
|
+
if( !/[^0-9]+/g.test( e.key ) )
|
|
8947
|
+
{
|
|
8948
|
+
const number = e.key;
|
|
8949
|
+
console.assert( parseInt( number ) != NaN );
|
|
8950
|
+
|
|
8951
|
+
slotDom.innerHTML = number;
|
|
8952
|
+
valueString = valueString.substring( 0, otpIndex - 1 ) + number + valueString.substring( otpIndex );
|
|
8953
|
+
|
|
8954
|
+
const nexActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + 1 ];
|
|
8955
|
+
if( nexActiveDom )
|
|
8956
|
+
{
|
|
8957
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8958
|
+
nexActiveDom.classList.add( "active" );
|
|
8959
|
+
nexActiveDom.focus();
|
|
8960
|
+
activeSlot++;
|
|
8961
|
+
}
|
|
8962
|
+
else
|
|
8963
|
+
{
|
|
8964
|
+
this.set( valueString );
|
|
8965
|
+
}
|
|
8966
|
+
}
|
|
8967
|
+
else if( e.key == "ArrowLeft" || e.key == "ArrowRight" )
|
|
8968
|
+
{
|
|
8969
|
+
const dt = ( e.key == "ArrowLeft" ) ? -1 : 1;
|
|
8970
|
+
const newActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + dt ];
|
|
8971
|
+
if( newActiveDom )
|
|
8972
|
+
{
|
|
8973
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8974
|
+
newActiveDom.classList.add( "active" );
|
|
8975
|
+
newActiveDom.focus();
|
|
8976
|
+
activeSlot += dt;
|
|
8977
|
+
}
|
|
8978
|
+
}
|
|
8979
|
+
else if( e.key == "Enter" && !valueString.includes( 'x' ) )
|
|
8980
|
+
{
|
|
8981
|
+
this.set( valueString );
|
|
8982
|
+
}
|
|
8983
|
+
} );
|
|
8984
|
+
}
|
|
8985
|
+
|
|
8986
|
+
if( i < ( groups.length - 1 ) )
|
|
8987
|
+
{
|
|
8988
|
+
LX.makeContainer( ["auto", "auto"], "mx-2", `-`, container );
|
|
8989
|
+
}
|
|
8990
|
+
}
|
|
8991
|
+
|
|
8992
|
+
console.assert( itemsCount == valueString.length, "OTP Value/Pattern Mismatch!" )
|
|
8993
|
+
}
|
|
8994
|
+
|
|
8995
|
+
_refreshInput( value );
|
|
8996
|
+
}
|
|
8997
|
+
}
|
|
8998
|
+
|
|
8999
|
+
LX.OTPInput = OTPInput;
|
|
9000
|
+
|
|
8100
9001
|
/**
|
|
8101
9002
|
* @class Pad
|
|
8102
9003
|
* @description Pad Widget
|
|
@@ -8756,7 +9657,7 @@ class Table extends Widget {
|
|
|
8756
9657
|
|
|
8757
9658
|
if( this.customFilters )
|
|
8758
9659
|
{
|
|
8759
|
-
const icon = LX.makeIcon( "circle-plus",
|
|
9660
|
+
const icon = LX.makeIcon( "circle-plus", { svgClass: "sm" } );
|
|
8760
9661
|
|
|
8761
9662
|
for( let f of this.customFilters )
|
|
8762
9663
|
{
|
|
@@ -8781,7 +9682,6 @@ class Table extends Widget {
|
|
|
8781
9682
|
headerContainer.appendChild( customFilterBtn.root );
|
|
8782
9683
|
}
|
|
8783
9684
|
|
|
8784
|
-
// const resetIcon = LX.makeIcon( "xmark", null, "sm" );
|
|
8785
9685
|
this._resetCustomFiltersBtn = new Button(null, "resetButton", ( v ) => {
|
|
8786
9686
|
this.activeCustomFilters = {};
|
|
8787
9687
|
this.refresh();
|
|
@@ -8793,7 +9693,7 @@ class Table extends Widget {
|
|
|
8793
9693
|
|
|
8794
9694
|
if( this.toggleColumns )
|
|
8795
9695
|
{
|
|
8796
|
-
const icon = LX.makeIcon( "sliders" );
|
|
9696
|
+
const icon = LX.makeIcon( "sliders-large" );
|
|
8797
9697
|
const toggleColumnsBtn = new Button( "toggleColumnsBtn", icon.innerHTML + "View", (value, e) => {
|
|
8798
9698
|
const menuOptions = data.head.map( ( colName, idx ) => {
|
|
8799
9699
|
const item = {
|
|
@@ -8864,7 +9764,7 @@ class Table extends Widget {
|
|
|
8864
9764
|
for( const el of body.childNodes )
|
|
8865
9765
|
{
|
|
8866
9766
|
data.checkMap[ el.getAttribute( "rowId" ) ] = this.checked;
|
|
8867
|
-
el.querySelector( "input" ).checked = this.checked;
|
|
9767
|
+
el.querySelector( "input[type='checkbox']" ).checked = this.checked;
|
|
8868
9768
|
}
|
|
8869
9769
|
});
|
|
8870
9770
|
|
|
@@ -8876,7 +9776,7 @@ class Table extends Widget {
|
|
|
8876
9776
|
{
|
|
8877
9777
|
const th = document.createElement( 'th' );
|
|
8878
9778
|
th.innerHTML = `<span>${ headData }</span>`;
|
|
8879
|
-
th.querySelector( "span" ).appendChild( LX.makeIcon( "menu-arrows",
|
|
9779
|
+
th.querySelector( "span" ).appendChild( LX.makeIcon( "menu-arrows", { svgClass: "sm" } ) );
|
|
8880
9780
|
|
|
8881
9781
|
const idx = data.head.indexOf( headData );
|
|
8882
9782
|
if( this.centered && this.centered.indexOf( idx ) > -1 )
|
|
@@ -9078,10 +9978,20 @@ class Table extends Widget {
|
|
|
9078
9978
|
input.addEventListener( 'change', function() {
|
|
9079
9979
|
data.checkMap[ rowId ] = this.checked;
|
|
9080
9980
|
|
|
9981
|
+
const headInput = table.querySelector( "thead input[type='checkbox']" );
|
|
9982
|
+
|
|
9081
9983
|
if( !this.checked )
|
|
9082
9984
|
{
|
|
9083
|
-
|
|
9084
|
-
|
|
9985
|
+
headInput.checked = data.checkMap[ ":root" ] = false;
|
|
9986
|
+
}
|
|
9987
|
+
else
|
|
9988
|
+
{
|
|
9989
|
+
const rowInputs = Array.from( table.querySelectorAll( "tbody input[type='checkbox']" ) );
|
|
9990
|
+
const uncheckedRowInputs = rowInputs.filter( i => { return !i.checked; } );
|
|
9991
|
+
if( !uncheckedRowInputs.length )
|
|
9992
|
+
{
|
|
9993
|
+
headInput.checked = data.checkMap[ ":root" ] = true;
|
|
9994
|
+
}
|
|
9085
9995
|
}
|
|
9086
9996
|
});
|
|
9087
9997
|
|
|
@@ -9117,7 +10027,7 @@ class Table extends Widget {
|
|
|
9117
10027
|
|
|
9118
10028
|
if( action == "delete" )
|
|
9119
10029
|
{
|
|
9120
|
-
button = LX.makeIcon( "trash-can", "Delete Row" );
|
|
10030
|
+
button = LX.makeIcon( "trash-can", { title: "Delete Row" } );
|
|
9121
10031
|
button.addEventListener( 'click', function() {
|
|
9122
10032
|
// Don't need to refresh table..
|
|
9123
10033
|
data.body.splice( r, 1 );
|
|
@@ -9126,7 +10036,7 @@ class Table extends Widget {
|
|
|
9126
10036
|
}
|
|
9127
10037
|
else if( action == "menu" )
|
|
9128
10038
|
{
|
|
9129
|
-
button = LX.makeIcon( "more-horizontal", "Menu" );
|
|
10039
|
+
button = LX.makeIcon( "more-horizontal", { title: "Menu" } );
|
|
9130
10040
|
button.addEventListener( 'click', function( event ) {
|
|
9131
10041
|
if( !options.onMenuAction )
|
|
9132
10042
|
{
|
|
@@ -9142,7 +10052,7 @@ class Table extends Widget {
|
|
|
9142
10052
|
else // custom actions
|
|
9143
10053
|
{
|
|
9144
10054
|
console.assert( action.constructor == Object );
|
|
9145
|
-
button = LX.makeIcon( action.icon, action.title );
|
|
10055
|
+
button = LX.makeIcon( action.icon, { title: action.title } );
|
|
9146
10056
|
|
|
9147
10057
|
if( action.callback )
|
|
9148
10058
|
{
|
|
@@ -10192,6 +11102,22 @@ class Panel {
|
|
|
10192
11102
|
return this._attachWidget( widget );
|
|
10193
11103
|
}
|
|
10194
11104
|
|
|
11105
|
+
/**
|
|
11106
|
+
* @method addOTP
|
|
11107
|
+
* @param {String} name Widget name
|
|
11108
|
+
* @param {String} value Default numeric value in string format
|
|
11109
|
+
* @param {Function} callback Callback function on change
|
|
11110
|
+
* @param {Object} options:
|
|
11111
|
+
* hideName: Don't use name as label [false]
|
|
11112
|
+
* disabled: Make the widget disabled [false]
|
|
11113
|
+
* pattern: OTP numeric pattern
|
|
11114
|
+
*/
|
|
11115
|
+
|
|
11116
|
+
addOTP( name, value, callback, options = {} ) {
|
|
11117
|
+
const widget = new OTPInput( name, value, callback, options );
|
|
11118
|
+
return this._attachWidget( widget );
|
|
11119
|
+
}
|
|
11120
|
+
|
|
10195
11121
|
/**
|
|
10196
11122
|
* @method addPad
|
|
10197
11123
|
* @param {String} name Widget name
|
|
@@ -10424,7 +11350,7 @@ class Branch {
|
|
|
10424
11350
|
// add widgets
|
|
10425
11351
|
for( let w of this.widgets )
|
|
10426
11352
|
{
|
|
10427
|
-
p.root.appendChild( w.
|
|
11353
|
+
p.root.appendChild( w.root );
|
|
10428
11354
|
}
|
|
10429
11355
|
});
|
|
10430
11356
|
dialog.widgets = this.widgets;
|
|
@@ -10728,7 +11654,7 @@ class Dialog {
|
|
|
10728
11654
|
|
|
10729
11655
|
for( let w of that.widgets )
|
|
10730
11656
|
{
|
|
10731
|
-
branch.content.appendChild( w.
|
|
11657
|
+
branch.content.appendChild( w.root );
|
|
10732
11658
|
}
|
|
10733
11659
|
|
|
10734
11660
|
branch.widgets = that.widgets;
|
|
@@ -12369,7 +13295,7 @@ class AssetView {
|
|
|
12369
13295
|
|
|
12370
13296
|
this.rightPanel.addText(null, this.path.join('/'), null, {
|
|
12371
13297
|
inputClass: "nobg", disabled: true, signal: "@on_folder_change",
|
|
12372
|
-
style: { fontWeight: "600", fontSize: "15px" }
|
|
13298
|
+
style: { fontWeight: "600", fontSize: "15px" }
|
|
12373
13299
|
});
|
|
12374
13300
|
|
|
12375
13301
|
this.rightPanel.endLine();
|
|
@@ -13106,7 +14032,7 @@ Element.prototype.addClass = function( className ) {
|
|
|
13106
14032
|
}
|
|
13107
14033
|
|
|
13108
14034
|
Element.prototype.getComputedSize = function() {
|
|
13109
|
-
// Since we use "box-sizing: border-box" now,
|
|
14035
|
+
// Since we use "box-sizing: border-box" now,
|
|
13110
14036
|
// it's all included in offsetWidth/offsetHeight
|
|
13111
14037
|
return {
|
|
13112
14038
|
width: this.offsetWidth,
|
|
@@ -13248,6 +14174,7 @@ LX.ICONS = {
|
|
|
13248
14174
|
"copy": [448, 512, [], "regular", "M384 336l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L400 115.9 400 320c0 8.8-7.2 16-16 16zM192 384l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1L192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-32-48 0 0 32c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l32 0 0-48-32 0z"],
|
|
13249
14175
|
"paste": [512, 512, [], "regular", "M104.6 48L64 48C28.7 48 0 76.7 0 112L0 384c0 35.3 28.7 64 64 64l96 0 0-48-96 0c-8.8 0-16-7.2-16-16l0-272c0-8.8 7.2-16 16-16l16 0c0 17.7 14.3 32 32 32l72.4 0C202 108.4 227.6 96 256 96l62 0c-7.1-27.6-32.2-48-62-48l-40.6 0C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48zM144 56a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM448 464l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L464 243.9 464 448c0 8.8-7.2 16-16 16zM256 512l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9l-67.9-67.9c-9-9-21.2-14.1-33.9-14.1L256 128c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64z"],
|
|
13250
14176
|
"clipboard": [384, 512, [], "regular", "M280 64l40 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 128C0 92.7 28.7 64 64 64l40 0 9.6 0C121 27.5 153.3 0 192 0s71 27.5 78.4 64l9.6 0zM64 112c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l256 0c8.8 0 16-7.2 16-16l0-320c0-8.8-7.2-16-16-16l-16 0 0 24c0 13.3-10.7 24-24 24l-88 0-88 0c-13.3 0-24-10.7-24-24l0-24-16 0zm128-8a24 24 0 1 0 0-48 24 24 0 1 0 0 48z"],
|
|
14177
|
+
"eye-dropper": [512, 512, [], "solid", "M341.6 29.2L240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4L482.8 170.4c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6l0 42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480l42.4 0c21.2 0 41.6-8.4 56.6-23.4L309.4 335.9l-45.3-45.3L143.4 411.3c-3 3-7.1 4.7-11.3 4.7L96 416l0-36.1c0-4.2 1.7-8.3 4.7-11.3L221.4 247.9l-45.3-45.3L55.4 323.3z"],
|
|
13251
14178
|
"edit": [512, 512, [], "regular", "M441 58.9L453.1 71c9.4 9.4 9.4 24.6 0 33.9L424 134.1 377.9 88 407 58.9c9.4-9.4 24.6-9.4 33.9 0zM209.8 256.2L344 121.9 390.1 168 255.8 302.2c-2.9 2.9-6.5 5-10.4 6.1l-58.5 16.7 16.7-58.5c1.1-3.9 3.2-7.5 6.1-10.4zM373.1 25L175.8 222.2c-8.7 8.7-15 19.4-18.3 31.1l-28.6 100c-2.4 8.4-.1 17.4 6.1 23.6s15.2 8.5 23.6 6.1l100-28.6c11.8-3.4 22.5-9.7 31.1-18.3L487 138.9c28.1-28.1 28.1-73.7 0-101.8L474.9 25C446.8-3.1 401.2-3.1 373.1 25zM88 64C39.4 64 0 103.4 0 152L0 424c0 48.6 39.4 88 88 88l272 0c48.6 0 88-39.4 88-88l0-112c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 112c0 22.1-17.9 40-40 40L88 464c-22.1 0-40-17.9-40-40l0-272c0-22.1 17.9-40 40-40l112 0c13.3 0 24-10.7 24-24s-10.7-24-24-24L88 64z"],
|
|
13252
14179
|
"envelope": [512, 512, [], "regular", "M64 112c-8.8 0-16 7.2-16 16l0 22.1L220.5 291.7c20.7 17 50.4 17 71.1 0L464 150.1l0-22.1c0-8.8-7.2-16-16-16L64 112zM48 212.2L48 384c0 8.8 7.2 16 16 16l384 0c8.8 0 16-7.2 16-16l0-171.8L322 328.8c-38.4 31.5-93.7 31.5-132 0L48 212.2zM0 128C0 92.7 28.7 64 64 64l384 0c35.3 0 64 28.7 64 64l0 256c0 35.3-28.7 64-64 64L64 448c-35.3 0-64-28.7-64-64L0 128z"],
|
|
13253
14180
|
"envelope-open": [512, 512, [], "regular", "M255.4 48.2c.2-.1 .4-.2 .6-.2s.4 .1 .6 .2L460.6 194c2.1 1.5 3.4 3.9 3.4 6.5l0 13.6L291.5 355.7c-20.7 17-50.4 17-71.1 0L48 214.1l0-13.6c0-2.6 1.2-5 3.4-6.5L255.4 48.2zM48 276.2L190 392.8c38.4 31.5 93.7 31.5 132 0L464 276.2 464 456c0 4.4-3.6 8-8 8L56 464c-4.4 0-8-3.6-8-8l0-179.8zM256 0c-10.2 0-20.2 3.2-28.5 9.1L23.5 154.9C8.7 165.4 0 182.4 0 200.5L0 456c0 30.9 25.1 56 56 56l400 0c30.9 0 56-25.1 56-56l0-255.5c0-18.1-8.7-35.1-23.4-45.6L284.5 9.1C276.2 3.2 266.2 0 256 0z"],
|