lisichatbot 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +213 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisichatbot",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -540,6 +540,8 @@ function renderOptions(options, field, isSingleSelect = true) {
540
540
  optionsWrapper.style.alignItems = 'flex-start';
541
541
  optionsWrapper.style.gap = '8px';
542
542
 
543
+ let hasPreselectedOptions = false; // ✅ Track if any options are pre-selected
544
+
543
545
  options.forEach((option, index) => {
544
546
  const optionName = option.name || option;
545
547
  const optionValue = option.value !== undefined ? option.value : option;
@@ -562,6 +564,7 @@ function renderOptions(options, field, isSingleSelect = true) {
562
564
  clone.classList.add('cf-checked');
563
565
  clone.style.backgroundColor = config.selectedBackground;
564
566
  console.log(` ✅ Pre-selected: ${optionName}`);
567
+ hasPreselectedOptions = true; // ✅ Mark that we have pre-selections
565
568
  } else {
566
569
  clone.classList.remove('cf-checked');
567
570
  clone.style.backgroundColor = 'transparent';
@@ -610,6 +613,31 @@ function renderOptions(options, field, isSingleSelect = true) {
610
613
  handleOptionClick(el, field, isSingleSelect);
611
614
  };
612
615
  });
616
+
617
+ // ✅ FIX: Enable Next button if options are pre-selected
618
+ if (hasPreselectedOptions) {
619
+ // Set currentSelection for pre-selected options
620
+ if (isSingleSelect) {
621
+ chatState.currentSelection = {
622
+ field,
623
+ value: existingData,
624
+ name: options.find(o => JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(existingData))?.name || existingData
625
+ };
626
+ } else {
627
+ const selectedNames = existingData.map(val => {
628
+ const opt = options.find(o => JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(val));
629
+ return opt ? (opt.name || opt) : val;
630
+ }).join(', ');
631
+ chatState.currentSelection = {
632
+ field,
633
+ value: existingData,
634
+ name: selectedNames
635
+ };
636
+ }
637
+
638
+ enableNextButton();
639
+ console.log(` ✅ Pre-selected options found - Next button enabled`);
640
+ }
613
641
  }
614
642
 
615
643
  // =============================================================================
@@ -637,6 +665,8 @@ function renderColorOptions(options, field) {
637
665
  optionsWrapper.style.alignItems = 'flex-start';
638
666
  optionsWrapper.style.gap = '8px';
639
667
 
668
+ let hasPreselectedOptions = false; // ✅ Track if any options are pre-selected
669
+
640
670
  options.forEach((option, index) => {
641
671
  const optionName = option.name || option;
642
672
  const optionValue = option.value !== undefined ? option.value : option;
@@ -654,6 +684,7 @@ function renderColorOptions(options, field) {
654
684
  clone.classList.add('cf-checked');
655
685
  clone.style.backgroundColor = config.selectedBackground;
656
686
  console.log(` ✅ Pre-selected color: ${optionName}`);
687
+ hasPreselectedOptions = true; // ✅ Mark that we have pre-selections
657
688
  } else {
658
689
  clone.classList.remove('cf-checked');
659
690
  clone.style.backgroundColor = 'transparent';
@@ -711,6 +742,24 @@ function renderColorOptions(options, field) {
711
742
  handleOptionClick(el, field, false);
712
743
  };
713
744
  });
745
+
746
+ // ✅ FIX: Enable Next button if options are pre-selected
747
+ if (hasPreselectedOptions) {
748
+ // Set currentSelection for pre-selected options
749
+ const selectedNames = existingData.map(val => {
750
+ const opt = options.find(o => JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(val));
751
+ return opt ? (opt.name || opt) : val;
752
+ }).join(', ');
753
+
754
+ chatState.currentSelection = {
755
+ field,
756
+ value: existingData,
757
+ name: selectedNames
758
+ };
759
+
760
+ enableNextButton();
761
+ console.log(` ✅ Pre-selected color options found - Next button enabled`);
762
+ }
714
763
  }
715
764
 
716
765
  // =============================================================================
@@ -738,6 +787,8 @@ function renderCustomSelectOptions(options, field, customConfig) {
738
787
  optionsWrapper.style.alignItems = 'flex-start';
739
788
  optionsWrapper.style.gap = '8px';
740
789
 
790
+ let hasPreselectedOption = false; // ✅ Track if any option is pre-selected
791
+
741
792
  options.forEach((option, index) => {
742
793
  const optionName = option.name || option;
743
794
  const optionValue = option.value !== undefined ? option.value : option;
@@ -755,6 +806,7 @@ function renderCustomSelectOptions(options, field, customConfig) {
755
806
  clone.classList.add('cf-checked');
756
807
  clone.style.backgroundColor = config.selectedBackground;
757
808
  console.log(` ✅ Pre-selected: ${optionName}`);
809
+ hasPreselectedOption = true; // ✅ Mark that we have a pre-selection
758
810
  } else {
759
811
  clone.classList.remove('cf-checked');
760
812
  clone.style.backgroundColor = 'transparent';
@@ -799,6 +851,7 @@ function renderCustomSelectOptions(options, field, customConfig) {
799
851
  customClone.classList.add('cf-checked');
800
852
  customClone.style.backgroundColor = config.selectedBackground;
801
853
  console.log(` ✅ Pre-selected: Custom Range [${existingData[0]}, ${existingData[1]}]`);
854
+ hasPreselectedOption = true; // ✅ Mark that custom is pre-selected
802
855
  } else {
803
856
  customClone.classList.remove('cf-checked');
804
857
  customClone.style.backgroundColor = 'transparent';
@@ -842,6 +895,35 @@ function renderCustomSelectOptions(options, field, customConfig) {
842
895
  handleCustomSelectClick(el, field, customConfig);
843
896
  };
844
897
  });
898
+
899
+ // ✅ FIX: Enable Next button if option is pre-selected
900
+ if (hasPreselectedOption) {
901
+ // Set currentSelection
902
+ const isCustomSelected = Array.isArray(existingData) && existingData.length === 2;
903
+
904
+ if (isCustomSelected) {
905
+ // Custom range selected - currentSelection will be set by validateMinMax
906
+ const validation = validateMinMax(field, customConfig);
907
+ if (validation.valid) {
908
+ enableNextButton();
909
+ console.log(` ✅ Pre-selected custom range is valid - Next button enabled`);
910
+ }
911
+ } else {
912
+ // Regular option selected
913
+ const selectedOption = options.find(o =>
914
+ JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(existingData)
915
+ );
916
+
917
+ chatState.currentSelection = {
918
+ field,
919
+ value: existingData,
920
+ name: selectedOption ? (selectedOption.name || selectedOption) : existingData
921
+ };
922
+
923
+ enableNextButton();
924
+ console.log(` ✅ Pre-selected option found - Next button enabled`);
925
+ }
926
+ }
845
927
  }
846
928
 
847
929
  function renderMinMaxInputs(field, customConfig, existingData) {
@@ -1012,7 +1094,52 @@ function handleCustomSelectClick(element, field, customConfig) {
1012
1094
 
1013
1095
  console.log(`Custom-select clicked:`, { field, name: optionName, isCustom });
1014
1096
 
1097
+ // ✅ FIX: Check if this option is already selected - allow deselection
1098
+ const isAlreadySelected = element.classList.contains('cf-checked');
1099
+
1015
1100
  const allOptions = document.querySelectorAll(`[data-field="${field}"][data-chat-element="single-select-input"]`);
1101
+
1102
+ if (isAlreadySelected) {
1103
+ // ✅ Deselect the currently selected option
1104
+ console.log(` 🔄 Deselecting "${optionName}"`);
1105
+
1106
+ element.classList.remove('cf-checked');
1107
+ element.style.setProperty('background-color', 'transparent', 'important');
1108
+ const tickIcon = element.querySelector('[data-chat-input-element="tick-icon"]');
1109
+ if (tickIcon) tickIcon.style.setProperty('display', 'none', 'important');
1110
+
1111
+ // Hide range wrapper if custom was deselected
1112
+ if (isCustom) {
1113
+ const rangeWrapper = document.querySelector(`[data-chat-element="range-wrapper"][data-field="${field}"]`);
1114
+ if (rangeWrapper) {
1115
+ rangeWrapper.style.display = 'none';
1116
+ }
1117
+ }
1118
+
1119
+ // Clear data
1120
+ delete chatState.data[field];
1121
+ chatState.currentSelection = null;
1122
+
1123
+ console.log(` ❌ Deselected "${optionName}" - No selection`);
1124
+
1125
+ // ✅ Check if input is required - disable button if nothing selected
1126
+ const currentStep = flowData.flow[chatState.step];
1127
+ const inputRequired = currentStep.inputRequired === true;
1128
+
1129
+ if (inputRequired) {
1130
+ disableNextButton();
1131
+ console.log(' 🔒 Input required - Next button disabled');
1132
+ } else {
1133
+ enableNextButton();
1134
+ console.log(' 🔓 Input not required - Next button still enabled');
1135
+ }
1136
+
1137
+ return; // Exit early
1138
+ }
1139
+
1140
+ // ✅ Select this option (deselect others first)
1141
+ console.log(` ✅ Selecting "${optionName}"`);
1142
+
1016
1143
  allOptions.forEach(opt => {
1017
1144
  opt.classList.remove('cf-checked');
1018
1145
  opt.style.setProperty('background-color', 'transparent', 'important');
@@ -1460,27 +1587,63 @@ function handleOptionClick(element, field, isSingleSelect) {
1460
1587
  }
1461
1588
 
1462
1589
  if (isSingleSelect) {
1590
+ // ✅ FIX: Check if this option is already selected - allow deselection
1591
+ const isAlreadySelected = element.classList.contains('cf-checked');
1592
+
1463
1593
  const selector = `[data-field="${field}"][data-chat-element="${inputType}"]`;
1464
1594
  const allOptions = document.querySelectorAll(selector);
1465
1595
 
1466
- allOptions.forEach(opt => {
1467
- opt.classList.remove('cf-checked');
1468
- opt.style.setProperty('background-color', 'transparent', 'important');
1596
+ if (isAlreadySelected) {
1597
+ // ✅ Deselect the currently selected option
1598
+ console.log(` 🔄 Deselecting "${optionName}"`);
1469
1599
 
1470
- const otherTick = opt.querySelector('[data-chat-input-element="tick-icon"]');
1471
- const otherInput = opt.querySelector('[data-chat-input-element="input"]');
1600
+ element.classList.remove('cf-checked');
1601
+ element.style.setProperty('background-color', 'transparent', 'important');
1602
+ if (tickIcon) tickIcon.style.setProperty('display', 'none', 'important');
1603
+ if (input) input.checked = false;
1472
1604
 
1473
- if (otherTick) otherTick.style.setProperty('display', 'none', 'important');
1474
- if (otherInput) otherInput.checked = false;
1475
- });
1605
+ // Clear data
1606
+ delete chatState.data[field];
1607
+ chatState.currentSelection = null;
1608
+
1609
+ console.log(` ❌ Deselected "${optionName}" - No selection`);
1610
+
1611
+ // ✅ Check if input is required - disable button if nothing selected
1612
+ const currentStep = flowData.flow[chatState.step];
1613
+ const inputRequired = currentStep.inputRequired === true;
1614
+
1615
+ if (inputRequired) {
1616
+ disableNextButton();
1617
+ console.log(' 🔒 Input required - Next button disabled');
1618
+ } else {
1619
+ enableNextButton();
1620
+ console.log(' 🔓 Input not required - Next button still enabled');
1621
+ }
1622
+ } else {
1623
+ // ✅ Select this option (deselect others first)
1624
+ console.log(` ✅ Selecting "${optionName}"`);
1625
+
1626
+ allOptions.forEach(opt => {
1627
+ opt.classList.remove('cf-checked');
1628
+ opt.style.setProperty('background-color', 'transparent', 'important');
1629
+
1630
+ const otherTick = opt.querySelector('[data-chat-input-element="tick-icon"]');
1631
+ const otherInput = opt.querySelector('[data-chat-input-element="input"]');
1632
+
1633
+ if (otherTick) otherTick.style.setProperty('display', 'none', 'important');
1634
+ if (otherInput) otherInput.checked = false;
1635
+ });
1476
1636
 
1477
- element.classList.add('cf-checked');
1478
- element.style.setProperty('background-color', config.selectedBackground, 'important');
1479
- if (tickIcon) tickIcon.style.setProperty('display', 'block', 'important');
1480
- if (input) input.checked = true;
1637
+ element.classList.add('cf-checked');
1638
+ element.style.setProperty('background-color', config.selectedBackground, 'important');
1639
+ if (tickIcon) tickIcon.style.setProperty('display', 'block', 'important');
1640
+ if (input) input.checked = true;
1481
1641
 
1482
- chatState.data[field] = value;
1483
- chatState.currentSelection = { field, value, name: optionName };
1642
+ chatState.data[field] = value;
1643
+ chatState.currentSelection = { field, value, name: optionName };
1644
+
1645
+ enableNextButton();
1646
+ }
1484
1647
 
1485
1648
  } else {
1486
1649
  const isChecked = !element.classList.contains('cf-checked');
@@ -1764,9 +1927,19 @@ async function showNextStep() {
1764
1927
  } else if (inputType === 'multi-select-color') {
1765
1928
  renderColorOptions(nextStep.input.options, nextStep.input.field);
1766
1929
 
1767
- if (!inputRequired) {
1930
+ // ✅ Check if pre-filled - renderColorOptions handles enabling if pre-filled
1931
+ // Only disable if NOT pre-filled and required
1932
+ const existingData = chatState.data[nextStep.input.field];
1933
+ const hasPreFill = Array.isArray(existingData) && existingData.length > 0;
1934
+
1935
+ if (inputRequired && !hasPreFill) {
1936
+ disableNextButton();
1937
+ console.log(' 🔒 Multi-select-color required with no pre-fill - Next button disabled');
1938
+ } else if (!inputRequired && !hasPreFill) {
1768
1939
  enableNextButton();
1940
+ console.log(' 🔓 Multi-select-color not required - Next button enabled');
1769
1941
  }
1942
+ // If hasPreFill, renderColorOptions already handled it
1770
1943
  } else if (inputType === 'single-select-custom') {
1771
1944
  renderCustomSelectOptions(
1772
1945
  nextStep.input.options,
@@ -1774,11 +1947,18 @@ async function showNextStep() {
1774
1947
  nextStep.input.custom
1775
1948
  );
1776
1949
 
1777
- if (inputRequired) {
1950
+ // ✅ Check if pre-filled - renderCustomSelectOptions handles enabling if pre-filled
1951
+ const existingData = chatState.data[nextStep.input.field];
1952
+ const hasPreFill = existingData !== undefined && existingData !== null;
1953
+
1954
+ if (inputRequired && !hasPreFill) {
1778
1955
  disableNextButton();
1779
- } else {
1956
+ console.log(' 🔒 Single-select-custom required with no pre-fill - Next button disabled');
1957
+ } else if (!inputRequired && !hasPreFill) {
1780
1958
  enableNextButton();
1959
+ console.log(' 🔓 Single-select-custom not required - Next button enabled');
1781
1960
  }
1961
+ // If hasPreFill, renderCustomSelectOptions already handled it
1782
1962
  } else if (inputType === 'multi-select-dropdown') {
1783
1963
  // ✅ Render multi-select dropdown
1784
1964
  renderMultiSelectDropdown(nextStep.input.options, nextStep.input.field);
@@ -1795,9 +1975,24 @@ async function showNextStep() {
1795
1975
  const isSingleSelect = inputType === 'single-select';
1796
1976
  renderOptions(nextStep.input.options, nextStep.input.field, isSingleSelect);
1797
1977
 
1798
- if (!inputRequired) {
1978
+ // ✅ Check if pre-filled - renderOptions handles enabling if pre-filled
1979
+ const existingData = chatState.data[nextStep.input.field];
1980
+ let hasPreFill = false;
1981
+
1982
+ if (isSingleSelect) {
1983
+ hasPreFill = existingData !== undefined && existingData !== null;
1984
+ } else {
1985
+ hasPreFill = Array.isArray(existingData) && existingData.length > 0;
1986
+ }
1987
+
1988
+ if (inputRequired && !hasPreFill) {
1989
+ disableNextButton();
1990
+ console.log(` 🔒 ${inputType} required with no pre-fill - Next button disabled`);
1991
+ } else if (!inputRequired && !hasPreFill) {
1799
1992
  enableNextButton();
1993
+ console.log(` 🔓 ${inputType} not required - Next button enabled`);
1800
1994
  }
1995
+ // If hasPreFill, renderOptions already handled it
1801
1996
  }
1802
1997
  } else {
1803
1998
  const delay = nextStep.autoAdvanceDelay !== undefined ? nextStep.autoAdvanceDelay : config.autoAdvanceDelay;