lisichatbot 1.2.5 → 1.2.6

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 +170 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisichatbot",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -145,7 +145,7 @@ function addMessage(content, type = 'bot', hasInput = false, stepNumber = null)
145
145
  console.log(` Calling editStep(${stepNumber})...`);
146
146
  editStep(stepNumber);
147
147
  };
148
- editIcon.style.setProperty('display', 'block', 'important');
148
+ editIcon.style.setProperty('display', 'flex', 'important');
149
149
  editIcon.style.setProperty('margin-left', '8px', 'important');
150
150
  editIcon.style.setProperty('cursor', 'pointer', 'important');
151
151
  console.log(` ✏️ Edit icon SHOWN (step ${stepNumber} is latest previous step with input)`);
@@ -184,7 +184,7 @@ function addMessage(content, type = 'bot', hasInput = false, stepNumber = null)
184
184
 
185
185
  // Only show if has input AND it's a previous step AND it's latest instance
186
186
  if (hasInput && stepNumber !== null && stepNumber < chatState.step && isLatest) {
187
- editIconAfterAppend.style.setProperty('display', 'block', 'important');
187
+ editIconAfterAppend.style.setProperty('display', 'flex', 'important');
188
188
 
189
189
  // Debug: Check spacing
190
190
  setTimeout(() => {
@@ -238,7 +238,7 @@ function updateEditIcons() {
238
238
  editStep(stepNumber);
239
239
  };
240
240
  editIcon.setAttribute('data-chat-step', stepNumber);
241
- editIcon.style.setProperty('display', 'block', 'important');
241
+ editIcon.style.setProperty('display', 'flex', 'important');
242
242
  editIcon.style.setProperty('cursor', 'pointer', 'important');
243
243
  editIcon.style.setProperty('margin-left', '8px', 'important');
244
244
  console.log(` ✏️ Step ${stepNumber}: Icon SHOWN (latest previous step)`);
@@ -648,6 +648,7 @@ function renderMinMaxInputs(field, customConfig, existingData) {
648
648
  const rangeWrapper = document.createElement('div');
649
649
  rangeWrapper.setAttribute('data-chat-element', 'range-wrapper');
650
650
  rangeWrapper.setAttribute('data-field', field);
651
+ rangeWrapper.style.marginBottom = '16px'; // Add space below wrapper
651
652
 
652
653
  // Check if should show min/max (custom option selected)
653
654
  // Data is stored as array [min, max]
@@ -660,6 +661,7 @@ function renderMinMaxInputs(field, customConfig, existingData) {
660
661
  // Clone and setup min input
661
662
  const minClone = minTemplate.cloneNode(true);
662
663
  minClone.style.display = '';
664
+ minClone.style.marginRight = '12px'; // Add space between inputs
663
665
  minClone.setAttribute('data-field', field);
664
666
 
665
667
  const minInput = minClone.querySelector('[data-chat-input-element="input"]');
@@ -712,14 +714,48 @@ function renderMinMaxInputs(field, customConfig, existingData) {
712
714
 
713
715
  elements.messages.appendChild(rangeWrapper);
714
716
 
715
- // Add focus handlers to select custom option when editing
716
- if (minInput) {
717
- minInput.onfocus = () => selectCustomOption(field);
718
- minInput.oninput = () => validateMinMax(field, customConfig);
719
- }
720
- if (maxInput) {
721
- maxInput.onfocus = () => selectCustomOption(field);
722
- maxInput.oninput = () => validateMinMax(field, customConfig);
717
+ // Add handlers for both inputs
718
+ if (minInput && maxInput) {
719
+ const updateVisualFeedback = () => {
720
+ const minFilled = minInput.value.trim() !== '';
721
+ const maxFilled = maxInput.value.trim() !== '';
722
+ const anyFilled = minFilled || maxFilled;
723
+
724
+ // Get tick icons
725
+ const minTick = minClone.querySelector('[data-chat-input-element="tick-icon"]');
726
+ const maxTick = maxClone.querySelector('[data-chat-input-element="tick-icon"]');
727
+
728
+ // Update background and tick for BOTH inputs
729
+ if (anyFilled) {
730
+ minClone.style.backgroundColor = config.selectedBackground;
731
+ maxClone.style.backgroundColor = config.selectedBackground;
732
+ if (minTick) minTick.style.display = 'block';
733
+ if (maxTick) maxTick.style.display = 'block';
734
+ } else {
735
+ minClone.style.backgroundColor = 'transparent';
736
+ maxClone.style.backgroundColor = 'transparent';
737
+ if (minTick) minTick.style.display = 'none';
738
+ if (maxTick) maxTick.style.display = 'none';
739
+ }
740
+ };
741
+
742
+ minInput.onfocus = () => {
743
+ selectCustomOption(field);
744
+ updateVisualFeedback();
745
+ };
746
+ minInput.oninput = () => {
747
+ updateVisualFeedback();
748
+ validateMinMax(field, customConfig);
749
+ };
750
+
751
+ maxInput.onfocus = () => {
752
+ selectCustomOption(field);
753
+ updateVisualFeedback();
754
+ };
755
+ maxInput.oninput = () => {
756
+ updateVisualFeedback();
757
+ validateMinMax(field, customConfig);
758
+ };
723
759
  }
724
760
  }
725
761
 
@@ -783,10 +819,39 @@ function handleCustomSelectClick(element, field, customConfig) {
783
819
  chatState.currentSelection = null;
784
820
  console.log(' ℹ️ Custom selected - waiting for min/max input');
785
821
  } else {
786
- // Hide min/max inputs
822
+ // Hide min/max inputs and clear them
787
823
  const rangeWrapper = document.querySelector(`[data-chat-element="range-wrapper"][data-field="${field}"]`);
788
824
  if (rangeWrapper) {
789
825
  rangeWrapper.style.display = 'none';
826
+
827
+ // Clear input values
828
+ const minInput = rangeWrapper.querySelector('[data-input-type="min"] [data-chat-input-element="input"]');
829
+ const maxInput = rangeWrapper.querySelector('[data-input-type="max"] [data-chat-input-element="input"]');
830
+
831
+ if (minInput) minInput.value = '';
832
+ if (maxInput) maxInput.value = '';
833
+
834
+ // Reset visual feedback (background and ticks)
835
+ const minContainer = rangeWrapper.querySelector('[data-chat-element="single-select-custom-min"]');
836
+ const maxContainer = rangeWrapper.querySelector('[data-chat-element="single-select-custom-max"]');
837
+
838
+ if (minContainer) {
839
+ minContainer.style.backgroundColor = 'transparent';
840
+ const minTick = minContainer.querySelector('[data-chat-input-element="tick-icon"]');
841
+ if (minTick) minTick.style.display = 'none';
842
+ }
843
+
844
+ if (maxContainer) {
845
+ maxContainer.style.backgroundColor = 'transparent';
846
+ const maxTick = maxContainer.querySelector('[data-chat-input-element="tick-icon"]');
847
+ if (maxTick) maxTick.style.display = 'none';
848
+ }
849
+
850
+ // Hide error message
851
+ const errorDiv = rangeWrapper.querySelector('[data-chat-element="range-error"]');
852
+ if (errorDiv) errorDiv.style.display = 'none';
853
+
854
+ console.log(' 🧹 Min/max inputs cleared and hidden');
790
855
  }
791
856
 
792
857
  // Parse and save regular value
@@ -809,7 +874,7 @@ function validateMinMax(field, customConfig) {
809
874
  const maxInput = document.querySelector(`[data-field="${field}"][data-input-type="max"] [data-chat-input-element="input"]`);
810
875
  const errorDiv = document.querySelector(`[data-chat-element="range-error"][data-field="${field}"]`);
811
876
 
812
- if (!minInput || !maxInput) return false;
877
+ if (!minInput || !maxInput) return { valid: false, error: null };
813
878
 
814
879
  const minValue = parseFloat(minInput.value);
815
880
  const maxValue = parseFloat(maxInput.value);
@@ -819,66 +884,85 @@ function validateMinMax(field, customConfig) {
819
884
  const minConstraint = customConfig.min !== undefined ? customConfig.min : 0;
820
885
  const maxConstraint = customConfig.max !== undefined ? customConfig.max : 100;
821
886
 
822
- // Helper to show error
823
- const showError = (message) => {
887
+ // Helper to show error in div
888
+ const showErrorDiv = (message) => {
824
889
  if (errorDiv) {
825
890
  errorDiv.textContent = message;
826
891
  errorDiv.style.display = 'block';
827
892
  }
828
- console.log(' ❌ Validation error:', message);
829
- disableNextButton();
830
- return false;
831
893
  };
832
894
 
833
- // Helper to hide error
834
- const hideError = () => {
895
+ // Helper to hide error div
896
+ const hideErrorDiv = () => {
835
897
  if (errorDiv) {
836
898
  errorDiv.style.display = 'none';
837
899
  }
838
900
  };
839
901
 
840
- // Validation rules
902
+ // Validation rules - return error message if invalid
841
903
 
842
904
  // 1. Check if only one is filled
843
905
  if (minFilled && !maxFilled) {
844
- return showError(config.customRangeErrors.maxRequired);
906
+ const error = config.customRangeErrors.maxRequired;
907
+ showErrorDiv(error);
908
+ console.log(' ❌ Validation error:', error);
909
+ disableNextButton();
910
+ return { valid: false, error };
845
911
  }
846
912
 
847
913
  if (!minFilled && maxFilled) {
848
- return showError(config.customRangeErrors.minRequired);
914
+ const error = config.customRangeErrors.minRequired;
915
+ showErrorDiv(error);
916
+ console.log(' ❌ Validation error:', error);
917
+ disableNextButton();
918
+ return { valid: false, error };
849
919
  }
850
920
 
851
921
  // 2. Check if both are empty
852
922
  if (!minFilled && !maxFilled) {
853
- hideError();
923
+ hideErrorDiv();
854
924
  disableNextButton();
855
- return false;
925
+ return { valid: false, error: null };
856
926
  }
857
927
 
858
928
  // 3. Check if values are valid numbers
859
929
  if (isNaN(minValue) || isNaN(maxValue)) {
860
- return showError(config.customRangeErrors.bothRequired);
930
+ const error = config.customRangeErrors.bothRequired;
931
+ showErrorDiv(error);
932
+ console.log(' ❌ Validation error:', error);
933
+ disableNextButton();
934
+ return { valid: false, error };
861
935
  }
862
936
 
863
937
  // 4. Check min constraint
864
938
  if (minValue < minConstraint) {
865
- const msg = config.customRangeErrors.minBelowConstraint.replace('{min}', minConstraint);
866
- return showError(msg);
939
+ const error = config.customRangeErrors.minBelowConstraint.replace('{min}', minConstraint);
940
+ showErrorDiv(error);
941
+ console.log(' ❌ Validation error:', error);
942
+ disableNextButton();
943
+ return { valid: false, error };
867
944
  }
868
945
 
869
946
  // 5. Check max constraint
870
947
  if (maxValue > maxConstraint) {
871
- const msg = config.customRangeErrors.maxAboveConstraint.replace('{max}', maxConstraint);
872
- return showError(msg);
948
+ const error = config.customRangeErrors.maxAboveConstraint.replace('{max}', maxConstraint);
949
+ showErrorDiv(error);
950
+ console.log(' ❌ Validation error:', error);
951
+ disableNextButton();
952
+ return { valid: false, error };
873
953
  }
874
954
 
875
955
  // 6. Check min < max
876
956
  if (minValue >= maxValue) {
877
- return showError(config.customRangeErrors.minGreaterThanMax);
957
+ const error = config.customRangeErrors.minGreaterThanMax;
958
+ showErrorDiv(error);
959
+ console.log(' ❌ Validation error:', error);
960
+ disableNextButton();
961
+ return { valid: false, error };
878
962
  }
879
963
 
880
964
  // All valid! Hide error and save data as array
881
- hideError();
965
+ hideErrorDiv();
882
966
 
883
967
  // Store as array [min, max]
884
968
  chatState.data[field] = [minValue, maxValue];
@@ -890,7 +974,7 @@ function validateMinMax(field, customConfig) {
890
974
 
891
975
  console.log(' ✅ Range valid - stored as array:', [minValue, maxValue]);
892
976
  enableNextButton();
893
- return true;
977
+ return { valid: true, error: null };
894
978
  }
895
979
 
896
980
  // =============================================================================
@@ -1106,6 +1190,45 @@ async function handleNext() {
1106
1190
  return;
1107
1191
  }
1108
1192
 
1193
+ // VALIDATION: Check for single-select-custom validation before proceeding
1194
+ if (currentStep.inputType === 'single-select-custom' && currentStep.input) {
1195
+ const field = currentStep.input.field;
1196
+ const customConfig = currentStep.input.custom;
1197
+
1198
+ // Check if custom range was selected (data is array)
1199
+ const selectedValue = chatState.data[field];
1200
+ const isCustomRange = Array.isArray(selectedValue);
1201
+
1202
+ if (isCustomRange && customConfig) {
1203
+ // Validate the custom range
1204
+ const validation = validateMinMax(field, customConfig);
1205
+
1206
+ if (!validation.valid && validation.error) {
1207
+ // Show error as bot message
1208
+ console.log(' ⚠️ Validation failed, showing error message');
1209
+
1210
+ // Hide current inputs (options and range wrapper)
1211
+ const optionsWrapper = document.querySelector('[data-chat-element="options-wrapper"]');
1212
+ if (optionsWrapper) {
1213
+ optionsWrapper.style.display = 'none';
1214
+ }
1215
+
1216
+ const rangeWrapper = document.querySelector(`[data-chat-element="range-wrapper"][data-field="${field}"]`);
1217
+ if (rangeWrapper) {
1218
+ rangeWrapper.style.display = 'none';
1219
+ }
1220
+
1221
+ // Add error message as bot message
1222
+ addMessage(validation.error, 'bot', false, null);
1223
+
1224
+ // Re-display the same step with fresh inputs
1225
+ await showNextStep();
1226
+
1227
+ return; // Stop here, don't proceed
1228
+ }
1229
+ }
1230
+ }
1231
+
1109
1232
  // Call onNext validation if exists
1110
1233
  if (currentStep.onNext) {
1111
1234
  try {
@@ -1155,6 +1278,13 @@ async function handleNext() {
1155
1278
  chatState.step = targetStep;
1156
1279
  console.log(` ✅ Jumped to step ${targetStep}`);
1157
1280
 
1281
+ // Hide all range-wrappers
1282
+ const allRangeWrappers = document.querySelectorAll('[data-chat-element="range-wrapper"]');
1283
+ allRangeWrappers.forEach(wrapper => {
1284
+ wrapper.style.display = 'none';
1285
+ });
1286
+ console.log(' 🙈 Hidden all range-wrappers');
1287
+
1158
1288
  // Update edit icons for the new position
1159
1289
  updateEditIcons();
1160
1290
 
@@ -1169,6 +1299,13 @@ async function handleNext() {
1169
1299
  // Normal flow: Move to next step
1170
1300
  chatState.step++;
1171
1301
 
1302
+ // Hide all range-wrappers (custom min/max inputs)
1303
+ const allRangeWrappers = document.querySelectorAll('[data-chat-element="range-wrapper"]');
1304
+ allRangeWrappers.forEach(wrapper => {
1305
+ wrapper.style.display = 'none';
1306
+ });
1307
+ console.log(' 🙈 Hidden all range-wrappers');
1308
+
1172
1309
  // Update edit icons for all previous steps
1173
1310
  updateEditIcons();
1174
1311