lexgui 0.7.0 → 0.7.1

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.
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  const LX = {
10
- version: "0.7.0",
10
+ version: "0.7.1",
11
11
  ready: false,
12
12
  extensions: [], // Store extensions used
13
13
  signals: {}, // Events and triggers
@@ -762,7 +762,8 @@ class Popover {
762
762
  this.root.tabIndex = "1";
763
763
  this.root.className = "lexpopover";
764
764
 
765
- const nestedDialog = trigger.closest( "dialog" );
765
+ const refElement = trigger ?? this.reference;
766
+ const nestedDialog = refElement.closest( "dialog" );
766
767
  if( nestedDialog && nestedDialog.dataset[ "modal" ] == 'true' )
767
768
  {
768
769
  this._parent = nestedDialog;
@@ -6202,7 +6203,10 @@ LX.makeContainer = makeContainer;
6202
6203
  * @param {Object} options
6203
6204
  * side: Side of the tooltip
6204
6205
  * offset: Tooltip margin offset
6206
+ * offsetX: Tooltip margin horizontal offset
6207
+ * offsetY: Tooltip margin vertical offset
6205
6208
  * active: Tooltip active by default [true]
6209
+ * callback: Callback function to execute when the tooltip is shown
6206
6210
  */
6207
6211
 
6208
6212
  function asTooltip( trigger, content, options = {} )
@@ -6214,6 +6218,10 @@ function asTooltip( trigger, content, options = {} )
6214
6218
  let tooltipDom = null;
6215
6219
  let tooltipParent = LX.root;
6216
6220
 
6221
+ const _offset = options.offset ?? 6;
6222
+ const _offsetX = options.offsetX ?? _offset;
6223
+ const _offsetY = options.offsetY ?? _offset;
6224
+
6217
6225
  trigger.addEventListener( "mouseenter", function(e) {
6218
6226
 
6219
6227
  if( trigger.dataset[ "disableTooltip" ] == "true" )
@@ -6223,7 +6231,7 @@ function asTooltip( trigger, content, options = {} )
6223
6231
 
6224
6232
  tooltipDom = document.createElement( "div" );
6225
6233
  tooltipDom.className = "lextooltip";
6226
- tooltipDom.innerHTML = content;
6234
+ tooltipDom.innerHTML = trigger.dataset[ "tooltipContent" ] ?? content;
6227
6235
 
6228
6236
  const nestedDialog = trigger.closest( "dialog" );
6229
6237
  if( nestedDialog && nestedDialog.dataset[ "modal" ] == 'true' )
@@ -6240,32 +6248,33 @@ function asTooltip( trigger, content, options = {} )
6240
6248
  LX.doAsync( () => {
6241
6249
 
6242
6250
  const position = [ 0, 0 ];
6251
+ const offsetX = parseFloat( trigger.dataset[ "tooltipOffsetX" ] ?? _offsetX );
6252
+ const offsetY = parseFloat( trigger.dataset[ "tooltipOffsetY" ] ?? _offsetY );
6243
6253
  const rect = this.getBoundingClientRect();
6244
- const offset = options.offset ?? 6;
6245
6254
  let alignWidth = true;
6246
6255
 
6247
6256
  switch( options.side ?? "top" )
6248
6257
  {
6249
6258
  case "left":
6250
- position[ 0 ] += ( rect.x - tooltipDom.offsetWidth - offset );
6259
+ position[ 0 ] += ( rect.x - tooltipDom.offsetWidth - offsetX );
6251
6260
  alignWidth = false;
6252
6261
  break;
6253
6262
  case "right":
6254
- position[ 0 ] += ( rect.x + rect.width + offset );
6263
+ position[ 0 ] += ( rect.x + rect.width + offsetX );
6255
6264
  alignWidth = false;
6256
6265
  break;
6257
6266
  case "top":
6258
- position[ 1 ] += ( rect.y - tooltipDom.offsetHeight - offset );
6267
+ position[ 1 ] += ( rect.y - tooltipDom.offsetHeight - offsetY );
6259
6268
  alignWidth = true;
6260
6269
  break;
6261
6270
  case "bottom":
6262
- position[ 1 ] += ( rect.y + rect.height + offset );
6271
+ position[ 1 ] += ( rect.y + rect.height + offsetY );
6263
6272
  alignWidth = true;
6264
6273
  break;
6265
6274
  }
6266
6275
 
6267
- if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - tooltipDom.offsetWidth * 0.5; }
6268
- else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - tooltipDom.offsetHeight * 0.5; }
6276
+ if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - tooltipDom.offsetWidth * 0.5 + offsetX; }
6277
+ else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - tooltipDom.offsetHeight * 0.5 + offsetY; }
6269
6278
 
6270
6279
  // Avoid collisions
6271
6280
  position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - tooltipDom.offsetWidth - 4 );
@@ -6280,6 +6289,11 @@ function asTooltip( trigger, content, options = {} )
6280
6289
 
6281
6290
  tooltipDom.style.left = `${ position[ 0 ] }px`;
6282
6291
  tooltipDom.style.top = `${ position[ 1 ] }px`;
6292
+
6293
+ if( options.callback )
6294
+ {
6295
+ options.callback( tooltipDom, trigger );
6296
+ }
6283
6297
  } );
6284
6298
  } );
6285
6299
 
@@ -11015,38 +11029,110 @@ class RangeInput extends BaseComponent {
11015
11029
 
11016
11030
  constructor( name, value, callback, options = {} ) {
11017
11031
 
11018
- super( BaseComponent.RANGE, name, value, options );
11032
+ const ogValue = LX.deepCopy( value );
11033
+
11034
+ super( BaseComponent.RANGE, name, LX.deepCopy( ogValue ), options );
11035
+
11036
+ const isRangeValue = ( value.constructor == Array && value.length == 2 );
11037
+ if( isRangeValue )
11038
+ {
11039
+ value = ogValue[ 0 ];
11040
+ options.fill = false; // Range inputs do not fill by default
11041
+ }
11019
11042
 
11020
11043
  this.onGetValue = () => {
11021
- return value;
11044
+ let finalValue = value;
11045
+ if( isRangeValue )
11046
+ {
11047
+ finalValue = [ value, ogValue[ 1 ] ];
11048
+ }
11049
+ else if( options.left )
11050
+ {
11051
+ finalValue = ( ( +slider.max ) - value + ( +slider.min ) );
11052
+ }
11053
+ return finalValue;
11022
11054
  };
11023
11055
 
11024
11056
  this.onSetValue = ( newValue, skipCallback, event ) => {
11025
11057
 
11026
- if( isNaN( newValue ) )
11058
+ let newTpContent = "";
11059
+
11060
+ const diff = ( options.max - options.min );
11061
+
11062
+ if( isRangeValue )
11027
11063
  {
11028
- return;
11064
+ slider.value = value = LX.clamp( +newValue[ 0 ], +slider.min, +slider.max );
11065
+ this._maxSlider.value = ogValue[ 1 ] = LX.clamp( +newValue[ 1 ], +slider.min, +slider.max );
11066
+
11067
+ // Update the range slider
11068
+ const diffOffset = ( value / diff ) - 0.5;
11069
+ const diffMaxOffset = ( ogValue[ 1 ] / diff ) - 0.5;
11070
+ const remappedMin = LX.remapRange( value, options.min, options.max, 0, 1 );
11071
+ const remappedMax = LX.remapRange( ogValue[ 1 ], options.min, options.max, 0, 1 );
11072
+ slider.style.setProperty("--range-min-value", `${ remappedMin * 100 }%`);
11073
+ slider.style.setProperty("--range-max-value", `${ remappedMax * 100 }%`);
11074
+ slider.style.setProperty("--range-fix-min-offset", `${ -diffOffset }rem`);
11075
+ slider.style.setProperty("--range-fix-max-offset", `${ diffMaxOffset }rem`);
11076
+
11077
+ container.dataset[ "tooltipOffsetX" ] = container.offsetWidth * remappedMin + container.offsetWidth * ( remappedMax - remappedMin ) * 0.5 - ( container.offsetWidth * 0.5 );
11078
+ newTpContent = `${ value } - ${ ogValue[ 1 ] }`;
11029
11079
  }
11080
+ else
11081
+ {
11082
+ if( isNaN( newValue ) )
11083
+ {
11084
+ return;
11085
+ }
11030
11086
 
11031
- slider.value = value = LX.clamp( +newValue, +slider.min, +slider.max );
11087
+ slider.value = value = LX.clamp( +newValue, +slider.min, +slider.max );
11088
+ const remapped = LX.remapRange( value, options.min, options.max, 0, 1 ) * 0.5;
11089
+ container.dataset[ "tooltipOffsetX" ] = container.offsetWidth * remapped - ( container.offsetWidth * 0.5 );
11090
+ newTpContent = `${ value }`;
11091
+ }
11092
+
11093
+ container.dataset[ "tooltipContent" ] = newTpContent;
11094
+ if( this._labelTooltip )
11095
+ {
11096
+ this._labelTooltip.innerHTML = newTpContent;
11097
+ }
11032
11098
 
11033
11099
  if( !skipCallback )
11034
11100
  {
11035
- this._trigger( new LX.IEvent( name, options.left ? ( ( +slider.max ) - value + ( +slider.min ) ) : value, event ), callback );
11101
+ let finalValue = value;
11102
+ if( isRangeValue )
11103
+ {
11104
+ finalValue = [ value, ogValue[ 1 ] ];
11105
+ }
11106
+ else if( options.left )
11107
+ {
11108
+ finalValue = ( ( +slider.max ) - value + ( +slider.min ) );
11109
+ }
11110
+
11111
+ this._trigger( new LX.IEvent( name, finalValue, event ), callback );
11036
11112
  }
11037
11113
  };
11038
11114
 
11039
11115
  this.onResize = ( rect ) => {
11040
11116
  const realNameWidth = ( this.root.domName?.style.width ?? "0px" );
11041
11117
  container.style.width = options.inputWidth ?? `calc( 100% - ${ realNameWidth })`;
11118
+ if( isRangeValue )
11119
+ {
11120
+ const diff = ( options.max - options.min );
11121
+ const diffOffset = ( value / diff ) - 0.5;
11122
+ const diffMaxOffset = ( ogValue[ 1 ] / diff ) - 0.5;
11123
+ slider.style.setProperty("--range-min-value", `${ LX.remapRange( value, options.min, options.max, 0, 1 ) * 100 }%`);
11124
+ slider.style.setProperty("--range-max-value", `${ LX.remapRange( ogValue[ 1 ], options.min, options.max, 0, 1 ) * 100 }%`);
11125
+ slider.style.setProperty("--range-fix-min-offset", `${ -diffOffset }rem`);
11126
+ slider.style.setProperty("--range-fix-max-offset", `${ diffMaxOffset }rem`);
11127
+ }
11042
11128
  };
11043
11129
 
11044
11130
  const container = document.createElement( 'div' );
11045
- container.className = "lexrange";
11131
+ container.className = "lexrange relative";
11046
11132
  this.root.appendChild( container );
11047
11133
 
11048
11134
  let slider = document.createElement( 'input' );
11049
- slider.className = "lexrangeslider " + ( options.className ?? "" );
11135
+ slider.className = "lexrangeslider " + ( isRangeValue ? "pointer-events-none " : "" ) + ( options.className ?? "" );
11050
11136
  slider.min = options.min ?? 0;
11051
11137
  slider.max = options.max ?? 100;
11052
11138
  slider.step = options.step ?? 1;
@@ -11058,16 +11144,9 @@ class RangeInput extends BaseComponent {
11058
11144
  value = LX.clamp( value, +slider.min, +slider.max );
11059
11145
  }
11060
11146
 
11061
- if( options.left )
11062
- {
11063
- value = ( ( +slider.max ) - value + ( +slider.min ) );
11064
- }
11065
-
11066
- slider.value = value;
11067
- container.appendChild( slider );
11068
-
11069
11147
  if( options.left ?? false )
11070
11148
  {
11149
+ value = ( ( +slider.max ) - value + ( +slider.min ) );
11071
11150
  slider.classList.add( "left" );
11072
11151
  }
11073
11152
 
@@ -11076,23 +11155,30 @@ class RangeInput extends BaseComponent {
11076
11155
  slider.classList.add( "no-fill" );
11077
11156
  }
11078
11157
 
11158
+ slider.value = value;
11159
+ container.appendChild( slider );
11160
+
11079
11161
  slider.addEventListener( "input", e => {
11080
- this.set( e.target.valueAsNumber, false, e );
11162
+ this.set( isRangeValue ? [ e.target.valueAsNumber, ogValue[ 1 ] ] : e.target.valueAsNumber, false, e );
11081
11163
  }, { passive: false });
11082
11164
 
11083
- slider.addEventListener( "mousedown", function( e ) {
11084
- if( options.onPress )
11085
- {
11086
- options.onPress.bind( slider )( e, slider );
11087
- }
11088
- }, false );
11165
+ // If its a range value, we need to update the slider using the thumbs
11166
+ if( !isRangeValue )
11167
+ {
11168
+ slider.addEventListener( "mousedown", function( e ) {
11169
+ if( options.onPress )
11170
+ {
11171
+ options.onPress.bind( slider )( e, slider );
11172
+ }
11173
+ }, false );
11089
11174
 
11090
- slider.addEventListener( "mouseup", function( e ) {
11091
- if( options.onRelease )
11092
- {
11093
- options.onRelease.bind( slider )( e, slider );
11094
- }
11095
- }, false );
11175
+ slider.addEventListener( "mouseup", function( e ) {
11176
+ if( options.onRelease )
11177
+ {
11178
+ options.onRelease.bind( slider )( e, slider );
11179
+ }
11180
+ }, false );
11181
+ }
11096
11182
 
11097
11183
  // Method to change min, max, step parameters
11098
11184
  this.setLimits = ( newMin, newMax, newStep ) => {
@@ -11102,7 +11188,47 @@ class RangeInput extends BaseComponent {
11102
11188
  BaseComponent._dispatchEvent( slider, "input", true );
11103
11189
  };
11104
11190
 
11105
- LX.doAsync( this.onResize.bind( this ) );
11191
+ LX.doAsync( () => {
11192
+
11193
+ this.onResize();
11194
+
11195
+ let offsetX = 0;
11196
+ if( isRangeValue )
11197
+ {
11198
+ const remappedMin = LX.remapRange( value, options.min, options.max, 0, 1 );
11199
+ const remappedMax = LX.remapRange( ogValue[ 1 ], options.min, options.max, 0, 1 );
11200
+ offsetX = container.offsetWidth * remappedMin + container.offsetWidth * ( remappedMax - remappedMin ) * 0.5 - ( container.offsetWidth * 0.5 );
11201
+ }
11202
+ else
11203
+ {
11204
+ const remapped = LX.remapRange( value, options.min, options.max, 0, 1 ) * 0.5;
11205
+ offsetX = container.offsetWidth * remapped - ( container.offsetWidth * 0.5 );
11206
+ }
11207
+ LX.asTooltip( container, `${ value }${ isRangeValue ? `- ${ ogValue[ 1 ] }` : `` }`, { offsetX, callback: ( tpDom ) => {
11208
+ this._labelTooltip = tpDom;
11209
+ } } );
11210
+ } );
11211
+
11212
+ if( ogValue.constructor == Array ) // Its a range value
11213
+ {
11214
+ let maxSlider = document.createElement( 'input' );
11215
+ maxSlider.className = "lexrangeslider no-fill pointer-events-none overlap absolute top-0 left-0 " + ( options.className ?? "" );
11216
+ maxSlider.min = options.min ?? 0;
11217
+ maxSlider.max = options.max ?? 100;
11218
+ maxSlider.step = options.step ?? 1;
11219
+ maxSlider.type = "range";
11220
+ maxSlider.disabled = options.disabled ?? false;
11221
+ this._maxSlider = maxSlider;
11222
+
11223
+ let maxRangeValue = ogValue[ 1 ];
11224
+ maxSlider.value = maxRangeValue = LX.clamp( maxRangeValue, +maxSlider.min, +maxSlider.max );
11225
+ container.appendChild( maxSlider );
11226
+
11227
+ maxSlider.addEventListener( "input", e => {
11228
+ ogValue[ 1 ] = +e.target.valueAsNumber;
11229
+ this.set( [ value, ogValue[ 1 ] ], false, e );
11230
+ }, { passive: false });
11231
+ }
11106
11232
  }
11107
11233
  }
11108
11234