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.js
CHANGED
|
@@ -12,7 +12,7 @@ console.warn( 'Script _build/lexgui.js_ is depracated and will be removed soon.
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
var LX = {
|
|
15
|
-
version: "0.5.
|
|
15
|
+
version: "0.5.7",
|
|
16
16
|
ready: false,
|
|
17
17
|
components: [], // Specific pre-build components
|
|
18
18
|
signals: {}, // Events and triggers
|
|
@@ -222,37 +222,141 @@ LX.getBase64Image = getBase64Image;
|
|
|
222
222
|
|
|
223
223
|
/**
|
|
224
224
|
* @method hexToRgb
|
|
225
|
-
* @description Convert a hexadecimal string to a valid RGB color
|
|
226
|
-
* @param {String}
|
|
225
|
+
* @description Convert a hexadecimal string to a valid RGB color
|
|
226
|
+
* @param {String} hex Hexadecimal color
|
|
227
227
|
*/
|
|
228
|
-
function hexToRgb(
|
|
228
|
+
function hexToRgb( hex )
|
|
229
229
|
{
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
const hexPattern = /^#(?:[A-Fa-f0-9]{3,4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/;
|
|
231
|
+
if( !hexPattern.test( hex ) )
|
|
232
|
+
{
|
|
233
|
+
throw( `Invalid Hex Color: ${ hex }` );
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
hex = hex.replace( /^#/, '' );
|
|
237
|
+
|
|
238
|
+
// Expand shorthand form (#RGB or #RGBA)
|
|
239
|
+
if( hex.length === 3 || hex.length === 4 )
|
|
240
|
+
{
|
|
241
|
+
hex = hex.split( '' ).map( c => c + c ).join( '' );
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const bigint = parseInt( hex, 16 );
|
|
245
|
+
|
|
246
|
+
const r = ( ( bigint >> ( hex.length === 8 ? 24 : 16 ) ) & 255 ) / 255;
|
|
247
|
+
const g = ( ( bigint >> ( hex.length === 8 ? 16 : 8 ) ) & 255 ) / 255;
|
|
248
|
+
const b = ( ( bigint >> ( hex.length === 8 ? 8 : 0 ) ) & 255 ) / 255;
|
|
249
|
+
const a = ( hex.length === 8 ? ( bigint & 255 ) : ( hex.length === 4 ? parseInt( hex.slice( -2 ), 16 ) : 255 ) ) / 255;
|
|
250
|
+
|
|
251
|
+
return { r, g, b, a };
|
|
234
252
|
}
|
|
235
253
|
|
|
236
254
|
LX.hexToRgb = hexToRgb;
|
|
237
255
|
|
|
256
|
+
/**
|
|
257
|
+
* @method hexToHsv
|
|
258
|
+
* @description Convert a hexadecimal string to HSV (0..360|0..1|0..1)
|
|
259
|
+
* @param {String} hexStr Hexadecimal color
|
|
260
|
+
*/
|
|
261
|
+
function hexToHsv( hexStr )
|
|
262
|
+
{
|
|
263
|
+
const rgb = hexToRgb( hexStr );
|
|
264
|
+
return rgbToHsv( rgb );
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
LX.hexToHsv = hexToHsv;
|
|
268
|
+
|
|
238
269
|
/**
|
|
239
270
|
* @method rgbToHex
|
|
240
|
-
* @description Convert a RGB color
|
|
241
|
-
* @param {
|
|
271
|
+
* @description Convert a RGB color to a hexadecimal string
|
|
272
|
+
* @param {Object} rgb Object containing RGB color
|
|
273
|
+
* @param {Number} scale Use 255 for 0..255 range or 1 for 0..1 range
|
|
242
274
|
*/
|
|
243
|
-
function rgbToHex( rgb )
|
|
275
|
+
function rgbToHex( rgb, scale = 255 )
|
|
244
276
|
{
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
277
|
+
const rgbArray = [ rgb.r, rgb.g, rgb.b ];
|
|
278
|
+
if( rgb.a != undefined ) rgbArray.push( rgb.a );
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
"#" +
|
|
282
|
+
rgbArray.map( c => {
|
|
283
|
+
c = Math.floor( c * scale );
|
|
284
|
+
const hex = c.toString(16);
|
|
285
|
+
return hex.length === 1 ? ( '0' + hex ) : hex;
|
|
286
|
+
}).join("")
|
|
287
|
+
);
|
|
252
288
|
}
|
|
253
289
|
|
|
254
290
|
LX.rgbToHex = rgbToHex;
|
|
255
291
|
|
|
292
|
+
/**
|
|
293
|
+
* @method rgbToCss
|
|
294
|
+
* @description Convert a RGB color (0..1) to a CSS color format
|
|
295
|
+
* @param {Object} rgb Object containing RGB color
|
|
296
|
+
*/
|
|
297
|
+
function rgbToCss( rgb )
|
|
298
|
+
{
|
|
299
|
+
return { r: Math.floor( rgb.r * 255 ), g: Math.floor( rgb.g * 255 ), b: Math.floor( rgb.b * 255 ), a: rgb.a };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
LX.rgbToCss = rgbToCss;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @method rgbToHsv
|
|
306
|
+
* @description Convert a RGB color (0..1) array to HSV (0..360|0..1|0..1)
|
|
307
|
+
* @param {Object} rgb Array containing R, G, B
|
|
308
|
+
*/
|
|
309
|
+
function rgbToHsv( rgb )
|
|
310
|
+
{
|
|
311
|
+
let { r, g, b, a } = rgb;
|
|
312
|
+
a = a ?? 1;
|
|
313
|
+
|
|
314
|
+
const max = Math.max(r, g, b);
|
|
315
|
+
const min = Math.min(r, g, b);
|
|
316
|
+
const d = max - min;
|
|
317
|
+
let h = 0;
|
|
318
|
+
|
|
319
|
+
if (d !== 0) {
|
|
320
|
+
if (max === r) { h = ((g - b) / d) % 6 }
|
|
321
|
+
else if (max === g) { h = (b - r) / d + 2 }
|
|
322
|
+
else { h = (r - g) / d + 4 }
|
|
323
|
+
h *= 60
|
|
324
|
+
if (h < 0) { h += 360 }
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const s = max === 0 ? 0 : (d / max);
|
|
328
|
+
const v = max;
|
|
329
|
+
|
|
330
|
+
return { h, s, v, a };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
LX.rgbToHsv = rgbToHsv;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @method hsvToRgb
|
|
337
|
+
* @description Convert an HSV color (0..360|0..1|0..1) array to RGB (0..1|0..255)
|
|
338
|
+
* @param {Array} hsv Array containing H, S, V
|
|
339
|
+
*/
|
|
340
|
+
function hsvToRgb( hsv )
|
|
341
|
+
{
|
|
342
|
+
const { h, s, v, a } = hsv;
|
|
343
|
+
const c = v * s;
|
|
344
|
+
const x = c * (1 - Math.abs( ( (h / 60) % 2 ) - 1) )
|
|
345
|
+
const m = v - c;
|
|
346
|
+
let r = 0, g = 0, b = 0;
|
|
347
|
+
|
|
348
|
+
if( h < 60 ) { r = c; g = x; b = 0; }
|
|
349
|
+
else if ( h < 120 ) { r = x; g = c; b = 0; }
|
|
350
|
+
else if ( h < 180 ) { r = 0; g = c; b = x; }
|
|
351
|
+
else if ( h < 240 ) { r = 0; g = x; b = c; }
|
|
352
|
+
else if ( h < 300 ) { r = x; g = 0; b = c; }
|
|
353
|
+
else { r = c; g = 0; b = x; }
|
|
354
|
+
|
|
355
|
+
return { r: ( r + m ), g: ( g + m ), b: ( b + m ), a };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
LX.hsvToRgb = hsvToRgb;
|
|
359
|
+
|
|
256
360
|
/**
|
|
257
361
|
* @method measureRealWidth
|
|
258
362
|
* @description Measure the pixel width of a text
|
|
@@ -584,18 +688,60 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
584
688
|
|
|
585
689
|
LX.makeCodeSnippet = makeCodeSnippet;
|
|
586
690
|
|
|
691
|
+
/**
|
|
692
|
+
* @method makeKbd
|
|
693
|
+
* @description Kbd element to display a keyboard key.
|
|
694
|
+
* @param {Array} keys
|
|
695
|
+
* @param {String} extraClass
|
|
696
|
+
*/
|
|
697
|
+
function makeKbd( keys, extraClass = "" )
|
|
698
|
+
{
|
|
699
|
+
const specialKeys = {
|
|
700
|
+
"Ctrl": '⌃',
|
|
701
|
+
"Enter": '↩',
|
|
702
|
+
"Shift": '⇧',
|
|
703
|
+
"CapsLock": '⇪',
|
|
704
|
+
"Meta": '⌘',
|
|
705
|
+
"Option": '⌥',
|
|
706
|
+
"Alt": '⌥',
|
|
707
|
+
"Tab": '⇥',
|
|
708
|
+
"ArrowUp": '↑',
|
|
709
|
+
"ArrowDown": '↓',
|
|
710
|
+
"ArrowLeft": '←',
|
|
711
|
+
"ArrowRight": '→',
|
|
712
|
+
"Space": '␣'
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
const kbd = LX.makeContainer( ["auto", "auto"], "flex flex-row ml-auto" );
|
|
716
|
+
|
|
717
|
+
for( const k of keys )
|
|
718
|
+
{
|
|
719
|
+
LX.makeContainer( ["auto", "auto"], "self-center text-xs fg-secondary select-none", specialKeys[ k ] ?? k, kbd );
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return kbd;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
LX.makeKbd = makeKbd;
|
|
726
|
+
|
|
587
727
|
/**
|
|
588
728
|
* @method makeIcon
|
|
589
729
|
* @description Gets an SVG element using one of LX.ICONS
|
|
590
730
|
* @param {String} iconName
|
|
591
|
-
* @param {
|
|
592
|
-
*
|
|
731
|
+
* @param {Object} options
|
|
732
|
+
* iconTitle
|
|
733
|
+
* extraClass
|
|
734
|
+
* svgClass
|
|
593
735
|
*/
|
|
594
|
-
function makeIcon( iconName,
|
|
736
|
+
function makeIcon( iconName, options = { } )
|
|
595
737
|
{
|
|
596
738
|
let data = LX.ICONS[ iconName ];
|
|
597
739
|
console.assert( data, `No icon named _${ iconName }_` );
|
|
598
740
|
|
|
741
|
+
const iconTitle = options.iconTitle;
|
|
742
|
+
const iconClass = options.iconClass;
|
|
743
|
+
const svgClass = options.svgClass;
|
|
744
|
+
|
|
599
745
|
// Just another name for the same icon..
|
|
600
746
|
if( data.constructor == String )
|
|
601
747
|
{
|
|
@@ -605,9 +751,9 @@ function makeIcon( iconName, iconTitle, extraClass = "" )
|
|
|
605
751
|
const svg = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
|
|
606
752
|
svg.setAttribute( "viewBox", `0 0 ${ data[ 0 ] } ${ data[ 1 ] }` );
|
|
607
753
|
|
|
608
|
-
if(
|
|
754
|
+
if( svgClass )
|
|
609
755
|
{
|
|
610
|
-
svg.classList.add(
|
|
756
|
+
svg.classList.add( svgClass );
|
|
611
757
|
}
|
|
612
758
|
|
|
613
759
|
if( data[ 5 ] )
|
|
@@ -635,7 +781,7 @@ function makeIcon( iconName, iconTitle, extraClass = "" )
|
|
|
635
781
|
|
|
636
782
|
const icon = document.createElement( "a" );
|
|
637
783
|
icon.title = iconTitle ?? "";
|
|
638
|
-
icon.className = "lexicon " +
|
|
784
|
+
icon.className = "lexicon " + ( iconClass ?? "" );
|
|
639
785
|
icon.appendChild( svg );
|
|
640
786
|
|
|
641
787
|
return icon;
|
|
@@ -722,7 +868,7 @@ function registerCommandbarEntry( name, callback )
|
|
|
722
868
|
|
|
723
869
|
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
724
870
|
|
|
725
|
-
//
|
|
871
|
+
// Utils classes
|
|
726
872
|
|
|
727
873
|
class vec2 {
|
|
728
874
|
|
|
@@ -750,6 +896,77 @@ class vec2 {
|
|
|
750
896
|
|
|
751
897
|
LX.vec2 = vec2;
|
|
752
898
|
|
|
899
|
+
class Color {
|
|
900
|
+
|
|
901
|
+
constructor( value ) {
|
|
902
|
+
|
|
903
|
+
Object.defineProperty( Color.prototype, "rgb", {
|
|
904
|
+
get: function() { return this._rgb; },
|
|
905
|
+
set: function( v ) { this._fromRGB( v ) }, enumerable: true, configurable: true
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
Object.defineProperty( Color.prototype, "hex", {
|
|
909
|
+
get: function() { return this._hex; },
|
|
910
|
+
set: function( v ) { this._fromHex( v ) }, enumerable: true, configurable: true
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
Object.defineProperty( Color.prototype, "hsv", {
|
|
914
|
+
get: function() { return this._hsv; },
|
|
915
|
+
set: function( v ) { this._fromHSV( v ) }, enumerable: true, configurable: true
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
this.set( value );
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
set( value ) {
|
|
922
|
+
|
|
923
|
+
if ( typeof value === 'string' && value.startsWith( '#' ) )
|
|
924
|
+
{
|
|
925
|
+
this._fromHex( value );
|
|
926
|
+
}
|
|
927
|
+
else if( 'r' in value && 'g' in value && 'b' in value)
|
|
928
|
+
{
|
|
929
|
+
value.a = value.a ?? 1.0;
|
|
930
|
+
this._fromRGB( value );
|
|
931
|
+
}
|
|
932
|
+
else if( 'h' in value && 's' in value && 'v' in value )
|
|
933
|
+
{
|
|
934
|
+
value.a = value.a ?? 1.0;
|
|
935
|
+
this._fromHSV( value );
|
|
936
|
+
}
|
|
937
|
+
else
|
|
938
|
+
{
|
|
939
|
+
throw( "Bad color model!", value );
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
setHSV( hsv ) { this._fromHSV( hsv ); }
|
|
944
|
+
setRGB( rgb ) { this._fromRGB( rgb ); }
|
|
945
|
+
setHex( hex ) { this._fromHex( hex ); }
|
|
946
|
+
|
|
947
|
+
_fromHex( hex ) {
|
|
948
|
+
this._fromRGB( hexToRgb( hex ) );
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
_fromRGB( rgb ) {
|
|
952
|
+
this._rgb = rgb;
|
|
953
|
+
this._hsv = rgbToHsv( rgb );
|
|
954
|
+
this._hex = rgbToHex( rgb );
|
|
955
|
+
this.css = rgbToCss( this._rgb );
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
_fromHSV( hsv ) {
|
|
959
|
+
this._hsv = hsv;
|
|
960
|
+
this._rgb = hsvToRgb( hsv );
|
|
961
|
+
this._hex = rgbToHex( this._rgb );
|
|
962
|
+
this.css = rgbToCss( this._rgb );
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
LX.Color = Color;
|
|
967
|
+
|
|
968
|
+
// Command bar creation
|
|
969
|
+
|
|
753
970
|
function _createCommandbar( root )
|
|
754
971
|
{
|
|
755
972
|
let commandbar = document.createElement( "dialog" );
|
|
@@ -1163,6 +1380,19 @@ function init( options = { } )
|
|
|
1163
1380
|
|
|
1164
1381
|
LX.init = init;
|
|
1165
1382
|
|
|
1383
|
+
/**
|
|
1384
|
+
* @method setStrictViewport
|
|
1385
|
+
* @param {Boolean} value
|
|
1386
|
+
*/
|
|
1387
|
+
|
|
1388
|
+
function setStrictViewport( value )
|
|
1389
|
+
{
|
|
1390
|
+
this.usingStrictViewport = value ?? true;
|
|
1391
|
+
document.documentElement.setAttribute( "data-strictVP", ( this.usingStrictViewport ) ? "true" : "false" );
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
LX.setStrictViewport = setStrictViewport;
|
|
1395
|
+
|
|
1166
1396
|
/**
|
|
1167
1397
|
* @method setCommandbarState
|
|
1168
1398
|
* @param {Boolean} value
|
|
@@ -1807,6 +2037,13 @@ class DropdownMenu {
|
|
|
1807
2037
|
submenuIcon.className = "fa-solid fa-angle-right fa-xs";
|
|
1808
2038
|
menuItem.appendChild( submenuIcon );
|
|
1809
2039
|
}
|
|
2040
|
+
else if( item.kbd )
|
|
2041
|
+
{
|
|
2042
|
+
item.kbd = [].concat( item.kbd );
|
|
2043
|
+
|
|
2044
|
+
const kbd = LX.makeKbd( item.kbd );
|
|
2045
|
+
menuItem.appendChild( kbd );
|
|
2046
|
+
}
|
|
1810
2047
|
|
|
1811
2048
|
if( item.icon )
|
|
1812
2049
|
{
|
|
@@ -1844,39 +2081,504 @@ class DropdownMenu {
|
|
|
1844
2081
|
} );
|
|
1845
2082
|
}
|
|
1846
2083
|
|
|
1847
|
-
menuItem.addEventListener("mouseover", e => {
|
|
2084
|
+
menuItem.addEventListener("mouseover", e => {
|
|
2085
|
+
|
|
2086
|
+
let path = menuItem.id;
|
|
2087
|
+
let p = parentDom;
|
|
2088
|
+
|
|
2089
|
+
while( p )
|
|
2090
|
+
{
|
|
2091
|
+
path += "/" + p.id;
|
|
2092
|
+
p = p.currentParent?.parentElement;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => {
|
|
2096
|
+
if( !path.includes( m.id ) )
|
|
2097
|
+
{
|
|
2098
|
+
m.currentParent.built = false;
|
|
2099
|
+
m.remove();
|
|
2100
|
+
}
|
|
2101
|
+
} );
|
|
2102
|
+
|
|
2103
|
+
if( item.submenu )
|
|
2104
|
+
{
|
|
2105
|
+
if( menuItem.built )
|
|
2106
|
+
{
|
|
2107
|
+
return;
|
|
2108
|
+
}
|
|
2109
|
+
menuItem.built = true;
|
|
2110
|
+
this._create( item.submenu, menuItem );
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
e.stopPropagation();
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
_adjustPosition() {
|
|
2119
|
+
|
|
2120
|
+
const position = [ 0, 0 ];
|
|
2121
|
+
|
|
2122
|
+
// Place menu using trigger position and user options
|
|
2123
|
+
{
|
|
2124
|
+
const rect = this._trigger.getBoundingClientRect();
|
|
2125
|
+
|
|
2126
|
+
let alignWidth = true;
|
|
2127
|
+
|
|
2128
|
+
switch( this.side )
|
|
2129
|
+
{
|
|
2130
|
+
case "left":
|
|
2131
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
2132
|
+
alignWidth = false;
|
|
2133
|
+
break;
|
|
2134
|
+
case "right":
|
|
2135
|
+
position[ 0 ] += ( rect.x + rect.width );
|
|
2136
|
+
alignWidth = false;
|
|
2137
|
+
break;
|
|
2138
|
+
case "top":
|
|
2139
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
2140
|
+
alignWidth = true;
|
|
2141
|
+
break;
|
|
2142
|
+
case "bottom":
|
|
2143
|
+
position[ 1 ] += ( rect.y + rect.height );
|
|
2144
|
+
alignWidth = true;
|
|
2145
|
+
break;
|
|
2146
|
+
default:
|
|
2147
|
+
break;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
switch( this.align )
|
|
2151
|
+
{
|
|
2152
|
+
case "start":
|
|
2153
|
+
if( alignWidth ) { position[ 0 ] += rect.x; }
|
|
2154
|
+
else { position[ 1 ] += rect.y; }
|
|
2155
|
+
break;
|
|
2156
|
+
case "center":
|
|
2157
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - this.root.offsetWidth * 0.5; }
|
|
2158
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - this.root.offsetHeight * 0.5; }
|
|
2159
|
+
break;
|
|
2160
|
+
case "end":
|
|
2161
|
+
if( alignWidth ) { position[ 0 ] += rect.x - this.root.offsetWidth + rect.width; }
|
|
2162
|
+
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
2163
|
+
break;
|
|
2164
|
+
default:
|
|
2165
|
+
break;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
if( this.avoidCollisions )
|
|
2170
|
+
{
|
|
2171
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - this.root.offsetWidth - this._windowPadding );
|
|
2172
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - this.root.offsetHeight - this._windowPadding );
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
this.root.style.left = `${ position[ 0 ] }px`;
|
|
2176
|
+
this.root.style.top = `${ position[ 1 ] }px`;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
_addSeparator( parent ) {
|
|
2180
|
+
const separator = document.createElement('div');
|
|
2181
|
+
separator.className = "separator";
|
|
2182
|
+
parent = parent ?? this.root;
|
|
2183
|
+
parent.appendChild( separator );
|
|
2184
|
+
}
|
|
2185
|
+
};
|
|
2186
|
+
|
|
2187
|
+
LX.DropdownMenu = DropdownMenu;
|
|
2188
|
+
|
|
2189
|
+
/**
|
|
2190
|
+
* @class ColorPicker
|
|
2191
|
+
*/
|
|
2192
|
+
|
|
2193
|
+
class ColorPicker {
|
|
2194
|
+
|
|
2195
|
+
static currentPicker = false;
|
|
2196
|
+
|
|
2197
|
+
constructor( hexValue, trigger, options = {} ) {
|
|
2198
|
+
|
|
2199
|
+
console.assert( trigger, "ColorPicker needs a DOM element as trigger!" );
|
|
2200
|
+
|
|
2201
|
+
this._windowPadding = 4;
|
|
2202
|
+
this.side = options.side ?? "bottom";
|
|
2203
|
+
this.align = options.align ?? "center";
|
|
2204
|
+
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
2205
|
+
this.colorModel = options.colorModel ?? "Hex";
|
|
2206
|
+
this.useAlpha = options.useAlpha ?? false;
|
|
2207
|
+
this.callback = options.onChange;
|
|
2208
|
+
|
|
2209
|
+
if( !this.callback )
|
|
2210
|
+
{
|
|
2211
|
+
console.warn( "Define a callback in _options.onChange_ to allow getting new Color values!" );
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
if( ColorPicker.currentPicker )
|
|
2215
|
+
{
|
|
2216
|
+
ColorPicker.currentPicker.destroy();
|
|
2217
|
+
return;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
this._trigger = trigger;
|
|
2221
|
+
trigger.classList.add( "triggered" );
|
|
2222
|
+
trigger.picker = this;
|
|
2223
|
+
|
|
2224
|
+
this.root = document.createElement( "div" );
|
|
2225
|
+
this.root.tabIndex = "1";
|
|
2226
|
+
this.root.className = "lexcolorpicker";
|
|
2227
|
+
this.root.dataset["side"] = this.side;
|
|
2228
|
+
LX.root.appendChild( this.root );
|
|
2229
|
+
|
|
2230
|
+
this.root.addEventListener( "keydown", (e) => {
|
|
2231
|
+
if( e.key == "Escape" )
|
|
2232
|
+
{
|
|
2233
|
+
e.preventDefault();
|
|
2234
|
+
e.stopPropagation();
|
|
2235
|
+
this.destroy();
|
|
2236
|
+
}
|
|
2237
|
+
} )
|
|
2238
|
+
|
|
2239
|
+
ColorPicker.currentPicker = this;
|
|
2240
|
+
|
|
2241
|
+
this.markerHalfSize = 8;
|
|
2242
|
+
this.markerSize = this.markerHalfSize * 2;
|
|
2243
|
+
this.currentColor = new Color( hexValue );
|
|
2244
|
+
|
|
2245
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2246
|
+
|
|
2247
|
+
// Intensity, Sat
|
|
2248
|
+
this.colorPickerBackground = document.createElement( 'div' );
|
|
2249
|
+
this.colorPickerBackground.className = "lexcolorpickerbg";
|
|
2250
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2251
|
+
this.root.appendChild( this.colorPickerBackground );
|
|
2252
|
+
|
|
2253
|
+
this.intSatMarker = document.createElement( 'div' );
|
|
2254
|
+
this.intSatMarker.className = "lexcolormarker";
|
|
2255
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
2256
|
+
this.colorPickerBackground.appendChild( this.intSatMarker );
|
|
2257
|
+
|
|
2258
|
+
doAsync( this._svToPosition.bind( this, this.currentColor.hsv.s, this.currentColor.hsv.v ) );
|
|
2259
|
+
|
|
2260
|
+
let innerMouseDown = e => {
|
|
2261
|
+
var doc = this.root.ownerDocument;
|
|
2262
|
+
doc.addEventListener( 'mousemove', innerMouseMove );
|
|
2263
|
+
doc.addEventListener( 'mouseup', innerMouseUp );
|
|
2264
|
+
document.body.classList.add( 'noevents' );
|
|
2265
|
+
e.stopImmediatePropagation();
|
|
2266
|
+
e.stopPropagation();
|
|
2267
|
+
|
|
2268
|
+
const currentLeft = ( e.offsetX - this.markerHalfSize );
|
|
2269
|
+
this.intSatMarker.style.left = currentLeft + "px";
|
|
2270
|
+
const currentTop = ( e.offsetY - this.markerHalfSize );
|
|
2271
|
+
this.intSatMarker.style.top = currentTop + "px";
|
|
2272
|
+
this._positionToSv( currentLeft, currentTop );
|
|
2273
|
+
this._updateColorValue();
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
let innerMouseMove = e => {
|
|
2277
|
+
const dX = e.movementX;
|
|
2278
|
+
const dY = e.movementY;
|
|
2279
|
+
|
|
2280
|
+
const rect = this.colorPickerBackground.getBoundingClientRect();
|
|
2281
|
+
const mouseX = e.offsetX - rect.x;
|
|
2282
|
+
const mouseY = e.offsetY - rect.y;
|
|
2283
|
+
|
|
2284
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerBackground.offsetWidth || dX > 0 ) )
|
|
2285
|
+
{
|
|
2286
|
+
this.intSatMarker.style.left = LX.clamp( parseInt( this.intSatMarker.style.left ) + dX, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) + "px";
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
if ( dY != 0 && ( mouseY >= 0 || dY < 0 ) && ( mouseY < this.colorPickerBackground.offsetHeight || dY > 0 ) )
|
|
2290
|
+
{
|
|
2291
|
+
this.intSatMarker.style.top = LX.clamp( parseInt( this.intSatMarker.style.top ) + dY, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) + "px";
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
this._positionToSv( parseInt( this.intSatMarker.style.left ), parseInt( this.intSatMarker.style.top ) );
|
|
2295
|
+
this._updateColorValue();
|
|
2296
|
+
|
|
2297
|
+
e.stopPropagation();
|
|
2298
|
+
e.preventDefault();
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
let innerMouseUp = e => {
|
|
2302
|
+
var doc = this.root.ownerDocument;
|
|
2303
|
+
doc.removeEventListener( 'mousemove', innerMouseMove );
|
|
2304
|
+
doc.removeEventListener( 'mouseup', innerMouseUp );
|
|
2305
|
+
document.body.classList.remove( 'noevents' );
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
this.colorPickerBackground.addEventListener( "mousedown", innerMouseDown );
|
|
2309
|
+
|
|
2310
|
+
const hueAlphaContainer = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1 items-center", "", this.root );
|
|
2311
|
+
|
|
2312
|
+
if( window.EyeDropper )
|
|
2313
|
+
{
|
|
2314
|
+
hueAlphaContainer.appendChild( new Button(null, "eyedrop", async () => {
|
|
2315
|
+
const eyeDropper = new EyeDropper()
|
|
2316
|
+
try {
|
|
2317
|
+
const result = await eyeDropper.open();
|
|
2318
|
+
this.fromHexColor( result.sRGBHex );
|
|
2319
|
+
} catch ( err ) {
|
|
2320
|
+
// console.error("EyeDropper cancelled or failed: ", err)
|
|
2321
|
+
}
|
|
2322
|
+
}, { icon: "eye-dropper", buttonClass: "bg-none", title: "Sample Color" }).root );
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
const innerHueAlpha = LX.makeContainer( ["100%", "100%"], "flex flex-col gap-2", "", hueAlphaContainer );
|
|
2326
|
+
|
|
2327
|
+
// Hue
|
|
2328
|
+
this.colorPickerTracker = document.createElement( 'div' );
|
|
2329
|
+
this.colorPickerTracker.className = "lexhuetracker";
|
|
2330
|
+
innerHueAlpha.appendChild( this.colorPickerTracker );
|
|
2331
|
+
|
|
2332
|
+
this.hueMarker = document.createElement( 'div' );
|
|
2333
|
+
this.hueMarker.className = "lexcolormarker";
|
|
2334
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2335
|
+
this.colorPickerTracker.appendChild( this.hueMarker );
|
|
2336
|
+
|
|
2337
|
+
doAsync( () => {
|
|
2338
|
+
const hueLeft = LX.remapRange( this.currentColor.hsv.h, 0, 360, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2339
|
+
this.hueMarker.style.left = hueLeft + "px";
|
|
2340
|
+
} );
|
|
2341
|
+
|
|
2342
|
+
const _fromHueX = ( hueX ) => {
|
|
2343
|
+
this.hueMarker.style.left = hueX + "px";
|
|
2344
|
+
this.currentColor.hsv.h = LX.remapRange( hueX, 0, this.colorPickerTracker.offsetWidth - this.markerSize, 0, 360 );
|
|
2345
|
+
|
|
2346
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2347
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2348
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2349
|
+
this._updateColorValue();
|
|
2350
|
+
};
|
|
2351
|
+
|
|
2352
|
+
let innerMouseDownHue = e => {
|
|
2353
|
+
const doc = this.root.ownerDocument;
|
|
2354
|
+
doc.addEventListener( 'mousemove', innerMouseMoveHue );
|
|
2355
|
+
doc.addEventListener( 'mouseup', innerMouseUpHue );
|
|
2356
|
+
document.body.classList.add( 'noevents' );
|
|
2357
|
+
e.stopImmediatePropagation();
|
|
2358
|
+
e.stopPropagation();
|
|
2359
|
+
|
|
2360
|
+
const hueX = clamp( e.offsetX - this.markerHalfSize, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2361
|
+
_fromHueX( hueX );
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
let innerMouseMoveHue = e => {
|
|
2365
|
+
let dX = e.movementX;
|
|
2366
|
+
|
|
2367
|
+
const rect = this.colorPickerTracker.getBoundingClientRect();
|
|
2368
|
+
const mouseX = e.offsetX - rect.x;
|
|
2369
|
+
|
|
2370
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerTracker.offsetWidth || dX > 0 ) )
|
|
2371
|
+
{
|
|
2372
|
+
const hueX = LX.clamp( parseInt( this.hueMarker.style.left ) + dX, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2373
|
+
_fromHueX( hueX )
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
e.stopPropagation();
|
|
2377
|
+
e.preventDefault();
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
let innerMouseUpHue = e => {
|
|
2381
|
+
var doc = this.root.ownerDocument;
|
|
2382
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveHue );
|
|
2383
|
+
doc.removeEventListener( 'mouseup', innerMouseUpHue );
|
|
2384
|
+
document.body.classList.remove( 'noevents' );
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
this.colorPickerTracker.addEventListener( "mousedown", innerMouseDownHue );
|
|
2388
|
+
|
|
2389
|
+
// Alpha
|
|
2390
|
+
if( this.useAlpha )
|
|
2391
|
+
{
|
|
2392
|
+
this.alphaTracker = document.createElement( 'div' );
|
|
2393
|
+
this.alphaTracker.className = "lexalphatracker";
|
|
2394
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b })`;
|
|
2395
|
+
innerHueAlpha.appendChild( this.alphaTracker );
|
|
2396
|
+
|
|
2397
|
+
this.alphaMarker = document.createElement( 'div' );
|
|
2398
|
+
this.alphaMarker.className = "lexcolormarker";
|
|
2399
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2400
|
+
this.alphaTracker.appendChild( this.alphaMarker );
|
|
2401
|
+
|
|
2402
|
+
doAsync( () => {
|
|
2403
|
+
const alphaLeft = LX.remapRange( this.currentColor.hsv.a, 0, 1, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2404
|
+
this.alphaMarker.style.left = alphaLeft + "px";
|
|
2405
|
+
} );
|
|
2406
|
+
|
|
2407
|
+
const _fromAlphaX = ( alphaX ) => {
|
|
2408
|
+
this.alphaMarker.style.left = alphaX + "px";
|
|
2409
|
+
this.currentColor.hsv.a = LX.remapRange( alphaX, 0, this.alphaTracker.offsetWidth - this.markerSize, 0, 1 );
|
|
2410
|
+
this._updateColorValue();
|
|
2411
|
+
// Update alpha marker once the color is updated
|
|
2412
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2413
|
+
};
|
|
2414
|
+
|
|
2415
|
+
let innerMouseDownAlpha = e => {
|
|
2416
|
+
const doc = this.root.ownerDocument;
|
|
2417
|
+
doc.addEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2418
|
+
doc.addEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2419
|
+
document.body.classList.add( 'noevents' );
|
|
2420
|
+
e.stopImmediatePropagation();
|
|
2421
|
+
e.stopPropagation();
|
|
2422
|
+
const alphaX = clamp( e.offsetX - this.markerHalfSize, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2423
|
+
_fromAlphaX( alphaX );
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
let innerMouseMoveAlpha = e => {
|
|
2427
|
+
let dX = e.movementX;
|
|
2428
|
+
|
|
2429
|
+
const rect = this.alphaTracker.getBoundingClientRect();
|
|
2430
|
+
const mouseX = e.offsetX - rect.x;
|
|
2431
|
+
|
|
2432
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.alphaTracker.offsetWidth || dX > 0 ) )
|
|
2433
|
+
{
|
|
2434
|
+
const alphaX = LX.clamp( parseInt( this.alphaMarker.style.left ) + dX, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2435
|
+
_fromAlphaX( alphaX );
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
e.stopPropagation();
|
|
2439
|
+
e.preventDefault();
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
let innerMouseUpAlpha = e => {
|
|
2443
|
+
var doc = this.root.ownerDocument;
|
|
2444
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2445
|
+
doc.removeEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2446
|
+
document.body.classList.remove( 'noevents' );
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
this.alphaTracker.addEventListener( "mousedown", innerMouseDownAlpha );
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
// Info display
|
|
2453
|
+
const colorLabel = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1", "", this.root );
|
|
2454
|
+
|
|
2455
|
+
colorLabel.appendChild( new Select( null, [ "CSS", "Hex", "HSV", "RGB" ], this.colorModel, v => {
|
|
2456
|
+
this.colorModel = v;
|
|
2457
|
+
this._updateColorValue( null, true );
|
|
2458
|
+
} ).root );
|
|
2459
|
+
|
|
2460
|
+
this.labelWidget = new TextInput( null, "", null, { inputClass: "bg-none", fit: true, disabled: true } );
|
|
2461
|
+
colorLabel.appendChild( this.labelWidget.root );
|
|
2462
|
+
|
|
2463
|
+
// Copy button
|
|
2464
|
+
{
|
|
2465
|
+
const copyButtonWidget = new Button(null, "copy", async () => {
|
|
2466
|
+
navigator.clipboard.writeText( this.labelWidget.value() );
|
|
2467
|
+
copyButtonWidget.root.querySelector( "input[type='checkbox']" ).style.pointerEvents = "none";
|
|
2468
|
+
|
|
2469
|
+
doAsync( () => {
|
|
2470
|
+
copyButtonWidget.root.swap( true );
|
|
2471
|
+
copyButtonWidget.root.querySelector( "input[type='checkbox']" ).style.pointerEvents = "auto";
|
|
2472
|
+
}, 3000 );
|
|
2473
|
+
|
|
2474
|
+
}, { swap: "check", icon: "copy", buttonClass: "bg-none", className: "ml-auto", title: "Copy" })
|
|
2475
|
+
|
|
2476
|
+
copyButtonWidget.root.querySelector( ".swap-on svg path" ).style.fill = "#42d065";
|
|
2477
|
+
|
|
2478
|
+
colorLabel.appendChild( copyButtonWidget.root );
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
this._updateColorValue( hexValue, true );
|
|
2482
|
+
|
|
2483
|
+
doAsync( () => {
|
|
2484
|
+
this._adjustPosition();
|
|
2485
|
+
|
|
2486
|
+
this.root.focus();
|
|
2487
|
+
|
|
2488
|
+
this._onClick = e => {
|
|
2489
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
2490
|
+
{
|
|
2491
|
+
return;
|
|
2492
|
+
}
|
|
2493
|
+
this.destroy();
|
|
2494
|
+
};
|
|
2495
|
+
|
|
2496
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
2497
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
2498
|
+
}, 10 );
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
fromHexColor( hexColor ) {
|
|
2502
|
+
|
|
2503
|
+
this.currentColor.setHex( hexColor );
|
|
2504
|
+
|
|
2505
|
+
// Decompose into HSV
|
|
2506
|
+
const { h, s, v } = this.currentColor.hsv;
|
|
2507
|
+
this._svToPosition( s, v );
|
|
2508
|
+
|
|
2509
|
+
const hueColor = new Color( { h, s: 1, v: 1 } );
|
|
2510
|
+
this.hueMarker.style.backgroundColor = this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2511
|
+
this.hueMarker.style.left = LX.remapRange( h, 0, 360, -this.markerHalfSize, this.colorPickerTracker.offsetWidth - this.markerHalfSize ) + "px";
|
|
2512
|
+
|
|
2513
|
+
this._updateColorValue( hexColor );
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
destroy() {
|
|
2517
|
+
|
|
2518
|
+
this._trigger.classList.remove( "triggered" );
|
|
2519
|
+
|
|
2520
|
+
delete this._trigger.picker;
|
|
1848
2521
|
|
|
1849
|
-
|
|
1850
|
-
|
|
2522
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
2523
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
1851
2524
|
|
|
1852
|
-
|
|
1853
|
-
{
|
|
1854
|
-
path += "/" + p.id;
|
|
1855
|
-
p = p.currentParent?.parentElement;
|
|
1856
|
-
}
|
|
2525
|
+
LX.root.querySelectorAll( ".lexcolorpicker" ).forEach( m => { m.remove(); } );
|
|
1857
2526
|
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
{
|
|
1861
|
-
m.currentParent.built = false;
|
|
1862
|
-
m.remove();
|
|
1863
|
-
}
|
|
1864
|
-
} );
|
|
2527
|
+
ColorPicker.currentPicker = null;
|
|
2528
|
+
}
|
|
1865
2529
|
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
menuItem.built = true;
|
|
1873
|
-
this._create( item.submenu, menuItem );
|
|
1874
|
-
}
|
|
2530
|
+
_svToPosition( s, v ) {
|
|
2531
|
+
this.intSatMarker.style.left = `${ LX.remapRange( s, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) }px`;
|
|
2532
|
+
this.intSatMarker.style.top = `${ LX.remapRange( 1 - v, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) }px`
|
|
2533
|
+
};
|
|
1875
2534
|
|
|
1876
|
-
|
|
1877
|
-
|
|
2535
|
+
_positionToSv( left, top ) {
|
|
2536
|
+
this.currentColor.hsv.s = LX.remapRange( left, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize, 0, 1 );
|
|
2537
|
+
this.currentColor.hsv.v = 1 - LX.remapRange( top, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize, 0, 1 );
|
|
2538
|
+
};
|
|
2539
|
+
|
|
2540
|
+
_updateColorValue( newHexValue, skipCallback = false ) {
|
|
2541
|
+
|
|
2542
|
+
this.currentColor.set( newHexValue ?? this.currentColor.hsv );
|
|
2543
|
+
|
|
2544
|
+
if( this.callback && !skipCallback )
|
|
2545
|
+
{
|
|
2546
|
+
this.callback( this.currentColor );
|
|
1878
2547
|
}
|
|
1879
|
-
|
|
2548
|
+
|
|
2549
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
2550
|
+
|
|
2551
|
+
if( this.useAlpha )
|
|
2552
|
+
{
|
|
2553
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b })`;
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
const toFixed = ( s, n = 2) => { return s.toFixed( n ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' ) };
|
|
2557
|
+
|
|
2558
|
+
if( this.colorModel == "CSS" )
|
|
2559
|
+
{
|
|
2560
|
+
const { r, g, b, a } = this.currentColor.css;
|
|
2561
|
+
this.labelWidget.set( `rgb${ this.useAlpha ? 'a' : '' }(${ r },${ g },${ b }${ this.useAlpha ? ',' + toFixed( a ) : '' })` );
|
|
2562
|
+
}
|
|
2563
|
+
else if( this.colorModel == "Hex" )
|
|
2564
|
+
{
|
|
2565
|
+
this.labelWidget.set( ( this.useAlpha ? this.currentColor.hex : this.currentColor.hex.substr( 0, 7 ) ).toUpperCase() );
|
|
2566
|
+
}
|
|
2567
|
+
else if( this.colorModel == "HSV" )
|
|
2568
|
+
{
|
|
2569
|
+
const { h, s, v, a } = this.currentColor.hsv;
|
|
2570
|
+
const components = [ Math.floor( h ) + 'º', Math.floor( s * 100 ) + '%', Math.floor( v * 100 ) + '%' ];
|
|
2571
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2572
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2573
|
+
}
|
|
2574
|
+
else // RGB
|
|
2575
|
+
{
|
|
2576
|
+
const { r, g, b, a } = this.currentColor.rgb;
|
|
2577
|
+
const components = [ toFixed( r ), toFixed( g ), toFixed( b ) ];
|
|
2578
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2579
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2580
|
+
}
|
|
2581
|
+
};
|
|
1880
2582
|
|
|
1881
2583
|
_adjustPosition() {
|
|
1882
2584
|
|
|
@@ -1938,16 +2640,9 @@ class DropdownMenu {
|
|
|
1938
2640
|
this.root.style.left = `${ position[ 0 ] }px`;
|
|
1939
2641
|
this.root.style.top = `${ position[ 1 ] }px`;
|
|
1940
2642
|
}
|
|
1941
|
-
|
|
1942
|
-
_addSeparator( parent ) {
|
|
1943
|
-
const separator = document.createElement('div');
|
|
1944
|
-
separator.className = "separator";
|
|
1945
|
-
parent = parent ?? this.root;
|
|
1946
|
-
parent.appendChild( separator );
|
|
1947
|
-
}
|
|
1948
2643
|
};
|
|
1949
2644
|
|
|
1950
|
-
LX.
|
|
2645
|
+
LX.ColorPicker = ColorPicker;
|
|
1951
2646
|
|
|
1952
2647
|
class Area {
|
|
1953
2648
|
|
|
@@ -3740,7 +4435,7 @@ class Menubar {
|
|
|
3740
4435
|
// Otherwise, create it
|
|
3741
4436
|
button = document.createElement('div');
|
|
3742
4437
|
const disabled = options.disabled ?? false;
|
|
3743
|
-
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
4438
|
+
button.className = "lexmenubutton main" + (disabled ? " disabled" : "");
|
|
3744
4439
|
button.title = name;
|
|
3745
4440
|
button.innerHTML = "<a><image src='" + src + "' class='lexicon' style='height:32px;'></a>";
|
|
3746
4441
|
|
|
@@ -3810,57 +4505,14 @@ class Menubar {
|
|
|
3810
4505
|
|
|
3811
4506
|
for( let i = 0; i < buttons.length; ++i )
|
|
3812
4507
|
{
|
|
3813
|
-
|
|
3814
|
-
let button = document.createElement( "label" );
|
|
4508
|
+
const data = buttons[ i ];
|
|
3815
4509
|
const title = data.title;
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
button.title = title ?? "";
|
|
3819
|
-
this.buttonContainer.appendChild( button );
|
|
3820
|
-
|
|
3821
|
-
const icon = document.createElement( "a" );
|
|
3822
|
-
icon.className = data.icon + " lexicon";
|
|
3823
|
-
button.appendChild( icon );
|
|
3824
|
-
|
|
3825
|
-
let trigger = icon;
|
|
3826
|
-
|
|
3827
|
-
if( data.swap )
|
|
3828
|
-
{
|
|
3829
|
-
button.classList.add( "swap" );
|
|
3830
|
-
icon.classList.add( "swap-off" );
|
|
3831
|
-
|
|
3832
|
-
const input = document.createElement( "input" );
|
|
3833
|
-
input.type = "checkbox";
|
|
3834
|
-
button.prepend( input );
|
|
3835
|
-
trigger = input;
|
|
3836
|
-
|
|
3837
|
-
const swapIcon = document.createElement( "a" );
|
|
3838
|
-
swapIcon.className = data.swap + " swap-on lexicon";
|
|
3839
|
-
button.appendChild( swapIcon );
|
|
3840
|
-
|
|
3841
|
-
button.swap = function() {
|
|
3842
|
-
const swapInput = this.querySelector( "input" );
|
|
3843
|
-
swapInput.checked = !swapInput.checked;
|
|
3844
|
-
};
|
|
3845
|
-
|
|
3846
|
-
// Set if swap has to be performed
|
|
3847
|
-
button.setState = function( v ) {
|
|
3848
|
-
const swapInput = this.querySelector( "input" );
|
|
3849
|
-
swapInput.checked = v;
|
|
3850
|
-
};
|
|
3851
|
-
}
|
|
3852
|
-
|
|
3853
|
-
trigger.addEventListener("click", e => {
|
|
3854
|
-
if( data.callback && !disabled )
|
|
3855
|
-
{
|
|
3856
|
-
const swapInput = button.querySelector( "input" );
|
|
3857
|
-
data.callback.call( this, e, swapInput?.checked );
|
|
3858
|
-
}
|
|
3859
|
-
});
|
|
4510
|
+
const button = new Button( title, "", data.callback, { title, buttonClass: "bg-none", disabled: data.disabled, icon: data.icon, hideName: true, swap: data.swap } )
|
|
4511
|
+
this.buttonContainer.appendChild( button.root );
|
|
3860
4512
|
|
|
3861
4513
|
if( title )
|
|
3862
4514
|
{
|
|
3863
|
-
this.buttons[ title ] = button;
|
|
4515
|
+
this.buttons[ title ] = button.root;
|
|
3864
4516
|
}
|
|
3865
4517
|
}
|
|
3866
4518
|
}
|
|
@@ -3947,7 +4599,7 @@ class SideBar {
|
|
|
3947
4599
|
|
|
3948
4600
|
if( this.collapsable )
|
|
3949
4601
|
{
|
|
3950
|
-
const icon = LX.makeIcon( "sidebar", "Toggle Sidebar", "toggler" );
|
|
4602
|
+
const icon = LX.makeIcon( "sidebar", { title: "Toggle Sidebar", iconClass: "toggler" } );
|
|
3951
4603
|
this.header.appendChild( icon );
|
|
3952
4604
|
|
|
3953
4605
|
icon.addEventListener( "click", (e) => {
|
|
@@ -4434,7 +5086,7 @@ class SideBar {
|
|
|
4434
5086
|
|
|
4435
5087
|
if( options.action )
|
|
4436
5088
|
{
|
|
4437
|
-
const actionIcon = LX.makeIcon( options.action.icon ?? "more-horizontal", options.action.name );
|
|
5089
|
+
const actionIcon = LX.makeIcon( options.action.icon ?? "more-horizontal", { title: options.action.name } );
|
|
4438
5090
|
itemDom.appendChild( actionIcon );
|
|
4439
5091
|
|
|
4440
5092
|
actionIcon.addEventListener( "click", (e) => {
|
|
@@ -4494,7 +5146,7 @@ class SideBar {
|
|
|
4494
5146
|
|
|
4495
5147
|
if( suboptions.action )
|
|
4496
5148
|
{
|
|
4497
|
-
const actionIcon = LX.makeIcon( suboptions.action.icon ?? "more-horizontal", suboptions.action.name );
|
|
5149
|
+
const actionIcon = LX.makeIcon( suboptions.action.icon ?? "more-horizontal", { title: suboptions.action.name } );
|
|
4498
5150
|
subentry.appendChild( actionIcon );
|
|
4499
5151
|
|
|
4500
5152
|
actionIcon.addEventListener( "click", (e) => {
|
|
@@ -4563,14 +5215,15 @@ class Widget {
|
|
|
4563
5215
|
static SEPARATOR = 26;
|
|
4564
5216
|
static KNOB = 27;
|
|
4565
5217
|
static SIZE = 28;
|
|
4566
|
-
static
|
|
4567
|
-
static
|
|
4568
|
-
static
|
|
4569
|
-
static
|
|
4570
|
-
static
|
|
4571
|
-
static
|
|
4572
|
-
static
|
|
4573
|
-
static
|
|
5218
|
+
static OTP = 29;
|
|
5219
|
+
static PAD = 30;
|
|
5220
|
+
static FORM = 31;
|
|
5221
|
+
static DIAL = 32;
|
|
5222
|
+
static COUNTER = 33;
|
|
5223
|
+
static TABLE = 34;
|
|
5224
|
+
static TABS = 35;
|
|
5225
|
+
static LABEL = 36;
|
|
5226
|
+
static BLANK = 37;
|
|
4574
5227
|
|
|
4575
5228
|
static NO_CONTEXT_TYPES = [
|
|
4576
5229
|
Widget.BUTTON,
|
|
@@ -4685,7 +5338,7 @@ class Widget {
|
|
|
4685
5338
|
|
|
4686
5339
|
_addResetProperty( container, callback ) {
|
|
4687
5340
|
|
|
4688
|
-
const domEl = LX.makeIcon( "rotate-left", "Reset" )
|
|
5341
|
+
const domEl = LX.makeIcon( "rotate-left", { title: "Reset" } )
|
|
4689
5342
|
domEl.style.display = "none";
|
|
4690
5343
|
domEl.style.marginRight = "6px";
|
|
4691
5344
|
domEl.style.marginLeft = "0";
|
|
@@ -5815,40 +6468,17 @@ class Button extends Widget {
|
|
|
5815
6468
|
super( Widget.BUTTON, name, null, options );
|
|
5816
6469
|
|
|
5817
6470
|
this.onGetValue = () => {
|
|
5818
|
-
return wValue.
|
|
6471
|
+
return wValue.querySelector( "input" )?.checked;
|
|
5819
6472
|
};
|
|
5820
6473
|
|
|
5821
6474
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
5822
6475
|
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
if( options.icon )
|
|
5826
|
-
{
|
|
5827
|
-
let icon = null;
|
|
5828
|
-
|
|
5829
|
-
// @legacy
|
|
5830
|
-
if( options.icon.includes( "fa-" ) )
|
|
5831
|
-
{
|
|
5832
|
-
icon = document.createElement( 'a' );
|
|
5833
|
-
icon.className = options.icon;
|
|
5834
|
-
}
|
|
5835
|
-
else
|
|
5836
|
-
{
|
|
5837
|
-
icon = LX.makeIcon( options.icon );
|
|
5838
|
-
}
|
|
5839
|
-
|
|
5840
|
-
wValue.prepend( icon );
|
|
5841
|
-
}
|
|
5842
|
-
else if( options.img )
|
|
5843
|
-
{
|
|
5844
|
-
let img = document.createElement( 'img' );
|
|
5845
|
-
img.src = options.img;
|
|
5846
|
-
wValue.prepend( img );
|
|
5847
|
-
}
|
|
5848
|
-
else
|
|
6476
|
+
if( !( options.swap ?? false ) )
|
|
5849
6477
|
{
|
|
5850
|
-
|
|
6478
|
+
return;
|
|
5851
6479
|
}
|
|
6480
|
+
|
|
6481
|
+
this.root.setState( newValue, skipCallback );
|
|
5852
6482
|
};
|
|
5853
6483
|
|
|
5854
6484
|
this.onResize = ( rect ) => {
|
|
@@ -5872,25 +6502,98 @@ class Button extends Widget {
|
|
|
5872
6502
|
wValue.classList.add( "selected" );
|
|
5873
6503
|
}
|
|
5874
6504
|
|
|
5875
|
-
|
|
6505
|
+
if( options.icon )
|
|
6506
|
+
{
|
|
6507
|
+
let icon = null;
|
|
6508
|
+
|
|
6509
|
+
// @legacy
|
|
6510
|
+
if( options.icon.includes( "fa-" ) )
|
|
6511
|
+
{
|
|
6512
|
+
icon = document.createElement( 'a' );
|
|
6513
|
+
icon.className = options.icon + " lexicon";
|
|
6514
|
+
}
|
|
6515
|
+
else
|
|
6516
|
+
{
|
|
6517
|
+
icon = LX.makeIcon( options.icon );
|
|
6518
|
+
}
|
|
6519
|
+
|
|
6520
|
+
wValue.prepend( icon );
|
|
6521
|
+
}
|
|
6522
|
+
else if( options.img )
|
|
6523
|
+
{
|
|
6524
|
+
let img = document.createElement( 'img' );
|
|
6525
|
+
img.src = options.img;
|
|
6526
|
+
wValue.prepend( img );
|
|
6527
|
+
}
|
|
6528
|
+
else
|
|
6529
|
+
{
|
|
6530
|
+
wValue.innerHTML = `<span>${ ( value || "" ) }</span>`;
|
|
6531
|
+
}
|
|
5876
6532
|
|
|
5877
6533
|
if( options.disabled )
|
|
5878
6534
|
{
|
|
5879
6535
|
wValue.setAttribute( "disabled", true );
|
|
5880
6536
|
}
|
|
5881
6537
|
|
|
5882
|
-
|
|
6538
|
+
let trigger = wValue;
|
|
6539
|
+
|
|
6540
|
+
if( options.swap )
|
|
6541
|
+
{
|
|
6542
|
+
wValue.classList.add( "swap" );
|
|
6543
|
+
wValue.querySelector( "a" ).classList.add( "swap-off" );
|
|
6544
|
+
|
|
6545
|
+
const input = document.createElement( "input" );
|
|
6546
|
+
input.type = "checkbox";
|
|
6547
|
+
wValue.prepend( input );
|
|
6548
|
+
|
|
6549
|
+
let swapIcon = null;
|
|
6550
|
+
|
|
6551
|
+
// @legacy
|
|
6552
|
+
if( options.swap.includes( "fa-" ) )
|
|
6553
|
+
{
|
|
6554
|
+
swapIcon = document.createElement( 'a' );
|
|
6555
|
+
swapIcon.className = options.swap + " swap-on lexicon";
|
|
6556
|
+
}
|
|
6557
|
+
else
|
|
6558
|
+
{
|
|
6559
|
+
swapIcon = LX.makeIcon( options.swap, { iconClass: "swap-on" } );
|
|
6560
|
+
}
|
|
6561
|
+
|
|
6562
|
+
wValue.appendChild( swapIcon );
|
|
6563
|
+
|
|
6564
|
+
this.root.swap = function( skipCallback ) {
|
|
6565
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6566
|
+
swapInput.checked = !swapInput.checked;
|
|
6567
|
+
if( !skipCallback )
|
|
6568
|
+
{
|
|
6569
|
+
trigger.click();
|
|
6570
|
+
}
|
|
6571
|
+
};
|
|
6572
|
+
|
|
6573
|
+
// Set if swap has to be performed
|
|
6574
|
+
this.root.setState = function( v, skipCallback ) {
|
|
6575
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6576
|
+
swapInput.checked = v;
|
|
6577
|
+
if( !skipCallback )
|
|
6578
|
+
{
|
|
6579
|
+
trigger.click();
|
|
6580
|
+
}
|
|
6581
|
+
};
|
|
6582
|
+
}
|
|
6583
|
+
|
|
6584
|
+
trigger.addEventListener( "click", e => {
|
|
5883
6585
|
if( options.selectable )
|
|
5884
6586
|
{
|
|
5885
6587
|
if( options.parent )
|
|
5886
6588
|
{
|
|
5887
|
-
options.parent.querySelectorAll(".lexbutton.selected").forEach(
|
|
6589
|
+
options.parent.querySelectorAll(".lexbutton.selected").forEach( b => { if( b == wValue ) return; b.classList.remove( "selected" ) } );
|
|
5888
6590
|
}
|
|
5889
6591
|
|
|
5890
6592
|
wValue.classList.toggle('selected');
|
|
5891
6593
|
}
|
|
5892
6594
|
|
|
5893
|
-
|
|
6595
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6596
|
+
this._trigger( new IEvent( name, swapInput?.checked ?? value, e ), callback );
|
|
5894
6597
|
});
|
|
5895
6598
|
|
|
5896
6599
|
if( options.tooltip )
|
|
@@ -6285,7 +6988,7 @@ class Select extends Widget {
|
|
|
6285
6988
|
|
|
6286
6989
|
const selectRoot = selectedOption.root;
|
|
6287
6990
|
const rect = selectRoot.getBoundingClientRect();
|
|
6288
|
-
const nestedDialog = parent.parentElement.closest( "dialog" );
|
|
6991
|
+
const nestedDialog = parent.parentElement.closest( "dialog" ) ?? parent.parentElement.closest( ".lexcolorpicker" );
|
|
6289
6992
|
|
|
6290
6993
|
// Manage vertical aspect
|
|
6291
6994
|
{
|
|
@@ -7335,31 +8038,52 @@ class ColorInput extends Widget {
|
|
|
7335
8038
|
|
|
7336
8039
|
constructor( name, value, callback, options = {} ) {
|
|
7337
8040
|
|
|
7338
|
-
|
|
8041
|
+
const useAlpha = options.useAlpha ??
|
|
8042
|
+
( ( value.constructor === Object && 'a' in value ) || ( value.constructor === String && [ 5, 9 ].includes( value.length ) ) );
|
|
8043
|
+
|
|
8044
|
+
const widgetColor = new Color( value );
|
|
8045
|
+
|
|
8046
|
+
// Force always hex internally
|
|
8047
|
+
value = useAlpha ? widgetColor.hex : widgetColor.hex.substr( 0, 7 );
|
|
7339
8048
|
|
|
7340
8049
|
super( Widget.COLOR, name, value, options );
|
|
7341
8050
|
|
|
7342
8051
|
this.onGetValue = () => {
|
|
7343
|
-
|
|
8052
|
+
const currentColor = new Color( value );
|
|
8053
|
+
return options.useRGB ? currentColor.rgb : value;
|
|
7344
8054
|
};
|
|
7345
8055
|
|
|
7346
8056
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
7347
8057
|
|
|
7348
|
-
|
|
8058
|
+
const newColor = new Color( newValue );
|
|
8059
|
+
|
|
8060
|
+
colorSampleRGB.style.color = value = newColor.hex.substr( 0, 7 );
|
|
8061
|
+
|
|
8062
|
+
if( useAlpha )
|
|
7349
8063
|
{
|
|
7350
|
-
|
|
8064
|
+
colorSampleAlpha.style.color = value = newColor.hex;
|
|
7351
8065
|
}
|
|
7352
8066
|
|
|
7353
8067
|
if( !this._skipTextUpdate )
|
|
7354
8068
|
{
|
|
7355
|
-
textWidget.set(
|
|
8069
|
+
textWidget.set( value, true, event );
|
|
7356
8070
|
}
|
|
7357
8071
|
|
|
7358
|
-
color.value = value = newValue;
|
|
7359
|
-
|
|
7360
8072
|
if( !skipCallback )
|
|
7361
8073
|
{
|
|
7362
|
-
|
|
8074
|
+
let retValue = value;
|
|
8075
|
+
|
|
8076
|
+
if( options.useRGB )
|
|
8077
|
+
{
|
|
8078
|
+
retValue = newColor.rgb;
|
|
8079
|
+
|
|
8080
|
+
if( !useAlpha )
|
|
8081
|
+
{
|
|
8082
|
+
delete retValue.a;
|
|
8083
|
+
}
|
|
8084
|
+
}
|
|
8085
|
+
|
|
8086
|
+
this._trigger( new IEvent( name, retValue, event ), callback );
|
|
7363
8087
|
}
|
|
7364
8088
|
};
|
|
7365
8089
|
|
|
@@ -7372,30 +8096,50 @@ class ColorInput extends Widget {
|
|
|
7372
8096
|
container.className = "lexcolor";
|
|
7373
8097
|
this.root.appendChild( container );
|
|
7374
8098
|
|
|
7375
|
-
let
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
8099
|
+
let sampleContainer = LX.makeContainer( ["18px", "18px"], "flex flex-row bg-contrast rounded overflow-hidden", "", container );
|
|
8100
|
+
sampleContainer.tabIndex = "1";
|
|
8101
|
+
sampleContainer.addEventListener( "click", e => {
|
|
8102
|
+
if( ( options.disabled ?? false ) )
|
|
8103
|
+
{
|
|
8104
|
+
return;
|
|
8105
|
+
}
|
|
8106
|
+
new ColorPicker( value, sampleContainer, {
|
|
8107
|
+
colorModel: options.useRGB ? "RGB" : "Hex",
|
|
8108
|
+
useAlpha,
|
|
8109
|
+
onChange: ( color ) => {
|
|
8110
|
+
this._fromColorPicker = true;
|
|
8111
|
+
this.set( color.hex );
|
|
8112
|
+
delete this._fromColorPicker;
|
|
8113
|
+
}
|
|
8114
|
+
} );
|
|
8115
|
+
} );
|
|
8116
|
+
|
|
8117
|
+
let colorSampleRGB = document.createElement( 'div' );
|
|
8118
|
+
colorSampleRGB.className = "lexcolorsample";
|
|
8119
|
+
colorSampleRGB.style.color = value;
|
|
8120
|
+
sampleContainer.appendChild( colorSampleRGB );
|
|
7382
8121
|
|
|
7383
|
-
|
|
8122
|
+
let colorSampleAlpha = null;
|
|
8123
|
+
|
|
8124
|
+
if( useAlpha )
|
|
7384
8125
|
{
|
|
7385
|
-
|
|
8126
|
+
colorSampleAlpha = document.createElement( 'div' );
|
|
8127
|
+
colorSampleAlpha.className = "lexcolorsample";
|
|
8128
|
+
colorSampleAlpha.style.color = value;
|
|
8129
|
+
sampleContainer.appendChild( colorSampleAlpha );
|
|
8130
|
+
}
|
|
8131
|
+
else
|
|
8132
|
+
{
|
|
8133
|
+
colorSampleRGB.style.width = "18px";
|
|
7386
8134
|
}
|
|
7387
8135
|
|
|
7388
|
-
|
|
7389
|
-
this.set( e.target.value, false, e );
|
|
7390
|
-
}, false );
|
|
7391
|
-
|
|
7392
|
-
const textWidget = new TextInput( null, color.value, v => {
|
|
8136
|
+
const textWidget = new TextInput( null, value, v => {
|
|
7393
8137
|
this._skipTextUpdate = true;
|
|
7394
8138
|
this.set( v );
|
|
7395
8139
|
delete this._skipTextUpdate;
|
|
7396
|
-
}, { width: "calc( 100% -
|
|
8140
|
+
}, { width: "calc( 100% - 24px )", disabled: options.disabled });
|
|
7397
8141
|
|
|
7398
|
-
textWidget.root.style.marginLeft = "
|
|
8142
|
+
textWidget.root.style.marginLeft = "6px";
|
|
7399
8143
|
container.appendChild( textWidget.root );
|
|
7400
8144
|
|
|
7401
8145
|
doAsync( this.onResize.bind( this ) );
|
|
@@ -7705,7 +8449,6 @@ class NumberInput extends Widget {
|
|
|
7705
8449
|
else if( e.altKey ) mult *= 0.1;
|
|
7706
8450
|
value = ( +vecinput.valueAsNumber + mult * dt );
|
|
7707
8451
|
this.set( value, false, e );
|
|
7708
|
-
// vecinput.value = ( +new_value ).toFixed( 4 ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' );
|
|
7709
8452
|
}
|
|
7710
8453
|
|
|
7711
8454
|
e.stopPropagation();
|
|
@@ -8103,6 +8846,164 @@ class SizeInput extends Widget {
|
|
|
8103
8846
|
|
|
8104
8847
|
LX.SizeInput = SizeInput;
|
|
8105
8848
|
|
|
8849
|
+
/**
|
|
8850
|
+
* @class OTPInput
|
|
8851
|
+
* @description OTPInput Widget
|
|
8852
|
+
*/
|
|
8853
|
+
|
|
8854
|
+
class OTPInput extends Widget {
|
|
8855
|
+
|
|
8856
|
+
constructor( name, value, callback, options = {} ) {
|
|
8857
|
+
|
|
8858
|
+
const pattern = options.pattern ?? "xxx-xxx";
|
|
8859
|
+
const patternSize = ( pattern.match(/x/g) || [] ).length;
|
|
8860
|
+
|
|
8861
|
+
value = String( value );
|
|
8862
|
+
if( !value.length )
|
|
8863
|
+
{
|
|
8864
|
+
value = "x".repeat( patternSize );
|
|
8865
|
+
}
|
|
8866
|
+
|
|
8867
|
+
super( Widget.OTP, name, value, options );
|
|
8868
|
+
|
|
8869
|
+
this.onGetValue = () => {
|
|
8870
|
+
return +value;
|
|
8871
|
+
};
|
|
8872
|
+
|
|
8873
|
+
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
8874
|
+
|
|
8875
|
+
value = newValue;
|
|
8876
|
+
|
|
8877
|
+
_refreshInput( value );
|
|
8878
|
+
|
|
8879
|
+
if( !skipCallback )
|
|
8880
|
+
{
|
|
8881
|
+
this._trigger( new IEvent( name, +newValue, event ), callback );
|
|
8882
|
+
}
|
|
8883
|
+
};
|
|
8884
|
+
|
|
8885
|
+
this.onResize = ( rect ) => {
|
|
8886
|
+
const realNameWidth = ( this.root.domName?.offsetWidth ?? 0 );
|
|
8887
|
+
container.style.width = `calc( 100% - ${ realNameWidth }px)`;
|
|
8888
|
+
};
|
|
8889
|
+
|
|
8890
|
+
this.disabled = options.disabled ?? false;
|
|
8891
|
+
|
|
8892
|
+
const container = document.createElement( 'div' );
|
|
8893
|
+
container.className = "lexotp flex flex-row items-center";
|
|
8894
|
+
this.root.appendChild( container );
|
|
8895
|
+
|
|
8896
|
+
const groups = pattern.split( '-' );
|
|
8897
|
+
|
|
8898
|
+
const _refreshInput = ( valueString ) => {
|
|
8899
|
+
|
|
8900
|
+
container.innerHTML = "";
|
|
8901
|
+
|
|
8902
|
+
let itemsCount = 0;
|
|
8903
|
+
let activeSlot = 0;
|
|
8904
|
+
|
|
8905
|
+
for( let i = 0; i < groups.length; ++i )
|
|
8906
|
+
{
|
|
8907
|
+
const g = groups[ i ];
|
|
8908
|
+
|
|
8909
|
+
for( let j = 0; j < g.length; ++j )
|
|
8910
|
+
{
|
|
8911
|
+
let number = valueString[ itemsCount++ ];
|
|
8912
|
+
number = ( number == 'x' ? '' : number );
|
|
8913
|
+
|
|
8914
|
+
const slotDom = LX.makeContainer( ["36px", "30px"],
|
|
8915
|
+
"lexotpslot border-top border-bottom border-left px-3 cursor-text select-none font-medium outline-none", number, container );
|
|
8916
|
+
slotDom.tabIndex = "1";
|
|
8917
|
+
|
|
8918
|
+
if( this.disabled )
|
|
8919
|
+
{
|
|
8920
|
+
slotDom.classList.add( "disabled" );
|
|
8921
|
+
}
|
|
8922
|
+
|
|
8923
|
+
const otpIndex = itemsCount;
|
|
8924
|
+
|
|
8925
|
+
if( j == 0 )
|
|
8926
|
+
{
|
|
8927
|
+
slotDom.className += " rounded-l";
|
|
8928
|
+
}
|
|
8929
|
+
else if( j == ( g.length - 1 ) )
|
|
8930
|
+
{
|
|
8931
|
+
slotDom.className += " rounded-r border-right";
|
|
8932
|
+
}
|
|
8933
|
+
|
|
8934
|
+
slotDom.addEventListener( "click", () => {
|
|
8935
|
+
if( this.disabled ) { return; }
|
|
8936
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8937
|
+
const activeDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot ];
|
|
8938
|
+
activeDom.classList.add( "active" );
|
|
8939
|
+
activeDom.focus();
|
|
8940
|
+
} );
|
|
8941
|
+
|
|
8942
|
+
slotDom.addEventListener( "blur", () => {
|
|
8943
|
+
if( this.disabled ) { return; }
|
|
8944
|
+
doAsync( () => {
|
|
8945
|
+
if( container.contains( document.activeElement ) ) { return; }
|
|
8946
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8947
|
+
}, 10 );
|
|
8948
|
+
} );
|
|
8949
|
+
|
|
8950
|
+
slotDom.addEventListener( "keyup", e => {
|
|
8951
|
+
if( this.disabled ) { return; }
|
|
8952
|
+
if( !/[^0-9]+/g.test( e.key ) )
|
|
8953
|
+
{
|
|
8954
|
+
const number = e.key;
|
|
8955
|
+
console.assert( parseInt( number ) != NaN );
|
|
8956
|
+
|
|
8957
|
+
slotDom.innerHTML = number;
|
|
8958
|
+
valueString = valueString.substring( 0, otpIndex - 1 ) + number + valueString.substring( otpIndex );
|
|
8959
|
+
|
|
8960
|
+
const nexActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + 1 ];
|
|
8961
|
+
if( nexActiveDom )
|
|
8962
|
+
{
|
|
8963
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8964
|
+
nexActiveDom.classList.add( "active" );
|
|
8965
|
+
nexActiveDom.focus();
|
|
8966
|
+
activeSlot++;
|
|
8967
|
+
}
|
|
8968
|
+
else
|
|
8969
|
+
{
|
|
8970
|
+
this.set( valueString );
|
|
8971
|
+
}
|
|
8972
|
+
}
|
|
8973
|
+
else if( e.key == "ArrowLeft" || e.key == "ArrowRight" )
|
|
8974
|
+
{
|
|
8975
|
+
const dt = ( e.key == "ArrowLeft" ) ? -1 : 1;
|
|
8976
|
+
const newActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + dt ];
|
|
8977
|
+
if( newActiveDom )
|
|
8978
|
+
{
|
|
8979
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8980
|
+
newActiveDom.classList.add( "active" );
|
|
8981
|
+
newActiveDom.focus();
|
|
8982
|
+
activeSlot += dt;
|
|
8983
|
+
}
|
|
8984
|
+
}
|
|
8985
|
+
else if( e.key == "Enter" && !valueString.includes( 'x' ) )
|
|
8986
|
+
{
|
|
8987
|
+
this.set( valueString );
|
|
8988
|
+
}
|
|
8989
|
+
} );
|
|
8990
|
+
}
|
|
8991
|
+
|
|
8992
|
+
if( i < ( groups.length - 1 ) )
|
|
8993
|
+
{
|
|
8994
|
+
LX.makeContainer( ["auto", "auto"], "mx-2", `-`, container );
|
|
8995
|
+
}
|
|
8996
|
+
}
|
|
8997
|
+
|
|
8998
|
+
console.assert( itemsCount == valueString.length, "OTP Value/Pattern Mismatch!" )
|
|
8999
|
+
}
|
|
9000
|
+
|
|
9001
|
+
_refreshInput( value );
|
|
9002
|
+
}
|
|
9003
|
+
}
|
|
9004
|
+
|
|
9005
|
+
LX.OTPInput = OTPInput;
|
|
9006
|
+
|
|
8106
9007
|
/**
|
|
8107
9008
|
* @class Pad
|
|
8108
9009
|
* @description Pad Widget
|
|
@@ -8762,7 +9663,7 @@ class Table extends Widget {
|
|
|
8762
9663
|
|
|
8763
9664
|
if( this.customFilters )
|
|
8764
9665
|
{
|
|
8765
|
-
const icon = LX.makeIcon( "circle-plus",
|
|
9666
|
+
const icon = LX.makeIcon( "circle-plus", { svgClass: "sm" } );
|
|
8766
9667
|
|
|
8767
9668
|
for( let f of this.customFilters )
|
|
8768
9669
|
{
|
|
@@ -8787,7 +9688,6 @@ class Table extends Widget {
|
|
|
8787
9688
|
headerContainer.appendChild( customFilterBtn.root );
|
|
8788
9689
|
}
|
|
8789
9690
|
|
|
8790
|
-
// const resetIcon = LX.makeIcon( "xmark", null, "sm" );
|
|
8791
9691
|
this._resetCustomFiltersBtn = new Button(null, "resetButton", ( v ) => {
|
|
8792
9692
|
this.activeCustomFilters = {};
|
|
8793
9693
|
this.refresh();
|
|
@@ -8799,7 +9699,7 @@ class Table extends Widget {
|
|
|
8799
9699
|
|
|
8800
9700
|
if( this.toggleColumns )
|
|
8801
9701
|
{
|
|
8802
|
-
const icon = LX.makeIcon( "sliders" );
|
|
9702
|
+
const icon = LX.makeIcon( "sliders-large" );
|
|
8803
9703
|
const toggleColumnsBtn = new Button( "toggleColumnsBtn", icon.innerHTML + "View", (value, e) => {
|
|
8804
9704
|
const menuOptions = data.head.map( ( colName, idx ) => {
|
|
8805
9705
|
const item = {
|
|
@@ -8870,7 +9770,7 @@ class Table extends Widget {
|
|
|
8870
9770
|
for( const el of body.childNodes )
|
|
8871
9771
|
{
|
|
8872
9772
|
data.checkMap[ el.getAttribute( "rowId" ) ] = this.checked;
|
|
8873
|
-
el.querySelector( "input" ).checked = this.checked;
|
|
9773
|
+
el.querySelector( "input[type='checkbox']" ).checked = this.checked;
|
|
8874
9774
|
}
|
|
8875
9775
|
});
|
|
8876
9776
|
|
|
@@ -8882,7 +9782,7 @@ class Table extends Widget {
|
|
|
8882
9782
|
{
|
|
8883
9783
|
const th = document.createElement( 'th' );
|
|
8884
9784
|
th.innerHTML = `<span>${ headData }</span>`;
|
|
8885
|
-
th.querySelector( "span" ).appendChild( LX.makeIcon( "menu-arrows",
|
|
9785
|
+
th.querySelector( "span" ).appendChild( LX.makeIcon( "menu-arrows", { svgClass: "sm" } ) );
|
|
8886
9786
|
|
|
8887
9787
|
const idx = data.head.indexOf( headData );
|
|
8888
9788
|
if( this.centered && this.centered.indexOf( idx ) > -1 )
|
|
@@ -9084,10 +9984,20 @@ class Table extends Widget {
|
|
|
9084
9984
|
input.addEventListener( 'change', function() {
|
|
9085
9985
|
data.checkMap[ rowId ] = this.checked;
|
|
9086
9986
|
|
|
9987
|
+
const headInput = table.querySelector( "thead input[type='checkbox']" );
|
|
9988
|
+
|
|
9087
9989
|
if( !this.checked )
|
|
9088
9990
|
{
|
|
9089
|
-
|
|
9090
|
-
|
|
9991
|
+
headInput.checked = data.checkMap[ ":root" ] = false;
|
|
9992
|
+
}
|
|
9993
|
+
else
|
|
9994
|
+
{
|
|
9995
|
+
const rowInputs = Array.from( table.querySelectorAll( "tbody input[type='checkbox']" ) );
|
|
9996
|
+
const uncheckedRowInputs = rowInputs.filter( i => { return !i.checked; } );
|
|
9997
|
+
if( !uncheckedRowInputs.length )
|
|
9998
|
+
{
|
|
9999
|
+
headInput.checked = data.checkMap[ ":root" ] = true;
|
|
10000
|
+
}
|
|
9091
10001
|
}
|
|
9092
10002
|
});
|
|
9093
10003
|
|
|
@@ -9123,7 +10033,7 @@ class Table extends Widget {
|
|
|
9123
10033
|
|
|
9124
10034
|
if( action == "delete" )
|
|
9125
10035
|
{
|
|
9126
|
-
button = LX.makeIcon( "trash-can", "Delete Row" );
|
|
10036
|
+
button = LX.makeIcon( "trash-can", { title: "Delete Row" } );
|
|
9127
10037
|
button.addEventListener( 'click', function() {
|
|
9128
10038
|
// Don't need to refresh table..
|
|
9129
10039
|
data.body.splice( r, 1 );
|
|
@@ -9132,7 +10042,7 @@ class Table extends Widget {
|
|
|
9132
10042
|
}
|
|
9133
10043
|
else if( action == "menu" )
|
|
9134
10044
|
{
|
|
9135
|
-
button = LX.makeIcon( "more-horizontal", "Menu" );
|
|
10045
|
+
button = LX.makeIcon( "more-horizontal", { title: "Menu" } );
|
|
9136
10046
|
button.addEventListener( 'click', function( event ) {
|
|
9137
10047
|
if( !options.onMenuAction )
|
|
9138
10048
|
{
|
|
@@ -9148,7 +10058,7 @@ class Table extends Widget {
|
|
|
9148
10058
|
else // custom actions
|
|
9149
10059
|
{
|
|
9150
10060
|
console.assert( action.constructor == Object );
|
|
9151
|
-
button = LX.makeIcon( action.icon, action.title );
|
|
10061
|
+
button = LX.makeIcon( action.icon, { title: action.title } );
|
|
9152
10062
|
|
|
9153
10063
|
if( action.callback )
|
|
9154
10064
|
{
|
|
@@ -10198,6 +11108,22 @@ class Panel {
|
|
|
10198
11108
|
return this._attachWidget( widget );
|
|
10199
11109
|
}
|
|
10200
11110
|
|
|
11111
|
+
/**
|
|
11112
|
+
* @method addOTP
|
|
11113
|
+
* @param {String} name Widget name
|
|
11114
|
+
* @param {String} value Default numeric value in string format
|
|
11115
|
+
* @param {Function} callback Callback function on change
|
|
11116
|
+
* @param {Object} options:
|
|
11117
|
+
* hideName: Don't use name as label [false]
|
|
11118
|
+
* disabled: Make the widget disabled [false]
|
|
11119
|
+
* pattern: OTP numeric pattern
|
|
11120
|
+
*/
|
|
11121
|
+
|
|
11122
|
+
addOTP( name, value, callback, options = {} ) {
|
|
11123
|
+
const widget = new OTPInput( name, value, callback, options );
|
|
11124
|
+
return this._attachWidget( widget );
|
|
11125
|
+
}
|
|
11126
|
+
|
|
10201
11127
|
/**
|
|
10202
11128
|
* @method addPad
|
|
10203
11129
|
* @param {String} name Widget name
|
|
@@ -10430,7 +11356,7 @@ class Branch {
|
|
|
10430
11356
|
// add widgets
|
|
10431
11357
|
for( let w of this.widgets )
|
|
10432
11358
|
{
|
|
10433
|
-
p.root.appendChild( w.
|
|
11359
|
+
p.root.appendChild( w.root );
|
|
10434
11360
|
}
|
|
10435
11361
|
});
|
|
10436
11362
|
dialog.widgets = this.widgets;
|
|
@@ -10734,7 +11660,7 @@ class Dialog {
|
|
|
10734
11660
|
|
|
10735
11661
|
for( let w of that.widgets )
|
|
10736
11662
|
{
|
|
10737
|
-
branch.content.appendChild( w.
|
|
11663
|
+
branch.content.appendChild( w.root );
|
|
10738
11664
|
}
|
|
10739
11665
|
|
|
10740
11666
|
branch.widgets = that.widgets;
|
|
@@ -12375,7 +13301,7 @@ class AssetView {
|
|
|
12375
13301
|
|
|
12376
13302
|
this.rightPanel.addText(null, this.path.join('/'), null, {
|
|
12377
13303
|
inputClass: "nobg", disabled: true, signal: "@on_folder_change",
|
|
12378
|
-
style: { fontWeight: "600", fontSize: "15px" }
|
|
13304
|
+
style: { fontWeight: "600", fontSize: "15px" }
|
|
12379
13305
|
});
|
|
12380
13306
|
|
|
12381
13307
|
this.rightPanel.endLine();
|
|
@@ -13112,7 +14038,7 @@ Element.prototype.addClass = function( className ) {
|
|
|
13112
14038
|
}
|
|
13113
14039
|
|
|
13114
14040
|
Element.prototype.getComputedSize = function() {
|
|
13115
|
-
// Since we use "box-sizing: border-box" now,
|
|
14041
|
+
// Since we use "box-sizing: border-box" now,
|
|
13116
14042
|
// it's all included in offsetWidth/offsetHeight
|
|
13117
14043
|
return {
|
|
13118
14044
|
width: this.offsetWidth,
|
|
@@ -13254,6 +14180,7 @@ LX.ICONS = {
|
|
|
13254
14180
|
"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"],
|
|
13255
14181
|
"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"],
|
|
13256
14182
|
"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"],
|
|
14183
|
+
"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"],
|
|
13257
14184
|
"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"],
|
|
13258
14185
|
"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"],
|
|
13259
14186
|
"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"],
|