lexgui 0.5.2 → 0.5.3

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.5.2",
9
+ version: "0.5.3",
10
10
  ready: false,
11
11
  components: [], // Specific pre-build components
12
12
  signals: {}, // Events and triggers
@@ -1625,7 +1625,7 @@ class DropdownMenu {
1625
1625
  {
1626
1626
  f.call( this, key, menuItem, v );
1627
1627
  }
1628
- });
1628
+ }, { className: "accent" });
1629
1629
  const input = checkbox.root.querySelector( "input" );
1630
1630
  menuItem.prepend( input );
1631
1631
 
@@ -1789,7 +1789,7 @@ class Area {
1789
1789
  root.className += " " + options.className;
1790
1790
  }
1791
1791
 
1792
- var width = options.width || "calc( 100% )";
1792
+ var width = options.width || "100%";
1793
1793
  var height = options.height || "100%";
1794
1794
 
1795
1795
  // This has default options..
@@ -2381,7 +2381,7 @@ class Area {
2381
2381
 
2382
2382
  if( options.sticky ?? true )
2383
2383
  {
2384
- bar.root.classList.add( "sticky" );
2384
+ bar.root.className += " sticky top-0";
2385
2385
  }
2386
2386
 
2387
2387
  return menubar;
@@ -2478,7 +2478,8 @@ class Area {
2478
2478
  selected: b.selected,
2479
2479
  icon: b.icon,
2480
2480
  img: b.img,
2481
- className: b.class
2481
+ className: b.class ?? "",
2482
+ title: b.name
2482
2483
  };
2483
2484
 
2484
2485
  if( group )
@@ -2781,6 +2782,12 @@ class Tabs {
2781
2782
 
2782
2783
  this.area = area.sections[1];
2783
2784
  this.area.root.className += " lexareatabscontent";
2785
+
2786
+ if( options.contentClass )
2787
+ {
2788
+ this.area.root.className += ` ${ options.contentClass }`;
2789
+ }
2790
+
2784
2791
  this.selected = null;
2785
2792
  this.root = container;
2786
2793
  this.tabs = {};
@@ -2800,8 +2807,8 @@ class Tabs {
2800
2807
  var transition = this.thumb.style.transition;
2801
2808
  this.thumb.style.transition = "none";
2802
2809
  this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
2803
- this.thumb.style.width = ( tabEl.offsetWidth - 5 ) + "px";
2804
- this.thumb.style.height = ( tabEl.offsetHeight - 6 ) + "px";
2810
+ this.thumb.style.width = ( tabEl.offsetWidth ) + "px";
2811
+ this.thumb.style.height = ( tabEl.offsetHeight ) + "px";
2805
2812
  flushCss( this.thumb );
2806
2813
  this.thumb.style.transition = transition;
2807
2814
  });
@@ -2973,8 +2980,8 @@ class Tabs {
2973
2980
  if( isSelected && this.thumb )
2974
2981
  {
2975
2982
  this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
2976
- this.thumb.style.width = ( tabEl.offsetWidth - 5 ) + "px";
2977
- this.thumb.style.height = ( tabEl.offsetHeight - 6 ) + "px";
2983
+ this.thumb.style.width = ( tabEl.offsetWidth ) + "px";
2984
+ this.thumb.style.height = ( tabEl.offsetHeight ) + "px";
2978
2985
  this.thumb.item = tabEl;
2979
2986
  }
2980
2987
 
@@ -3738,12 +3745,11 @@ class SideBar {
3738
3745
  // Entry filter
3739
3746
  if( ( options.filter ?? false ) )
3740
3747
  {
3741
- const panel = new Panel();
3742
- panel.addText(null, "", (value, event) => {
3748
+ const filterTextInput = new TextInput(null, "", (value, event) => {
3743
3749
  this.filterString = value;
3744
3750
  this.update();
3745
- }, { placeholder: "Search...", icon: "fa-solid fa-magnifying-glass" });
3746
- this.filter = panel.root.childNodes[ 0 ];
3751
+ }, { inputClass: "outline", placeholder: "Search...", icon: "fa-solid fa-magnifying-glass", className: "lexsidebarfilter" });
3752
+ this.filter = filterTextInput.root;
3747
3753
  this.root.appendChild( this.filter );
3748
3754
  }
3749
3755
 
@@ -3766,7 +3772,7 @@ class SideBar {
3766
3772
  // Set width depending on header/footer
3767
3773
  doAsync( () => {
3768
3774
  // This account for header, footer and all inner paddings
3769
- const contentOffset = 32 + ( this.header?.offsetHeight ?? 0 ) +
3775
+ const contentOffset = ( this.header?.offsetHeight ?? 0 ) +
3770
3776
  ( this.filter?.offsetHeight ?? 0 ) +
3771
3777
  ( this.footer?.offsetHeight ?? 0 );
3772
3778
  this.content.style.height = `calc(100% - ${ contentOffset }px)`;
@@ -4138,7 +4144,7 @@ class SideBar {
4138
4144
  const f = options.callback;
4139
4145
  item.value = value;
4140
4146
  if( f ) f.call( this, key, value, event );
4141
- }, { label: key, signal: ( "@checkbox_" + key ) });
4147
+ }, { className: "accent", label: key, signal: ( "@checkbox_" + key ) });
4142
4148
  itemDom.appendChild( panel.root.childNodes[ 0 ] );
4143
4149
  }
4144
4150
  else
@@ -4378,8 +4384,6 @@ class Widget {
4378
4384
 
4379
4385
  if( type != Widget.TITLE )
4380
4386
  {
4381
- // root.style.width = "calc(100% - " + (this._currentBranch || type == Widget.FILE || type == Widget.TREE ? 10 : 20) + "px)";
4382
-
4383
4387
  if( options.width )
4384
4388
  {
4385
4389
  root.style.width = root.style.minWidth = options.width;
@@ -4415,6 +4419,7 @@ class Widget {
4415
4419
  domName.innerHTML = name;
4416
4420
  domName.title = options.title ?? domName.innerHTML;
4417
4421
  domName.style.width = options.nameWidth || LX.DEFAULT_NAME_WIDTH;
4422
+ domName.style.minWidth = domName.style.width;
4418
4423
 
4419
4424
  root.appendChild( domName );
4420
4425
  root.domName = domName;
@@ -4645,16 +4650,18 @@ function ADD_CUSTOM_WIDGET( customWidgetName, options = {} )
4645
4650
  container.className = "lexcustomcontainer";
4646
4651
  container.style.width = "100%";
4647
4652
  element.appendChild( container );
4653
+ element.dataset["opened"] = false;
4648
4654
 
4649
- let buttonName = "<a class='fa-solid " + (options.icon ?? "fa-cube") + "' style='float:left'></a>";
4655
+ let buttonName = "<a class='fa-solid " + (options.icon ?? "fa-cube") + "'></a>";
4650
4656
  buttonName += customWidgetName + (!instance ? " [empty]" : "");
4651
4657
  // Add always icon to keep spacing right
4652
- buttonName += "<a class='fa-solid " + (instance ? "fa-bars-staggered" : " ") + " menu' style='float:right; width:5%;'></a>";
4658
+ buttonName += "<a class='fa-solid " + (instance ? "fa-bars-staggered" : " ") + " menu'></a>";
4653
4659
 
4654
4660
  let buttonEl = this.addButton(null, buttonName, (value, event) => {
4655
4661
  if( instance )
4656
4662
  {
4657
4663
  element.querySelector(".lexcustomitems").toggleAttribute('hidden');
4664
+ element.dataset["opened"] = !element.querySelector(".lexcustomitems").hasAttribute("hidden");
4658
4665
  }
4659
4666
  else
4660
4667
  {
@@ -4663,6 +4670,7 @@ function ADD_CUSTOM_WIDGET( customWidgetName, options = {} )
4663
4670
  instance = {};
4664
4671
  refresh_widget();
4665
4672
  element.querySelector(".lexcustomitems").toggleAttribute('hidden', false);
4673
+ element.dataset["opened"] = !element.querySelector(".lexcustomitems").hasAttribute("hidden");
4666
4674
  });
4667
4675
  });
4668
4676
  }
@@ -4777,7 +4785,7 @@ class NodeTree {
4777
4785
  _createItem( parent, node, level = 0, selectedId ) {
4778
4786
 
4779
4787
  const that = this;
4780
- const nodeFilterInput = this.domEl.querySelector( "#lexnodetree_filter" );
4788
+ const nodeFilterInput = this.domEl.querySelector( ".lexnodetree_filter" );
4781
4789
 
4782
4790
  node.children = node.children ?? [];
4783
4791
  if( nodeFilterInput && nodeFilterInput.value != "" && !node.id.includes( nodeFilterInput.value ) )
@@ -5356,14 +5364,7 @@ class TextInput extends Widget {
5356
5364
 
5357
5365
  this._lastValueTriggered = value = newValue;
5358
5366
 
5359
- if( options.disabled )
5360
- {
5361
- wValue.innerText = newValue;
5362
- }
5363
- else
5364
- {
5365
- wValue.value = newValue;
5366
- }
5367
+ wValue.value = newValue;
5367
5368
 
5368
5369
  if( !skipCallback )
5369
5370
  {
@@ -5384,21 +5385,17 @@ class TextInput extends Widget {
5384
5385
  };
5385
5386
 
5386
5387
  let container = document.createElement( 'div' );
5387
- container.className = "lextext" + ( options.warning ? " lexwarning" : "" );
5388
+ container.className = ( options.warning ? " lexwarning" : "" );
5388
5389
  container.style.display = "flex";
5389
5390
  this.root.appendChild( container );
5390
5391
 
5391
- if( options.textClass )
5392
- {
5393
- container.classList.add( options.textClass );
5394
- }
5395
-
5396
5392
  this.disabled = ( options.disabled || options.warning ) ?? ( options.url ? true : false );
5397
5393
  let wValue = null;
5398
5394
 
5399
5395
  if( !this.disabled )
5400
5396
  {
5401
5397
  wValue = document.createElement( 'input' );
5398
+ wValue.className = "lextext " + ( options.inputClass ?? "" );
5402
5399
  wValue.type = options.type || "";
5403
5400
  wValue.value = wValue.iValue = value || "";
5404
5401
  wValue.style.width = "100%";
@@ -5451,21 +5448,29 @@ class TextInput extends Widget {
5451
5448
  }
5452
5449
 
5453
5450
  }
5454
- else
5451
+ else if( options.url )
5455
5452
  {
5456
- wValue = document.createElement( options.url ? 'a' : 'div' );
5457
-
5458
- if( options.url )
5459
- {
5460
- wValue.href = options.url;
5461
- wValue.target = "_blank";
5462
- }
5453
+ wValue = document.createElement( 'a' );
5454
+ wValue.href = options.url;
5455
+ wValue.target = "_blank";
5463
5456
 
5464
5457
  const icon = options.warning ? '<i class="fa-solid fa-triangle-exclamation"></i>' : '';
5465
5458
  wValue.innerHTML = ( icon + value ) || "";
5466
5459
  wValue.style.width = "100%";
5467
5460
  wValue.style.textAlign = options.float ?? "";
5468
- wValue.className = "ellipsis-overflow";
5461
+ wValue.className = "lextext ellipsis-overflow";
5462
+ }
5463
+ else
5464
+ {
5465
+ wValue = document.createElement( 'input' );
5466
+
5467
+ const icon = options.warning ? '<i class="fa-solid fa-triangle-exclamation"></i>' : '';
5468
+ wValue.disabled = true;
5469
+ wValue.innerHTML = icon;
5470
+ wValue.value = value;
5471
+ wValue.style.width = "100%";
5472
+ wValue.style.textAlign = options.float ?? "";
5473
+ wValue.className = "lextext ellipsis-overflow " + ( options.inputClass ?? "" );
5469
5474
  }
5470
5475
 
5471
5476
  Object.assign( wValue.style, options.style ?? {} );
@@ -5596,6 +5601,12 @@ class Button extends Widget {
5596
5601
  var wValue = document.createElement( 'button' );
5597
5602
  wValue.title = options.title ?? "";
5598
5603
  wValue.className = "lexbutton " + ( options.buttonClass ?? "" );
5604
+
5605
+ if( options.icon )
5606
+ {
5607
+ wValue.classList.add( "justify-center" );
5608
+ }
5609
+
5599
5610
  this.root.appendChild( wValue );
5600
5611
 
5601
5612
  if( options.selected )
@@ -5902,7 +5913,7 @@ class Form extends Widget {
5902
5913
  }
5903
5914
 
5904
5915
  entryData.placeholder = entryData.placeholder ?? entry;
5905
- entryData.width = "calc(100% - 10px)";
5916
+ entryData.width = "100%";
5906
5917
 
5907
5918
  // this.addLabel( entry, { textClass: "formlabel" } );
5908
5919
 
@@ -5932,7 +5943,7 @@ class Form extends Widget {
5932
5943
  {
5933
5944
  callback( container.formData, event );
5934
5945
  }
5935
- }, { buttonClass: "primary", width: "calc(100% - 10px)" } );
5946
+ }, { buttonClass: "primary" } );
5936
5947
 
5937
5948
  container.appendChild( submitButton.root );
5938
5949
  }
@@ -5975,7 +5986,7 @@ class Select extends Widget {
5975
5986
  // Reset filter
5976
5987
  if( filter )
5977
5988
  {
5978
- filter.querySelector( "input" ).value = "";
5989
+ filter.root.querySelector( "input" ).value = "";
5979
5990
  const filteredOptions = this._filterOptions( values, "" );
5980
5991
  list.refresh( filteredOptions );
5981
5992
  }
@@ -6002,7 +6013,7 @@ class Select extends Widget {
6002
6013
 
6003
6014
  // Add select widget button
6004
6015
  let buttonName = value;
6005
- buttonName += "<a class='fa-solid fa-angle-down' style='float:right; margin-right: 3px;'></a>";
6016
+ buttonName += "<a class='fa-solid fa-angle-down'></a>";
6006
6017
 
6007
6018
  const _placeOptions = ( parent ) => {
6008
6019
 
@@ -6028,6 +6039,7 @@ class Select extends Widget {
6028
6039
  {
6029
6040
  const rect = nestedDialog.getBoundingClientRect();
6030
6041
  topPosition -= rect.y;
6042
+ maxY -= rect.y;
6031
6043
  }
6032
6044
 
6033
6045
  parent.style.top = ( topPosition + selectRoot.offsetHeight ) + 'px';
@@ -6093,7 +6105,7 @@ class Select extends Widget {
6093
6105
 
6094
6106
  if( filter )
6095
6107
  {
6096
- filter.querySelector( "input" ).focus();
6108
+ filter.root.querySelector( "input" ).focus();
6097
6109
  }
6098
6110
 
6099
6111
  }, { buttonClass: "array", skipInlineCount: true, disabled: options.disabled } );
@@ -6132,7 +6144,7 @@ class Select extends Widget {
6132
6144
  this.unfocus_event = true;
6133
6145
  setTimeout( () => delete this.unfocus_event, 200 );
6134
6146
  }
6135
- else if ( e.relatedTarget && e.relatedTarget.tagName == "INPUT" )
6147
+ else if ( e.relatedTarget && ( e.relatedTarget.tagName == "INPUT" || e.relatedTarget.classList.contains("lexoptions") ) )
6136
6148
  {
6137
6149
  return;
6138
6150
  }
@@ -6153,12 +6165,13 @@ class Select extends Widget {
6153
6165
  filterOptions.trigger = "input";
6154
6166
  filterOptions.icon = "fa-solid fa-magnifying-glass";
6155
6167
  filterOptions.className = "lexfilter";
6168
+ filterOptions.inputClass = "outline";
6156
6169
 
6157
- let filter = new TextInput(null, options.filterValue ?? "", ( v ) => {
6170
+ filter = new TextInput(null, options.filterValue ?? "", ( v ) => {
6158
6171
  const filteredOptions = this._filterOptions( values, v );
6159
6172
  list.refresh( filteredOptions );
6160
6173
  }, filterOptions );
6161
- filter.root.querySelector( ".lextext" ).classList.remove( "lextext" );
6174
+ filter.root.querySelector( ".lextext" ).style.border = "1px solid transparent";
6162
6175
 
6163
6176
  const input = filter.root.querySelector( "input" );
6164
6177
 
@@ -6179,12 +6192,12 @@ class Select extends Widget {
6179
6192
  list.appendChild( listOptions );
6180
6193
 
6181
6194
  // Add select options list
6182
- list.refresh = ( options ) => {
6195
+ list.refresh = ( currentOptions ) => {
6183
6196
 
6184
6197
  // Empty list
6185
6198
  listOptions.innerHTML = "";
6186
6199
 
6187
- if( !options.length )
6200
+ if( !currentOptions.length )
6188
6201
  {
6189
6202
  let iValue = options.emptyMsg ?? "No options found.";
6190
6203
 
@@ -6200,9 +6213,9 @@ class Select extends Widget {
6200
6213
  return;
6201
6214
  }
6202
6215
 
6203
- for( let i = 0; i < options.length; i++ )
6216
+ for( let i = 0; i < currentOptions.length; i++ )
6204
6217
  {
6205
- let iValue = options[ i ];
6218
+ let iValue = currentOptions[ i ];
6206
6219
  let li = document.createElement( "li" );
6207
6220
  let option = document.createElement( "div" );
6208
6221
  option.className = "option";
@@ -6527,13 +6540,15 @@ class ItemArray extends Widget {
6527
6540
  container.className = "lexarray";
6528
6541
  container.style.width = "100%";
6529
6542
  this.root.appendChild( container );
6543
+ this.root.dataset["opened"] = false;
6530
6544
 
6531
- const angleDown = `<a class='fa-solid fa-angle-down' style='float:right; margin-right: 3px;'></a>`;
6545
+ const angleDown = `<a class='fa-solid fa-angle-down'></a>`;
6532
6546
 
6533
6547
  let buttonName = "Array (size " + values.length + ")";
6534
6548
  buttonName += angleDown;
6535
6549
 
6536
6550
  const toggleButton = new Button(null, buttonName, () => {
6551
+ this.root.dataset["opened"] = this.root.dataset["opened"] == "true" ? false : true;
6537
6552
  this.root.querySelector(".lexarrayitems").toggleAttribute('hidden');
6538
6553
  }, { buttonClass: 'array' });
6539
6554
  container.appendChild( toggleButton.root );
@@ -6597,7 +6612,7 @@ class ItemArray extends Widget {
6597
6612
  }
6598
6613
 
6599
6614
  buttonName = "Add item";
6600
- buttonName += "<a class='fa-solid fa-plus' style='float:right; margin-right: 3px; margin-top: 2px;'></a>";
6615
+ buttonName += "<a class='fa-solid fa-plus'></a>";
6601
6616
 
6602
6617
  const addButton = new Button(null, buttonName, (v, event) => {
6603
6618
  values.push( options.innerValues ? options.innerValues[ 0 ] : "" );
@@ -6847,7 +6862,7 @@ class Checkbox extends Widget {
6847
6862
 
6848
6863
  let checkbox = document.createElement( "input" );
6849
6864
  checkbox.type = "checkbox";
6850
- checkbox.className = "lexcheckbox " + ( options.className ?? "" );
6865
+ checkbox.className = "lexcheckbox " + ( options.className ?? "primary" );
6851
6866
  checkbox.checked = value;
6852
6867
  checkbox.disabled = options.disabled ?? false;
6853
6868
  container.appendChild( checkbox );
@@ -7068,8 +7083,7 @@ class ColorInput extends Widget {
7068
7083
  newValue = hexToRgb( newValue );
7069
7084
  }
7070
7085
 
7071
- // Means it was called from the color input listener, not the text
7072
- if( event )
7086
+ if( !this._skipTextUpdate )
7073
7087
  {
7074
7088
  textWidget.set( newValue, true, event );
7075
7089
  }
@@ -7095,9 +7109,8 @@ class ColorInput extends Widget {
7095
7109
  color.style.width = "32px";
7096
7110
  color.type = 'color';
7097
7111
  color.className = "colorinput";
7098
- color.id = "color" + simple_guidGenerator();
7099
7112
  color.useRGB = options.useRGB ?? false;
7100
- color.value = color.iValue = value;
7113
+ color.value = value;
7101
7114
  container.appendChild( color );
7102
7115
 
7103
7116
  if( options.disabled )
@@ -7110,8 +7123,10 @@ class ColorInput extends Widget {
7110
7123
  }, false );
7111
7124
 
7112
7125
  const textWidget = new TextInput( null, color.value, v => {
7126
+ this._skipTextUpdate = true;
7113
7127
  this.set( v );
7114
- }, { width: "calc( 100% - 32px )"});
7128
+ delete this._skipTextUpdate;
7129
+ }, { width: "calc( 100% - 32px )", disabled: options.disabled });
7115
7130
 
7116
7131
  textWidget.root.style.marginLeft = "4px";
7117
7132
  container.appendChild( textWidget.root );
@@ -7163,12 +7178,23 @@ class RangeInput extends Widget {
7163
7178
 
7164
7179
  let slider = document.createElement( 'input' );
7165
7180
  slider.className = "lexrangeslider " + ( options.className ?? "" );
7166
- slider.value = slider.iValue = value;
7167
7181
  slider.min = options.min ?? 0;
7168
7182
  slider.max = options.max ?? 100;
7169
7183
  slider.step = options.step ?? 1;
7170
7184
  slider.type = "range";
7171
7185
  slider.disabled = options.disabled ?? false;
7186
+
7187
+ if( value.constructor == Number )
7188
+ {
7189
+ value = clamp( value, +slider.min, +slider.max );
7190
+ }
7191
+
7192
+ if( options.left )
7193
+ {
7194
+ value = ( ( +slider.max ) - value + ( +slider.min ) );
7195
+ }
7196
+
7197
+ slider.value = value;
7172
7198
  container.appendChild( slider );
7173
7199
 
7174
7200
  if( options.left ?? false )
@@ -7207,11 +7233,6 @@ class RangeInput extends Widget {
7207
7233
  Widget._dispatchEvent( slider, "input", true );
7208
7234
  };
7209
7235
 
7210
- if( value.constructor == Number )
7211
- {
7212
- value = clamp( value, +slider.min, +slider.max );
7213
- }
7214
-
7215
7236
  doAsync( this.onResize.bind( this ) );
7216
7237
  }
7217
7238
  }
@@ -8133,7 +8154,7 @@ class FileInput extends Widget {
8133
8154
  {
8134
8155
  let settingsDialog = null;
8135
8156
 
8136
- const settingButton = new Button(null, "<a style='margin-top: 0px;' class='fa-solid fa-gear'></a>", () => {
8157
+ const settingButton = new Button(null, "", () => {
8137
8158
 
8138
8159
  if( settingsDialog )
8139
8160
  {
@@ -8145,7 +8166,7 @@ class FileInput extends Widget {
8145
8166
  p.addButton( null, "Reload", v => { input.dispatchEvent( new Event( 'change' ) ) } );
8146
8167
  }, { onclose: ( root ) => { root.remove(); settingsDialog = null; } } );
8147
8168
 
8148
- }, { className: "micro", skipInlineCount: true, title: "Settings" });
8169
+ }, { skipInlineCount: true, title: "Settings", disabled: options.disabled, icon: "fa-solid fa-gear" });
8149
8170
 
8150
8171
  this.root.appendChild( settingButton.root );
8151
8172
  }
@@ -8208,9 +8229,9 @@ class Tree extends Widget {
8208
8229
  if( options.filter )
8209
8230
  {
8210
8231
  nodeFilterInput = document.createElement('input');
8211
- nodeFilterInput.id = "lexnodetree_filter";
8232
+ nodeFilterInput.className = "lexnodetree_filter";
8212
8233
  nodeFilterInput.setAttribute("placeholder", "Filter..");
8213
- nodeFilterInput.style.width = "calc( 100% - 17px )";
8234
+ nodeFilterInput.style.width = "100%";
8214
8235
  nodeFilterInput.addEventListener('input', () => {
8215
8236
  this.innerTree.refresh();
8216
8237
  });
@@ -8360,11 +8381,11 @@ class Counter extends Widget {
8360
8381
  container.className = "lexcounter";
8361
8382
  this.root.appendChild( container );
8362
8383
 
8363
- const substrButton = new Button(null, "<a style='margin-top: 0px;' class='fa-solid fa-minus'></a>", ( value, e ) => {
8384
+ const substrButton = new Button(null, "", ( value, e ) => {
8364
8385
  let mult = step ?? 1;
8365
8386
  if( e.shiftKey ) mult *= 10;
8366
8387
  this.set( counterText.count - mult, false, e );
8367
- }, { className: "micro", skipInlineCount: true, title: "Minus" });
8388
+ }, { skipInlineCount: true, title: "Minus", icon: "fa-solid fa-minus" });
8368
8389
 
8369
8390
  container.appendChild( substrButton.root );
8370
8391
 
@@ -8386,11 +8407,11 @@ class Counter extends Widget {
8386
8407
  containerBox.appendChild( counterLabel );
8387
8408
  }
8388
8409
 
8389
- const addButton = new Button(null, "<a style='margin-top: 0px;' class='fa-solid fa-plus'></a>", ( value, e ) => {
8410
+ const addButton = new Button(null, "", ( value, e ) => {
8390
8411
  let mult = step ?? 1;
8391
8412
  if( e.shiftKey ) mult *= 10;
8392
8413
  this.set( counterText.count + mult, false, e );
8393
- }, { className: "micro", skipInlineCount: true, title: "Plus" });
8414
+ }, { skipInlineCount: true, title: "Plus", icon: "fa-solid fa-plus" });
8394
8415
  container.appendChild( addButton.root );
8395
8416
  }
8396
8417
  }
@@ -8461,7 +8482,7 @@ class Table extends Widget {
8461
8482
  filterOptions.placeholder = `Filter ${ this.filter }...`;
8462
8483
  filterOptions.skipWidget = true;
8463
8484
  filterOptions.trigger = "input";
8464
- filterOptions.textClass = "outline";
8485
+ filterOptions.inputClass = "outline";
8465
8486
 
8466
8487
  let filter = new TextInput(null, "", ( v ) => {
8467
8488
  this._currentFilter = v;
@@ -8494,7 +8515,7 @@ class Table extends Widget {
8494
8515
  return item;
8495
8516
  } );
8496
8517
  new DropdownMenu( customFilterBtn.root, menuOptions, { side: "bottom", align: "start" });
8497
- }, { buttonClass: "dashed" } );
8518
+ }, { buttonClass: " primary dashed" } );
8498
8519
  headerContainer.appendChild( customFilterBtn.root );
8499
8520
  }
8500
8521
 
@@ -8569,7 +8590,7 @@ class Table extends Widget {
8569
8590
  th.style.width = "0px";
8570
8591
  const input = document.createElement( 'input' );
8571
8592
  input.type = "checkbox";
8572
- input.className = "lexcheckbox";
8593
+ input.className = "lexcheckbox accent";
8573
8594
  input.checked = data.checkMap[ ":root" ] ?? false;
8574
8595
  th.appendChild( input );
8575
8596
 
@@ -8736,7 +8757,7 @@ class Table extends Widget {
8736
8757
 
8737
8758
  const row = document.createElement( 'tr' );
8738
8759
  const rowId = LX.getSupportedDOMName( bodyData.join( '-' ) );
8739
- row.setAttribute( "rowId", rowId.substr(0, 16) );
8760
+ row.setAttribute( "rowId", rowId.substr(0, 32) );
8740
8761
 
8741
8762
  if( options.sortable )
8742
8763
  {
@@ -8787,7 +8808,7 @@ class Table extends Widget {
8787
8808
  const td = document.createElement( 'td' );
8788
8809
  const input = document.createElement( 'input' );
8789
8810
  input.type = "checkbox";
8790
- input.className = "lexcheckbox";
8811
+ input.className = "lexcheckbox accent";
8791
8812
  input.checked = data.checkMap[ rowId ];
8792
8813
  td.appendChild( input );
8793
8814
 
@@ -8934,7 +8955,7 @@ class Panel {
8934
8955
  root.className += " " + options.className;
8935
8956
  }
8936
8957
 
8937
- root.style.width = options.width || "calc( 100% - 6px )";
8958
+ root.style.width = options.width || "100%";
8938
8959
  root.style.height = options.height || "100%";
8939
8960
  Object.assign( root.style, options.style ?? {} );
8940
8961
 
@@ -9049,10 +9070,11 @@ class Panel {
9049
9070
 
9050
9071
  /**
9051
9072
  * @method endLine
9073
+ * @param {String} className Extra class to customize inline widgets parent container
9052
9074
  * @description Stop inlining widgets. Use it only if the number of widgets to be inlined is NOT specified.
9053
9075
  */
9054
9076
 
9055
- endLine( justifyContent ) {
9077
+ endLine( className ) {
9056
9078
 
9057
9079
  if( this._inlineWidgetsLeft == -1 )
9058
9080
  {
@@ -9067,9 +9089,9 @@ class Panel {
9067
9089
  this._inlineContainer = document.createElement('div');
9068
9090
  this._inlineContainer.className = "lexinlinewidgets";
9069
9091
 
9070
- if( justifyContent )
9092
+ if( className )
9071
9093
  {
9072
- this._inlineContainer.style.justifyContent = justifyContent;
9094
+ this._inlineContainer.className += ` ${ className }`;
9073
9095
  }
9074
9096
  }
9075
9097
 
@@ -9212,7 +9234,7 @@ class Panel {
9212
9234
  }
9213
9235
  else
9214
9236
  {
9215
- el.classList.add("nobranch");
9237
+ el.className += " nobranch w-full";
9216
9238
  this.root.appendChild( el );
9217
9239
  }
9218
9240
  }
@@ -9276,7 +9298,7 @@ class Panel {
9276
9298
  let input = document.createElement('input');
9277
9299
  input.className = 'lexinput-filter';
9278
9300
  input.setAttribute( "placeholder", options.placeholder );
9279
- input.style.width = "calc( 100% - 17px )";
9301
+ input.style.width = "100%";
9280
9302
  input.value = options.filterValue || "";
9281
9303
 
9282
9304
  let searchIcon = document.createElement('a');
@@ -9454,6 +9476,7 @@ class Panel {
9454
9476
  * pattern: Regular expression that value must match
9455
9477
  * trigger: Choose onchange trigger (default, input) [default]
9456
9478
  * inputWidth: Width of the text input
9479
+ * inputClass: Class to add to the native input element
9457
9480
  * skipReset: Don't add the reset value button when value changes
9458
9481
  * float: Justify input text content
9459
9482
  * justifyName: Justify name content
@@ -9493,6 +9516,7 @@ class Panel {
9493
9516
 
9494
9517
  addLabel( value, options = {} ) {
9495
9518
  options.disabled = true;
9519
+ options.inputClass = ( options.inputClass ?? "" ) + " nobg";
9496
9520
  const widget = this.addText( null, value, null, options );
9497
9521
  widget.type = Widget.LABEL;
9498
9522
  return widget;
@@ -9509,6 +9533,7 @@ class Panel {
9509
9533
  * icon: Icon class to show as button value
9510
9534
  * img: Path to image to show as button value
9511
9535
  * title: Text to show in native Element title
9536
+ * buttonClass: Class to add to the native button element
9512
9537
  */
9513
9538
 
9514
9539
  addButton( name, value, callback, options = {} ) {
@@ -10048,7 +10073,6 @@ class Branch {
10048
10073
  root.className += " " + options.className;
10049
10074
  }
10050
10075
 
10051
- root.style.width = "calc(100% - 7px)";
10052
10076
  root.style.margin = "0 auto";
10053
10077
 
10054
10078
  var that = this;
@@ -10086,7 +10110,7 @@ class Branch {
10086
10110
  this.grabber.setAttribute( "hidden", true );
10087
10111
  doAsync( () => {
10088
10112
  this.content.setAttribute( "hidden", true );
10089
- }, 15 );
10113
+ }, 10 );
10090
10114
  }
10091
10115
 
10092
10116
  this.onclick = function( e ) {
@@ -10236,6 +10260,7 @@ class Branch {
10236
10260
  let value = element.children[ 1 ];
10237
10261
 
10238
10262
  name.style.width = size;
10263
+ name.style.minWidth = size;
10239
10264
 
10240
10265
  switch( widget.type )
10241
10266
  {
@@ -10270,7 +10295,8 @@ class Footer {
10270
10295
  root.className = "lexfooter";
10271
10296
 
10272
10297
  const wrapper = document.createElement( "div" );
10273
- wrapper.className = "wrapper";
10298
+ wrapper.style.minHeight = "48px";
10299
+ wrapper.className = "w-full";
10274
10300
  root.appendChild( wrapper );
10275
10301
 
10276
10302
  if( options.columns && options.columns.constructor == Array )
@@ -10345,6 +10371,10 @@ class Footer {
10345
10371
  // Append directly to body
10346
10372
  const parent = options.parent ?? document.body;
10347
10373
  parent.appendChild( root );
10374
+
10375
+ // Set always at bottom
10376
+ root.previousElementSibling.style.height = "unset";
10377
+ root.previousElementSibling.style.flexGrow = "1";
10348
10378
  }
10349
10379
 
10350
10380
  }
@@ -10543,7 +10573,6 @@ class Dialog {
10543
10573
  root.style.left = position[ 0 ] ?? "50%";
10544
10574
  root.style.top = position[ 1 ] ?? "50%";
10545
10575
 
10546
- panel.root.style.width = "calc( 100% - 30px )";
10547
10576
  panel.root.style.height = title ? "calc( 100% - " + ( titleDiv.offsetHeight + 30 ) + "px )" : "calc( 100% - 51px )";
10548
10577
  }
10549
10578
 
@@ -10615,8 +10644,8 @@ class PocketDialog extends Dialog {
10615
10644
  this.root.style.top = dragMargin + "px";
10616
10645
  }
10617
10646
 
10618
- this.panel.root.style.width = "calc( 100% - 12px )";
10619
- this.panel.root.style.height = "calc( 100% - 40px )";
10647
+ this.panel.root.style.width = "100%";
10648
+ this.panel.root.style.height = "100%";
10620
10649
  this.dock_pos = PocketDialog.TOP;
10621
10650
 
10622
10651
  this.minimized = false;
@@ -12022,11 +12051,15 @@ class AssetView {
12022
12051
  this.rightPanel.sameLine();
12023
12052
  this.rightPanel.addSelect( "Filter", this.allowedTypes, this.allowedTypes[ 0 ], v => this._refreshContent.call(this, null, v), { width: "30%", minWidth: "128px" } );
12024
12053
  this.rightPanel.addText( null, this.searchValue ?? "", v => this._refreshContent.call(this, v, null), { placeholder: "Search assets.." } );
12025
- this.rightPanel.addButton( null, "<a class='fa fa-arrow-up-short-wide'></a>", on_sort.bind(this), { className: "micro", title: "Sort" } );
12026
- this.rightPanel.addButton( null, "<a class='fa-solid fa-grip'></a>", on_change_view.bind(this), { className: "micro", title: "View" } );
12054
+ this.rightPanel.addButton( null, "<a class='fa fa-arrow-up-short-wide'></a>", on_sort.bind(this), { title: "Sort" } );
12055
+ this.rightPanel.addButton( null, "<a class='fa-solid fa-grip'></a>", on_change_view.bind(this), { title: "View" } );
12027
12056
  // Content Pages
12028
- this.rightPanel.addButton( null, "<a class='fa-solid fa-angles-left'></a>", on_change_page.bind(this, -1), { className: "micro", title: "Previous Page" } );
12029
- this.rightPanel.addButton( null, "<a class='fa-solid fa-angles-right'></a>", on_change_page.bind(this, 1), { className: "micro", title: "Next Page" } );
12057
+ this.rightPanel.addButton( null, "<a class='fa-solid fa-angles-left'></a>", on_change_page.bind(this, -1), { title: "Previous Page", className: "ml-auto" } );
12058
+ this.rightPanel.addButton( null, "<a class='fa-solid fa-angles-right'></a>", on_change_page.bind(this, 1), { title: "Next Page" } );
12059
+ const textString = "Page " + this.contentPage + " / " + ((((this.currentData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1);
12060
+ this.rightPanel.addText(null, textString, null, {
12061
+ inputClass: "nobg", disabled: true, signal: "@on_page_change", maxWidth: "16ch" }
12062
+ );
12030
12063
  this.rightPanel.endLine();
12031
12064
 
12032
12065
  if( !this.skipBrowser )
@@ -12060,9 +12093,13 @@ class AssetView {
12060
12093
  icon: "fa-solid fa-arrows-rotate",
12061
12094
  callback: domEl => { this._refreshContent(); }
12062
12095
  }
12063
- ], { width: "20%", minWidth: "164px", noSelection: true } );
12064
- this.rightPanel.addText(null, this.path.join('/'), null, { width: "70%", maxWidth: "calc(70% - 64px)", minWidth: "164px", disabled: true, signal: "@on_folder_change", style: { fontWeight: "bolder", fontSize: "16px", color: "#aaa" } });
12065
- this.rightPanel.addText(null, "Page " + this.contentPage + " / " + ((((this.currentData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1), null, {disabled: true, signal: "@on_page_change", width: "fit-content"})
12096
+ ], { noSelection: true } );
12097
+
12098
+ this.rightPanel.addText(null, this.path.join('/'), null, {
12099
+ inputClass: "nobg", disabled: true, signal: "@on_folder_change",
12100
+ style: { fontWeight: "600", fontSize: "15px" }
12101
+ });
12102
+
12066
12103
  this.rightPanel.endLine();
12067
12104
  }
12068
12105
 
@@ -12340,7 +12377,9 @@ class AssetView {
12340
12377
  }
12341
12378
 
12342
12379
  this.allowNextPage = filteredData.length - 1 > AssetView.MAX_PAGE_ELEMENTS;
12343
- LX.emit("@on_page_change", "Page " + this.contentPage + " / " + ((((filteredData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1));
12380
+
12381
+ const textString = "Page " + this.contentPage + " / " + ((((filteredData.length - 1) / AssetView.MAX_PAGE_ELEMENTS )|0) + 1);
12382
+ LX.emit( "@on_page_change", textString );
12344
12383
 
12345
12384
  if( this.onRefreshContent )
12346
12385
  {