lisichatbot 1.2.9 β†’ 1.3.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +195 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisichatbot",
3
- "version": "1.2.9",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -656,6 +656,13 @@ function renderMinMaxInputs(field, customConfig, existingData) {
656
656
  return;
657
657
  }
658
658
 
659
+ // Remove existing rangeWrapper if it exists (for edit flow)
660
+ const existingRangeWrapper = elements.messages.querySelector(`[data-chat-element="range-wrapper"][data-field="${field}"]`);
661
+ if (existingRangeWrapper) {
662
+ console.log(' πŸ—‘οΈ Removing existing rangeWrapper for re-render');
663
+ existingRangeWrapper.remove();
664
+ }
665
+
659
666
  // Create wrapper for min/max
660
667
  const rangeWrapper = document.createElement('div');
661
668
  rangeWrapper.setAttribute('data-chat-element', 'range-wrapper');
@@ -690,7 +697,7 @@ function renderMinMaxInputs(field, customConfig, existingData) {
690
697
  minInput.min = customConfig.min !== undefined ? customConfig.min : 0;
691
698
  minInput.max = customConfig.max !== undefined ? customConfig.max : 100;
692
699
  minInput.value = showMinMax && existingData[0] !== undefined ? existingData[0] : '';
693
- minInput.placeholder = `Min (${minInput.min}+)`;
700
+ // Removed placeholder
694
701
 
695
702
  if (showMinMax) {
696
703
  console.log(` βœ… Pre-filled min: ${existingData[0]}`);
@@ -713,7 +720,7 @@ function renderMinMaxInputs(field, customConfig, existingData) {
713
720
  maxInput.min = customConfig.min !== undefined ? customConfig.min : 0;
714
721
  maxInput.max = customConfig.max !== undefined ? customConfig.max : 100;
715
722
  maxInput.value = showMinMax && existingData[1] !== undefined ? existingData[1] : '';
716
- maxInput.placeholder = `Max (${maxInput.max} max)`;
723
+ // Removed placeholder
717
724
 
718
725
  if (showMinMax) {
719
726
  console.log(` βœ… Pre-filled max: ${existingData[1]}`);
@@ -760,6 +767,14 @@ function renderMinMaxInputs(field, customConfig, existingData) {
760
767
  }
761
768
  };
762
769
 
770
+ // Apply visual feedback immediately if pre-filled
771
+ if (showMinMax) {
772
+ updateVisualFeedback();
773
+ // Also run validation to set currentSelection
774
+ validateMinMax(field, customConfig);
775
+ console.log(' βœ… Applied visual feedback for pre-filled values');
776
+ }
777
+
763
778
  minInput.onfocus = () => {
764
779
  selectCustomOption(field);
765
780
  updateVisualFeedback();
@@ -832,8 +847,16 @@ function handleCustomSelectClick(element, field, customConfig) {
832
847
  if (isCustom) {
833
848
  // Show min/max inputs
834
849
  const rangeWrapper = document.querySelector(`[data-chat-element="range-wrapper"][data-field="${field}"]`);
850
+ console.log(' πŸ“¦ Looking for rangeWrapper:', `[data-chat-element="range-wrapper"][data-field="${field}"]`);
851
+ console.log(' πŸ“¦ Found rangeWrapper:', rangeWrapper);
852
+
835
853
  if (rangeWrapper) {
854
+ console.log(' πŸ“¦ Current display:', rangeWrapper.style.display);
836
855
  rangeWrapper.style.display = 'flex'; // Keep flex!
856
+ console.log(' βœ… Set rangeWrapper display to flex');
857
+ console.log(' πŸ“¦ New display:', rangeWrapper.style.display);
858
+ } else {
859
+ console.log(' ❌ rangeWrapper not found!');
837
860
  }
838
861
 
839
862
  // Don't save data yet - wait for validation
@@ -845,12 +868,18 @@ function handleCustomSelectClick(element, field, customConfig) {
845
868
  if (rangeWrapper) {
846
869
  rangeWrapper.style.display = 'none';
847
870
 
848
- // Clear input values
849
- const minInput = rangeWrapper.querySelector('[data-input-type="min"] [data-chat-input-element="input"]');
850
- const maxInput = rangeWrapper.querySelector('[data-input-type="max"] [data-chat-input-element="input"]');
871
+ // Clear input values - fixed selectors
872
+ const minInput = document.querySelector(`[data-field="${field}"][data-input-type="min"][data-chat-input-element="input"]`);
873
+ const maxInput = document.querySelector(`[data-field="${field}"][data-input-type="max"][data-chat-input-element="input"]`);
851
874
 
852
- if (minInput) minInput.value = '';
853
- if (maxInput) maxInput.value = '';
875
+ if (minInput) {
876
+ minInput.value = '';
877
+ console.log(' 🧹 Cleared min input');
878
+ }
879
+ if (maxInput) {
880
+ maxInput.value = '';
881
+ console.log(' 🧹 Cleared max input');
882
+ }
854
883
 
855
884
  // Reset visual feedback (background and ticks)
856
885
  const minContainer = rangeWrapper.querySelector('[data-chat-element="single-select-custom-min"]');
@@ -1019,15 +1048,35 @@ function validateMinMax(field, customConfig) {
1019
1048
 
1020
1049
  // Store as array [min, max]
1021
1050
  chatState.data[field] = [minValue, maxValue];
1051
+
1052
+ // Get the current step's input config for formatting
1053
+ const currentStep = flowData.flow[chatState.step];
1054
+ const inputConfig = currentStep?.input || {};
1055
+ const valueType = inputConfig.selectedInputValueType;
1056
+ const prefix = inputConfig.selectedInputPrefix || '';
1057
+ const suffix = inputConfig.selectedInputSuffix || '';
1058
+
1059
+ // Format display name
1060
+ let displayName = `${minValue}-${maxValue}`;
1061
+ if (valueType === 'arrayRange') {
1062
+ const formattedMin = minValue.toLocaleString();
1063
+ const formattedMax = maxValue.toLocaleString();
1064
+ displayName = `${formattedMin} - ${formattedMax}`;
1065
+ }
1066
+
1067
+ // Add prefix and suffix with spaces
1068
+ if (prefix) displayName = `${prefix} ${displayName}`;
1069
+ if (suffix) displayName = `${displayName} ${suffix}`;
1070
+
1022
1071
  chatState.currentSelection = {
1023
1072
  field,
1024
1073
  value: [minValue, maxValue],
1025
- name: `${minValue}-${maxValue}`
1074
+ name: displayName
1026
1075
  };
1027
1076
 
1028
1077
  console.log(`βœ…βœ…βœ… ALL VALIDATION PASSED!`);
1029
1078
  console.log(`πŸ’Ύ Data saved: chatState.data.${field} = [${minValue}, ${maxValue}]`);
1030
- console.log(`πŸ’Ύ Current selection: ${minValue}-${maxValue}`);
1079
+ console.log(`πŸ’Ύ Display name: "${displayName}"`);
1031
1080
  console.log(`🟒 Next button: ENABLED\n`);
1032
1081
 
1033
1082
  enableNextButton();
@@ -1038,7 +1087,7 @@ function validateMinMax(field, customConfig) {
1038
1087
  // TEXT/NUMBER INPUT RENDERING
1039
1088
  // =============================================================================
1040
1089
 
1041
- function renderTextInput(field, inputType = 'text') {
1090
+ function renderTextInput(field, inputType = 'text', inputConfig = {}) {
1042
1091
  if (!elements.messages) return;
1043
1092
 
1044
1093
  // Determine input type attribute value
@@ -1056,6 +1105,17 @@ function renderTextInput(field, inputType = 'text') {
1056
1105
  // Get existing data for this field (for pre-filling when editing)
1057
1106
  const existingValue = chatState.data[field];
1058
1107
  console.log(`πŸ“ Pre-filling ${field}:`, existingValue);
1108
+
1109
+ // Check if validation should be applied (only if input has min/max defined)
1110
+ const hasValidation = inputType === 'number' &&
1111
+ (inputConfig.min !== undefined || inputConfig.max !== undefined);
1112
+
1113
+ if (hasValidation) {
1114
+ console.log(` πŸ” Validation enabled for ${field}:`, {
1115
+ min: inputConfig.min,
1116
+ max: inputConfig.max
1117
+ });
1118
+ }
1059
1119
 
1060
1120
  // Clone existing input element
1061
1121
  const clone = existingInput.cloneNode(true);
@@ -1072,17 +1132,46 @@ function renderTextInput(field, inputType = 'text') {
1072
1132
  inputElement.setAttribute('data-field', field);
1073
1133
  inputElement.name = field;
1074
1134
 
1135
+ // Set min/max attributes if validation enabled
1136
+ if (hasValidation) {
1137
+ if (inputConfig.min !== undefined) {
1138
+ inputElement.min = inputConfig.min;
1139
+ }
1140
+ if (inputConfig.max !== undefined) {
1141
+ inputElement.max = inputConfig.max;
1142
+ }
1143
+ }
1144
+
1075
1145
  // Pre-fill value if it exists
1076
1146
  if (existingValue !== undefined && existingValue !== null) {
1077
1147
  inputElement.value = existingValue;
1078
1148
  console.log(` βœ… Pre-filled with: ${existingValue}`);
1149
+
1150
+ // If validation enabled, validate the pre-filled value
1151
+ if (hasValidation) {
1152
+ const value = parseFloat(existingValue);
1153
+ const min = inputConfig.min;
1154
+ const max = inputConfig.max;
1155
+
1156
+ let isValid = !isNaN(value);
1157
+ if (isValid && min !== undefined && value < min) isValid = false;
1158
+ if (isValid && max !== undefined && value > max) isValid = false;
1159
+
1160
+ if (isValid) {
1161
+ enableNextButton();
1162
+ console.log(` βœ… Pre-filled value is valid: ${value}`);
1163
+ } else {
1164
+ disableNextButton();
1165
+ console.log(` ❌ Pre-filled value is invalid: ${value}`);
1166
+ }
1167
+ }
1079
1168
  } else {
1080
1169
  inputElement.value = '';
1081
1170
  }
1082
1171
 
1083
1172
  inputElement.type = inputType === 'number' ? 'number' : 'text';
1084
1173
 
1085
- // Add input event to enable Next button when user types
1174
+ // Add input event handler
1086
1175
  inputElement.oninput = (e) => {
1087
1176
  const value = inputType === 'number' ? parseFloat(e.target.value) : e.target.value;
1088
1177
 
@@ -1090,11 +1179,36 @@ function renderTextInput(field, inputType = 'text') {
1090
1179
  chatState.data[field] = value;
1091
1180
  chatState.currentSelection = { field, value, name: value };
1092
1181
 
1093
- // Enable Next button if there's a value
1094
- if (value !== '' && value !== null && !isNaN(value)) {
1095
- enableNextButton();
1182
+ // Apply validation ONLY if min/max defined at input level
1183
+ if (hasValidation) {
1184
+ const min = inputConfig.min;
1185
+ const max = inputConfig.max;
1186
+
1187
+ // Check if value is valid
1188
+ let isValid = true;
1189
+ let errorMessage = '';
1190
+
1191
+ if (value === '' || isNaN(value)) {
1192
+ isValid = false;
1193
+ errorMessage = 'Please enter a valid number';
1194
+ } else if (min !== undefined && value < min) {
1195
+ isValid = false;
1196
+ errorMessage = `Value must be at least ${min}`;
1197
+ } else if (max !== undefined && value > max) {
1198
+ isValid = false;
1199
+ errorMessage = `Value must be at most ${max}`;
1200
+ }
1201
+
1202
+ if (isValid) {
1203
+ enableNextButton();
1204
+ console.log(` βœ… Number input valid: ${value}`);
1205
+ } else {
1206
+ disableNextButton();
1207
+ console.log(` ❌ Number input invalid: ${errorMessage}`);
1208
+ }
1096
1209
  } else {
1097
- disableNextButton();
1210
+ // No validation - just log
1211
+ console.log(` πŸ“ Input updated: ${value} (no validation)`);
1098
1212
  }
1099
1213
  };
1100
1214
  }
@@ -1330,14 +1444,34 @@ async function handleNext() {
1330
1444
 
1331
1445
  // Add user message (only if selection was made)
1332
1446
  if (chatState.currentSelection) {
1333
- addMessage(chatState.currentSelection.name, 'user', false, chatState.step);
1447
+ // Get the step's input config
1448
+ const inputConfig = currentStep.input || {};
1449
+ const valueType = inputConfig.selectedInputValueType;
1450
+ const prefix = inputConfig.selectedInputPrefix || '';
1451
+ const suffix = inputConfig.selectedInputSuffix || '';
1452
+
1453
+ let displayName = chatState.currentSelection.name;
1454
+
1455
+ // Format based on valueType
1456
+ if (valueType === 'arrayRange' && Array.isArray(chatState.currentSelection.value)) {
1457
+ const [min, max] = chatState.currentSelection.value;
1458
+ const formattedMin = min.toLocaleString();
1459
+ const formattedMax = max.toLocaleString();
1460
+ displayName = `${formattedMin} - ${formattedMax}`;
1461
+ }
1462
+
1463
+ // Add prefix and suffix with spaces
1464
+ if (prefix) displayName = `${prefix} ${displayName}`;
1465
+ if (suffix) displayName = `${displayName} ${suffix}`;
1466
+
1467
+ addMessage(displayName, 'user', false, chatState.step);
1334
1468
 
1335
1469
  // Save to history
1336
1470
  chatState.history.push({
1337
1471
  step: chatState.step,
1338
1472
  field: chatState.currentSelection.field,
1339
1473
  value: chatState.currentSelection.value,
1340
- name: chatState.currentSelection.name
1474
+ name: displayName
1341
1475
  });
1342
1476
  }
1343
1477
 
@@ -1437,13 +1571,21 @@ async function showNextStep() {
1437
1571
 
1438
1572
  if (inputType === 'text' || inputType === 'number') {
1439
1573
  // Render text or number input
1440
- renderTextInput(nextStep.input.field, inputType);
1574
+ renderTextInput(nextStep.input.field, inputType, nextStep.input);
1441
1575
 
1442
- // Disable Next button initially (enabled when user types)
1443
- if (inputRequired) {
1576
+ // Check if validation is enabled (number input with min/max defined)
1577
+ const hasValidation = inputType === 'number' &&
1578
+ (nextStep.input.min !== undefined || nextStep.input.max !== undefined);
1579
+
1580
+ // Initial Next button state
1581
+ if (inputRequired || hasValidation) {
1582
+ // Disable if input is required OR has validation rules
1444
1583
  disableNextButton();
1584
+ console.log(' πŸ”’ Next button disabled initially (input required or validation enabled)');
1445
1585
  } else {
1586
+ // Enable if optional and no validation
1446
1587
  enableNextButton();
1588
+ console.log(' πŸ”“ Next button enabled (optional input, no validation)');
1447
1589
  }
1448
1590
  } else if (inputType === 'multi-select-color') {
1449
1591
  // Render color options with color blocks
@@ -1478,19 +1620,39 @@ async function showNextStep() {
1478
1620
  }
1479
1621
  }
1480
1622
  } else {
1481
- // Auto-advance for steps without input
1482
- setTimeout(() => {
1483
- chatState.step++;
1484
-
1485
- // Update edit icons after auto-advance
1486
- updateEditIcons();
1487
-
1488
- if (chatState.step < flowData.flow.length) {
1489
- showNextStep();
1490
- } else {
1491
- handleCompletion();
1492
- }
1493
- }, config.autoAdvanceDelay);
1623
+ // No input
1624
+ const shouldAutoAdvance = nextStep.nextButtonDisplay !== false;
1625
+
1626
+ if (shouldAutoAdvance) {
1627
+ // Auto-advance for steps without input (default behavior)
1628
+ setTimeout(() => {
1629
+ chatState.step++;
1630
+
1631
+ // Update edit icons after auto-advance
1632
+ updateEditIcons();
1633
+
1634
+ if (chatState.step < flowData.flow.length) {
1635
+ showNextStep();
1636
+ } else {
1637
+ handleCompletion();
1638
+ }
1639
+ }, config.autoAdvanceDelay);
1640
+ } else {
1641
+ // Don't auto-advance if nextButtonDisplay is explicitly false
1642
+ console.log(' ⏸️ Not auto-advancing (nextButtonDisplay: false)');
1643
+ }
1644
+ }
1645
+
1646
+ // Handle nextButtonDisplay - default is true
1647
+ const showNextButton = nextStep.nextButtonDisplay !== false;
1648
+ if (elements.nextBtn) {
1649
+ if (showNextButton) {
1650
+ elements.nextBtn.style.display = '';
1651
+ console.log(' πŸ‘οΈ Next button shown (nextButtonDisplay: true or undefined)');
1652
+ } else {
1653
+ elements.nextBtn.style.display = 'none';
1654
+ console.log(' πŸ™ˆ Next button hidden (nextButtonDisplay: false)');
1655
+ }
1494
1656
  }
1495
1657
 
1496
1658
  // Always update edit icons at the end to ensure correct state