lisichatbot 1.0.1 → 1.0.3

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 +111 -95
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisichatbot",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -67,35 +67,43 @@ function disableNextButton() {
67
67
  function addMessage(content, type = 'bot', isEditable = false, stepNumber = null) {
68
68
  if (!elements.messages) return;
69
69
 
70
- const messageDiv = document.createElement('div');
71
- messageDiv.className = `cf-message cf-${type}`;
72
- messageDiv.setAttribute('data-chat-element', `${type}-message-wrapper`);
70
+ // Find the wrapper element directly by data-chat-element
71
+ const wrapperSelector = `[data-chat-element="${type}-message-wrapper"]`;
72
+ const existingWrapper = document.querySelector(wrapperSelector);
73
73
 
74
+ if (!existingWrapper) {
75
+ console.error(`Element with ${wrapperSelector} not found in HTML. Please add it to your HTML.`);
76
+ return;
77
+ }
78
+
79
+ // Clone the existing wrapper
80
+ const clone = existingWrapper.cloneNode(true);
81
+
82
+ // Add step number if provided
74
83
  if (stepNumber !== null) {
75
- messageDiv.setAttribute('data-chat-step', stepNumber);
84
+ clone.setAttribute('data-chat-step', stepNumber);
76
85
  }
77
-
78
- let editIcon = '';
79
- if (isEditable && type === 'user') {
80
- editIcon = `
81
- <button class="cf-edit-icon"
82
- data-chat-element="edit-button"
83
- data-chat-step="${stepNumber}"
84
- onclick="editStep(${stepNumber})"
85
- title="Edit this response">
86
- ✏️
87
- </button>
88
- `;
86
+
87
+ // Find text element in clone and set content
88
+ const textElement = clone.querySelector(`[data-chat-element="${type}-message-text"]`);
89
+ if (textElement) {
90
+ textElement.textContent = content;
91
+ } else {
92
+ console.error(`Element with data-chat-element="${type}-message-text" not found in wrapper`);
89
93
  }
90
-
91
- messageDiv.innerHTML = `
92
- <div class="cf-message-content" data-chat-element="${type}-message-text">
93
- ${content}
94
- </div>
95
- ${editIcon}
96
- `;
97
-
98
- elements.messages.appendChild(messageDiv);
94
+
95
+ // Handle edit button for user messages
96
+ if (isEditable && type === 'user' && stepNumber !== null) {
97
+ const editButton = clone.querySelector('[data-chat-element="edit-button"]');
98
+ if (editButton) {
99
+ editButton.setAttribute('data-chat-step', stepNumber);
100
+ editButton.onclick = () => editStep(stepNumber);
101
+ editButton.style.display = 'inline-block';
102
+ }
103
+ }
104
+
105
+ // Append to messages container
106
+ elements.messages.appendChild(clone);
99
107
  scrollToBottom();
100
108
  }
101
109
 
@@ -106,56 +114,63 @@ function addMessage(content, type = 'bot', isEditable = false, stepNumber = null
106
114
  function renderOptions(options, field, isSingleSelect = true) {
107
115
  if (!elements.messages) return;
108
116
 
109
- const messageDiv = document.createElement('div');
110
- messageDiv.className = 'cf-message cf-bot';
111
- messageDiv.setAttribute('data-chat-message', 'bot');
112
-
113
117
  // Determine input type attribute value
114
118
  const inputTypeAttr = isSingleSelect ? 'single-select-input' : 'multi-select-input';
119
+
120
+ // Find existing option element in HTML by data-chat-element
121
+ const optionSelector = `[data-chat-element="${inputTypeAttr}"]`;
122
+ const existingOption = document.querySelector(optionSelector);
115
123
 
116
- const optionsHtml = options.map((option, index) => {
124
+ if (!existingOption) {
125
+ console.error(`Element with ${optionSelector} not found in HTML. Please add it to your HTML.`);
126
+ return;
127
+ }
128
+
129
+ // Create wrapper to hold all options
130
+ const optionsWrapper = document.createElement('div');
131
+ optionsWrapper.setAttribute('data-chat-element', 'options-wrapper');
132
+
133
+ // Clone and fill option element for each option
134
+ options.forEach((option, index) => {
117
135
  const optionName = option.name || option;
118
136
  const optionValue = option.value !== undefined ? option.value : option;
119
137
  const valueStr = typeof optionValue === 'object' ?
120
138
  JSON.stringify(optionValue) : String(optionValue);
121
139
 
122
- return `
123
- <label class="cf-option ${isSingleSelect ? 'cf-single' : 'cf-multi'}"
124
- data-chat-input-element="container"
125
- data-chat-element="${inputTypeAttr}"
126
- data-field="${field}"
127
- data-value='${valueStr}'
128
- data-name="${optionName}"
129
- data-index="${index}">
130
-
131
- <div class="cf-tick"
132
- data-chat-input-element="tick-icon"
133
- style="display: none;">✓</div>
134
-
135
- <input type="${isSingleSelect ? 'radio' : 'checkbox'}"
136
- name="${field}"
137
- value="${valueStr}"
138
- data-chat-input-element="input"
139
- data-chat-element="${inputTypeAttr}"
140
- style="display: none;">
141
-
142
- <span class="cf-option-text"
143
- data-chat-input-element="text">${optionName}</span>
144
- </label>
145
- `;
146
- }).join('');
147
-
148
- messageDiv.innerHTML = `
149
- <div class="cf-message-content" data-chat-element="bot-message-text">
150
- <div class="cf-options" data-chat-element="options-wrapper">${optionsHtml}</div>
151
- </div>
152
- `;
153
-
154
- elements.messages.appendChild(messageDiv);
140
+ // Clone existing option element
141
+ const clone = existingOption.cloneNode(true);
142
+
143
+ // Set data attributes on container
144
+ clone.setAttribute('data-chat-element', inputTypeAttr);
145
+ clone.setAttribute('data-field', field);
146
+ clone.setAttribute('data-value', valueStr);
147
+ clone.setAttribute('data-name', optionName);
148
+ clone.setAttribute('data-index', index);
149
+
150
+ // Find and set input
151
+ const input = clone.querySelector('[data-chat-input-element="input"]');
152
+ if (input) {
153
+ input.setAttribute('data-chat-element', inputTypeAttr);
154
+ input.name = field;
155
+ input.value = valueStr;
156
+ }
157
+
158
+ // Find and set text
159
+ const textElement = clone.querySelector('[data-chat-input-element="text"]');
160
+ if (textElement) {
161
+ textElement.textContent = optionName;
162
+ }
163
+
164
+ // Append to wrapper
165
+ optionsWrapper.appendChild(clone);
166
+ });
167
+
168
+ // Append wrapper to messages
169
+ elements.messages.appendChild(optionsWrapper);
155
170
  scrollToBottom();
156
171
 
157
- // Add click handlers using custom attribute selector
158
- const optionElements = messageDiv.querySelectorAll('[data-chat-input-element="container"]');
172
+ // Add click handlers
173
+ const optionElements = optionsWrapper.querySelectorAll('[data-chat-input-element="container"]');
159
174
  optionElements.forEach(el => {
160
175
  el.onclick = () => handleOptionClick(el, field, isSingleSelect);
161
176
  });
@@ -388,11 +403,13 @@ function handleCompletion() {
388
403
  // INITIALIZATION
389
404
  // =============================================================================
390
405
 
391
- function init(containerId, flowConfig) {
392
- // Get container
393
- elements.container = document.getElementById(containerId);
406
+ function init(flowName, flowConfig) {
407
+ // Find container by data-chat-element="chat-wrapper"
408
+ elements.container = document.querySelector('[data-chat-element="chat-wrapper"]');
409
+
394
410
  if (!elements.container) {
395
- console.error('Container not found:', containerId);
411
+ console.error('Container with data-chat-element="chat-wrapper" not found');
412
+ console.error('Please add <div data-chat-element="chat-wrapper"></div> to your HTML');
396
413
  return null;
397
414
  }
398
415
 
@@ -410,34 +427,32 @@ function init(containerId, flowConfig) {
410
427
  chatState.history = [];
411
428
  chatState.currentSelection = null;
412
429
 
413
- // Create UI with data-chat-element attributes
414
- elements.container.innerHTML = `
415
- <div class="cf-wrapper" data-chat-element="chat-wrapper">
416
- <div class="cf-messages"
417
- id="cfMessages"
418
- data-chat-element="messages-container"></div>
419
- <div class="cf-bottom"
420
- data-chat-element="navigation-bottom">
421
- <button id="cfNextBtn"
422
- class="cf-next-btn"
423
- data-chat-element="next-button"
424
- style="opacity: 0.5; cursor: not-allowed;"
425
- disabled>
426
- Next →
427
- </button>
428
- </div>
429
- </div>
430
- `;
430
+ // Find existing elements (don't create new ones)
431
+ elements.messages = elements.container.querySelector('[data-chat-element="messages-container"]');
432
+ elements.nextBtn = elements.container.querySelector('[data-chat-element="next-button"]');
431
433
 
432
- // Get elements
433
- elements.messages = document.getElementById('cfMessages');
434
- elements.nextBtn = document.getElementById('cfNextBtn');
434
+ // Validate required elements exist
435
+ if (!elements.messages) {
436
+ console.error('messages-container not found. Please add <div data-chat-element="messages-container"></div>');
437
+ return null;
438
+ }
435
439
 
436
- // Add event listener
437
- if (elements.nextBtn) {
438
- elements.nextBtn.onclick = handleNext;
440
+ if (!elements.nextBtn) {
441
+ console.error('next-button not found. Please add <button data-chat-element="next-button"></button>');
442
+ return null;
439
443
  }
440
444
 
445
+ // Clear ONLY messages container (not entire chat-wrapper)
446
+ elements.messages.innerHTML = '';
447
+
448
+ // Reset button state
449
+ elements.nextBtn.disabled = true;
450
+ elements.nextBtn.style.opacity = '0.5';
451
+ elements.nextBtn.style.cursor = 'not-allowed';
452
+
453
+ // Add event listener
454
+ elements.nextBtn.onclick = handleNext;
455
+
441
456
  // Expose editStep globally for onclick handlers
442
457
  if (typeof window !== 'undefined') {
443
458
  window.editStep = editStep;
@@ -446,12 +461,13 @@ function init(containerId, flowConfig) {
446
461
  // Start
447
462
  showNextStep();
448
463
 
449
- console.log('✅ Conversational Flow Builder initialized with custom attributes');
464
+ console.log(`✅ Flow "${flowName}" initialized`);
450
465
 
451
466
  return {
452
467
  getState,
453
468
  reset,
454
- goToStep
469
+ goToStep,
470
+ editStep
455
471
  };
456
472
  }
457
473