lexgui 0.6.9 → 0.6.11

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.js CHANGED
@@ -14,7 +14,7 @@ console.warn( 'Script _build/lexgui.js_ is depracated and will be removed soon.
14
14
  */
15
15
 
16
16
  const LX = {
17
- version: "0.6.9",
17
+ version: "0.6.11",
18
18
  ready: false,
19
19
  components: [], // Specific pre-build components
20
20
  signals: {}, // Events and triggers
@@ -318,7 +318,7 @@ function _createCommandbar( root )
318
318
 
319
319
  const _propagateAdd = ( item, filter, path, skipPropagation ) => {
320
320
 
321
- if( !item )
321
+ if( !item || ( item.constructor != Object ) )
322
322
  {
323
323
  return;
324
324
  }
@@ -725,8 +725,6 @@ class Popover {
725
725
 
726
726
  constructor( trigger, content, options = {} ) {
727
727
 
728
- console.assert( trigger, "Popover needs a DOM element as trigger!" );
729
-
730
728
  if( Popover.activeElement )
731
729
  {
732
730
  Popover.activeElement.destroy();
@@ -734,13 +732,20 @@ class Popover {
734
732
  }
735
733
 
736
734
  this._trigger = trigger;
737
- trigger.classList.add( "triggered" );
738
- trigger.active = this;
735
+
736
+ if( trigger )
737
+ {
738
+ trigger.classList.add( "triggered" );
739
+ trigger.active = this;
740
+ }
739
741
 
740
742
  this._windowPadding = 4;
741
743
  this.side = options.side ?? "bottom";
742
744
  this.align = options.align ?? "center";
745
+ this.sideOffset = options.sideOffset ?? 0;
746
+ this.alignOffset = options.alignOffset ?? 0;
743
747
  this.avoidCollisions = options.avoidCollisions ?? true;
748
+ this.reference = options.reference;
744
749
 
745
750
  this.root = document.createElement( "div" );
746
751
  this.root.dataset["side"] = this.side;
@@ -775,29 +780,35 @@ class Popover {
775
780
  LX.doAsync( () => {
776
781
  this._adjustPosition();
777
782
 
778
- this.root.focus();
783
+ if( this._trigger )
784
+ {
785
+ this.root.focus();
779
786
 
780
- this._onClick = e => {
781
- if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
782
- {
783
- return;
784
- }
785
- this.destroy();
786
- };
787
+ this._onClick = e => {
788
+ if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
789
+ {
790
+ return;
791
+ }
792
+ this.destroy();
793
+ };
794
+
795
+ document.body.addEventListener( "mousedown", this._onClick, true );
796
+ document.body.addEventListener( "focusin", this._onClick, true );
797
+ }
787
798
 
788
- document.body.addEventListener( "mousedown", this._onClick, true );
789
- document.body.addEventListener( "focusin", this._onClick, true );
790
799
  }, 10 );
791
800
  }
792
801
 
793
802
  destroy() {
794
803
 
795
- this._trigger.classList.remove( "triggered" );
796
-
797
- delete this._trigger.active;
804
+ if( this._trigger )
805
+ {
806
+ this._trigger.classList.remove( "triggered" );
807
+ delete this._trigger.active;
798
808
 
799
- document.body.removeEventListener( "mousedown", this._onClick, true );
800
- document.body.removeEventListener( "focusin", this._onClick, true );
809
+ document.body.removeEventListener( "mousedown", this._onClick, true );
810
+ document.body.removeEventListener( "focusin", this._onClick, true );
811
+ }
801
812
 
802
813
  this.root.remove();
803
814
 
@@ -810,26 +821,28 @@ class Popover {
810
821
 
811
822
  // Place menu using trigger position and user options
812
823
  {
813
- const rect = this._trigger.getBoundingClientRect();
824
+ const el = this.reference ?? this._trigger;
825
+ console.assert( el, "Popover needs a trigger or reference element!" );
826
+ const rect = el.getBoundingClientRect();
814
827
 
815
828
  let alignWidth = true;
816
829
 
817
830
  switch( this.side )
818
831
  {
819
832
  case "left":
820
- position[ 0 ] += ( rect.x - this.root.offsetWidth );
833
+ position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
821
834
  alignWidth = false;
822
835
  break;
823
836
  case "right":
824
- position[ 0 ] += ( rect.x + rect.width );
837
+ position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
825
838
  alignWidth = false;
826
839
  break;
827
840
  case "top":
828
- position[ 1 ] += ( rect.y - this.root.offsetHeight );
841
+ position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
829
842
  alignWidth = true;
830
843
  break;
831
844
  case "bottom":
832
- position[ 1 ] += ( rect.y + rect.height );
845
+ position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
833
846
  alignWidth = true;
834
847
  break;
835
848
  }
@@ -849,6 +862,9 @@ class Popover {
849
862
  else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
850
863
  break;
851
864
  }
865
+
866
+ if( alignWidth ) { position[ 0 ] += this.alignOffset; }
867
+ else { position[ 1 ] += this.alignOffset; }
852
868
  }
853
869
 
854
870
  if( this.avoidCollisions )
@@ -985,6 +1001,8 @@ class DropdownMenu {
985
1001
  this._windowPadding = 4;
986
1002
  this.side = options.side ?? "bottom";
987
1003
  this.align = options.align ?? "center";
1004
+ this.sideOffset = options.sideOffset ?? 0;
1005
+ this.alignOffset = options.alignOffset ?? 0;
988
1006
  this.avoidCollisions = options.avoidCollisions ?? true;
989
1007
  this.onBlur = options.onBlur;
990
1008
  this.inPlace = false;
@@ -1227,19 +1245,19 @@ class DropdownMenu {
1227
1245
  switch( this.side )
1228
1246
  {
1229
1247
  case "left":
1230
- position[ 0 ] += ( rect.x - this.root.offsetWidth );
1248
+ position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
1231
1249
  alignWidth = false;
1232
1250
  break;
1233
1251
  case "right":
1234
- position[ 0 ] += ( rect.x + rect.width );
1252
+ position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
1235
1253
  alignWidth = false;
1236
1254
  break;
1237
1255
  case "top":
1238
- position[ 1 ] += ( rect.y - this.root.offsetHeight );
1256
+ position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
1239
1257
  alignWidth = true;
1240
1258
  break;
1241
1259
  case "bottom":
1242
- position[ 1 ] += ( rect.y + rect.height );
1260
+ position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
1243
1261
  alignWidth = true;
1244
1262
  break;
1245
1263
  }
@@ -1259,6 +1277,9 @@ class DropdownMenu {
1259
1277
  else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
1260
1278
  break;
1261
1279
  }
1280
+
1281
+ if( alignWidth ) { position[ 0 ] += this.alignOffset; }
1282
+ else { position[ 1 ] += this.alignOffset; }
1262
1283
  }
1263
1284
 
1264
1285
  if( this.avoidCollisions )
@@ -1537,7 +1558,7 @@ class ColorPicker {
1537
1558
  copyButtonWidget.root.querySelector( "input[type='checkbox']" ).style.pointerEvents = "none";
1538
1559
 
1539
1560
  LX.doAsync( () => {
1540
- copyButtonWidget.root.swap( true );
1561
+ copyButtonWidget.swap( true );
1541
1562
  copyButtonWidget.root.querySelector( "input[type='checkbox']" ).style.pointerEvents = "auto";
1542
1563
  }, 3000 );
1543
1564
 
@@ -6020,6 +6041,176 @@ LX.drawSpline = drawSpline;
6020
6041
 
6021
6042
  // area.js @jxarco
6022
6043
 
6044
+ class AreaOverlayButtons {
6045
+
6046
+ /**
6047
+ * @constructor AreaOverlayButtons
6048
+ */
6049
+
6050
+ constructor( area, buttonsArray, options = {} ) {
6051
+
6052
+ this.area = area;
6053
+ this.options = options;
6054
+
6055
+ this.buttons = {};
6056
+
6057
+ this._buildButtons( buttonsArray, options );
6058
+ }
6059
+
6060
+ _buildButtons( buttonsArray, options ) {
6061
+
6062
+ options.className = "lexoverlaybuttons";
6063
+
6064
+ let overlayPanel = this.area.addPanel( options );
6065
+ let overlayGroup = null;
6066
+
6067
+ const container = document.createElement( "div" );
6068
+ container.className = "lexoverlaybuttonscontainer";
6069
+ container.appendChild( overlayPanel.root );
6070
+ this.area.attach( container );
6071
+
6072
+ const float = options.float;
6073
+ let floatClass = "";
6074
+
6075
+ if( float )
6076
+ {
6077
+ for( let i = 0; i < float.length; i++ )
6078
+ {
6079
+ const t = float[ i ];
6080
+ switch( t )
6081
+ {
6082
+ case 'h': break;
6083
+ case 'v': floatClass += " vertical"; break;
6084
+ case 't': break;
6085
+ case 'm': floatClass += " middle"; break;
6086
+ case 'b': floatClass += " bottom"; break;
6087
+ case 'l': break;
6088
+ case 'c': floatClass += " center"; break;
6089
+ case 'r': floatClass += " right"; break;
6090
+ }
6091
+ }
6092
+
6093
+ container.className += ` ${ floatClass }`;
6094
+ }
6095
+
6096
+ const _addButton = ( b, group, last ) => {
6097
+
6098
+ const _options = {
6099
+ width: "auto",
6100
+ selectable: b.selectable,
6101
+ selected: b.selected,
6102
+ icon: b.icon,
6103
+ img: b.img,
6104
+ className: b.class ?? "",
6105
+ title: b.name,
6106
+ overflowContainerX: overlayPanel.root,
6107
+ swap: b.swap
6108
+ };
6109
+
6110
+ if( group )
6111
+ {
6112
+ if( !overlayGroup )
6113
+ {
6114
+ overlayGroup = document.createElement('div');
6115
+ overlayGroup.className = "lexoverlaygroup";
6116
+ overlayPanel.queuedContainer = overlayGroup;
6117
+ }
6118
+
6119
+ _options.parent = overlayGroup;
6120
+ }
6121
+
6122
+ let callback = b.callback;
6123
+ let widget = null;
6124
+
6125
+ if( b.options )
6126
+ {
6127
+ widget = overlayPanel.addSelect( null, b.options, b.value ?? b.name, callback, _options );
6128
+ }
6129
+ else
6130
+ {
6131
+ widget = overlayPanel.addButton( null, b.name, function( value, event ) {
6132
+ if( b.selectable )
6133
+ {
6134
+ if( b.group )
6135
+ {
6136
+ let _prev = b.selected;
6137
+ b.group.forEach( sub => sub.selected = false );
6138
+ b.selected = !_prev;
6139
+ }
6140
+ else
6141
+ {
6142
+ b.selected = !b.selected;
6143
+ }
6144
+ }
6145
+
6146
+ if( callback )
6147
+ {
6148
+ callback( value, event, widget.root );
6149
+ }
6150
+
6151
+ }, _options );
6152
+ }
6153
+
6154
+ this.buttons[ b.name ] = widget;
6155
+
6156
+ // ends the group
6157
+ if( overlayGroup && last )
6158
+ {
6159
+ overlayPanel.root.appendChild( overlayGroup );
6160
+ overlayGroup = null;
6161
+ overlayPanel.clearQueue();
6162
+ }
6163
+ };
6164
+
6165
+ const _refreshPanel = function() {
6166
+
6167
+ overlayPanel.clear();
6168
+
6169
+ for( let b of buttonsArray )
6170
+ {
6171
+ if( b === null )
6172
+ {
6173
+ // Add a separator
6174
+ const separator = document.createElement("div");
6175
+ separator.className = "lexoverlayseparator" + floatClass;
6176
+ overlayPanel.root.appendChild( separator );
6177
+ continue;
6178
+ }
6179
+
6180
+ if( b.constructor === Array )
6181
+ {
6182
+ for( let i = 0; i < b.length; ++i )
6183
+ {
6184
+ let sub = b[ i ];
6185
+ sub.group = b;
6186
+ _addButton( sub, true, i == ( b.length - 1 ) );
6187
+ }
6188
+ }
6189
+ else
6190
+ {
6191
+ _addButton( b );
6192
+ }
6193
+ }
6194
+
6195
+ // Add floating info
6196
+ if( float )
6197
+ {
6198
+ var height = 0;
6199
+ overlayPanel.root.childNodes.forEach( c => { height += c.offsetHeight; } );
6200
+
6201
+ if( container.className.includes( "middle" ) )
6202
+ {
6203
+ container.style.top = "-moz-calc( 50% - " + (height * 0.5) + "px )";
6204
+ container.style.top = "-webkit-calc( 50% - " + (height * 0.5) + "px )";
6205
+ container.style.top = "calc( 50% - " + (height * 0.5) + "px )";
6206
+ }
6207
+ }
6208
+ };
6209
+
6210
+ _refreshPanel();
6211
+ }
6212
+ }
6213
+
6023
6214
  class Area {
6024
6215
 
6025
6216
  /**
@@ -6785,8 +6976,7 @@ class Area {
6785
6976
  // Add to last split section if area has been split
6786
6977
  if( this.sections.length )
6787
6978
  {
6788
- this.sections[ 1 ].addOverlayButtons( buttons, options );
6789
- return;
6979
+ return this.sections[ 1 ].addOverlayButtons( buttons, options );
6790
6980
  }
6791
6981
 
6792
6982
  console.assert( buttons.constructor == Array && buttons.length );
@@ -6794,152 +6984,10 @@ class Area {
6794
6984
  // Set area to relative to use local position
6795
6985
  this.root.style.position = "relative";
6796
6986
 
6797
- options.className = "lexoverlaybuttons";
6798
-
6799
- let overlayPanel = this.addPanel( options );
6800
- let overlayGroup = null;
6801
-
6802
- const container = document.createElement("div");
6803
- container.className = "lexoverlaybuttonscontainer";
6804
- container.appendChild( overlayPanel.root );
6805
- this.attach( container );
6806
-
6807
- const float = options.float;
6808
- let floatClass = "";
6809
-
6810
- if( float )
6811
- {
6812
- for( let i = 0; i < float.length; i++ )
6813
- {
6814
- const t = float[ i ];
6815
- switch( t )
6816
- {
6817
- case 'h': break;
6818
- case 'v': floatClass += " vertical"; break;
6819
- case 't': break;
6820
- case 'm': floatClass += " middle"; break;
6821
- case 'b': floatClass += " bottom"; break;
6822
- case 'l': break;
6823
- case 'c': floatClass += " center"; break;
6824
- case 'r': floatClass += " right"; break;
6825
- }
6826
- }
6827
-
6828
- container.className += ` ${ floatClass }`;
6829
- }
6830
-
6831
- const _addButton = function( b, group, last ) {
6832
-
6833
- const _options = {
6834
- width: "auto",
6835
- selectable: b.selectable,
6836
- selected: b.selected,
6837
- icon: b.icon,
6838
- img: b.img,
6839
- className: b.class ?? "",
6840
- title: b.name,
6841
- overflowContainerX: overlayPanel.root,
6842
- swap: b.swap
6843
- };
6844
-
6845
- if( group )
6846
- {
6847
- if( !overlayGroup )
6848
- {
6849
- overlayGroup = document.createElement('div');
6850
- overlayGroup.className = "lexoverlaygroup";
6851
- overlayPanel.queuedContainer = overlayGroup;
6852
- }
6853
-
6854
- _options.parent = overlayGroup;
6855
- }
6856
-
6857
- let callback = b.callback;
6858
-
6859
- if( b.options )
6860
- {
6861
- overlayPanel.addSelect( null, b.options, b.name, callback, _options );
6862
- }
6863
- else
6864
- {
6865
- const button = overlayPanel.addButton( null, b.name, function( value, event ) {
6866
- if( b.selectable )
6867
- {
6868
- if( b.group )
6869
- {
6870
- let _prev = b.selected;
6871
- b.group.forEach( sub => sub.selected = false );
6872
- b.selected = !_prev;
6873
- }
6874
- else
6875
- {
6876
- b.selected = !b.selected;
6877
- }
6878
- }
6879
-
6880
- if( callback )
6881
- {
6882
- callback( value, event, button.root );
6883
- }
6884
-
6885
- }, _options );
6886
- }
6887
-
6888
- // ends the group
6889
- if( overlayGroup && last )
6890
- {
6891
- overlayPanel.root.appendChild( overlayGroup );
6892
- overlayGroup = null;
6893
- overlayPanel.clearQueue();
6894
- }
6895
- };
6896
-
6897
- const _refreshPanel = function() {
6898
-
6899
- overlayPanel.clear();
6900
-
6901
- for( let b of buttons )
6902
- {
6903
- if( b === null )
6904
- {
6905
- // Add a separator
6906
- const separator = document.createElement("div");
6907
- separator.className = "lexoverlayseparator" + floatClass;
6908
- overlayPanel.root.appendChild( separator );
6909
- continue;
6910
- }
6911
-
6912
- if( b.constructor === Array )
6913
- {
6914
- for( let i = 0; i < b.length; ++i )
6915
- {
6916
- let sub = b[ i ];
6917
- sub.group = b;
6918
- _addButton(sub, true, i == ( b.length - 1 ));
6919
- }
6920
- }
6921
- else
6922
- {
6923
- _addButton( b );
6924
- }
6925
- }
6926
-
6927
- // Add floating info
6928
- if( float )
6929
- {
6930
- var height = 0;
6931
- overlayPanel.root.childNodes.forEach( c => { height += c.offsetHeight; } );
6932
-
6933
- if( container.className.includes( "middle" ) )
6934
- {
6935
- container.style.top = "-moz-calc( 50% - " + (height * 0.5) + "px )";
6936
- container.style.top = "-webkit-calc( 50% - " + (height * 0.5) + "px )";
6937
- container.style.top = "calc( 50% - " + (height * 0.5) + "px )";
6938
- }
6939
- }
6940
- };
6987
+ // Reset if already exists
6988
+ this.overlayButtons = new AreaOverlayButtons( this, buttons, options );
6941
6989
 
6942
- _refreshPanel();
6990
+ return this.overlayButtons;
6943
6991
  }
6944
6992
 
6945
6993
  /**
@@ -8462,14 +8510,15 @@ class Button extends Widget {
8462
8510
  super( Widget.BUTTON, name, null, options );
8463
8511
 
8464
8512
  this.onGetValue = () => {
8465
- return wValue.querySelector( "input" )?.checked;
8513
+ const swapInput = wValue.querySelector( "input" );
8514
+ return swapInput ? swapInput.checked : value
8466
8515
  };
8467
8516
 
8468
8517
  this.onSetValue = ( newValue, skipCallback, event ) => {
8469
8518
 
8470
8519
  if( ( options.swap ?? false ) )
8471
8520
  {
8472
- this.root.setState( newValue, skipCallback );
8521
+ this.setState( newValue, skipCallback );
8473
8522
  return;
8474
8523
  }
8475
8524
 
@@ -8499,6 +8548,30 @@ class Button extends Widget {
8499
8548
  wValue.style.width = `calc( 100% - ${ realNameWidth })`;
8500
8549
  };
8501
8550
 
8551
+ // In case of swap, set if a change has to be performed
8552
+ this.setState = function( v, skipCallback ) {
8553
+ const swapInput = wValue.querySelector( "input" );
8554
+
8555
+ if( swapInput )
8556
+ {
8557
+ swapInput.checked = v;
8558
+ }
8559
+ else if( options.selectable )
8560
+ {
8561
+ if( options.parent )
8562
+ {
8563
+ options.parent.querySelectorAll(".lexbutton.selected").forEach( b => { if( b == wValue ) return; b.classList.remove( "selected" ); } );
8564
+ }
8565
+
8566
+ wValue.classList.toggle( "selected", v );
8567
+ }
8568
+
8569
+ if( !skipCallback )
8570
+ {
8571
+ this._trigger( new LX.IEvent( name, swapInput ? swapInput.checked : ( options.selectable ? v : value ), null ), callback );
8572
+ }
8573
+ };
8574
+
8502
8575
  var wValue = document.createElement( 'button' );
8503
8576
  wValue.title = options.tooltip ? "" : ( options.title ?? "" );
8504
8577
  wValue.className = "lexbutton p-1 " + ( options.buttonClass ?? "" );
@@ -8518,7 +8591,7 @@ class Button extends Widget {
8518
8591
  }
8519
8592
  else if( options.icon )
8520
8593
  {
8521
- const icon = LX.makeIcon( options.icon );
8594
+ const icon = LX.makeIcon( options.icon, { iconClass: options.iconClass, svgClass: options.svgClass } );
8522
8595
  const iconPosition = options.iconPosition ?? "cover";
8523
8596
 
8524
8597
  // Default
@@ -8589,7 +8662,7 @@ class Button extends Widget {
8589
8662
  const swapIcon = LX.makeIcon( options.swap, { iconClass: "swap-on" } );
8590
8663
  wValue.appendChild( swapIcon );
8591
8664
 
8592
- this.root.swap = function( skipCallback ) {
8665
+ this.swap = function( skipCallback ) {
8593
8666
  const swapInput = wValue.querySelector( "input" );
8594
8667
  swapInput.checked = !swapInput.checked;
8595
8668
  if( !skipCallback )
@@ -8597,19 +8670,10 @@ class Button extends Widget {
8597
8670
  trigger.click();
8598
8671
  }
8599
8672
  };
8600
-
8601
- // Set if swap has to be performed
8602
- this.root.setState = function( v, skipCallback ) {
8603
- const swapInput = wValue.querySelector( "input" );
8604
- swapInput.checked = v;
8605
- if( !skipCallback )
8606
- {
8607
- trigger.click();
8608
- }
8609
- };
8610
8673
  }
8611
8674
 
8612
8675
  trigger.addEventListener( "click", e => {
8676
+ let isSelected;
8613
8677
  if( options.selectable )
8614
8678
  {
8615
8679
  if( options.parent )
@@ -8617,7 +8681,7 @@ class Button extends Widget {
8617
8681
  options.parent.querySelectorAll(".lexbutton.selected").forEach( b => { if( b == wValue ) return; b.classList.remove( "selected" ); } );
8618
8682
  }
8619
8683
 
8620
- wValue.classList.toggle('selected');
8684
+ isSelected = wValue.classList.toggle('selected');
8621
8685
  }
8622
8686
 
8623
8687
  if( options.fileInput )
@@ -8627,7 +8691,7 @@ class Button extends Widget {
8627
8691
  else
8628
8692
  {
8629
8693
  const swapInput = wValue.querySelector( "input" );
8630
- this._trigger( new LX.IEvent( name, swapInput?.checked ?? value, e ), callback );
8694
+ this._trigger( new LX.IEvent( name, swapInput?.checked ?? ( options.selectable ? isSelected : value ), e ), callback );
8631
8695
  }
8632
8696
  });
8633
8697
 
@@ -8919,16 +8983,17 @@ class Form extends Widget {
8919
8983
 
8920
8984
  if( entryData.constructor != Object )
8921
8985
  {
8922
- entryData = { };
8986
+ const oldValue = JSON.parse( JSON.stringify( entryData ) );
8987
+ entryData = { value: oldValue };
8923
8988
  data[ entry ] = entryData;
8924
8989
  }
8925
8990
 
8926
- entryData.placeholder = entryData.placeholder ?? entry;
8991
+ entryData.placeholder = entryData.placeholder ?? ( entryData.label ?? `Enter ${ entry }` );
8927
8992
  entryData.width = "100%";
8928
8993
 
8929
8994
  if( !( options.skipLabels ?? false ) )
8930
8995
  {
8931
- const label = new LX.TextInput( null, entry, null, { disabled: true, inputClass: "formlabel nobg" } );
8996
+ const label = new LX.TextInput( null, entryData.label ?? entry, null, { disabled: true, inputClass: "formlabel nobg" } );
8932
8997
  container.appendChild( label.root );
8933
8998
  }
8934
8999
 
@@ -9033,6 +9098,7 @@ class Select extends Widget {
9033
9098
  }
9034
9099
 
9035
9100
  this.root.dataset["opened"] = ( !!suboptionsFunc );
9101
+ list.style.height = ""; // set auto height by default
9036
9102
 
9037
9103
  if( !skipCallback )
9038
9104
  {
@@ -9054,7 +9120,7 @@ class Select extends Widget {
9054
9120
  wValue.name = name;
9055
9121
  wValue.iValue = value;
9056
9122
 
9057
- if( options.overflowContainer )
9123
+ if( options.overflowContainer !== undefined )
9058
9124
  {
9059
9125
  options.overflowContainerX = options.overflowContainerY = options.overflowContainer;
9060
9126
  }
@@ -9067,7 +9133,7 @@ class Select extends Widget {
9067
9133
 
9068
9134
  // Manage vertical aspect
9069
9135
  {
9070
- const overflowContainer = options.overflowContainerY ?? parent.getParentArea();
9136
+ const overflowContainer = options.overflowContainerY !== undefined ? options.overflowContainerY : parent.getParentArea();
9071
9137
  const listHeight = parent.offsetHeight;
9072
9138
  let topPosition = rect.y;
9073
9139
 
@@ -9087,18 +9153,25 @@ class Select extends Widget {
9087
9153
  }
9088
9154
 
9089
9155
  parent.style.top = ( topPosition + selectRoot.offsetHeight ) + 'px';
9156
+ list.style.height = ""; // set auto height by default
9090
9157
 
9091
- const showAbove = ( topPosition + listHeight ) > maxY;
9092
- if( showAbove )
9158
+ const failBelow = ( topPosition + listHeight ) > maxY;
9159
+ const failAbove = ( topPosition - listHeight ) < 0;
9160
+ if( failBelow && !failAbove )
9093
9161
  {
9094
9162
  parent.style.top = ( topPosition - listHeight ) + 'px';
9095
9163
  parent.classList.add( "place-above" );
9096
9164
  }
9165
+ // If does not fit in any direction, put it below but limit height..
9166
+ else if( failBelow && failAbove )
9167
+ {
9168
+ list.style.height = `${ maxY - topPosition - 32 }px`; // 32px margin
9169
+ }
9097
9170
  }
9098
9171
 
9099
9172
  // Manage horizontal aspect
9100
9173
  {
9101
- const overflowContainer = options.overflowContainerX ?? parent.getParentArea();
9174
+ const overflowContainer = options.overflowContainerX !== undefined ? options.overflowContainerX : parent.getParentArea();
9102
9175
  const listWidth = parent.offsetWidth;
9103
9176
  let leftPosition = rect.x;
9104
9177
 
@@ -9526,10 +9599,12 @@ class Layers extends Widget {
9526
9599
  container.style.width = `calc( 100% - ${ realNameWidth })`;
9527
9600
  };
9528
9601
 
9529
- var container = document.createElement( "div" );
9602
+ const container = document.createElement( "div" );
9530
9603
  container.className = "lexlayers";
9531
9604
  this.root.appendChild( container );
9532
9605
 
9606
+ const maxBits = options.maxBits ?? 16;
9607
+
9533
9608
  this.setLayers = ( val ) => {
9534
9609
 
9535
9610
  container.innerHTML = "";
@@ -9538,19 +9613,19 @@ class Layers extends Widget {
9538
9613
  let nbits = binary.length;
9539
9614
 
9540
9615
  // fill zeros
9541
- for( let i = 0; i < ( 16 - nbits ); ++i )
9616
+ for( let i = 0; i < ( maxBits - nbits ); ++i )
9542
9617
  {
9543
9618
  binary = '0' + binary;
9544
9619
  }
9545
9620
 
9546
- for( let bit = 0; bit < 16; ++bit )
9621
+ for( let bit = 0; bit < maxBits; ++bit )
9547
9622
  {
9548
9623
  let layer = document.createElement( "div" );
9549
9624
  layer.className = "lexlayer";
9550
9625
 
9551
9626
  if( val != undefined )
9552
9627
  {
9553
- const valueBit = binary[ 16 - bit - 1 ];
9628
+ const valueBit = binary[ maxBits - bit - 1 ];
9554
9629
  if( valueBit != undefined && valueBit == '1' )
9555
9630
  {
9556
9631
  layer.classList.add( "selected" );
@@ -9558,7 +9633,7 @@ class Layers extends Widget {
9558
9633
  }
9559
9634
 
9560
9635
  layer.innerText = bit + 1;
9561
- layer.title = "Bit " + bit + ", value " + (1 << bit);
9636
+ layer.title = "Bit " + bit + ", value " + ( 1 << bit );
9562
9637
  container.appendChild( layer );
9563
9638
 
9564
9639
  layer.addEventListener( "click", e => {
@@ -10205,9 +10280,7 @@ class ColorInput extends Widget {
10205
10280
  colorModel: options.useRGB ? "RGB" : "Hex",
10206
10281
  useAlpha,
10207
10282
  onChange: ( color ) => {
10208
- this._fromColorPicker = true;
10209
10283
  this.set( color.hex );
10210
- delete this._fromColorPicker;
10211
10284
  }
10212
10285
  } );
10213
10286
 
@@ -10245,6 +10318,7 @@ class ColorInput extends Widget {
10245
10318
  this._skipTextUpdate = true;
10246
10319
  this.set( v );
10247
10320
  delete this._skipTextUpdate;
10321
+ this.picker.fromHexColor( v );
10248
10322
  }, { width: "calc( 100% - 24px )", disabled: options.disabled });
10249
10323
 
10250
10324
  textWidget.root.style.marginLeft = "6px";
@@ -10614,15 +10688,15 @@ class Vector extends Widget {
10614
10688
 
10615
10689
  for( let i = 0; i < vectorInputs.length; ++i )
10616
10690
  {
10617
- let value = newValue[ i ];
10618
- value = LX.clamp( value, +vectorInputs[ i ].min, +vectorInputs[ i ].max );
10619
- value = LX.round( value, options.precision ) ?? 0;
10620
- vectorInputs[ i ].value = newValue[ i ] = value;
10691
+ let vecValue = newValue[ i ];
10692
+ vecValue = LX.clamp( vecValue, +vectorInputs[ i ].min, +vectorInputs[ i ].max );
10693
+ vecValue = LX.round( vecValue, options.precision ) ?? 0;
10694
+ vectorInputs[ i ].value = value[ i ] = vecValue;
10621
10695
  }
10622
10696
 
10623
10697
  if( !skipCallback )
10624
10698
  {
10625
- this._trigger( new LX.IEvent( name, newValue, event ), callback );
10699
+ this._trigger( new LX.IEvent( name, value, event ), callback );
10626
10700
  }
10627
10701
  };
10628
10702
 
@@ -11212,12 +11286,18 @@ class Progress extends Widget {
11212
11286
  };
11213
11287
 
11214
11288
  this.onSetValue = ( newValue, skipCallback, event ) => {
11289
+ newValue = LX.clamp( newValue, progress.min, progress.max );
11215
11290
  this.root.querySelector("meter").value = newValue;
11216
11291
  _updateColor();
11217
11292
  if( this.root.querySelector("span") )
11218
11293
  {
11219
11294
  this.root.querySelector("span").innerText = newValue;
11220
11295
  }
11296
+
11297
+ if( !skipCallback )
11298
+ {
11299
+ this._trigger( new LX.IEvent( name, newValue, event ), options.callback );
11300
+ }
11221
11301
  };
11222
11302
 
11223
11303
  this.onResize = ( rect ) => {
@@ -11301,11 +11381,6 @@ class Progress extends Widget {
11301
11381
  const rect = progress.getBoundingClientRect();
11302
11382
  const newValue = LX.round( LX.remapRange( e.offsetX - rect.x, 0, rect.width, progress.min, progress.max ) );
11303
11383
  this.set( newValue, false, e );
11304
-
11305
- if( options.callback )
11306
- {
11307
- options.callback( newValue, e );
11308
- }
11309
11384
  }
11310
11385
 
11311
11386
  e.stopPropagation();
@@ -11517,9 +11592,16 @@ class TabSections extends Widget {
11517
11592
  throw( "Param @tabs must be an Array!" );
11518
11593
  }
11519
11594
 
11595
+ if( !tabs.length )
11596
+ {
11597
+ throw( "Tab list cannot be empty!" );
11598
+ }
11599
+
11520
11600
  const vertical = options.vertical ?? true;
11521
11601
  const showNames = !vertical && ( options.showNames ?? false );
11522
11602
 
11603
+ this.tabDOMs = {};
11604
+
11523
11605
  let container = document.createElement( 'div' );
11524
11606
  container.className = "lextabscontainer";
11525
11607
  if( !vertical )
@@ -11532,25 +11614,25 @@ class TabSections extends Widget {
11532
11614
  container.appendChild( tabContainer );
11533
11615
  this.root.appendChild( container );
11534
11616
 
11535
- for( let i = 0; i < tabs.length; ++i )
11617
+ // Check at least 1 is selected
11618
+ if( tabs.findIndex( e => e.selected === true ) < 0 )
11619
+ {
11620
+ tabs[ 0 ].selected = true;
11621
+ }
11622
+
11623
+ for( let tab of tabs )
11536
11624
  {
11537
- const tab = tabs[ i ];
11538
11625
  console.assert( tab.name );
11539
- const isSelected = ( i == 0 );
11540
11626
  let tabEl = document.createElement( "div" );
11541
- tabEl.className = "lextab " + (i == tabs.length - 1 ? "last" : "") + ( isSelected ? "selected" : "" );
11627
+ tabEl.className = "lextab " + ( ( tab.selected ?? false ) ? "selected" : "" );
11542
11628
  tabEl.innerHTML = ( showNames ? tab.name : "" );
11543
11629
  tabEl.appendChild( LX.makeIcon( tab.icon ?? "Hash", { title: tab.name, iconClass: tab.iconClass, svgClass: tab.svgClass } ) );
11630
+ this.tabDOMs[ tab.name ] = tabEl;
11544
11631
 
11545
11632
  let infoContainer = document.createElement( "div" );
11546
11633
  infoContainer.id = tab.name.replace( /\s/g, '' );
11547
11634
  infoContainer.className = "widgets";
11548
-
11549
- if( !isSelected )
11550
- {
11551
- infoContainer.toggleAttribute( "hidden", true );
11552
- }
11553
-
11635
+ infoContainer.toggleAttribute( "hidden", !( tab.selected ?? false ) );
11554
11636
  container.appendChild( infoContainer );
11555
11637
 
11556
11638
  tabEl.addEventListener( "click", e => {
@@ -11580,6 +11662,20 @@ class TabSections extends Widget {
11580
11662
  creationPanel.clearQueue();
11581
11663
  }
11582
11664
  }
11665
+
11666
+ this.tabs = tabs;
11667
+ }
11668
+
11669
+ select( name ) {
11670
+
11671
+ const tabEl = this.tabDOMs[ name ];
11672
+
11673
+ if( !tabEl )
11674
+ {
11675
+ return;
11676
+ }
11677
+
11678
+ tabEl.click();
11583
11679
  }
11584
11680
  }
11585
11681
 
@@ -14031,46 +14127,43 @@ class Menubar {
14031
14127
  }
14032
14128
 
14033
14129
  let button = this.buttons[ name ];
14130
+ // If the button already exists, delete it
14131
+ // since only one button of this type can exist
14034
14132
  if( button )
14035
14133
  {
14036
- button.innerHTML = "";
14037
- button.appendChild( LX.makeIcon( icon, { svgClass: "xl" } ) );
14038
- return;
14134
+ delete this.buttons[ name ];
14135
+ LX.deleteElement( button.root );
14039
14136
  }
14040
14137
 
14041
14138
  // Otherwise, create it
14042
- button = document.createElement('div');
14043
- const disabled = options.disabled ?? false;
14044
- button.className = "lexmenubutton main" + (disabled ? " disabled" : "");
14045
- button.title = name;
14046
- button.appendChild( LX.makeIcon( icon, { svgClass: "xl" } ) );
14139
+ button = new LX.Button( name, null, callback, {
14140
+ title: name,
14141
+ buttonClass: "lexmenubutton main bg-none",
14142
+ disabled: options.disabled,
14143
+ icon,
14144
+ svgClass: "xl",
14145
+ hideName: true,
14146
+ swap: options.swap
14147
+ } );
14047
14148
 
14048
14149
  if( options.float == "right" )
14049
14150
  {
14050
- button.right = true;
14151
+ button.root.right = true;
14051
14152
  }
14052
14153
 
14053
14154
  if( this.root.lastChild && this.root.lastChild.right )
14054
14155
  {
14055
- this.root.lastChild.before( button );
14156
+ this.root.lastChild.before( button.root );
14056
14157
  }
14057
14158
  else if( options.float == "left" )
14058
14159
  {
14059
- this.root.prepend( button );
14160
+ this.root.prepend( button.root );
14060
14161
  }
14061
14162
  else
14062
14163
  {
14063
- this.root.appendChild( button );
14164
+ this.root.appendChild( button.root );
14064
14165
  }
14065
14166
 
14066
- const _b = button.querySelector('a');
14067
- _b.addEventListener("click", (e) => {
14068
- if( callback && !disabled )
14069
- {
14070
- callback.call( this, _b, e );
14071
- }
14072
- });
14073
-
14074
14167
  this.buttons[ name ] = button;
14075
14168
  }
14076
14169
 
@@ -14176,7 +14269,7 @@ class Menubar {
14176
14269
 
14177
14270
  if( title )
14178
14271
  {
14179
- this.buttons[ title ] = button.root;
14272
+ this.buttons[ title ] = button;
14180
14273
  }
14181
14274
  }
14182
14275
  }
@@ -14937,10 +15030,14 @@ class AssetView {
14937
15030
 
14938
15031
  if( options.rootPath )
14939
15032
  {
14940
- if(options.rootPath.constructor !== String)
14941
- console.warn("Asset Root Path must be a String (now is " + path.constructor.name + ")");
15033
+ if( options.rootPath.constructor !== String )
15034
+ {
15035
+ console.warn( `Asset Root Path must be a String (now is a ${ path.constructor.name })` );
15036
+ }
14942
15037
  else
15038
+ {
14943
15039
  this.rootPath = options.rootPath;
15040
+ }
14944
15041
  }
14945
15042
 
14946
15043
  let div = document.createElement('div');
@@ -15309,7 +15406,7 @@ class AssetView {
15309
15406
  this.content.className = (isContentLayout ? "lexassetscontent" : "lexassetscontent list");
15310
15407
  let that = this;
15311
15408
 
15312
- const add_item = function(item) {
15409
+ const _addItem = function(item) {
15313
15410
 
15314
15411
  const type = item.type.charAt( 0 ).toUpperCase() + item.type.slice( 1 );
15315
15412
  const extension = LX.getExtension( item.id );
@@ -15334,20 +15431,27 @@ class AssetView {
15334
15431
  return;
15335
15432
  }
15336
15433
 
15434
+ const dialog = itemEl.closest('dialog');
15337
15435
  const rect = itemEl.getBoundingClientRect();
15338
15436
  const targetRect = e.target.getBoundingClientRect();
15339
- const parentRect = desc.parentElement.getBoundingClientRect();
15340
15437
 
15341
- let localOffsetX = targetRect.x - parentRect.x - ( targetRect.x - rect.x );
15342
- let localOffsetY = targetRect.y - parentRect.y - ( targetRect.y - rect.y );
15438
+ let localOffsetX = rect.x + e.offsetX;
15439
+ let localOffsetY = rect.y + e.offsetY;
15440
+
15441
+ if( dialog )
15442
+ {
15443
+ const dialogRect = dialog.getBoundingClientRect();
15444
+ localOffsetX -= dialogRect.x;
15445
+ localOffsetY -= dialogRect.y;
15446
+ }
15343
15447
 
15344
15448
  if( e.target.classList.contains( "lexassettitle" ) )
15345
15449
  {
15346
15450
  localOffsetY += ( targetRect.y - rect.y );
15347
15451
  }
15348
15452
 
15349
- desc.style.left = (localOffsetX + e.offsetX + 12) + "px";
15350
- desc.style.top = (localOffsetY + e.offsetY) + "px";
15453
+ desc.style.left = ( localOffsetX ) + "px";
15454
+ desc.style.top = ( localOffsetY - 36 ) + "px";
15351
15455
  });
15352
15456
 
15353
15457
  itemEl.addEventListener("mouseenter", () => {
@@ -15545,7 +15649,7 @@ class AssetView {
15545
15649
  } });
15546
15650
  }else
15547
15651
  {
15548
- item.domEl = add_item( item );
15652
+ item.domEl = _addItem( item );
15549
15653
  }
15550
15654
  }
15551
15655
 
@@ -15747,4 +15851,281 @@ class AssetView {
15747
15851
 
15748
15852
  LX.AssetView = AssetView;
15749
15853
 
15854
+ // tour.js @jxarco
15855
+
15856
+ class Tour {
15857
+
15858
+ /**
15859
+ * @constructor Tour
15860
+ * @param {Array} steps
15861
+ * @param {Object} options
15862
+ * useModal: Use a modal to highlight the tour step [true]
15863
+ * offset: Horizontal and vertical margin offset [0]
15864
+ * horizontalOffset: Horizontal offset [0]
15865
+ * verticalOffset: Vertical offset [0]
15866
+ * radius: Radius for the tour step highlight [8]
15867
+ */
15868
+
15869
+ constructor( steps, options = {} ) {
15870
+
15871
+ this.steps = steps || [];
15872
+ this.currentStep = 0;
15873
+
15874
+ this.useModal = options.useModal ?? true;
15875
+ this.offset = options.offset ?? 8;
15876
+ this.horizontalOffset = options.horizontalOffset;
15877
+ this.verticalOffset = options.verticalOffset;
15878
+ this.radius = options.radius ?? 12;
15879
+
15880
+ this.tourContainer = LX.makeContainer( ["100%", "100%"], "tour-container" );
15881
+ this.tourContainer.style.display = "none";
15882
+ document.body.appendChild( this.tourContainer );
15883
+
15884
+ this.tourMask = LX.makeContainer( ["100%", "100%"], "tour-mask" );
15885
+ }
15886
+
15887
+ /**
15888
+ * @method begin
15889
+ */
15890
+
15891
+ begin() {
15892
+
15893
+ this.currentStep = 0;
15894
+
15895
+ if ( this.useModal )
15896
+ {
15897
+ this.tourMask.style.display = "block";
15898
+ this.tourContainer.appendChild( this.tourMask );
15899
+ }
15900
+
15901
+ this.tourContainer.style.display = "block";
15902
+
15903
+ this._showStep( 0 );
15904
+ }
15905
+
15906
+ /**
15907
+ * @method stop
15908
+ */
15909
+
15910
+ stop() {
15911
+
15912
+ if( this.useModal )
15913
+ {
15914
+ this.tourMask.style.display = "none";
15915
+ this.tourContainer.removeChild( this.tourMask );
15916
+ }
15917
+
15918
+ this._popover?.destroy();
15919
+
15920
+ this.tourContainer.style.display = "none";
15921
+ }
15922
+
15923
+ // Show the current step of the tour
15924
+ _showStep( stepOffset = 1 ) {
15925
+
15926
+ this.currentStep += stepOffset;
15927
+
15928
+ const step = this.steps[ this.currentStep ];
15929
+ if ( !step ) {
15930
+ this.stop();
15931
+ return;
15932
+ }
15933
+
15934
+ const prevStep = this.steps[ this.currentStep - 1 ];
15935
+ const nextStep = this.steps[ this.currentStep + 1 ];
15936
+
15937
+ this._generateMask( step.reference );
15938
+ this._createHighlight( step, prevStep, nextStep );
15939
+ }
15940
+
15941
+ // Generate mask for the specific step reference
15942
+ // using a fullscreen SVG with "rect" elements
15943
+ _generateMask( reference ) {
15944
+
15945
+ this.tourMask.innerHTML = ""; // Clear previous content
15946
+
15947
+ const svg = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
15948
+ svg.style.width = "100%";
15949
+ svg.style.height = "100%";
15950
+ this.tourMask.appendChild( svg );
15951
+
15952
+ const clipPath = document.createElementNS( "http://www.w3.org/2000/svg", "clipPath" );
15953
+ clipPath.setAttribute( "id", "svgTourClipPath" );
15954
+ svg.appendChild( clipPath );
15955
+
15956
+ function ceilAndShiftRect( p, s ) {
15957
+ const cp = Math.ceil( p );
15958
+ const delta = cp - p;
15959
+ const ds = s - delta;
15960
+ return [ cp, ds ];
15961
+ }
15962
+
15963
+ const refBounding = reference.getBoundingClientRect();
15964
+ const [ boundingX, boundingWidth ] = ceilAndShiftRect( refBounding.x, refBounding.width );
15965
+ const [ boundingY, boundingHeight ] = ceilAndShiftRect( refBounding.y, refBounding.height );
15966
+
15967
+ const vOffset = this.verticalOffset ?? this.offset;
15968
+ const hOffset = this.horizontalOffset ?? this.offset;
15969
+
15970
+ // Left
15971
+ {
15972
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
15973
+ rect.setAttribute( "x", 0 );
15974
+ rect.setAttribute( "y", 0 );
15975
+ rect.setAttribute( "width", boundingX - hOffset );
15976
+ rect.setAttribute( "height", window.innerHeight );
15977
+ rect.setAttribute( "stroke", "none" );
15978
+ clipPath.appendChild( rect );
15979
+ }
15980
+
15981
+ // Top
15982
+ {
15983
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
15984
+ rect.setAttribute( "x", boundingX - hOffset );
15985
+ rect.setAttribute( "y", 0 );
15986
+ rect.setAttribute( "width", boundingWidth + hOffset * 2 );
15987
+ rect.setAttribute( "height", boundingY - vOffset );
15988
+ rect.setAttribute( "stroke", "none" );
15989
+ clipPath.appendChild( rect );
15990
+ }
15991
+
15992
+ // Bottom
15993
+ {
15994
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
15995
+ rect.setAttribute( "x", boundingX - hOffset );
15996
+ rect.setAttribute( "y", boundingY + boundingHeight + vOffset );
15997
+ rect.setAttribute( "width", boundingWidth + hOffset * 2 );
15998
+ rect.setAttribute( "height", window.innerHeight - boundingY - boundingHeight - vOffset );
15999
+ rect.setAttribute( "stroke", "none" );
16000
+ clipPath.appendChild( rect );
16001
+ }
16002
+
16003
+ // Right
16004
+ {
16005
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16006
+ rect.setAttribute( "x", boundingX + boundingWidth + hOffset );
16007
+ rect.setAttribute( "y", 0 );
16008
+ rect.setAttribute( "width", window.innerWidth - boundingX - boundingWidth );
16009
+ rect.setAttribute( "height", window.innerHeight );
16010
+ rect.setAttribute( "stroke", "none" );
16011
+ clipPath.appendChild( rect );
16012
+ }
16013
+
16014
+ // Reference Highlight
16015
+ const refContainer = LX.makeContainer( ["0", "0"], "tour-ref-mask" );
16016
+ refContainer.style.left = `${ boundingX - hOffset - 1 }px`;
16017
+ refContainer.style.top = `${ boundingY - vOffset - 1 }px`;
16018
+ refContainer.style.width = `${ boundingWidth + hOffset * 2 + 2 }px`;
16019
+ refContainer.style.height = `${ boundingHeight + vOffset * 2 + 2}px`;
16020
+ this.tourContainer.appendChild( refContainer );
16021
+
16022
+ const referenceMask = document.createElementNS( "http://www.w3.org/2000/svg", "mask" );
16023
+ referenceMask.setAttribute( "id", "svgTourReferenceMask" );
16024
+ svg.appendChild( referenceMask );
16025
+
16026
+ // Reference Mask
16027
+ {
16028
+ const rectWhite = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16029
+ rectWhite.setAttribute( "width", boundingWidth + hOffset * 2 + 2 );
16030
+ rectWhite.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
16031
+ rectWhite.setAttribute( "stroke", "none" );
16032
+ rectWhite.setAttribute( "fill", "white" );
16033
+ referenceMask.appendChild( rectWhite );
16034
+
16035
+ const rectBlack = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16036
+ rectBlack.setAttribute( "rx", this.radius );
16037
+ rectBlack.setAttribute( "width", boundingWidth + hOffset * 2 + 2);
16038
+ rectBlack.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
16039
+ rectBlack.setAttribute( "stroke", "none" );
16040
+ rectBlack.setAttribute( "fill", "black" );
16041
+ referenceMask.appendChild( rectBlack );
16042
+ }
16043
+ }
16044
+
16045
+ // Create the container with the user hints
16046
+ _createHighlight( step, previousStep, nextStep ) {
16047
+
16048
+ const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
16049
+
16050
+ {
16051
+ const header = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
16052
+ LX.makeContainer( ["70%", "auto"], "p-2 font-medium", step.title, header );
16053
+ const closer = LX.makeContainer( ["30%", "auto"], "flex flex-row p-2 justify-end", "", header );
16054
+ const closeIcon = LX.makeIcon( "X" );
16055
+ closer.appendChild( closeIcon );
16056
+
16057
+ closeIcon.listen( "click", () => {
16058
+ this.stop();
16059
+ } );
16060
+ }
16061
+
16062
+ LX.makeContainer( ["100%", "auto"], "p-2 text-md", step.content, popoverContainer, { maxWidth: "400px" } );
16063
+ const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
16064
+
16065
+ {
16066
+ const footerSteps = LX.makeContainer( ["50%", "auto"], "p-2 gap-1 self-center flex flex-row text-md", "", footer );
16067
+ for( let i = 0; i < this.steps.length; i++ )
16068
+ {
16069
+ const stepIndicator = document.createElement( "span" );
16070
+ stepIndicator.className = "tour-step-indicator";
16071
+ if( i === this.currentStep )
16072
+ {
16073
+ stepIndicator.classList.add( "active" );
16074
+ }
16075
+ footerSteps.appendChild( stepIndicator );
16076
+ }
16077
+ }
16078
+
16079
+ const footerButtons = LX.makeContainer( ["50%", "auto"], "text-md", "", footer );
16080
+ const footerPanel = new LX.Panel();
16081
+
16082
+ let numButtons = 1;
16083
+
16084
+ if( previousStep )
16085
+ {
16086
+ numButtons++;
16087
+ }
16088
+
16089
+ if( numButtons > 1 )
16090
+ {
16091
+ footerPanel.sameLine( 2, "justify-end" );
16092
+ }
16093
+
16094
+ if( previousStep )
16095
+ {
16096
+ footerPanel.addButton( null, "Previous", () => {
16097
+ this._showStep( -1 );
16098
+ }, { buttonClass: "contrast" } );
16099
+ }
16100
+
16101
+ if( nextStep )
16102
+ {
16103
+ footerPanel.addButton( null, "Next", () => {
16104
+ this._showStep( 1 );
16105
+ }, { buttonClass: "accent" } );
16106
+ }
16107
+ else
16108
+ {
16109
+ footerPanel.addButton( null, "Finish", () => {
16110
+ this.stop();
16111
+ } );
16112
+ }
16113
+
16114
+ footerButtons.appendChild( footerPanel.root );
16115
+
16116
+ const sideOffset = ( step.side === "left" || step.side === "right" ? this.horizontalOffset : this.verticalOffset ) ?? this.offset;
16117
+ const alignOffset = ( step.align === "start" || step.align === "end" ? sideOffset : 0 );
16118
+
16119
+ this._popover?.destroy();
16120
+ this._popover = new LX.Popover( null, [ popoverContainer ], {
16121
+ reference: step.reference,
16122
+ side: step.side,
16123
+ align: step.align,
16124
+ sideOffset,
16125
+ alignOffset: step.align === "start" ? -alignOffset : alignOffset,
16126
+ } );
16127
+ }
16128
+ }
16129
+ LX.Tour = Tour;
16130
+
15750
16131
  })( typeof(window) != 'undefined' ? window : (typeof(self) != 'undefined' ? self : global ) );