lexgui 0.6.0 → 0.6.2

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.
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  var LX = {
9
- version: "0.6.0",
9
+ version: "0.6.2",
10
10
  ready: false,
11
11
  components: [], // Specific pre-build components
12
12
  signals: {}, // Events and triggers
@@ -85,7 +85,21 @@ LX.doAsync = doAsync;
85
85
  */
86
86
  function getSupportedDOMName( text )
87
87
  {
88
- return text.replace( /\s/g, '' ).replaceAll('@', '_').replaceAll('+', '_plus_').replaceAll( '.', '' );
88
+ console.assert( typeof text == "string", "getSupportedDOMName: Text is not a string!" );
89
+
90
+ let name = text.trim();
91
+
92
+ // Replace specific known symbols
93
+ name = name.replace( /@/g, '_at_' ).replace( /\+/g, '_plus_' ).replace( /\./g, '_dot_' );
94
+ name = name.replace( /[^a-zA-Z0-9_-]/g, '_' );
95
+
96
+ // prefix with an underscore if needed
97
+ if( /^[0-9]/.test( name ) )
98
+ {
99
+ name = '_' + name;
100
+ }
101
+
102
+ return name;
89
103
  }
90
104
 
91
105
  LX.getSupportedDOMName = getSupportedDOMName;
@@ -2296,7 +2310,7 @@ class DropdownMenu {
2296
2310
 
2297
2311
  console.assert( trigger, "DropdownMenu needs a DOM element as trigger!" );
2298
2312
 
2299
- if( DropdownMenu.currentMenu )
2313
+ if( DropdownMenu.currentMenu || !items?.length )
2300
2314
  {
2301
2315
  DropdownMenu.currentMenu.destroy();
2302
2316
  this.invalid = true;
@@ -2314,6 +2328,7 @@ class DropdownMenu {
2314
2328
  this.align = options.align ?? "center";
2315
2329
  this.avoidCollisions = options.avoidCollisions ?? true;
2316
2330
  this.onBlur = options.onBlur;
2331
+ this.inPlace = false;
2317
2332
 
2318
2333
  this.root = document.createElement( "div" );
2319
2334
  this.root.id = "root";
@@ -2333,7 +2348,8 @@ class DropdownMenu {
2333
2348
 
2334
2349
  this._onClick = e => {
2335
2350
 
2336
- if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
2351
+ // Check if the click is inside a menu or on the trigger
2352
+ if( e.target && ( e.target.closest( ".lexdropdownmenu" ) != undefined || e.target == this._trigger ) )
2337
2353
  {
2338
2354
  return;
2339
2355
  }
@@ -2341,7 +2357,8 @@ class DropdownMenu {
2341
2357
  this.destroy( true );
2342
2358
  };
2343
2359
 
2344
- document.body.addEventListener( "click", this._onClick );
2360
+ document.body.addEventListener( "mousedown", this._onClick, true );
2361
+ document.body.addEventListener( "focusin", this._onClick, true );
2345
2362
  }, 10 );
2346
2363
  }
2347
2364
 
@@ -2351,7 +2368,8 @@ class DropdownMenu {
2351
2368
 
2352
2369
  delete this._trigger.ddm;
2353
2370
 
2354
- document.body.removeEventListener( "click", this._onClick );
2371
+ document.body.removeEventListener( "mousedown", this._onClick, true );
2372
+ document.body.removeEventListener( "focusin", this._onClick, true );
2355
2373
 
2356
2374
  LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => { m.remove(); } );
2357
2375
 
@@ -2376,7 +2394,7 @@ class DropdownMenu {
2376
2394
  let newParent = document.createElement( "div" );
2377
2395
  newParent.tabIndex = "1";
2378
2396
  newParent.className = "lexdropdownmenu";
2379
- newParent.id = parentDom.id;
2397
+ newParent.dataset["id"] = parentDom.dataset["id"];
2380
2398
  newParent.dataset["side"] = "right"; // submenus always come from the right
2381
2399
  LX.root.appendChild( newParent );
2382
2400
 
@@ -2408,7 +2426,7 @@ class DropdownMenu {
2408
2426
  }
2409
2427
 
2410
2428
  const key = item.name ?? item;
2411
- const pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
2429
+ const pKey = LX.getSupportedDOMName( key );
2412
2430
 
2413
2431
  // Item already created
2414
2432
  if( parentDom.querySelector( "#" + pKey ) )
@@ -2418,7 +2436,7 @@ class DropdownMenu {
2418
2436
 
2419
2437
  const menuItem = document.createElement('div');
2420
2438
  menuItem.className = "lexdropdownmenuitem" + ( item.name ? "" : " label" ) + ( item.disabled ?? false ? " disabled" : "" ) + ( ` ${ item.className ?? "" }` );
2421
- menuItem.id = pKey;
2439
+ menuItem.dataset["id"] = pKey;
2422
2440
  menuItem.innerHTML = `<span>${ key }</span>`;
2423
2441
  menuItem.tabIndex = "1";
2424
2442
  parentDom.appendChild( menuItem );
@@ -2504,24 +2522,24 @@ class DropdownMenu {
2504
2522
 
2505
2523
  menuItem.addEventListener("mouseover", e => {
2506
2524
 
2507
- let path = menuItem.id;
2525
+ let path = menuItem.dataset["id"];
2508
2526
  let p = parentDom;
2509
2527
 
2510
2528
  while( p )
2511
2529
  {
2512
- path += "/" + p.id;
2530
+ path += "/" + p.dataset["id"];
2513
2531
  p = p.currentParent?.parentElement;
2514
2532
  }
2515
2533
 
2516
2534
  LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => {
2517
- if( !path.includes( m.id ) )
2535
+ if( !path.includes( m.dataset["id"] ) )
2518
2536
  {
2519
2537
  m.currentParent.built = false;
2520
2538
  m.remove();
2521
2539
  }
2522
2540
  } );
2523
2541
 
2524
- if( item.submenu )
2542
+ if( item.submenu && this.inPlace )
2525
2543
  {
2526
2544
  if( menuItem.built )
2527
2545
  {
@@ -2595,6 +2613,7 @@ class DropdownMenu {
2595
2613
 
2596
2614
  this.root.style.left = `${ position[ 0 ] }px`;
2597
2615
  this.root.style.top = `${ position[ 1 ] }px`;
2616
+ this.inPlace = true;
2598
2617
  }
2599
2618
 
2600
2619
  _addSeparator( parent ) {
@@ -3456,6 +3475,7 @@ class Area {
3456
3475
  const type = options.type ?? "horizontal";
3457
3476
  const sizes = options.sizes || [ "50%", "50%" ];
3458
3477
  const auto = (options.sizes === 'auto') || ( options.sizes && options.sizes[ 0 ] == "auto" && options.sizes[ 1 ] == "auto" );
3478
+ const rect = this.root.getBoundingClientRect();
3459
3479
 
3460
3480
  // Secondary area fills space
3461
3481
  if( !sizes[ 1 ] || ( sizes[ 0 ] != "auto" && sizes[ 1 ] == "auto" ) )
@@ -3506,7 +3526,7 @@ class Area {
3506
3526
 
3507
3527
  if( !fixedSize )
3508
3528
  {
3509
- const parentWidth = this.root.offsetWidth;
3529
+ const parentWidth = rect.width;
3510
3530
  const leftPx = parsePixelSize( sizes[ 0 ], parentWidth );
3511
3531
  const rightPx = parsePixelSize( sizes[ 1 ], parentWidth );
3512
3532
  const leftPercent = ( leftPx / parentWidth ) * 100;
@@ -3530,10 +3550,11 @@ class Area {
3530
3550
  if( auto )
3531
3551
  {
3532
3552
  primarySize[ 1 ] = "auto";
3553
+ secondarySize[ 1 ] = "auto";
3533
3554
  }
3534
3555
  else if( !fixedSize )
3535
3556
  {
3536
- const parentHeight = this.root.offsetHeight;
3557
+ const parentHeight = rect.height;
3537
3558
  const topPx = parsePixelSize( sizes[ 0 ], parentHeight );
3538
3559
  const bottomPx = parsePixelSize( sizes[ 1 ], parentHeight );
3539
3560
  const topPercent = ( topPx / parentHeight ) * 100;
@@ -3556,6 +3577,72 @@ class Area {
3556
3577
  let area1 = new Area( { width: primarySize[ 0 ], height: primarySize[ 1 ], skipAppend: true, className: "split" + ( options.menubar || options.sidebar ? "" : " origin" ) } );
3557
3578
  let area2 = new Area( { width: secondarySize[ 0 ], height: secondarySize[ 1 ], skipAppend: true, className: "split" } );
3558
3579
 
3580
+ /*
3581
+ If the parent area is not in the DOM, we need to wait for the resize event to get the its correct size
3582
+ and set the sizes of the split areas accordingly.
3583
+ */
3584
+ if( !fixedSize && ( !rect.width || !rect.height ) )
3585
+ {
3586
+ const observer = new ResizeObserver( entries => {
3587
+
3588
+ console.assert( entries.length == 1, "AreaResizeObserver: more than one entry" );
3589
+
3590
+ const rect = entries[ 0 ].contentRect;
3591
+ if( !rect.width || !rect.height )
3592
+ {
3593
+ return;
3594
+ }
3595
+
3596
+ this._update( [ rect.width, rect.height ], false );
3597
+
3598
+ // On auto splits, we only need to set the size of the parent area
3599
+ if( !auto )
3600
+ {
3601
+ if( type == "horizontal" )
3602
+ {
3603
+ const parentWidth = rect.width;
3604
+ const leftPx = parsePixelSize( sizes[ 0 ], parentWidth );
3605
+ const rightPx = parsePixelSize( sizes[ 1 ], parentWidth );
3606
+ const leftPercent = ( leftPx / parentWidth ) * 100;
3607
+ const rightPercent = ( rightPx / parentWidth ) * 100;
3608
+
3609
+ // Style using percentages
3610
+ primarySize[ 0 ] = `calc(${ leftPercent }% - ${ splitbarOffset }px)`;
3611
+ secondarySize[ 0 ] = `calc(${ rightPercent }% - ${ splitbarOffset }px)`;
3612
+ }
3613
+ else // vertical
3614
+ {
3615
+ const parentHeight = rect.height;
3616
+ const topPx = parsePixelSize( sizes[ 0 ], parentHeight );
3617
+ const bottomPx = parsePixelSize( sizes[ 1 ], parentHeight );
3618
+ const topPercent = ( topPx / parentHeight ) * 100;
3619
+ const bottomPercent = ( bottomPx / parentHeight ) * 100;
3620
+
3621
+ primarySize[ 1 ] = ( sizes[ 0 ] == "auto" ? "auto" : `calc(${ topPercent }% - ${ splitbarOffset }px)`);
3622
+ secondarySize[ 1 ] = ( sizes[ 1 ] == "auto" ? "auto" : `calc(${ bottomPercent }% - ${ splitbarOffset }px)`);
3623
+ }
3624
+
3625
+ area1.root.style.width = primarySize[ 0 ];
3626
+ area1.root.style.height = primarySize[ 1 ];
3627
+
3628
+ area2.root.style.width = secondarySize[ 0 ];
3629
+ area2.root.style.height = secondarySize[ 1 ];
3630
+ }
3631
+
3632
+ area1._update();
3633
+ area2._update();
3634
+
3635
+ // Stop observing
3636
+ observer.disconnect();
3637
+ });
3638
+
3639
+ // Observe the parent area until the DOM is ready
3640
+ // and the size is set correctly.
3641
+ doAsync( () => {
3642
+ observer.observe( this.root );
3643
+ }, 100 );
3644
+ }
3645
+
3559
3646
  if( auto && type == "vertical" )
3560
3647
  {
3561
3648
  // Listen resize event on first area
@@ -3565,6 +3652,7 @@ class Area {
3565
3652
  const size = entry.target.getComputedSize();
3566
3653
  area2.root.style.height = "calc(100% - " + ( size.height ) + "px )";
3567
3654
  }
3655
+ resizeObserver.disconnect();
3568
3656
  });
3569
3657
 
3570
3658
  resizeObserver.observe( area1.root );
@@ -3608,7 +3696,7 @@ class Area {
3608
3696
  this.type = type;
3609
3697
 
3610
3698
  // Update sizes
3611
- this._update();
3699
+ this._update( rect.width || rect.height ? [ rect.width, rect.height ] : undefined );
3612
3700
 
3613
3701
  if( !resize )
3614
3702
  {
@@ -3665,6 +3753,11 @@ class Area {
3665
3753
  this.minHeight = minh;
3666
3754
  this.maxWidth = maxw;
3667
3755
  this.maxHeight = maxh;
3756
+
3757
+ if( minw != 0 ) this.root.style.minWidth = `${ minw }px`;
3758
+ if( minh != 0 ) this.root.style.minHeight = `${ minh }px`;
3759
+ if( maxw != Infinity ) this.root.style.maxWidth = `${ maxw }px`;
3760
+ if( maxh != Infinity ) this.root.style.maxHeight = `${ maxh }px`;
3668
3761
  }
3669
3762
 
3670
3763
  /**
@@ -3724,7 +3817,7 @@ class Area {
3724
3817
  {
3725
3818
  this.offset = area2.root.offsetHeight;
3726
3819
  area2.root.classList.add("fadeout-vertical");
3727
- this._moveSplit(-Infinity, true);
3820
+ this._moveSplit( -Infinity, true );
3728
3821
 
3729
3822
  }
3730
3823
  else
@@ -4032,7 +4125,6 @@ class Area {
4032
4125
  {
4033
4126
  _addButton( b );
4034
4127
  }
4035
-
4036
4128
  }
4037
4129
 
4038
4130
  // Add floating info
@@ -4124,12 +4216,12 @@ class Area {
4124
4216
 
4125
4217
  if( a1.maxWidth != Infinity )
4126
4218
  {
4127
- a2Root.style.minWidth = "calc( 100% - " + parseInt( a1.maxWidth ) + "px" + " )";
4219
+ a2Root.style.minWidth = `calc( 100% - ${ parseInt( a1.maxWidth ) }px )`;
4128
4220
  }
4129
4221
  }
4130
4222
  else
4131
4223
  {
4132
- var size = Math.max( ( a2Root.offsetHeight + dt ) + a2.offset, parseInt(a2.minHeight) );
4224
+ var size = Math.max( ( a2Root.offsetHeight + dt ) + a2.offset, parseInt( a2.minHeight ) );
4133
4225
  if( forceWidth ) size = forceWidth;
4134
4226
 
4135
4227
  const parentHeight = this.size[ 1 ];
@@ -4143,7 +4235,10 @@ class Area {
4143
4235
  a2Root.style.height = `${ bottomPercent }%`;
4144
4236
  a2Root.style.height = `${ bottomPercent }%`;
4145
4237
 
4146
- a1Root.style.minHeight = a1.minHeight + "px";
4238
+ if( a1.maxHeight != Infinity )
4239
+ {
4240
+ a2Root.style.minHeight = `calc( 100% - ${ parseInt( a1.maxHeight ) }px )`;
4241
+ }
4147
4242
  }
4148
4243
 
4149
4244
  if( !forceAnimation )
@@ -4165,15 +4260,24 @@ class Area {
4165
4260
  delete this.splitBar;
4166
4261
  }
4167
4262
 
4168
- _update() {
4169
-
4170
- const rect = this.root.getBoundingClientRect();
4263
+ _update( newSize, propagate = true ) {
4171
4264
 
4172
- this.size = [ rect.width, rect.height ];
4265
+ if( !newSize )
4266
+ {
4267
+ const rect = this.root.getBoundingClientRect();
4268
+ this.size = [ rect.width, rect.height ];
4269
+ }
4270
+ else
4271
+ {
4272
+ this.size = newSize;
4273
+ }
4173
4274
 
4174
- for( var i = 0; i < this.sections.length; i++ )
4275
+ if( propagate )
4175
4276
  {
4176
- this.sections[ i ]._update();
4277
+ for( var i = 0; i < this.sections.length; i++ )
4278
+ {
4279
+ this.sections[ i ]._update();
4280
+ }
4177
4281
  }
4178
4282
  }
4179
4283
  };
@@ -4573,7 +4677,7 @@ class Menubar {
4573
4677
 
4574
4678
  this.root.querySelectorAll(".lexmenuentry").forEach( e => {
4575
4679
  e.classList.remove( 'selected' );
4576
- e.built = false;
4680
+ delete e.dataset[ "built" ];
4577
4681
  } );
4578
4682
 
4579
4683
  if( this._currentDropdown )
@@ -4595,7 +4699,7 @@ class Menubar {
4595
4699
  for( let item of this.items )
4596
4700
  {
4597
4701
  let key = item.name;
4598
- let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
4702
+ let pKey = LX.getSupportedDOMName( key );
4599
4703
 
4600
4704
  // Item already created
4601
4705
  if( this.root.querySelector( "#" + pKey ) )
@@ -4614,8 +4718,8 @@ class Menubar {
4614
4718
  const _showEntry = () => {
4615
4719
  this._resetMenubar(true);
4616
4720
  entry.classList.add( "selected" );
4617
- entry.built = true;
4618
- this._currentDropdown = addDropdownMenu( entry, item.submenu, { side: "bottom", align: "start", onBlur: () => {
4721
+ entry.dataset["built"] = "true";
4722
+ this._currentDropdown = addDropdownMenu( entry, item.submenu ?? [], { side: "bottom", align: "start", onBlur: () => {
4619
4723
  this._resetMenubar();
4620
4724
  } });
4621
4725
  };
@@ -4635,7 +4739,7 @@ class Menubar {
4635
4739
 
4636
4740
  entry.addEventListener( "mouseover", (e) => {
4637
4741
 
4638
- if( this.focused && !entry.built )
4742
+ if( this.focused && !( entry.dataset[ "built" ] ?? false ) )
4639
4743
  {
4640
4744
  _showEntry();
4641
4745
  }
@@ -5228,7 +5332,7 @@ class SideBar {
5228
5332
 
5229
5333
  select( name ) {
5230
5334
 
5231
- let pKey = name.replace( /\s/g, '' ).replaceAll( '.', '' );
5335
+ let pKey = LX.getSupportedDOMName( name );
5232
5336
 
5233
5337
  const entry = this.items.find( v => v.name === pKey );
5234
5338
 
@@ -5266,7 +5370,7 @@ class SideBar {
5266
5370
  continue;
5267
5371
  }
5268
5372
 
5269
- let pKey = key.replace( /\s/g, '' ).replaceAll( '.', '' );
5373
+ let pKey = LX.getSupportedDOMName( key );
5270
5374
  let currentGroup = null;
5271
5375
 
5272
5376
  let entry = document.createElement( 'div' );
@@ -6532,7 +6636,7 @@ class Title extends Widget {
6532
6636
  // Note: Titles are not registered in Panel.widgets by now
6533
6637
  super( Widget.TITLE, null, null, options );
6534
6638
 
6535
- this.root.className = "lextitle";
6639
+ this.root.className = `lextitle ${ this.root.className }`;
6536
6640
 
6537
6641
  if( options.icon )
6538
6642
  {
@@ -6846,7 +6950,7 @@ class Button extends Widget {
6846
6950
 
6847
6951
  var wValue = document.createElement( 'button' );
6848
6952
  wValue.title = options.tooltip ? "" : ( options.title ?? "" );
6849
- wValue.className = "lexbutton " + ( options.buttonClass ?? "" );
6953
+ wValue.className = "lexbutton p-1 " + ( options.buttonClass ?? "" );
6850
6954
 
6851
6955
  this.root.appendChild( wValue );
6852
6956
 
@@ -6983,7 +7087,7 @@ class ComboButtons extends Widget {
6983
7087
  buttonEl.classList.add( options.buttonClass );
6984
7088
  }
6985
7089
 
6986
- if( shouldSelect && b.selected )
7090
+ if( shouldSelect && ( b.selected || options.selected?.includes( b.value ) ) )
6987
7091
  {
6988
7092
  buttonEl.classList.add("selected");
6989
7093
  currentValue = ( currentValue ).concat( [ b.value ] );
@@ -7032,7 +7136,7 @@ class ComboButtons extends Widget {
7032
7136
 
7033
7137
  if( !shouldToggle && currentValue.length > 1 )
7034
7138
  {
7035
- console.error( `Enable _options.toggle_ to allow selecting multiple options in ComboButtons.` )
7139
+ console.error( `Enable _options.toggle_ to allow selecting multiple options in ComboButtons.` );
7036
7140
  return;
7037
7141
  }
7038
7142
 
@@ -7046,9 +7150,12 @@ class ComboButtons extends Widget {
7046
7150
 
7047
7151
  if( currentValue.length > 1 )
7048
7152
  {
7049
- options.toggle = true;
7050
- shouldToggle = shouldSelect;
7051
- console.warn( `Multiple options selected in '${ name }' ComboButtons. Enabling _toggle_ mode.` );
7153
+ if( !shouldToggle )
7154
+ {
7155
+ options.toggle = true;
7156
+ shouldToggle = shouldSelect;
7157
+ console.warn( `Multiple options selected in '${ name }' ComboButtons. Enabling _toggle_ mode.` );
7158
+ }
7052
7159
  }
7053
7160
  else
7054
7161
  {
@@ -7467,7 +7574,7 @@ class Select extends Widget {
7467
7574
  this.unfocus_event = true;
7468
7575
  setTimeout( () => delete this.unfocus_event, 200 );
7469
7576
  }
7470
- else if ( e.relatedTarget && ( e.relatedTarget.tagName == "INPUT" || e.relatedTarget.classList.contains("lexoptions") ) )
7577
+ else if ( e.relatedTarget && listDialog.contains( e.relatedTarget ) )
7471
7578
  {
7472
7579
  return;
7473
7580
  }
@@ -8363,7 +8470,7 @@ class RadioGroup extends Widget {
8363
8470
  container.appendChild( optionItem );
8364
8471
 
8365
8472
  const optionButton = document.createElement( 'button' );
8366
- optionButton.className = "lexbutton";
8473
+ optionButton.className = "flex p-0 rounded-lg cursor-pointer";
8367
8474
  optionButton.disabled = options.disabled ?? false;
8368
8475
  optionItem.appendChild( optionButton );
8369
8476
 
@@ -8666,7 +8773,7 @@ class NumberInput extends Widget {
8666
8773
  box.className = "numberbox";
8667
8774
  container.appendChild( box );
8668
8775
 
8669
- let valueBox = LX.makeContainer( [ "auto", "100%" ], "relative flex flex-row", "", box );
8776
+ let valueBox = LX.makeContainer( [ "auto", "100%" ], "relative flex flex-row cursor-text", "", box );
8670
8777
 
8671
8778
  let vecinput = document.createElement( 'input' );
8672
8779
  vecinput.id = "number_" + simple_guidGenerator();
@@ -8685,7 +8792,7 @@ class NumberInput extends Widget {
8685
8792
  vecinput.value = vecinput.iValue = value;
8686
8793
  valueBox.appendChild( vecinput );
8687
8794
 
8688
- const dragIcon = LX.makeIcon( "MoveVertical", { iconClass: "drag-icon hidden", svgClass: "sm" } );
8795
+ const dragIcon = LX.makeIcon( "MoveVertical", { iconClass: "drag-icon hidden-opacity", svgClass: "sm" } );
8689
8796
  valueBox.appendChild( dragIcon );
8690
8797
 
8691
8798
  if( options.units )
@@ -8769,7 +8876,7 @@ class NumberInput extends Widget {
8769
8876
 
8770
8877
  let innerMouseDown = e => {
8771
8878
 
8772
- if( document.activeElement == vecinput )
8879
+ if( ( document.activeElement == vecinput ) || ( e.button != LX.MOUSE_LEFT_CLICK ) )
8773
8880
  {
8774
8881
  return;
8775
8882
  }
@@ -8778,13 +8885,13 @@ class NumberInput extends Widget {
8778
8885
  doc.addEventListener( 'mousemove', innerMouseMove );
8779
8886
  doc.addEventListener( 'mouseup', innerMouseUp );
8780
8887
  document.body.classList.add( 'noevents' );
8781
- dragIcon.classList.remove( 'hidden' );
8888
+ dragIcon.classList.remove( 'hidden-opacity' );
8782
8889
  e.stopImmediatePropagation();
8783
8890
  e.stopPropagation();
8784
8891
 
8785
8892
  if( !document.pointerLockElement )
8786
8893
  {
8787
- vecinput.requestPointerLock();
8894
+ valueBox.requestPointerLock();
8788
8895
  }
8789
8896
 
8790
8897
  if( options.onPress )
@@ -8816,7 +8923,7 @@ class NumberInput extends Widget {
8816
8923
  doc.removeEventListener( 'mousemove', innerMouseMove );
8817
8924
  doc.removeEventListener( 'mouseup', innerMouseUp );
8818
8925
  document.body.classList.remove( 'noevents' );
8819
- dragIcon.classList.add( 'hidden' );
8926
+ dragIcon.classList.add( 'hidden-opacity' );
8820
8927
 
8821
8928
  if( document.pointerLockElement )
8822
8929
  {
@@ -8829,7 +8936,7 @@ class NumberInput extends Widget {
8829
8936
  }
8830
8937
  }
8831
8938
 
8832
- vecinput.addEventListener( "mousedown", innerMouseDown );
8939
+ valueBox.addEventListener( "mousedown", innerMouseDown );
8833
8940
 
8834
8941
  doAsync( this.onResize.bind( this ) );
8835
8942
  }
@@ -8911,6 +9018,7 @@ class Vector extends Widget {
8911
9018
  vecinput.id = "vec" + numComponents + "_" + simple_guidGenerator();
8912
9019
  vecinput.idx = i;
8913
9020
  vectorInputs[ i ] = vecinput;
9021
+ box.appendChild( vecinput );
8914
9022
 
8915
9023
  if( value[ i ].constructor == Number )
8916
9024
  {
@@ -8920,7 +9028,7 @@ class Vector extends Widget {
8920
9028
 
8921
9029
  vecinput.value = vecinput.iValue = value[ i ];
8922
9030
 
8923
- const dragIcon = LX.makeIcon( "MoveVertical", { iconClass: "drag-icon hidden", svgClass: "sm" } );
9031
+ const dragIcon = LX.makeIcon( "MoveVertical", { iconClass: "drag-icon hidden-opacity", svgClass: "sm" } );
8924
9032
  box.appendChild( dragIcon );
8925
9033
 
8926
9034
  if( options.disabled )
@@ -8983,7 +9091,7 @@ class Vector extends Widget {
8983
9091
 
8984
9092
  function innerMouseDown( e )
8985
9093
  {
8986
- if( document.activeElement == vecinput )
9094
+ if( ( document.activeElement == vecinput ) || ( e.button != LX.MOUSE_LEFT_CLICK ) )
8987
9095
  {
8988
9096
  return;
8989
9097
  }
@@ -8992,13 +9100,13 @@ class Vector extends Widget {
8992
9100
  doc.addEventListener( 'mousemove', innerMouseMove );
8993
9101
  doc.addEventListener( 'mouseup', innerMouseUp );
8994
9102
  document.body.classList.add( 'noevents' );
8995
- dragIcon.classList.remove( 'hidden' );
9103
+ dragIcon.classList.remove( 'hidden-opacity' );
8996
9104
  e.stopImmediatePropagation();
8997
9105
  e.stopPropagation();
8998
9106
 
8999
9107
  if( !document.pointerLockElement )
9000
9108
  {
9001
- vecinput.requestPointerLock();
9109
+ box.requestPointerLock();
9002
9110
  }
9003
9111
 
9004
9112
  if( options.onPress )
@@ -9042,7 +9150,7 @@ class Vector extends Widget {
9042
9150
  doc.removeEventListener( 'mousemove', innerMouseMove );
9043
9151
  doc.removeEventListener( 'mouseup', innerMouseUp );
9044
9152
  document.body.classList.remove( 'noevents' );
9045
- dragIcon.classList.add('hidden');
9153
+ dragIcon.classList.add('hidden-opacity');
9046
9154
 
9047
9155
  if( document.pointerLockElement )
9048
9156
  {
@@ -9055,9 +9163,7 @@ class Vector extends Widget {
9055
9163
  }
9056
9164
  }
9057
9165
 
9058
- vecinput.addEventListener( "mousedown", innerMouseDown );
9059
-
9060
- box.appendChild( vecinput );
9166
+ box.addEventListener( "mousedown", innerMouseDown );
9061
9167
  container.appendChild( box );
9062
9168
  }
9063
9169
 
@@ -9990,34 +10096,90 @@ class Table extends Widget {
9990
10096
  if( this.customFilters )
9991
10097
  {
9992
10098
  const icon = LX.makeIcon( "CirclePlus", { svgClass: "sm" } );
10099
+ const separatorHtml = `<div class="lexcontainer border-right self-center mx-1" style="width: 1px; height: 70%;"></div>`;
9993
10100
 
9994
10101
  for( let f of this.customFilters )
9995
10102
  {
9996
- const customFilterBtn = new Button(null, icon.innerHTML + f.name, ( v ) => {
10103
+ f.widget = new Button(null, icon.innerHTML + f.name, ( v ) => {
9997
10104
 
9998
- const menuOptions = f.options.map( ( colName, idx ) => {
9999
- const item = {
10000
- name: colName,
10001
- checked: !!this.activeCustomFilters[ colName ],
10002
- callback: (key, v, dom) => {
10003
- if( v ) { this.activeCustomFilters[ key ] = f.name; }
10004
- else {
10005
- delete this.activeCustomFilters[ key ];
10105
+ const spanName = f.widget.root.querySelector( "span" );
10106
+
10107
+ if( f.options )
10108
+ {
10109
+ const menuOptions = f.options.map( ( colName, idx ) => {
10110
+ const item = {
10111
+ name: colName,
10112
+ checked: !!this.activeCustomFilters[ colName ],
10113
+ callback: (key, v, dom) => {
10114
+ if( v ) { this.activeCustomFilters[ key ] = f.name; }
10115
+ else {
10116
+ delete this.activeCustomFilters[ key ];
10117
+ }
10118
+ const activeFilters = Object.keys( this.activeCustomFilters ).filter( k => this.activeCustomFilters[ k ] == f.name );
10119
+ const filterBadgesHtml = activeFilters.reduce( ( acc, key ) => acc += LX.badge( key, "bg-tertiary text-sm" ), "" );
10120
+ spanName.innerHTML = icon.innerHTML + f.name + ( activeFilters.length ? separatorHtml : "" ) + filterBadgesHtml;
10121
+ this.refresh();
10006
10122
  }
10007
- this.refresh();
10008
10123
  }
10124
+ return item;
10125
+ } );
10126
+ new DropdownMenu( f.widget.root, menuOptions, { side: "bottom", align: "start" });
10127
+ }
10128
+ else if( f.type == "range" )
10129
+ {
10130
+ console.assert( f.min != undefined && f.max != undefined, "Range filter needs min and max values!" );
10131
+ const container = LX.makeContainer( ["240px", "auto"], "border bg-primary rounded-lg text-md" );
10132
+ const panel = new Panel();
10133
+ LX.makeContainer( ["100%", "auto"], "px-3 p-2 pb-0 text-md font-medium", f.name, container );
10134
+
10135
+ f.start = f.start ?? f.min;
10136
+ f.end = f.end ?? f.max;
10137
+
10138
+ panel.refresh = () => {
10139
+ panel.clear();
10140
+ panel.sameLine( 2, "justify-center" );
10141
+ panel.addNumber( null, f.start, (v) => {
10142
+ f.start = v;
10143
+ const inUse = ( f.start != f.min || f.end != f.max );
10144
+ spanName.innerHTML = icon.innerHTML + f.name + ( inUse ? separatorHtml + LX.badge( `${ f.start } - ${ f.end } ${ f.units ?? "" }`, "bg-tertiary text-sm" ) : "" );
10145
+ this.refresh();
10146
+ }, { skipSlider: true, min: f.min, max: f.max, step: f.step, units: f.units } );
10147
+ panel.addNumber( null, f.end, (v) => {
10148
+ f.end = v;
10149
+ const inUse = ( f.start != f.min || f.end != f.max );
10150
+ spanName.innerHTML = icon.innerHTML + f.name + ( inUse ? separatorHtml + LX.badge( `${ f.start } - ${ f.end } ${ f.units ?? "" }`, "bg-tertiary text-sm" ) : "" );
10151
+ this.refresh();
10152
+ }, { skipSlider: true, min: f.min, max: f.max, step: f.step, units: f.units } );
10153
+ panel.addButton( null, "Reset", () => {
10154
+ f.start = f.min;
10155
+ f.end = f.max;
10156
+ spanName.innerHTML = icon.innerHTML + f.name;
10157
+ panel.refresh();
10158
+ this.refresh();
10159
+ }, { buttonClass: "contrast" } );
10009
10160
  }
10010
- return item;
10011
- } );
10012
- new DropdownMenu( customFilterBtn.root, menuOptions, { side: "bottom", align: "start" });
10013
- }, { buttonClass: " primary dashed" } );
10014
- headerContainer.appendChild( customFilterBtn.root );
10161
+ panel.refresh();
10162
+ container.appendChild( panel.root );
10163
+ new Popover( f.widget.root, [ container ], { side: "bottom" } );
10164
+ }
10165
+
10166
+ }, { buttonClass: "px-2 primary dashed" } );
10167
+ headerContainer.appendChild( f.widget.root );
10015
10168
  }
10016
10169
 
10017
10170
  this._resetCustomFiltersBtn = new Button(null, "resetButton", ( v ) => {
10018
10171
  this.activeCustomFilters = {};
10019
- this.refresh();
10020
10172
  this._resetCustomFiltersBtn.root.classList.add( "hidden" );
10173
+ for( let f of this.customFilters )
10174
+ {
10175
+ f.widget.root.querySelector( "span" ).innerHTML = ( icon.innerHTML + f.name );
10176
+ if( f.type == "range" )
10177
+ {
10178
+ f.start = f.min;
10179
+ f.end = f.max;
10180
+ }
10181
+ }
10182
+ this.refresh();
10021
10183
  }, { title: "Reset filters", icon: "X" } );
10022
10184
  headerContainer.appendChild( this._resetCustomFiltersBtn.root );
10023
10185
  this._resetCustomFiltersBtn.root.classList.add( "hidden" );
@@ -10250,6 +10412,41 @@ class Table extends Widget {
10250
10412
  }
10251
10413
  }
10252
10414
 
10415
+ // Check range/date filters
10416
+ if( this.customFilters )
10417
+ {
10418
+ let acfMap = {};
10419
+
10420
+ for( let f of this.customFilters )
10421
+ {
10422
+ const acfName = f.name;
10423
+
10424
+ if( f.type == "range" )
10425
+ {
10426
+ acfMap[ acfName ] = acfMap[ acfName ] ?? false;
10427
+
10428
+ const filterColIndex = data.head.indexOf( acfName );
10429
+ if( filterColIndex > -1 )
10430
+ {
10431
+ const validRowValue = parseFloat( bodyData[ filterColIndex ] );
10432
+ const min = f.start ?? f.min;
10433
+ const max = f.end ?? f.max;
10434
+ acfMap[ acfName ] |= ( validRowValue >= min ) && ( validRowValue <= max );
10435
+ }
10436
+ }
10437
+ else if( f.type == "date" )
10438
+ {
10439
+ // TODO
10440
+ }
10441
+ }
10442
+
10443
+ const show = Object.values( acfMap ).reduce( ( e, acc ) => acc *= e );
10444
+ if( !show )
10445
+ {
10446
+ continue;
10447
+ }
10448
+ }
10449
+
10253
10450
  const row = document.createElement( 'tr' );
10254
10451
  const rowId = LX.getSupportedDOMName( bodyData.join( '-' ) );
10255
10452
  row.setAttribute( "rowId", rowId.substr(0, 32) );
@@ -11127,6 +11324,7 @@ class Panel {
11127
11324
  * @param {Object} options:
11128
11325
  * hideName: Don't use name as label [false]
11129
11326
  * float: Justify content (left, center, right) [center]
11327
+ * selected: Selected button by default (String|Array)
11130
11328
  * noSelection: Buttons can be clicked, but they are not selectable
11131
11329
  * toggle: Buttons can be toggled insted of selecting only one
11132
11330
  */
@@ -13409,7 +13607,7 @@ class AssetView {
13409
13607
 
13410
13608
  if( !this.skipBrowser )
13411
13609
  {
13412
- [left, right] = area.split({ type: "horizontal", sizes: ["15%", "85%"]});
13610
+ [ left, right ] = area.split({ type: "horizontal", sizes: ["15%", "85%"]});
13413
13611
  contentArea = right;
13414
13612
 
13415
13613
  left.setLimitBox( 210, 0 );
@@ -13619,7 +13817,7 @@ class AssetView {
13619
13817
  }
13620
13818
  else
13621
13819
  {
13622
- this.rightPanel = area.addPanel({ className: 'lexassetcontentpanel' });
13820
+ this.rightPanel = area.addPanel({ className: 'lexassetcontentpanel flex flex-col overflow-hidden' });
13623
13821
  }
13624
13822
 
13625
13823
  const on_sort = ( value, event ) => {
@@ -14663,26 +14861,31 @@ LX.ICONS = {
14663
14861
  "Folder": [512, 512, [], "solid", "M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z"],
14664
14862
  "FolderOpen": [576, 512, [], "solid", "M384 480l48 0c11.4 0 21.9-6 27.6-15.9l112-192c5.8-9.9 5.8-22.1 .1-32.1S555.5 224 544 224l-400 0c-11.4 0-21.9 6-27.6 15.9L48 357.1 48 96c0-8.8 7.2-16 16-16l117.5 0c4.2 0 8.3 1.7 11.3 4.7l26.5 26.5c21 21 49.5 32.8 79.2 32.8L416 144c8.8 0 16 7.2 16 16l0 32 48 0 0-32c0-35.3-28.7-64-64-64L298.5 96c-17 0-33.3-6.7-45.3-18.7L226.7 50.7c-12-12-28.3-18.7-45.3-18.7L64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l23.7 0L384 480z"],
14665
14863
  "FolderClosed": [512, 512, [], "solid", "M448 480L64 480c-35.3 0-64-28.7-64-64L0 192l512 0 0 224c0 35.3-28.7 64-64 64zm64-320L0 160 0 96C0 60.7 28.7 32 64 32l128 0c20.1 0 39.1 9.5 51.2 25.6l19.2 25.6c6 8.1 15.5 12.8 25.6 12.8l160 0c35.3 0 64 28.7 64 64z"],
14666
- "Play": [384, 512, [], "solid", "M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80L0 432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"],
14667
- "Pause": [320, 512, [], "solid", "M48 64C21.5 64 0 85.5 0 112L0 400c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48L48 64zm192 0c-26.5 0-48 21.5-48 48l0 288c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48l-32 0z"],
14864
+ "Function": [384, 512, [], "solid", "M314.7 32c-38.8 0-73.7 23.3-88.6 59.1L170.7 224 64 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l80 0L98.9 396.3c-5 11.9-16.6 19.7-29.5 19.7L32 416c-17.7 0-32 14.3-32 32s14.3 32 32 32l37.3 0c38.8 0 73.7-23.3 88.6-59.1L213.3 288 320 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-80 0 45.1-108.3c5-11.9 16.6-19.7 29.5-19.7L352 96c17.7 0 32-14.3 32-32s-14.3-32-32-32l-37.3 0z"],
14668
14865
  "Stop": [384, 512, [], "solid", "M0 128C0 92.7 28.7 64 64 64H320c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z"],
14669
14866
  "Image": [512, 512, [], "solid", "M448 80c8.8 0 16 7.2 16 16l0 319.8-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3L48 96c0-8.8 7.2-16 16-16l384 0zM64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"],
14670
14867
  "Images": [576, 512, [], "solid", "M160 80l352 0c8.8 0 16 7.2 16 16l0 224c0 8.8-7.2 16-16 16l-21.2 0L388.1 178.9c-4.4-6.8-12-10.9-20.1-10.9s-15.7 4.1-20.1 10.9l-52.2 79.8-12.4-16.9c-4.5-6.2-11.7-9.8-19.4-9.8s-14.8 3.6-19.4 9.8L175.6 336 160 336c-8.8 0-16-7.2-16-16l0-224c0-8.8 7.2-16 16-16zM96 96l0 224c0 35.3 28.7 64 64 64l352 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L160 32c-35.3 0-64 28.7-64 64zM48 120c0-13.3-10.7-24-24-24S0 106.7 0 120L0 344c0 75.1 60.9 136 136 136l320 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-320 0c-48.6 0-88-39.4-88-88l0-224zm208 24a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"],
14671
- "Function": [384, 512, [], "solid", "M314.7 32c-38.8 0-73.7 23.3-88.6 59.1L170.7 224 64 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l80 0L98.9 396.3c-5 11.9-16.6 19.7-29.5 19.7L32 416c-17.7 0-32 14.3-32 32s14.3 32 32 32l37.3 0c38.8 0 73.7-23.3 88.6-59.1L213.3 288 320 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-80 0 45.1-108.3c5-11.9 16.6-19.7 29.5-19.7L352 96c17.7 0 32-14.3 32-32s-14.3-32-32-32l-37.3 0z"],
14868
+ "Info": [512, 512, [], "solid", "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"],
14672
14869
  "Bone": [576, 512, [], "solid", "M153.7 144.8c6.9 16.3 20.6 31.2 38.3 31.2l192 0c17.7 0 31.4-14.9 38.3-31.2C434.4 116.1 462.9 96 496 96c44.2 0 80 35.8 80 80c0 30.4-17 56.9-42 70.4c-3.6 1.9-6 5.5-6 9.6s2.4 7.7 6 9.6c25 13.5 42 40 42 70.4c0 44.2-35.8 80-80 80c-33.1 0-61.6-20.1-73.7-48.8C415.4 350.9 401.7 336 384 336l-192 0c-17.7 0-31.4 14.9-38.3 31.2C141.6 395.9 113.1 416 80 416c-44.2 0-80-35.8-80-80c0-30.4 17-56.9 42-70.4c3.6-1.9 6-5.5 6-9.6s-2.4-7.7-6-9.6C17 232.9 0 206.4 0 176c0-44.2 35.8-80 80-80c33.1 0 61.6 20.1 73.7 48.8z"],
14673
14870
  "Puzzle": [512, 512, [], "solid", "M192 104.8c0-9.2-5.8-17.3-13.2-22.8C167.2 73.3 160 61.3 160 48c0-26.5 28.7-48 64-48s64 21.5 64 48c0 13.3-7.2 25.3-18.8 34c-7.4 5.5-13.2 13.6-13.2 22.8c0 12.8 10.4 23.2 23.2 23.2l56.8 0c26.5 0 48 21.5 48 48l0 56.8c0 12.8 10.4 23.2 23.2 23.2c9.2 0 17.3-5.8 22.8-13.2c8.7-11.6 20.7-18.8 34-18.8c26.5 0 48 28.7 48 64s-21.5 64-48 64c-13.3 0-25.3-7.2-34-18.8c-5.5-7.4-13.6-13.2-22.8-13.2c-12.8 0-23.2 10.4-23.2 23.2L384 464c0 26.5-21.5 48-48 48l-56.8 0c-12.8 0-23.2-10.4-23.2-23.2c0-9.2 5.8-17.3 13.2-22.8c11.6-8.7 18.8-20.7 18.8-34c0-26.5-28.7-48-64-48s-64 21.5-64 48c0 13.3 7.2 25.3 18.8 34c7.4 5.5 13.2 13.6 13.2 22.8c0 12.8-10.4 23.2-23.2 23.2L48 512c-26.5 0-48-21.5-48-48L0 343.2C0 330.4 10.4 320 23.2 320c9.2 0 17.3 5.8 22.8 13.2C54.7 344.8 66.7 352 80 352c26.5 0 48-28.7 48-64s-21.5-64-48-64c-13.3 0-25.3 7.2-34 18.8C40.5 250.2 32.4 256 23.2 256C10.4 256 0 245.6 0 232.8L0 176c0-26.5 21.5-48 48-48l120.8 0c12.8 0 23.2-10.4 23.2-23.2z"],
14674
14871
  "Lock": [448, 512, [], "solid", "M144 144l0 48 160 0 0-48c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192l0-48C80 64.5 144.5 0 224 0s144 64.5 144 144l0 48 16 0c35.3 0 64 28.7 64 64l0 192c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 256c0-35.3 28.7-64 64-64l16 0z"],
14675
14872
  "LockOpen": [576, 512, [], "solid", "M352 144c0-44.2 35.8-80 80-80s80 35.8 80 80l0 48c0 17.7 14.3 32 32 32s32-14.3 32-32l0-48C576 64.5 511.5 0 432 0S288 64.5 288 144l0 48L64 192c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-192c0-35.3-28.7-64-64-64l-32 0 0-48z"],
14676
14873
  "Shuffle": [512, 512, [], "solid", "M403.8 34.4c12-5 25.7-2.2 34.9 6.9l64 64c6 6 9.4 14.1 9.4 22.6s-3.4 16.6-9.4 22.6l-64 64c-9.2 9.2-22.9 11.9-34.9 6.9s-19.8-16.6-19.8-29.6l0-32-32 0c-10.1 0-19.6 4.7-25.6 12.8L284 229.3 244 176l31.2-41.6C293.3 110.2 321.8 96 352 96l32 0 0-32c0-12.9 7.8-24.6 19.8-29.6zM164 282.7L204 336l-31.2 41.6C154.7 401.8 126.2 416 96 416l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0c10.1 0 19.6-4.7 25.6-12.8L164 282.7zm274.6 188c-9.2 9.2-22.9 11.9-34.9 6.9s-19.8-16.6-19.8-29.6l0-32-32 0c-30.2 0-58.7-14.2-76.8-38.4L121.6 172.8c-6-8.1-15.5-12.8-25.6-12.8l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0c30.2 0 58.7 14.2 76.8 38.4L326.4 339.2c6 8.1 15.5 12.8 25.6 12.8l32 0 0-32c0-12.9 7.8-24.6 19.8-29.6s25.7-2.2 34.9 6.9l64 64c6 6 9.4 14.1 9.4 22.6s-3.4 16.6-9.4 22.6l-64 64z"],
14874
+ "Play": [384, 512, [], "solid", "M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80L0 432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"],
14875
+ "Pause": [320, 512, [], "solid", "M48 64C21.5 64 0 85.5 0 112L0 400c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48L48 64zm192 0c-26.5 0-48 21.5-48 48l0 288c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48l-32 0z"],
14876
+ "PlusCircle": [512, 512, [], "solid", "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM232 344l0-64-64 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l64 0 0-64c0-13.3 10.7-24 24-24s24 10.7 24 24l0 64 64 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-64 0 0 64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"],
14677
14877
  "LogIn": [512, 512, [], "solid", "M352 96l64 0c17.7 0 32 14.3 32 32l0 256c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0c53 0 96-43 96-96l0-256c0-53-43-96-96-96l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm-9.4 182.6c12.5-12.5 12.5-32.8 0-45.3l-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L242.7 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l210.7 0-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l128-128z"],
14678
14878
  "LogOut": [512, 512, [], "solid", "M502.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 224 192 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l210.7 0-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l128-128zM160 96c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 32C43 32 0 75 0 128L0 384c0 53 43 96 96 96l64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0c-17.7 0-32-14.3-32-32l0-256c0-17.7 14.3-32 32-32l64 0z"],
14679
14879
  "MousePointer": [320, 512, [], "solid", "M0 55.2L0 426c0 12.2 9.9 22 22 22c6.3 0 12.4-2.7 16.6-7.5L121.2 346l58.1 116.3c7.9 15.8 27.1 22.2 42.9 14.3s22.2-27.1 14.3-42.9L179.8 320l118.1 0c12.2 0 22.1-9.9 22.1-22.1c0-6.3-2.7-12.3-7.4-16.5L38.6 37.9C34.3 34.1 28.9 32 23.2 32C10.4 32 0 42.4 0 55.2z"],
14680
14880
  "User": [512, 512, [], "solid", "M256 288A144 144 0 1 0 256 0a144 144 0 1 0 0 288zm-94.7 32C72.2 320 0 392.2 0 481.3c0 17 13.8 30.7 30.7 30.7l450.6 0c17 0 30.7-13.8 30.7-30.7C512 392.2 439.8 320 350.7 320l-189.4 0z"],
14681
14881
  "HardDriveDownload": [512, 512, [], "solid", "M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 242.7-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7 288 32zM64 352c-35.3 0-64 28.7-64 64l0 32c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-32c0-35.3-28.7-64-64-64l-101.5 0-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352 64 352zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"],
14682
14882
  "HardDriveUpload": [512, 512, [], "solid", "M288 109.3L288 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-242.7-73.4 73.4c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l128-128c12.5-12.5 32.8-12.5 45.3 0l128 128c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L288 109.3zM64 352l128 0c0 35.3 28.7 64 64 64s64-28.7 64-64l128 0c35.3 0 64 28.7 64 64l0 32c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64l0-32c0-35.3 28.7-64 64-64zM432 456a24 24 0 1 0 0-48 24 24 0 1 0 0 48z"],
14683
- "CirclePlay": [512, 512, [], "solid", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9l0-176c0-8.7 4.7-16.7 12.3-20.9z"],
14684
- "CircleStop": [512, 512, [], "solid", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm192-96l128 0c17.7 0 32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32l0-128c0-17.7 14.3-32 32-32z"],
14883
+ "CircleCheck": [512, 512, ["CheckCircle2"], "solid", "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"],
14884
+ "CirclePlay": [512, 512, [], "solid", "M0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c-7.6 4.2-12.3 12.3-12.3 20.9l0 176c0 8.7 4.7 16.7 12.3 20.9s16.8 4.1 24.3-.5l144-88c7.1-4.4 11.5-12.1 11.5-20.5s-4.4-16.1-11.5-20.5l-144-88c-7.4-4.5-16.7-4.7-24.3-.5z"],
14885
+ "CirclePause": [512, 512, [], "solid", "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM224 192l0 128c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-128c0-17.7 14.3-32 32-32s32 14.3 32 32zm128 0l0 128c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-128c0-17.7 14.3-32 32-32s32 14.3 32 32z"],
14886
+ "CircleStop": [512, 512, [], "solid", "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM192 160l128 0c17.7 0 32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32l0-128c0-17.7 14.3-32 32-32z"],
14685
14887
  "CircleDot": [512, 512, [], "solid", "M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm256-96a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"],
14888
+ "CircleHelp": [512, 512, ["HelpCircle"], "solid", "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM169.8 165.3c7.9-22.3 29.1-37.3 52.8-37.3l58.3 0c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24l0-13.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1l-58.3 0c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"],
14686
14889
  "Apple": [384, 512, [], "solid", "M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"],
14687
14890
  "Chrome": [512, 512, [], "solid", "M0 256C0 209.4 12.47 165.6 34.27 127.1L144.1 318.3C166 357.5 207.9 384 256 384C270.3 384 283.1 381.7 296.8 377.4L220.5 509.6C95.9 492.3 0 385.3 0 256zM365.1 321.6C377.4 302.4 384 279.1 384 256C384 217.8 367.2 183.5 340.7 160H493.4C505.4 189.6 512 222.1 512 256C512 397.4 397.4 511.1 256 512L365.1 321.6zM477.8 128H256C193.1 128 142.3 172.1 130.5 230.7L54.19 98.47C101 38.53 174 0 256 0C350.8 0 433.5 51.48 477.8 128V128zM168 256C168 207.4 207.4 168 256 168C304.6 168 344 207.4 344 256C344 304.6 304.6 344 256 344C207.4 344 168 304.6 168 256z"],
14688
14891
  "Facebook": [512, 512, [], "solid", "M512 256C512 114.6 397.4 0 256 0S0 114.6 0 256C0 376 82.7 476.8 194.2 504.5V334.2H141.4V256h52.8V222.3c0-87.1 39.4-127.5 125-127.5c16.2 0 44.2 3.2 55.7 6.4V172c-6-.6-16.5-1-29.6-1c-42 0-58.2 15.9-58.2 57.2V256h83.6l-14.4 78.2H287V510.1C413.8 494.8 512 386.9 512 256h0z"],
@@ -14698,7 +14901,9 @@ LX.ICONS = {
14698
14901
  "Chain": "Link",
14699
14902
  "ChainBroken": "LinkOff",
14700
14903
  "ChainOff": "LinkOff",
14701
- "Unlink": "LinkOff"
14904
+ "Unlink": "LinkOff",
14905
+ "HelpCircle": "CircleHelp",
14906
+ "CheckCircle2": "CircleCheck"
14702
14907
  }
14703
14908
 
14704
14909
  // Alias for Lucide Icons