lexgui 0.6.10 → 0.6.12

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.
@@ -1,4 +1,4 @@
1
- // This is a generated file. Do not edit.
1
+ // This is a generated file. Do not edit.
2
2
  // Lexgui.js @jxarco
3
3
 
4
4
  /**
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  const LX = {
10
- version: "0.6.10",
10
+ version: "0.6.12",
11
11
  ready: false,
12
12
  components: [], // Specific pre-build components
13
13
  signals: {}, // Events and triggers
@@ -718,8 +718,6 @@ class Popover {
718
718
 
719
719
  constructor( trigger, content, options = {} ) {
720
720
 
721
- console.assert( trigger, "Popover needs a DOM element as trigger!" );
722
-
723
721
  if( Popover.activeElement )
724
722
  {
725
723
  Popover.activeElement.destroy();
@@ -727,13 +725,20 @@ class Popover {
727
725
  }
728
726
 
729
727
  this._trigger = trigger;
730
- trigger.classList.add( "triggered" );
731
- trigger.active = this;
728
+
729
+ if( trigger )
730
+ {
731
+ trigger.classList.add( "triggered" );
732
+ trigger.active = this;
733
+ }
732
734
 
733
735
  this._windowPadding = 4;
734
736
  this.side = options.side ?? "bottom";
735
737
  this.align = options.align ?? "center";
738
+ this.sideOffset = options.sideOffset ?? 0;
739
+ this.alignOffset = options.alignOffset ?? 0;
736
740
  this.avoidCollisions = options.avoidCollisions ?? true;
741
+ this.reference = options.reference;
737
742
 
738
743
  this.root = document.createElement( "div" );
739
744
  this.root.dataset["side"] = this.side;
@@ -768,29 +773,35 @@ class Popover {
768
773
  LX.doAsync( () => {
769
774
  this._adjustPosition();
770
775
 
771
- this.root.focus();
776
+ if( this._trigger )
777
+ {
778
+ this.root.focus();
772
779
 
773
- this._onClick = e => {
774
- if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
775
- {
776
- return;
777
- }
778
- this.destroy();
779
- };
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
+
788
+ document.body.addEventListener( "mousedown", this._onClick, true );
789
+ document.body.addEventListener( "focusin", this._onClick, true );
790
+ }
780
791
 
781
- document.body.addEventListener( "mousedown", this._onClick, true );
782
- document.body.addEventListener( "focusin", this._onClick, true );
783
792
  }, 10 );
784
793
  }
785
794
 
786
795
  destroy() {
787
796
 
788
- this._trigger.classList.remove( "triggered" );
789
-
790
- delete this._trigger.active;
797
+ if( this._trigger )
798
+ {
799
+ this._trigger.classList.remove( "triggered" );
800
+ delete this._trigger.active;
791
801
 
792
- document.body.removeEventListener( "mousedown", this._onClick, true );
793
- document.body.removeEventListener( "focusin", this._onClick, true );
802
+ document.body.removeEventListener( "mousedown", this._onClick, true );
803
+ document.body.removeEventListener( "focusin", this._onClick, true );
804
+ }
794
805
 
795
806
  this.root.remove();
796
807
 
@@ -803,26 +814,28 @@ class Popover {
803
814
 
804
815
  // Place menu using trigger position and user options
805
816
  {
806
- const rect = this._trigger.getBoundingClientRect();
817
+ const el = this.reference ?? this._trigger;
818
+ console.assert( el, "Popover needs a trigger or reference element!" );
819
+ const rect = el.getBoundingClientRect();
807
820
 
808
821
  let alignWidth = true;
809
822
 
810
823
  switch( this.side )
811
824
  {
812
825
  case "left":
813
- position[ 0 ] += ( rect.x - this.root.offsetWidth );
826
+ position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
814
827
  alignWidth = false;
815
828
  break;
816
829
  case "right":
817
- position[ 0 ] += ( rect.x + rect.width );
830
+ position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
818
831
  alignWidth = false;
819
832
  break;
820
833
  case "top":
821
- position[ 1 ] += ( rect.y - this.root.offsetHeight );
834
+ position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
822
835
  alignWidth = true;
823
836
  break;
824
837
  case "bottom":
825
- position[ 1 ] += ( rect.y + rect.height );
838
+ position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
826
839
  alignWidth = true;
827
840
  break;
828
841
  }
@@ -842,6 +855,9 @@ class Popover {
842
855
  else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
843
856
  break;
844
857
  }
858
+
859
+ if( alignWidth ) { position[ 0 ] += this.alignOffset; }
860
+ else { position[ 1 ] += this.alignOffset; }
845
861
  }
846
862
 
847
863
  if( this.avoidCollisions )
@@ -856,6 +872,58 @@ class Popover {
856
872
  }
857
873
  LX.Popover = Popover;
858
874
 
875
+ /**
876
+ * @class PopConfirm
877
+ */
878
+
879
+ class PopConfirm {
880
+
881
+ constructor( reference, options = {} ) {
882
+
883
+ const okText = options.confirmText ?? "Yes";
884
+ const cancelText = options.cancelText ?? "No";
885
+ const title = options.title ?? "Confirm";
886
+ const content = options.content ?? "Are you sure you want to proceed?";
887
+ const onConfirm = options.onConfirm;
888
+ const onCancel = options.onCancel;
889
+
890
+ const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
891
+
892
+ {
893
+ const headerDiv = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
894
+ LX.makeContainer( ["100%", "auto"], "p-1 font-medium text-md", title, headerDiv );
895
+ }
896
+
897
+ LX.makeContainer( ["100%", "auto"], "p-1 text-md", content, popoverContainer, { maxWidth: "400px" } );
898
+ const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
899
+ const footerButtons = LX.makeContainer( ["100%", "auto"], "text-md", "", footer );
900
+ const footerPanel = new LX.Panel();
901
+ footerButtons.appendChild( footerPanel.root );
902
+
903
+ footerPanel.sameLine( 2, "justify-end" );
904
+ footerPanel.addButton( null, cancelText, () => {
905
+ if( onCancel ) onCancel();
906
+ this._popover?.destroy();
907
+ }, { xbuttonClass: "contrast" } );
908
+ footerPanel.addButton( null, okText, () => {
909
+ if( onConfirm ) onConfirm();
910
+ this._popover?.destroy();
911
+ }, { buttonClass: "accent" } );
912
+
913
+ this._popover?.destroy();
914
+ this._popover = new LX.Popover( null, [ popoverContainer ], {
915
+ reference,
916
+ side: options.side ?? "top",
917
+ align: options.align,
918
+ sideOffset: options.sideOffset,
919
+ alignOffset: options.alignOffset,
920
+ } );
921
+
922
+ }
923
+ }
924
+
925
+ LX.PopConfirm = PopConfirm;
926
+
859
927
  /**
860
928
  * @class Sheet
861
929
  */
@@ -978,6 +1046,8 @@ class DropdownMenu {
978
1046
  this._windowPadding = 4;
979
1047
  this.side = options.side ?? "bottom";
980
1048
  this.align = options.align ?? "center";
1049
+ this.sideOffset = options.sideOffset ?? 0;
1050
+ this.alignOffset = options.alignOffset ?? 0;
981
1051
  this.avoidCollisions = options.avoidCollisions ?? true;
982
1052
  this.onBlur = options.onBlur;
983
1053
  this.inPlace = false;
@@ -1220,19 +1290,19 @@ class DropdownMenu {
1220
1290
  switch( this.side )
1221
1291
  {
1222
1292
  case "left":
1223
- position[ 0 ] += ( rect.x - this.root.offsetWidth );
1293
+ position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
1224
1294
  alignWidth = false;
1225
1295
  break;
1226
1296
  case "right":
1227
- position[ 0 ] += ( rect.x + rect.width );
1297
+ position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
1228
1298
  alignWidth = false;
1229
1299
  break;
1230
1300
  case "top":
1231
- position[ 1 ] += ( rect.y - this.root.offsetHeight );
1301
+ position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
1232
1302
  alignWidth = true;
1233
1303
  break;
1234
1304
  case "bottom":
1235
- position[ 1 ] += ( rect.y + rect.height );
1305
+ position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
1236
1306
  alignWidth = true;
1237
1307
  break;
1238
1308
  }
@@ -1252,6 +1322,9 @@ class DropdownMenu {
1252
1322
  else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
1253
1323
  break;
1254
1324
  }
1325
+
1326
+ if( alignWidth ) { position[ 0 ] += this.alignOffset; }
1327
+ else { position[ 1 ] += this.alignOffset; }
1255
1328
  }
1256
1329
 
1257
1330
  if( this.avoidCollisions )
@@ -1646,8 +1719,15 @@ class Calendar {
1646
1719
  this.root = LX.makeContainer( ["256px", "auto"], "p-1 text-md" );
1647
1720
 
1648
1721
  this.onChange = options.onChange;
1722
+ this.onPreviousMonth = options.onPreviousMonth;
1723
+ this.onNextMonth = options.onNextMonth;
1724
+
1649
1725
  this.untilToday = options.untilToday;
1650
1726
  this.fromToday = options.fromToday;
1727
+ this.range = options.range;
1728
+
1729
+ this.skipPrevMonth = options.skipPrevMonth;
1730
+ this.skipNextMonth = options.skipNextMonth;
1651
1731
 
1652
1732
  if( dateString )
1653
1733
  {
@@ -1671,7 +1751,7 @@ class Calendar {
1671
1751
  }
1672
1752
  }
1673
1753
 
1674
- _previousMonth() {
1754
+ _previousMonth( skipCallback ) {
1675
1755
 
1676
1756
  this.month = Math.max( 0, this.month - 1 );
1677
1757
 
@@ -1682,9 +1762,14 @@ class Calendar {
1682
1762
  }
1683
1763
 
1684
1764
  this.fromMonthYear( this.month, this.year );
1765
+
1766
+ if( !skipCallback && this.onPreviousMonth )
1767
+ {
1768
+ this.onPreviousMonth( this.currentDate );
1769
+ }
1685
1770
  }
1686
1771
 
1687
- _nextMonth() {
1772
+ _nextMonth( skipCallback ) {
1688
1773
 
1689
1774
  this.month = Math.min( this.month + 1, 12 );
1690
1775
 
@@ -1695,6 +1780,11 @@ class Calendar {
1695
1780
  }
1696
1781
 
1697
1782
  this.fromMonthYear( this.month, this.year );
1783
+
1784
+ if( !skipCallback && this.onNextMonth )
1785
+ {
1786
+ this.onNextMonth( this.currentDate );
1787
+ }
1698
1788
  }
1699
1789
 
1700
1790
  refresh() {
@@ -1705,19 +1795,25 @@ class Calendar {
1705
1795
  {
1706
1796
  const header = LX.makeContainer( ["100%", "auto"], "flex flex-row p-1", "", this.root );
1707
1797
 
1708
- const prevMonthIcon = LX.makeIcon( "Left", { title: "Previous Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
1709
- header.appendChild( prevMonthIcon );
1710
- prevMonthIcon.addEventListener( "click", () => {
1711
- this._previousMonth();
1712
- } );
1798
+ if( !this.skipPrevMonth )
1799
+ {
1800
+ const prevMonthIcon = LX.makeIcon( "Left", { title: "Previous Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
1801
+ header.appendChild( prevMonthIcon );
1802
+ prevMonthIcon.addEventListener( "click", () => {
1803
+ this._previousMonth();
1804
+ } );
1805
+ }
1713
1806
 
1714
1807
  LX.makeContainer( ["100%", "auto"], "text-center font-medium select-none", `${ this.monthName } ${ this.year }`, header );
1715
1808
 
1716
- const nextMonthIcon = LX.makeIcon( "Right", { title: "Next Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
1717
- header.appendChild( nextMonthIcon );
1718
- nextMonthIcon.addEventListener( "click", () => {
1719
- this._nextMonth();
1720
- } );
1809
+ if( !this.skipNextMonth )
1810
+ {
1811
+ const nextMonthIcon = LX.makeIcon( "Right", { title: "Next Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
1812
+ header.appendChild( nextMonthIcon );
1813
+ nextMonthIcon.addEventListener( "click", () => {
1814
+ this._nextMonth();
1815
+ } );
1816
+ }
1721
1817
  }
1722
1818
 
1723
1819
  // Body
@@ -1749,6 +1845,11 @@ class Calendar {
1749
1845
  const body = document.createElement( 'tbody' );
1750
1846
  daysTable.appendChild( body );
1751
1847
 
1848
+ let fromRangeDate = this.range ? LX.dateFromDateString( this.range[ 0 ] ) : null;
1849
+ let toRangeDate = this.range ? LX.dateFromDateString( this.range[ 1 ] ) : null;
1850
+
1851
+ this.currentDate ? new Date( `${ this.currentDate.month }/${ this.currentDate.day }/${ this.currentDate.year }` ) : null;
1852
+
1752
1853
  for( let week = 0; week < 6; week++ )
1753
1854
  {
1754
1855
  const hrow = document.createElement( 'tr' );
@@ -1761,15 +1862,28 @@ class Calendar {
1761
1862
 
1762
1863
  const dayDate = new Date( `${ this.month }/${ dayData.day }/${ this.year }` );
1763
1864
  const date = new Date();
1865
+ // today inclusives
1764
1866
  const beforeToday = this.untilToday ? ( dayDate.getTime() < date.getTime() ) : true;
1765
- const afterToday = this.fromToday ? ( dayDate.getTime() > date.getTime() ) : true;
1867
+ const afterToday = this.fromToday ? ( dayDate.getFullYear() > date.getFullYear() ||
1868
+ (dayDate.getFullYear() === date.getFullYear() && dayDate.getMonth() > date.getMonth()) ||
1869
+ (dayDate.getFullYear() === date.getFullYear() && dayDate.getMonth() === date.getMonth() && dayDate.getDate() >= date.getDate())
1870
+ ) : true;
1766
1871
  const selectable = dayData.currentMonth && beforeToday && afterToday;
1767
-
1768
- if( this.currentDate && ( dayData.day == this.currentDate.day ) && ( this.month == this.currentDate.month )
1769
- && ( this.year == this.currentDate.year ) && dayData.currentMonth )
1872
+ const currentDay = this.currentDate && ( dayData.day == this.currentDate.day ) && ( this.month == this.currentDate.month )
1873
+ && ( this.year == this.currentDate.year ) && dayData.currentMonth;
1874
+ const currentFromRange = selectable && fromRangeDate && ( dayData.day == fromRangeDate.getDate() ) && ( this.month == ( fromRangeDate.getMonth() + 1 ) )
1875
+ && ( this.year == fromRangeDate.getFullYear() );
1876
+ const currentToRange = selectable && toRangeDate && ( dayData.day == toRangeDate.getDate() ) && ( this.month == ( toRangeDate.getMonth() + 1 ) )
1877
+ && ( this.year == toRangeDate.getFullYear() );
1878
+
1879
+ if( ( !this.range && currentDay ) || this.range && ( currentFromRange || currentToRange ) )
1770
1880
  {
1771
1881
  th.className += ` bg-contrast fg-contrast`;
1772
1882
  }
1883
+ else if( this.range && selectable && ( dayDate > fromRangeDate ) && ( dayDate < toRangeDate ) )
1884
+ {
1885
+ th.className += ` bg-accent fg-contrast`;
1886
+ }
1773
1887
  else
1774
1888
  {
1775
1889
  th.className += ` ${ selectable ? "fg-primary" : "fg-tertiary" } hover:bg-secondary`;
@@ -1789,6 +1903,20 @@ class Calendar {
1789
1903
  }
1790
1904
  } );
1791
1905
  }
1906
+ // This event should only be applied in non current month days
1907
+ else if( this.range === undefined && !dayData.currentMonth )
1908
+ {
1909
+ th.addEventListener( "click", () => {
1910
+ if( dayData?.prevMonth )
1911
+ {
1912
+ this._previousMonth();
1913
+ }
1914
+ else
1915
+ {
1916
+ this._nextMonth();
1917
+ }
1918
+ } );
1919
+ }
1792
1920
  }
1793
1921
 
1794
1922
  body.appendChild( hrow );
@@ -1803,6 +1931,7 @@ class Calendar {
1803
1931
 
1804
1932
  this.day = parseInt( tokens[ 0 ] );
1805
1933
  this.month = parseInt( tokens[ 1 ] );
1934
+ this.monthName = this.getMonthName( this.month - 1 );
1806
1935
  this.year = parseInt( tokens[ 2 ] );
1807
1936
 
1808
1937
  this.currentDate = this._getCurrentDate();
@@ -1832,7 +1961,7 @@ class Calendar {
1832
1961
  // Fill in days from previous month
1833
1962
  for( let i = firstDay - 1; i >= 0; i--)
1834
1963
  {
1835
- calendarDays.push( { day: daysInPrevMonth - i, currentMonth: false } );
1964
+ calendarDays.push( { day: daysInPrevMonth - i, currentMonth: false, prevMonth: true } );
1836
1965
  }
1837
1966
 
1838
1967
  // Fill in current month days
@@ -1845,7 +1974,7 @@ class Calendar {
1845
1974
  const remaining = 42 - calendarDays.length;
1846
1975
  for( let i = 1; i <= remaining; i++ )
1847
1976
  {
1848
- calendarDays.push( { day: i, currentMonth: false } );
1977
+ calendarDays.push( { day: i, currentMonth: false, nextMonth: true } );
1849
1978
  }
1850
1979
 
1851
1980
  this.monthName = this.getMonthName( month );
@@ -1861,8 +1990,14 @@ class Calendar {
1861
1990
  return formatter.format( new Date( 2000, monthIndex, 1 ) );
1862
1991
  }
1863
1992
 
1864
- getFullDate() {
1865
- return `${ this.monthName } ${ this.day }${ this._getOrdinalSuffix( this.day ) }, ${ this.year }`;
1993
+ getFullDate( monthName, day, year ) {
1994
+ return `${ monthName ?? this.monthName } ${ day ?? this.day }${ this._getOrdinalSuffix( day ?? this.day ) }, ${ year ?? this.year }`;
1995
+ }
1996
+
1997
+ setRange( range ) {
1998
+ console.assert( range.constructor === Array, "Date Range must be in Array format" );
1999
+ this.range = range;
2000
+ this.refresh();
1866
2001
  }
1867
2002
 
1868
2003
  _getOrdinalSuffix( day ) {
@@ -1879,6 +2014,110 @@ class Calendar {
1879
2014
 
1880
2015
  LX.Calendar = Calendar;
1881
2016
 
2017
+ class CalendarRange {
2018
+
2019
+ /**
2020
+ * @constructor CalendarRange
2021
+ * @param {Array} range ["DD/MM/YYYY", "DD/MM/YYYY"]
2022
+ * @param {Object} options
2023
+ */
2024
+
2025
+ constructor( range, options = {} ) {
2026
+
2027
+ this.root = LX.makeContainer( ["auto", "auto"], "flex flex-row" );
2028
+
2029
+ console.assert( range && range.constructor === Array, "Range cannot be empty and has to be an Array!" );
2030
+
2031
+ let mustAdvanceMonth = false;
2032
+
2033
+ // Fix any issues with date range picking
2034
+ {
2035
+ const t0 = LX.dateFromDateString( range[ 0 ] );
2036
+ const t1 = LX.dateFromDateString( range[ 1 ] );
2037
+
2038
+ if( t0 > t1 )
2039
+ {
2040
+ const tmp = range[ 0 ];
2041
+ range[ 0 ] = range[ 1 ];
2042
+ range[ 1 ] = tmp;
2043
+ }
2044
+
2045
+ mustAdvanceMonth = ( t0.getMonth() == t1.getMonth() ) && ( t0.getFullYear() == t1.getFullYear() );
2046
+ }
2047
+
2048
+ this.from = range[ 0 ];
2049
+ this.to = range[ 1 ];
2050
+
2051
+ this._selectingRange = false;
2052
+
2053
+ const onChange = ( date ) => {
2054
+
2055
+ const newDateString = `${ date.day }/${ date.month }/${ date.year }`;
2056
+
2057
+ if( !this._selectingRange )
2058
+ {
2059
+ this.from = this.to = newDateString;
2060
+ this._selectingRange = true;
2061
+ }
2062
+ else
2063
+ {
2064
+ this.to = newDateString;
2065
+ this._selectingRange = false;
2066
+ }
2067
+
2068
+ const newRange = [ this.from, this.to ];
2069
+
2070
+ this.fromCalendar.setRange( newRange );
2071
+ this.toCalendar.setRange( newRange );
2072
+
2073
+ if( options.onChange )
2074
+ {
2075
+ options.onChange( newRange );
2076
+ }
2077
+
2078
+ };
2079
+
2080
+ this.fromCalendar = new LX.Calendar( this.from, {
2081
+ skipNextMonth: true,
2082
+ onChange,
2083
+ onPreviousMonth: () => {
2084
+ this.toCalendar._previousMonth();
2085
+ },
2086
+ range
2087
+ });
2088
+
2089
+ this.toCalendar = new LX.Calendar( this.to, {
2090
+ skipPrevMonth: true,
2091
+ onChange,
2092
+ onNextMonth: () => {
2093
+ this.fromCalendar._nextMonth();
2094
+ },
2095
+ range
2096
+ });
2097
+
2098
+ if( mustAdvanceMonth )
2099
+ {
2100
+ this.toCalendar._nextMonth( true );
2101
+ }
2102
+
2103
+ this.root.appendChild( this.fromCalendar.root );
2104
+ this.root.appendChild( this.toCalendar.root );
2105
+ }
2106
+
2107
+ getFullDate() {
2108
+
2109
+ const d0 = LX.dateFromDateString( this.from );
2110
+ const d0Month = this.fromCalendar.getMonthName( d0.getMonth() );
2111
+
2112
+ const d1 = LX.dateFromDateString( this.to );
2113
+ const d1Month = this.toCalendar.getMonthName( d1.getMonth() );
2114
+
2115
+ return `${ this.fromCalendar.getFullDate( d0Month, d0.getDate(), d0.getFullYear() ) } to ${ this.toCalendar.getFullDate( d1Month, d1.getDate(), d1.getFullYear() ) }`;
2116
+ }
2117
+ }
2118
+
2119
+ LX.CalendarRange = CalendarRange;
2120
+
1882
2121
  /**
1883
2122
  * @class Tabs
1884
2123
  */
@@ -4113,8 +4352,8 @@ Element.prototype.ignore = function( eventName, callbackName ) {
4113
4352
  callbackName = callbackName ?? ( "_on" + eventName );
4114
4353
  const callback = this[ callbackName ];
4115
4354
  this.removeEventListener( eventName, callback );
4116
- };
4117
-
4355
+ };
4356
+
4118
4357
  // icons.js @jxarco
4119
4358
 
4120
4359
  const RAW_ICONS = {
@@ -4292,8 +4531,8 @@ LX.LucideIconAlias = {
4292
4531
  "RotateRight": "RotateCw",
4293
4532
  "RotateBack": "RotateCcw",
4294
4533
  "RotateLeft": "RotateCcw",
4295
- };
4296
-
4534
+ };
4535
+
4297
4536
  // utils.js @jxarco
4298
4537
 
4299
4538
  function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
@@ -4729,6 +4968,22 @@ function hsvToRgb( hsv )
4729
4968
 
4730
4969
  LX.hsvToRgb = hsvToRgb;
4731
4970
 
4971
+ /**
4972
+ * @method dateFromDateString
4973
+ * @description Get an instance of Date() from a Date in String format (DD/MM/YYYY)
4974
+ * @param {String} dateString
4975
+ */
4976
+ function dateFromDateString( dateString )
4977
+ {
4978
+ const tokens = dateString.split( '/' );
4979
+ const day = parseInt( tokens[ 0 ] );
4980
+ const month = parseInt( tokens[ 1 ] );
4981
+ const year = parseInt( tokens[ 2 ] );
4982
+ return new Date( `${ month }/${ day }/${ year }` );
4983
+ }
4984
+
4985
+ LX.dateFromDateString = dateFromDateString;
4986
+
4732
4987
  /**
4733
4988
  * @method measureRealWidth
4734
4989
  * @description Measure the pixel width of a text
@@ -6009,8 +6264,8 @@ function drawSpline( ctx, pts, t )
6009
6264
  ctx.restore();
6010
6265
  }
6011
6266
 
6012
- LX.drawSpline = drawSpline;
6013
-
6267
+ LX.drawSpline = drawSpline;
6268
+
6014
6269
  // area.js @jxarco
6015
6270
 
6016
6271
  class AreaOverlayButtons {
@@ -7104,8 +7359,8 @@ class Area {
7104
7359
  }
7105
7360
  }
7106
7361
  }
7107
- LX.Area = Area;
7108
-
7362
+ LX.Area = Area;
7363
+
7109
7364
  // widget.js @jxarco
7110
7365
 
7111
7366
  /**
@@ -8660,6 +8915,20 @@ class Button extends Widget {
8660
8915
  {
8661
8916
  wValue.querySelector( ".file-input" ).click();
8662
8917
  }
8918
+ else if( options.mustConfirm )
8919
+ {
8920
+ new LX.PopConfirm( wValue, {
8921
+ onConfirm: () => {
8922
+ this._trigger( new LX.IEvent( name, value, e ), callback );
8923
+ },
8924
+ side: options.confirmSide,
8925
+ align: options.confirmAlign,
8926
+ confirmText: options.confirmText,
8927
+ cancelText: options.confirmCancelText,
8928
+ title: options.confirmTitle,
8929
+ content: options.confirmContent
8930
+ } );
8931
+ }
8663
8932
  else
8664
8933
  {
8665
8934
  const swapInput = wValue.querySelector( "input" );
@@ -8955,16 +9224,17 @@ class Form extends Widget {
8955
9224
 
8956
9225
  if( entryData.constructor != Object )
8957
9226
  {
8958
- entryData = { };
9227
+ const oldValue = JSON.parse( JSON.stringify( entryData ) );
9228
+ entryData = { value: oldValue };
8959
9229
  data[ entry ] = entryData;
8960
9230
  }
8961
9231
 
8962
- entryData.placeholder = entryData.placeholder ?? entry;
9232
+ entryData.placeholder = entryData.placeholder ?? ( entryData.label ?? `Enter ${ entry }` );
8963
9233
  entryData.width = "100%";
8964
9234
 
8965
9235
  if( !( options.skipLabels ?? false ) )
8966
9236
  {
8967
- const label = new LX.TextInput( null, entry, null, { disabled: true, inputClass: "formlabel nobg" } );
9237
+ const label = new LX.TextInput( null, entryData.label ?? entry, null, { disabled: true, inputClass: "formlabel nobg" } );
8968
9238
  container.appendChild( label.root );
8969
9239
  }
8970
9240
 
@@ -10659,15 +10929,15 @@ class Vector extends Widget {
10659
10929
 
10660
10930
  for( let i = 0; i < vectorInputs.length; ++i )
10661
10931
  {
10662
- let value = newValue[ i ];
10663
- value = LX.clamp( value, +vectorInputs[ i ].min, +vectorInputs[ i ].max );
10664
- value = LX.round( value, options.precision ) ?? 0;
10665
- vectorInputs[ i ].value = newValue[ i ] = value;
10932
+ let vecValue = newValue[ i ];
10933
+ vecValue = LX.clamp( vecValue, +vectorInputs[ i ].min, +vectorInputs[ i ].max );
10934
+ vecValue = LX.round( vecValue, options.precision ) ?? 0;
10935
+ vectorInputs[ i ].value = value[ i ] = vecValue;
10666
10936
  }
10667
10937
 
10668
10938
  if( !skipCallback )
10669
10939
  {
10670
- this._trigger( new LX.IEvent( name, newValue, event ), callback );
10940
+ this._trigger( new LX.IEvent( name, value, event ), callback );
10671
10941
  }
10672
10942
  };
10673
10943
 
@@ -11257,12 +11527,18 @@ class Progress extends Widget {
11257
11527
  };
11258
11528
 
11259
11529
  this.onSetValue = ( newValue, skipCallback, event ) => {
11530
+ newValue = LX.clamp( newValue, progress.min, progress.max );
11260
11531
  this.root.querySelector("meter").value = newValue;
11261
11532
  _updateColor();
11262
11533
  if( this.root.querySelector("span") )
11263
11534
  {
11264
11535
  this.root.querySelector("span").innerText = newValue;
11265
11536
  }
11537
+
11538
+ if( !skipCallback )
11539
+ {
11540
+ this._trigger( new LX.IEvent( name, newValue, event ), options.callback );
11541
+ }
11266
11542
  };
11267
11543
 
11268
11544
  this.onResize = ( rect ) => {
@@ -11346,11 +11622,6 @@ class Progress extends Widget {
11346
11622
  const rect = progress.getBoundingClientRect();
11347
11623
  const newValue = LX.round( LX.remapRange( e.offsetX - rect.x, 0, rect.width, progress.min, progress.max ) );
11348
11624
  this.set( newValue, false, e );
11349
-
11350
- if( options.callback )
11351
- {
11352
- options.callback( newValue, e );
11353
- }
11354
11625
  }
11355
11626
 
11356
11627
  e.stopPropagation();
@@ -12413,25 +12684,30 @@ LX.Table = Table;
12413
12684
 
12414
12685
  class DatePicker extends Widget {
12415
12686
 
12416
- constructor( name, dateString, callback, options = { } ) {
12687
+ constructor( name, dateValue, callback, options = { } ) {
12417
12688
 
12418
12689
  super( Widget.DATE, name, null, options );
12419
12690
 
12420
- if( options.today )
12691
+ const dateAsRange = ( dateValue?.constructor === Array );
12692
+
12693
+ if( !dateAsRange && options.today )
12421
12694
  {
12422
12695
  const date = new Date();
12423
- dateString = `${ date.getDate() }/${ date.getMonth() + 1 }/${ date.getFullYear() }`;
12696
+ dateValue = `${ date.getDate() }/${ date.getMonth() + 1 }/${ date.getFullYear() }`;
12424
12697
  }
12425
12698
 
12426
12699
  this.onGetValue = () => {
12427
- return dateString;
12700
+ return dateValue;
12428
12701
  };
12429
12702
 
12430
12703
  this.onSetValue = ( newValue, skipCallback, event ) => {
12431
12704
 
12432
- dateString = newValue;
12705
+ if( !dateAsRange )
12706
+ {
12707
+ this.calendar.fromDateString( newValue );
12708
+ }
12433
12709
 
12434
- this.calendar.fromDateString( newValue );
12710
+ dateValue = newValue;
12435
12711
 
12436
12712
  refresh( this.calendar.getFullDate() );
12437
12713
 
@@ -12446,26 +12722,80 @@ class DatePicker extends Widget {
12446
12722
  container.style.width = `calc( 100% - ${ realNameWidth })`;
12447
12723
  };
12448
12724
 
12449
- const container = document.createElement('div');
12450
- container.className = "lexdate";
12725
+ const container = LX.makeContainer( [ "auto", "auto" ], "lexdate flex flex-row" );
12451
12726
  this.root.appendChild( container );
12452
12727
 
12453
- this.calendar = new LX.Calendar( dateString, { onChange: ( date ) => {
12454
- this.set( `${ date.day }/${ date.month }/${ date.year }` );
12455
- }, ...options });
12728
+ if( !dateAsRange )
12729
+ {
12730
+ this.calendar = new LX.Calendar( dateValue, {
12731
+ onChange: ( date ) => {
12732
+ const newDateString = `${ date.day }/${ date.month }/${ date.year }`;
12733
+ this.set( newDateString );
12734
+ },
12735
+ ...options
12736
+ });
12737
+ }
12738
+ else
12739
+ {
12740
+ this.calendar = new LX.CalendarRange( dateValue, {
12741
+ onChange: ( dateRange ) => {
12742
+ this.set( dateRange );
12743
+ },
12744
+ ...options
12745
+ });
12746
+ }
12456
12747
 
12457
12748
  const refresh = ( currentDate ) => {
12749
+
12750
+ const emptyDate = !!currentDate;
12751
+
12458
12752
  container.innerHTML = "";
12753
+
12754
+ currentDate = currentDate ?? "Pick a date";
12755
+
12756
+ const dts = currentDate.split( " to " );
12757
+ const d0 = dateAsRange ? dts[ 0 ] : currentDate;
12758
+
12459
12759
  const calendarIcon = LX.makeIcon( "Calendar" );
12460
- const calendarButton = new LX.Button( null, currentDate ?? "Pick a date", () => {
12760
+ const calendarButton = new LX.Button( null, d0, () => {
12461
12761
  this._popover = new LX.Popover( calendarButton.root, [ this.calendar ] );
12462
- }, { buttonClass: `flex flex-row px-3 ${ currentDate ? "" : "fg-tertiary" } justify-between` } );
12463
-
12762
+ if( dateAsRange )
12763
+ {
12764
+ Object.assign( this._popover.root.style, { display: "flex", width: "auto" } );
12765
+ }
12766
+ }, { buttonClass: `flex flex-row px-3 ${ emptyDate ? "" : "fg-tertiary" } justify-between` } );
12464
12767
  calendarButton.root.querySelector( "button" ).appendChild( calendarIcon );
12768
+ calendarButton.root.style.width = "100%";
12465
12769
  container.appendChild( calendarButton.root );
12770
+
12771
+ if( dateAsRange )
12772
+ {
12773
+ const arrowRightIcon = LX.makeIcon( "ArrowRight" );
12774
+ LX.makeContainer( ["32px", "auto"], "content-center", arrowRightIcon.innerHTML, container );
12775
+
12776
+ const d1 = dts[ 1 ];
12777
+ const calendarIcon = LX.makeIcon( "Calendar" );
12778
+ const calendarButton = new LX.Button( null, d1, () => {
12779
+ this._popover = new LX.Popover( calendarButton.root, [ this.calendar ] );
12780
+ if( dateAsRange )
12781
+ {
12782
+ Object.assign( this._popover.root.style, { display: "flex", width: "auto" } );
12783
+ }
12784
+ }, { buttonClass: `flex flex-row px-3 ${ emptyDate ? "" : "fg-tertiary" } justify-between` } );
12785
+ calendarButton.root.querySelector( "button" ).appendChild( calendarIcon );
12786
+ calendarButton.root.style.width = "100%";
12787
+ container.appendChild( calendarButton.root );
12788
+ }
12466
12789
  };
12467
12790
 
12468
- refresh( dateString ? this.calendar.getFullDate(): null );
12791
+ if( dateValue )
12792
+ {
12793
+ refresh( this.calendar.getFullDate() );
12794
+ }
12795
+ else
12796
+ {
12797
+ refresh();
12798
+ }
12469
12799
 
12470
12800
  LX.doAsync( this.onResize.bind( this ) );
12471
12801
  }
@@ -12518,8 +12848,8 @@ class Map2D extends Widget {
12518
12848
  }
12519
12849
  }
12520
12850
 
12521
- LX.Map2D = Map2D;
12522
-
12851
+ LX.Map2D = Map2D;
12852
+
12523
12853
  // panel.js @jxarco
12524
12854
 
12525
12855
  /**
@@ -13131,6 +13461,7 @@ class Panel {
13131
13461
  * img: Path to image to show as button value
13132
13462
  * title: Text to show in native Element title
13133
13463
  * buttonClass: Class to add to the native button element
13464
+ * mustConfirm: User must confirm trigger in a popover
13134
13465
  */
13135
13466
 
13136
13467
  addButton( name, value, callback, options = {} ) {
@@ -13676,7 +14007,7 @@ class Panel {
13676
14007
  /**
13677
14008
  * @method addDate
13678
14009
  * @param {String} name Widget name
13679
- * @param {String} dateString
14010
+ * @param {String} dateValue
13680
14011
  * @param {Function} callback
13681
14012
  * @param {Object} options:
13682
14013
  * hideName: Don't use name as label [false]
@@ -13685,8 +14016,8 @@ class Panel {
13685
14016
  * fromToday: Allow dates only from current day
13686
14017
  */
13687
14018
 
13688
- addDate( name, dateString, callback, options = { } ) {
13689
- const widget = new LX.DatePicker( name, dateString, callback, options );
14019
+ addDate( name, dateValue, callback, options = { } ) {
14020
+ const widget = new LX.DatePicker( name, dateValue, callback, options );
13690
14021
  return this._attachWidget( widget );
13691
14022
  }
13692
14023
 
@@ -13704,8 +14035,8 @@ class Panel {
13704
14035
  }
13705
14036
  }
13706
14037
 
13707
- LX.Panel = Panel;
13708
-
14038
+ LX.Panel = Panel;
14039
+
13709
14040
  // branch.js @jxarco
13710
14041
 
13711
14042
  /**
@@ -13929,8 +14260,8 @@ class Branch {
13929
14260
  }
13930
14261
  }
13931
14262
  }
13932
- LX.Branch = Branch;
13933
-
14263
+ LX.Branch = Branch;
14264
+
13934
14265
  // menubar.js @jxarco
13935
14266
 
13936
14267
  /**
@@ -14244,8 +14575,8 @@ class Menubar {
14244
14575
  }
14245
14576
  }
14246
14577
  }
14247
- LX.Menubar = Menubar;
14248
-
14578
+ LX.Menubar = Menubar;
14579
+
14249
14580
  // sidebar.js @jxarco
14250
14581
 
14251
14582
  /**
@@ -14940,8 +15271,8 @@ class Sidebar {
14940
15271
  }
14941
15272
  }
14942
15273
  }
14943
- LX.Sidebar = Sidebar;
14944
-
15274
+ LX.Sidebar = Sidebar;
15275
+
14945
15276
  // asset_view.js @jxarco
14946
15277
 
14947
15278
  class AssetViewEvent {
@@ -15819,6 +16150,305 @@ class AssetView {
15819
16150
  }
15820
16151
  }
15821
16152
 
15822
- LX.AssetView = AssetView;
15823
-
15824
- export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Widget };
16153
+ LX.AssetView = AssetView;
16154
+
16155
+ // tour.js @jxarco
16156
+
16157
+ class Tour {
16158
+
16159
+ static ACTIVE_TOURS = [];
16160
+
16161
+ /**
16162
+ * @constructor Tour
16163
+ * @param {Array} steps
16164
+ * @param {Object} options
16165
+ * useModal: Use a modal to highlight the tour step [true]
16166
+ * offset: Horizontal and vertical margin offset [0]
16167
+ * horizontalOffset: Horizontal offset [0]
16168
+ * verticalOffset: Vertical offset [0]
16169
+ * radius: Radius for the tour step highlight [8]
16170
+ */
16171
+
16172
+ constructor( steps, options = {} ) {
16173
+
16174
+ this.steps = steps || [];
16175
+ this.currentStep = 0;
16176
+
16177
+ this.useModal = options.useModal ?? true;
16178
+ this.offset = options.offset ?? 8;
16179
+ this.horizontalOffset = options.horizontalOffset;
16180
+ this.verticalOffset = options.verticalOffset;
16181
+ this.radius = options.radius ?? 12;
16182
+
16183
+ this.tourContainer = document.querySelector( ".tour-container" );
16184
+ if( !this.tourContainer )
16185
+ {
16186
+ this.tourContainer = LX.makeContainer( ["100%", "100%"], "tour-container" );
16187
+ this.tourContainer.style.display = "none";
16188
+ document.body.appendChild( this.tourContainer );
16189
+
16190
+ window.addEventListener( "resize", () => {
16191
+
16192
+ for( const tour of Tour.ACTIVE_TOURS )
16193
+ {
16194
+ tour._showStep( 0 );
16195
+ }
16196
+ } );
16197
+ }
16198
+ }
16199
+
16200
+ /**
16201
+ * @method begin
16202
+ */
16203
+
16204
+ begin() {
16205
+
16206
+ this.currentStep = 0;
16207
+
16208
+ this.tourContainer.style.display = "block";
16209
+
16210
+ Tour.ACTIVE_TOURS.push( this );
16211
+
16212
+ this._showStep( 0 );
16213
+ }
16214
+
16215
+ /**
16216
+ * @method stop
16217
+ */
16218
+
16219
+ stop() {
16220
+
16221
+ if( this.useModal )
16222
+ {
16223
+ this.tourMask.remove();
16224
+ this.tourMask = undefined;
16225
+ }
16226
+
16227
+ this._popover?.destroy();
16228
+
16229
+ const index = Tour.ACTIVE_TOURS.indexOf( this );
16230
+ if( index !== -1 )
16231
+ {
16232
+ Tour.ACTIVE_TOURS.splice( index, 1 );
16233
+ }
16234
+
16235
+ this.tourContainer.innerHTML = "";
16236
+ this.tourContainer.style.display = "none";
16237
+ }
16238
+
16239
+ // Show the current step of the tour
16240
+ _showStep( stepOffset = 1 ) {
16241
+
16242
+ this.currentStep += stepOffset;
16243
+
16244
+ const step = this.steps[ this.currentStep ];
16245
+ if ( !step ) {
16246
+ this.stop();
16247
+ return;
16248
+ }
16249
+
16250
+ const prevStep = this.steps[ this.currentStep - 1 ];
16251
+ const nextStep = this.steps[ this.currentStep + 1 ];
16252
+
16253
+ if( this.useModal )
16254
+ {
16255
+ this._generateMask( step.reference );
16256
+ }
16257
+
16258
+ this._createHighlight( step, prevStep, nextStep );
16259
+ }
16260
+
16261
+ // Generate mask for the specific step reference
16262
+ // using a fullscreen SVG with "rect" elements
16263
+ _generateMask( reference ) {
16264
+
16265
+ this.tourContainer.innerHTML = ""; // Clear previous content
16266
+
16267
+ this.tourMask = LX.makeContainer( ["100%", "100%"], "tour-mask" );
16268
+ this.tourContainer.appendChild( this.tourMask );
16269
+
16270
+ const svg = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
16271
+ svg.style.width = "100%";
16272
+ svg.style.height = "100%";
16273
+ this.tourMask.appendChild( svg );
16274
+
16275
+ const clipPath = document.createElementNS( "http://www.w3.org/2000/svg", "clipPath" );
16276
+ clipPath.setAttribute( "id", "svgTourClipPath" );
16277
+ svg.appendChild( clipPath );
16278
+
16279
+ function ceilAndShiftRect( p, s ) {
16280
+ const cp = Math.ceil( p );
16281
+ const delta = cp - p;
16282
+ const ds = s - delta;
16283
+ return [ cp, ds ];
16284
+ }
16285
+
16286
+ const refBounding = reference.getBoundingClientRect();
16287
+ const [ boundingX, boundingWidth ] = ceilAndShiftRect( refBounding.x, refBounding.width );
16288
+ const [ boundingY, boundingHeight ] = ceilAndShiftRect( refBounding.y, refBounding.height );
16289
+
16290
+ const vOffset = this.verticalOffset ?? this.offset;
16291
+ const hOffset = this.horizontalOffset ?? this.offset;
16292
+
16293
+ // Left
16294
+ {
16295
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16296
+ rect.setAttribute( "x", 0 );
16297
+ rect.setAttribute( "y", 0 );
16298
+ rect.setAttribute( "width", Math.max( 0, boundingX - hOffset ) );
16299
+ rect.setAttribute( "height", window.innerHeight );
16300
+ rect.setAttribute( "stroke", "none" );
16301
+ clipPath.appendChild( rect );
16302
+ }
16303
+
16304
+ // Top
16305
+ {
16306
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16307
+ rect.setAttribute( "x", boundingX - hOffset );
16308
+ rect.setAttribute( "y", 0 );
16309
+ rect.setAttribute( "width", Math.max( 0, boundingWidth + hOffset * 2 ) );
16310
+ rect.setAttribute( "height", Math.max( 0, boundingY - vOffset ) );
16311
+ rect.setAttribute( "stroke", "none" );
16312
+ clipPath.appendChild( rect );
16313
+ }
16314
+
16315
+ // Bottom
16316
+ {
16317
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16318
+ rect.setAttribute( "x", boundingX - hOffset );
16319
+ rect.setAttribute( "y", boundingY + boundingHeight + vOffset );
16320
+ rect.setAttribute( "width", Math.max( 0, boundingWidth + hOffset * 2 ) );
16321
+ rect.setAttribute( "height", Math.max( 0, window.innerHeight - boundingY - boundingHeight - vOffset ) );
16322
+ rect.setAttribute( "stroke", "none" );
16323
+ clipPath.appendChild( rect );
16324
+ }
16325
+
16326
+ // Right
16327
+ {
16328
+ const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16329
+ rect.setAttribute( "x", boundingX + boundingWidth + hOffset );
16330
+ rect.setAttribute( "y", 0 );
16331
+ rect.setAttribute( "width", Math.max( 0, window.innerWidth - boundingX - boundingWidth ) );
16332
+ rect.setAttribute( "height", Math.max( 0, window.innerHeight ) );
16333
+ rect.setAttribute( "stroke", "none" );
16334
+ clipPath.appendChild( rect );
16335
+ }
16336
+
16337
+ // Reference Highlight
16338
+ const refContainer = LX.makeContainer( ["0", "0"], "tour-ref-mask" );
16339
+ refContainer.style.left = `${ boundingX - hOffset - 1 }px`;
16340
+ refContainer.style.top = `${ boundingY - vOffset - 1 }px`;
16341
+ refContainer.style.width = `${ boundingWidth + hOffset * 2 + 2 }px`;
16342
+ refContainer.style.height = `${ boundingHeight + vOffset * 2 + 2}px`;
16343
+ this.tourContainer.appendChild( refContainer );
16344
+
16345
+ const referenceMask = document.createElementNS( "http://www.w3.org/2000/svg", "mask" );
16346
+ referenceMask.setAttribute( "id", "svgTourReferenceMask" );
16347
+ svg.appendChild( referenceMask );
16348
+
16349
+ // Reference Mask
16350
+ {
16351
+ const rectWhite = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16352
+ rectWhite.setAttribute( "width", boundingWidth + hOffset * 2 + 2 );
16353
+ rectWhite.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
16354
+ rectWhite.setAttribute( "stroke", "none" );
16355
+ rectWhite.setAttribute( "fill", "white" );
16356
+ referenceMask.appendChild( rectWhite );
16357
+
16358
+ const rectBlack = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
16359
+ rectBlack.setAttribute( "rx", this.radius );
16360
+ rectBlack.setAttribute( "width", boundingWidth + hOffset * 2 + 2);
16361
+ rectBlack.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
16362
+ rectBlack.setAttribute( "stroke", "none" );
16363
+ rectBlack.setAttribute( "fill", "black" );
16364
+ referenceMask.appendChild( rectBlack );
16365
+ }
16366
+ }
16367
+
16368
+ // Create the container with the user hints
16369
+ _createHighlight( step, previousStep, nextStep ) {
16370
+
16371
+ const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
16372
+
16373
+ {
16374
+ const header = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
16375
+ LX.makeContainer( ["70%", "auto"], "p-2 font-medium", step.title, header );
16376
+ const closer = LX.makeContainer( ["30%", "auto"], "flex flex-row p-2 justify-end", "", header );
16377
+ const closeIcon = LX.makeIcon( "X" );
16378
+ closer.appendChild( closeIcon );
16379
+
16380
+ closeIcon.listen( "click", () => {
16381
+ this.stop();
16382
+ } );
16383
+ }
16384
+
16385
+ LX.makeContainer( ["100%", "auto"], "p-2 text-md", step.content, popoverContainer, { maxWidth: "400px" } );
16386
+ const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
16387
+
16388
+ {
16389
+ const footerSteps = LX.makeContainer( ["50%", "auto"], "p-2 gap-1 self-center flex flex-row text-md", "", footer );
16390
+ for( let i = 0; i < this.steps.length; i++ )
16391
+ {
16392
+ const stepIndicator = document.createElement( "span" );
16393
+ stepIndicator.className = "tour-step-indicator";
16394
+ if( i === this.currentStep )
16395
+ {
16396
+ stepIndicator.classList.add( "active" );
16397
+ }
16398
+ footerSteps.appendChild( stepIndicator );
16399
+ }
16400
+ }
16401
+
16402
+ const footerButtons = LX.makeContainer( ["50%", "auto"], "text-md", "", footer );
16403
+ const footerPanel = new LX.Panel();
16404
+
16405
+ let numButtons = 1;
16406
+
16407
+ if( previousStep )
16408
+ {
16409
+ numButtons++;
16410
+ }
16411
+
16412
+ if( numButtons > 1 )
16413
+ {
16414
+ footerPanel.sameLine( 2, "justify-end" );
16415
+ }
16416
+
16417
+ if( previousStep )
16418
+ {
16419
+ footerPanel.addButton( null, "Previous", () => {
16420
+ this._showStep( -1 );
16421
+ }, { buttonClass: "contrast" } );
16422
+ }
16423
+
16424
+ if( nextStep )
16425
+ {
16426
+ footerPanel.addButton( null, "Next", () => {
16427
+ this._showStep( 1 );
16428
+ }, { buttonClass: "accent" } );
16429
+ }
16430
+ else
16431
+ {
16432
+ footerPanel.addButton( null, "Finish", () => {
16433
+ this.stop();
16434
+ } );
16435
+ }
16436
+
16437
+ footerButtons.appendChild( footerPanel.root );
16438
+
16439
+ const sideOffset = ( step.side === "left" || step.side === "right" ? this.horizontalOffset : this.verticalOffset ) ?? this.offset;
16440
+ const alignOffset = ( step.align === "start" || step.align === "end" ? sideOffset : 0 );
16441
+
16442
+ this._popover?.destroy();
16443
+ this._popover = new LX.Popover( null, [ popoverContainer ], {
16444
+ reference: step.reference,
16445
+ side: step.side,
16446
+ align: step.align,
16447
+ sideOffset,
16448
+ alignOffset: step.align === "start" ? -alignOffset : alignOffset,
16449
+ } );
16450
+ }
16451
+ }
16452
+ LX.Tour = Tour;
16453
+
16454
+ export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Tour, Widget };