lisichatbot 1.8.7 → 1.8.9

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 +119 -30
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisichatbot",
3
- "version": "1.8.7",
3
+ "version": "1.8.9",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -18,13 +18,15 @@ let chatState = {
18
18
  currentSelection: null,
19
19
  returnToStep: null,
20
20
  completed: false,
21
- editPath: [] // ✅ NEW: Array of step names/numbers to edit in sequence
21
+ editPath: [], // ✅ NEW: Array of step names/numbers to edit in sequence
22
+ chatMode: 'create' // ✅ NEW: Track if in 'create' or 'edit' mode
22
23
  };
23
24
 
24
25
  let elements = {
25
26
  container: null,
26
27
  messages: null,
27
28
  nextBtn: null,
29
+ cancelBtn: null, // ✅ NEW: Cancel button element
28
30
  originalNextBtnText: null
29
31
  };
30
32
 
@@ -32,6 +34,7 @@ let config = {
32
34
  selectedBackground: '#667eea',
33
35
  autoAdvanceDelay: 2000,
34
36
  enableAnimations: true,
37
+ showCancelButton: false, // ✅ NEW: Control cancel button visibility
35
38
  customRangeErrors: {
36
39
  minRequired: 'Minimum value is required',
37
40
  maxRequired: 'Maximum value is required',
@@ -1075,13 +1078,16 @@ function renderMinMaxInputs(field, customConfig, existingData) {
1075
1078
  if (minInput) {
1076
1079
  minInput.setAttribute('data-field', field);
1077
1080
  minInput.setAttribute('data-input-type', 'min');
1078
- minInput.type = 'number';
1079
- minInput.min = customConfig.min !== undefined ? customConfig.min : 0;
1080
- minInput.max = customConfig.max !== undefined ? customConfig.max : 100;
1081
- minInput.value = showMinMax && existingData[0] !== undefined ? existingData[0] : '';
1081
+ minInput.type = 'text'; // Changed from 'number' to 'text' for locale formatting
1082
+ minInput.setAttribute('inputmode', 'numeric'); // Show numeric keyboard on mobile
1083
+ minInput.setAttribute('data-min', customConfig.min !== undefined ? customConfig.min : 0);
1084
+ minInput.setAttribute('data-max', customConfig.max !== undefined ? customConfig.max : 100);
1082
1085
 
1083
- if (showMinMax) {
1084
- console.log(` ✅ Pre-filled min: ${existingData[0]}`);
1086
+ if (showMinMax && existingData[0] !== undefined) {
1087
+ const numValue = Number(existingData[0]);
1088
+ minInput.value = numValue.toLocaleString();
1089
+ minInput.setAttribute('data-raw-value', existingData[0]);
1090
+ console.log(` ✅ Pre-filled min: ${existingData[0]} (display: ${numValue.toLocaleString()})`);
1085
1091
  }
1086
1092
  }
1087
1093
 
@@ -1096,13 +1102,16 @@ function renderMinMaxInputs(field, customConfig, existingData) {
1096
1102
  if (maxInput) {
1097
1103
  maxInput.setAttribute('data-field', field);
1098
1104
  maxInput.setAttribute('data-input-type', 'max');
1099
- maxInput.type = 'number';
1100
- maxInput.min = customConfig.min !== undefined ? customConfig.min : 0;
1101
- maxInput.max = customConfig.max !== undefined ? customConfig.max : 100;
1102
- maxInput.value = showMinMax && existingData[1] !== undefined ? existingData[1] : '';
1105
+ maxInput.type = 'text'; // Changed from 'number' to 'text' for locale formatting
1106
+ maxInput.setAttribute('inputmode', 'numeric'); // Show numeric keyboard on mobile
1107
+ maxInput.setAttribute('data-min', customConfig.min !== undefined ? customConfig.min : 0);
1108
+ maxInput.setAttribute('data-max', customConfig.max !== undefined ? customConfig.max : 100);
1103
1109
 
1104
- if (showMinMax) {
1105
- console.log(` ✅ Pre-filled max: ${existingData[1]}`);
1110
+ if (showMinMax && existingData[1] !== undefined) {
1111
+ const numValue = Number(existingData[1]);
1112
+ maxInput.value = numValue.toLocaleString();
1113
+ maxInput.setAttribute('data-raw-value', existingData[1]);
1114
+ console.log(` ✅ Pre-filled max: ${existingData[1]} (display: ${numValue.toLocaleString()})`);
1106
1115
  }
1107
1116
  }
1108
1117
 
@@ -1137,8 +1146,8 @@ function renderMinMaxInputs(field, customConfig, existingData) {
1137
1146
 
1138
1147
  if (minInput && maxInput) {
1139
1148
  const updateVisualFeedback = () => {
1140
- const minFilled = minInput.value.trim() !== '';
1141
- const maxFilled = maxInput.value.trim() !== '';
1149
+ const minFilled = (minInput.getAttribute('data-raw-value') || minInput.value.trim()) !== '';
1150
+ const maxFilled = (maxInput.getAttribute('data-raw-value') || maxInput.value.trim()) !== '';
1142
1151
  const anyFilled = minFilled || maxFilled;
1143
1152
 
1144
1153
  const minTick = minClone.querySelector('[data-chat-input-element="tick-icon"]');
@@ -1163,20 +1172,40 @@ function renderMinMaxInputs(field, customConfig, existingData) {
1163
1172
  console.log(' ✅ Applied visual feedback for pre-filled values');
1164
1173
  }
1165
1174
 
1166
- minInput.onfocus = () => {
1175
+ minInput.onchange = () => {
1167
1176
  selectCustomOption(field);
1168
- updateVisualFeedback();
1169
- };
1170
- minInput.oninput = () => {
1177
+ // Remove non-numeric characters except minus sign at start
1178
+ let value = minInput.value.replace(/[^\d-]/g, '');
1179
+ if (value.indexOf('-') > 0) {
1180
+ value = value.replace(/-/g, '');
1181
+ }
1182
+ minInput.setAttribute('data-raw-value', value);
1183
+
1184
+ // Format with locale string if valid number
1185
+ if (value && value !== '' && !isNaN(value)) {
1186
+ const numValue = Number(value);
1187
+ minInput.value = numValue.toLocaleString();
1188
+ }
1189
+
1171
1190
  updateVisualFeedback();
1172
1191
  validateMinMax(field, customConfig);
1173
1192
  };
1174
1193
 
1175
- maxInput.onfocus = () => {
1194
+ maxInput.onchange = () => {
1176
1195
  selectCustomOption(field);
1177
- updateVisualFeedback();
1178
- };
1179
- maxInput.oninput = () => {
1196
+ // Remove non-numeric characters except minus sign at start
1197
+ let value = maxInput.value.replace(/[^\d-]/g, '');
1198
+ if (value.indexOf('-') > 0) {
1199
+ value = value.replace(/-/g, '');
1200
+ }
1201
+ maxInput.setAttribute('data-raw-value', value);
1202
+
1203
+ // Format with locale string if valid number
1204
+ if (value && value !== '' && !isNaN(value)) {
1205
+ const numValue = Number(value);
1206
+ maxInput.value = numValue.toLocaleString();
1207
+ }
1208
+
1180
1209
  updateVisualFeedback();
1181
1210
  validateMinMax(field, customConfig);
1182
1211
  };
@@ -1328,10 +1357,12 @@ function handleCustomSelectClick(element, field, customConfig) {
1328
1357
 
1329
1358
  if (minInput) {
1330
1359
  minInput.value = '';
1360
+ minInput.removeAttribute('data-raw-value');
1331
1361
  console.log(' 🧹 Cleared min input');
1332
1362
  }
1333
1363
  if (maxInput) {
1334
1364
  maxInput.value = '';
1365
+ maxInput.removeAttribute('data-raw-value');
1335
1366
  console.log(' 🧹 Cleared max input');
1336
1367
  }
1337
1368
 
@@ -1401,17 +1432,20 @@ function validateMinMax(field, customConfig) {
1401
1432
  return { valid: false, error: null };
1402
1433
  }
1403
1434
 
1404
- const minValue = parseFloat(minInput.value);
1405
- const maxValue = parseFloat(maxInput.value);
1406
- const minFilled = minInput.value.trim() !== '';
1407
- const maxFilled = maxInput.value.trim() !== '';
1435
+ // Use data-raw-value for validation instead of formatted display value
1436
+ const minRawValue = minInput.getAttribute('data-raw-value') || '';
1437
+ const maxRawValue = maxInput.getAttribute('data-raw-value') || '';
1438
+ const minValue = parseFloat(minRawValue);
1439
+ const maxValue = parseFloat(maxRawValue);
1440
+ const minFilled = minRawValue.trim() !== '';
1441
+ const maxFilled = maxRawValue.trim() !== '';
1408
1442
 
1409
1443
  const minConstraint = customConfig.min !== undefined ? customConfig.min : 0;
1410
1444
  const maxConstraint = customConfig.max !== undefined ? customConfig.max : 100;
1411
1445
 
1412
1446
  console.log(`📊 Input values:
1413
- Min input value: "${minInput.value}" (filled: ${minFilled}, parsed: ${minValue})
1414
- Max input value: "${maxInput.value}" (filled: ${maxFilled}, parsed: ${maxValue})`);
1447
+ Min raw value: "${minRawValue}" (filled: ${minFilled}, parsed: ${minValue})
1448
+ Max raw value: "${maxRawValue}" (filled: ${maxFilled}, parsed: ${maxValue})`);
1415
1449
 
1416
1450
  console.log(`📏 Constraints:
1417
1451
  Min constraint: >= ${minConstraint}
@@ -2091,6 +2125,17 @@ async function handleNext() {
2091
2125
  try {
2092
2126
  disableNextButton();
2093
2127
 
2128
+ // ✅ NEW: Show loader and hide text when button is disabled
2129
+ const nextBtnText = elements.nextBtn.querySelector('[data-chat-element="next-button-text"]');
2130
+ const nextBtnLoader = elements.nextBtn.querySelector('[data-chat-element="next-button-loader"]');
2131
+
2132
+ if (nextBtnText) {
2133
+ nextBtnText.style.display = 'none';
2134
+ }
2135
+ if (nextBtnLoader) {
2136
+ nextBtnLoader.style.display = 'block';
2137
+ }
2138
+
2094
2139
  // ✅ NEW: Create showMessage helper function
2095
2140
  const showMessage = (message) => {
2096
2141
  console.log('💬 showMessage called:', message);
@@ -2105,6 +2150,14 @@ async function handleNext() {
2105
2150
  showMessage // ✅ NEW: Third parameter
2106
2151
  );
2107
2152
 
2153
+ // ✅ NEW: Hide loader and show text after onNext completes
2154
+ if (nextBtnText) {
2155
+ nextBtnText.style.display = '';
2156
+ }
2157
+ if (nextBtnLoader) {
2158
+ nextBtnLoader.style.display = 'none';
2159
+ }
2160
+
2108
2161
  // ✅ Still support showMessage in return object for backwards compatibility
2109
2162
  if (result && typeof result === 'object' && result.showMessage) {
2110
2163
  console.log('💬 onNext displaying message from return:', result.showMessage);
@@ -2355,6 +2408,18 @@ async function handleNext() {
2355
2408
  } catch (error) {
2356
2409
  console.error('Validation error:', error);
2357
2410
  alert('An error occurred. Please try again.');
2411
+
2412
+ // ✅ NEW: Hide loader and show text on error
2413
+ const nextBtnText = elements.nextBtn.querySelector('[data-chat-element="next-button-text"]');
2414
+ const nextBtnLoader = elements.nextBtn.querySelector('[data-chat-element="next-button-loader"]');
2415
+
2416
+ if (nextBtnText) {
2417
+ nextBtnText.style.display = '';
2418
+ }
2419
+ if (nextBtnLoader) {
2420
+ nextBtnLoader.style.display = 'none';
2421
+ }
2422
+
2358
2423
  enableNextButton();
2359
2424
  return;
2360
2425
  }
@@ -3229,12 +3294,14 @@ function init(flowName, flowConfig, options = {}) {
3229
3294
  hasEditData: Object.keys(editData).length > 0,
3230
3295
  selectedBackground: config.selectedBackground,
3231
3296
  autoAdvanceDelay: config.autoAdvanceDelay,
3297
+ showCancelButton: config.showCancelButton,
3232
3298
  customRangeErrors: config.customRangeErrors
3233
3299
  });
3234
3300
 
3235
3301
  flowData = flowConfig;
3236
3302
 
3237
3303
  chatState.step = 0;
3304
+ chatState.chatMode = mode; // ✅ NEW: Store mode in chatState as chatMode
3238
3305
 
3239
3306
  // ✅ NEW: Merge initialData with editData for edit mode
3240
3307
  if (mode === 'edit' && editData && Object.keys(editData).length > 0) {
@@ -3252,6 +3319,7 @@ function init(flowName, flowConfig, options = {}) {
3252
3319
 
3253
3320
  elements.messages = elements.container.querySelector('[data-chat-element="messages-container"]');
3254
3321
  elements.nextBtn = elements.container.querySelector('[data-chat-element="next-button"]');
3322
+ elements.cancelBtn = elements.container.querySelector('[data-chat-element="cancel-button"]');
3255
3323
 
3256
3324
  if (!elements.messages) {
3257
3325
  console.error('messages-container not found. Please add <div data-chat-element="messages-container"></div>');
@@ -3263,6 +3331,25 @@ function init(flowName, flowConfig, options = {}) {
3263
3331
  return null;
3264
3332
  }
3265
3333
 
3334
+ // ✅ NEW: Show/hide cancel button based on config
3335
+ if (elements.cancelBtn) {
3336
+ if (config.showCancelButton === true) {
3337
+ elements.cancelBtn.style.marginTop = '8px';
3338
+ elements.cancelBtn.style.display = '';
3339
+ console.log('✅ Cancel button found and shown (showCancelButton: true)');
3340
+ } else {
3341
+ elements.cancelBtn.style.display = 'none';
3342
+ console.log('🚫 Cancel button hidden (showCancelButton: false)');
3343
+ }
3344
+ } else {
3345
+ if (config.showCancelButton === true) {
3346
+ console.warn('⚠️ showCancelButton is true but cancel button element not found');
3347
+ console.warn(' Please add <button data-chat-element="cancel-button">Cancel</button> to your HTML');
3348
+ } else {
3349
+ console.log('ℹ️ Cancel button not found (optional, showCancelButton: false)');
3350
+ }
3351
+ }
3352
+
3266
3353
  const nextBtnTextElement = elements.nextBtn.querySelector('[data-chat-element="next-button-text"]');
3267
3354
  if (nextBtnTextElement) {
3268
3355
  elements.originalNextBtnText = nextBtnTextElement.textContent || nextBtnTextElement.innerText || 'Next';
@@ -3323,7 +3410,8 @@ function getState() {
3323
3410
  return {
3324
3411
  step: chatState.step,
3325
3412
  data: { ...chatState.data },
3326
- history: [...chatState.history]
3413
+ history: [...chatState.history],
3414
+ chatMode: chatState.chatMode // ✅ Include chatMode in state
3327
3415
  };
3328
3416
  }
3329
3417
 
@@ -3332,6 +3420,7 @@ function reset() {
3332
3420
  chatState.data = flowData.initialData || {};
3333
3421
  chatState.history = [];
3334
3422
  chatState.currentSelection = null;
3423
+ chatState.chatMode = 'create'; // ✅ Reset to create mode
3335
3424
 
3336
3425
  // ✅ Move back any injected elements before clearing
3337
3426
  if (elements.messages) {