@coveo/quantic 3.40.0 → 3.42.0

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 (62) hide show
  1. package/docs/out/quantic-docs.json +9 -0
  2. package/force-app/main/default/labels/CustomLabels.labels-meta.xml +91 -0
  3. package/force-app/main/default/lwc/quanticGeneratedAnswer/__tests__/quanticGeneratedAnswer.test.js +271 -22
  4. package/force-app/main/default/lwc/quanticGeneratedAnswer/quanticGeneratedAnswer.js +92 -31
  5. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/conversation.css +7 -0
  6. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/conversation.html +63 -0
  7. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/generatedAnswer.css +0 -11
  8. package/force-app/main/default/lwc/quanticGeneratedAnswer/templates/generatedAnswer.html +2 -2
  9. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/__tests__/quanticGeneratedAnswerBody.test.js +379 -0
  10. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/quanticGeneratedAnswerBody.js +152 -0
  11. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/quanticGeneratedAnswerBody.js-meta.xml +5 -0
  12. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/templates/answer.css +3 -0
  13. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/templates/answer.html +59 -0
  14. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/templates/cannotAnswer.html +7 -0
  15. package/force-app/main/default/lwc/quanticGeneratedAnswerBody/templates/error.html +7 -0
  16. package/force-app/main/default/lwc/quanticGeneratedAnswerCopyToClipboard/__tests__/quanticGeneratedAnswerCopyToClipboard.test.js +5 -1
  17. package/force-app/main/default/lwc/quanticGeneratedAnswerCopyToClipboard/quanticGeneratedAnswerCopyToClipboard.js +9 -2
  18. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/__tests__/quanticGeneratedAnswerFollowUpInput.test.js +109 -55
  19. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.css +59 -11
  20. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.html +14 -13
  21. package/force-app/main/default/lwc/quanticGeneratedAnswerFollowUpInput/quanticGeneratedAnswerFollowUpInput.js +40 -2
  22. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/__tests__/quanticGeneratedAnswerStreamOfThought.test.js +348 -0
  23. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/quanticGeneratedAnswerStreamOfThought.css +17 -0
  24. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/quanticGeneratedAnswerStreamOfThought.js +163 -0
  25. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/quanticGeneratedAnswerStreamOfThought.js-meta.xml +5 -0
  26. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/templates/collapsedSummary.css +1 -0
  27. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/templates/collapsedSummary.html +32 -0
  28. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/templates/streamOfThought.css +1 -0
  29. package/force-app/main/default/lwc/quanticGeneratedAnswerStreamOfThought/templates/streamOfThought.html +65 -0
  30. package/force-app/main/default/lwc/quanticGeneratedAnswerThread/__tests__/quanticGeneratedAnswerThread.test.js +285 -0
  31. package/force-app/main/default/lwc/quanticGeneratedAnswerThread/quanticGeneratedAnswerThread.css +47 -0
  32. package/force-app/main/default/lwc/quanticGeneratedAnswerThread/quanticGeneratedAnswerThread.html +67 -0
  33. package/force-app/main/default/lwc/quanticGeneratedAnswerThread/quanticGeneratedAnswerThread.js +93 -0
  34. package/force-app/main/default/lwc/quanticGeneratedAnswerThread/quanticGeneratedAnswerThread.js-meta.xml +5 -0
  35. package/force-app/main/default/lwc/quanticSourceCitations/__tests__/quanticSourceCitations.test.js +22 -2
  36. package/force-app/main/default/lwc/quanticSourceCitations/quanticSourceCitations.js +7 -0
  37. package/force-app/main/default/lwc/quanticThreadItem/quanticThreadItem.css +0 -4
  38. package/force-app/main/default/lwc/quanticThreadItem/quanticThreadItem.html +1 -1
  39. package/force-app/main/default/staticresources/coveoheadless/case-assist/headless.js +15 -15
  40. package/force-app/main/default/staticresources/coveoheadless/definitions/api/commerce/common/pagination.d.ts +1 -1
  41. package/force-app/main/default/staticresources/coveoheadless/definitions/commerce.index.d.ts +1 -1
  42. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/core/sub-controller/headless-sub-controller.d.ts +3 -1
  43. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/recent-queries-list/headless-recent-queries-list.d.ts +13 -2
  44. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/commerce/search/did-you-mean/headless-did-you-mean.d.ts +10 -1
  45. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/core/generated-answer/headless-core-generated-answer.d.ts +1 -0
  46. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/core/generated-answer/headless-core-interactive-citation.d.ts +3 -3
  47. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/generated-answer/headless-generated-answer.d.ts +2 -2
  48. package/force-app/main/default/staticresources/coveoheadless/definitions/controllers/generated-answer/interactive-citation-analytics-client.d.ts +3 -0
  49. package/force-app/main/default/staticresources/coveoheadless/definitions/features/analytics/analytics-utils.d.ts +3 -2
  50. package/force-app/main/default/staticresources/coveoheadless/definitions/features/follow-up-answers/follow-up-answers-actions.d.ts +32 -1
  51. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-actions.d.ts +26 -1
  52. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-analytics-actions.d.ts +2 -0
  53. package/force-app/main/default/staticresources/coveoheadless/definitions/features/generated-answer/generated-answer-state.d.ts +19 -0
  54. package/force-app/main/default/staticresources/coveoheadless/definitions/index.d.ts +1 -1
  55. package/force-app/main/default/staticresources/coveoheadless/definitions/ssr/commerce/controllers/did-you-mean/headless-did-you-mean.ssr.d.ts +4 -3
  56. package/force-app/main/default/staticresources/coveoheadless/definitions/ssr-commerce-next.index.d.ts +1 -1
  57. package/force-app/main/default/staticresources/coveoheadless/definitions/ssr-commerce.index.d.ts +1 -1
  58. package/force-app/main/default/staticresources/coveoheadless/definitions/ssr-next/commerce/controllers/did-you-mean/headless-did-you-mean.ssr.d.ts +4 -3
  59. package/force-app/main/default/staticresources/coveoheadless/headless.js +18 -18
  60. package/force-app/main/default/staticresources/coveoheadless/insight/headless.js +16 -16
  61. package/force-app/main/default/staticresources/coveoheadless/recommendation/headless.js +14 -14
  62. package/package.json +2 -2
@@ -12,15 +12,18 @@ jest.mock(
12
12
  {virtual: true}
13
13
  );
14
14
  jest.mock('c/quanticUtils', () => ({
15
- keys: {ENTER: 'Enter'},
15
+ keys: {ENTER: 'Enter', ESC: 'Escape'},
16
16
  }));
17
17
 
18
18
  const selectors = {
19
- input: 'lightning-input',
19
+ textarea: 'textarea',
20
20
  submitButton: 'lightning-button-icon',
21
- inputContainer: '.follow-up-input__input-container',
21
+ container: '.follow-up-input__container',
22
+ expander: '.follow-up-input__expander',
22
23
  };
23
24
 
25
+ const expandedClass = 'follow-up-input__expander--expanded';
26
+
24
27
  const createTestComponent = buildCreateTestComponent(
25
28
  QuanticGeneratedAnswerFollowUpInput,
26
29
  'c-quantic-generated-answer-follow-up-input'
@@ -31,17 +34,14 @@ describe('c-quantic-generated-answer-follow-up-input', () => {
31
34
  cleanup();
32
35
  });
33
36
 
34
- it('should render the input and submit button', async () => {
37
+ it('should render the textarea and submit button', async () => {
35
38
  const element = createTestComponent();
36
39
  await flushPromises();
37
40
 
38
- const input = element.shadowRoot.querySelector(selectors.input);
39
- const submitButton = element.shadowRoot.querySelector(
40
- selectors.submitButton
41
- );
42
-
43
- expect(input).not.toBeNull();
44
- expect(submitButton).not.toBeNull();
41
+ expect(element.shadowRoot.querySelector(selectors.textarea)).not.toBeNull();
42
+ expect(
43
+ element.shadowRoot.querySelector(selectors.submitButton)
44
+ ).not.toBeNull();
45
45
  });
46
46
 
47
47
  describe('submitting a follow up', () => {
@@ -52,9 +52,9 @@ describe('c-quantic-generated-answer-follow-up-input', () => {
52
52
  const handler = jest.fn();
53
53
  element.addEventListener('quantic__submitfollowup', handler);
54
54
 
55
- const input = element.shadowRoot.querySelector(selectors.input);
56
- input.value = 'follow up question';
57
- input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
55
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
56
+ textarea.value = 'follow up question';
57
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
58
58
 
59
59
  expect(handler).toHaveBeenCalledTimes(1);
60
60
  expect(handler.mock.calls[0][0].detail.value).toBe('follow up question');
@@ -67,29 +67,40 @@ describe('c-quantic-generated-answer-follow-up-input', () => {
67
67
  const handler = jest.fn();
68
68
  element.addEventListener('quantic__submitfollowup', handler);
69
69
 
70
- const input = element.shadowRoot.querySelector(selectors.input);
71
- input.value = 'another question';
70
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
71
+ textarea.value = 'another question';
72
72
 
73
- const submitButton = element.shadowRoot.querySelector(
74
- selectors.submitButton
75
- );
76
- submitButton.click();
73
+ element.shadowRoot.querySelector(selectors.submitButton).click();
77
74
 
78
75
  expect(handler).toHaveBeenCalledTimes(1);
79
76
  expect(handler.mock.calls[0][0].detail.value).toBe('another question');
80
77
  });
81
78
 
82
- it('should clear the input and blur it after a successful submit', async () => {
79
+ it('should clear the textarea after a successful submit', async () => {
83
80
  const element = createTestComponent();
84
81
  await flushPromises();
85
82
 
86
- const input = element.shadowRoot.querySelector(selectors.input);
87
- input.value = 'a question';
88
- input.blur = jest.fn();
83
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
84
+ textarea.value = 'a question';
85
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
89
86
 
90
- input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
87
+ expect(textarea.value).toBe('');
88
+ });
89
+
90
+ it('should collapse after a successful submit', async () => {
91
+ const element = createTestComponent();
92
+ await flushPromises();
93
+
94
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
95
+ textarea.dispatchEvent(new CustomEvent('focus'));
96
+ await flushPromises();
97
+
98
+ textarea.value = 'a question';
99
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
100
+ await flushPromises();
91
101
 
92
- expect(input.value).toBe('');
102
+ const expander = element.shadowRoot.querySelector(selectors.expander);
103
+ expect(expander.classList).not.toContain(expandedClass);
93
104
  });
94
105
  });
95
106
 
@@ -101,9 +112,9 @@ describe('c-quantic-generated-answer-follow-up-input', () => {
101
112
  const handler = jest.fn();
102
113
  element.addEventListener('quantic__submitfollowup', handler);
103
114
 
104
- const input = element.shadowRoot.querySelector(selectors.input);
105
- input.value = 'a question';
106
- input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
115
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
116
+ textarea.value = 'a question';
117
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
107
118
 
108
119
  expect(handler).not.toHaveBeenCalled();
109
120
  });
@@ -115,9 +126,9 @@ describe('c-quantic-generated-answer-follow-up-input', () => {
115
126
  const handler = jest.fn();
116
127
  element.addEventListener('quantic__submitfollowup', handler);
117
128
 
118
- const input = element.shadowRoot.querySelector(selectors.input);
119
- input.value = ' ';
120
- input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
129
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
130
+ textarea.value = ' ';
131
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
121
132
 
122
133
  expect(handler).not.toHaveBeenCalled();
123
134
  });
@@ -129,52 +140,95 @@ describe('c-quantic-generated-answer-follow-up-input', () => {
129
140
  const handler = jest.fn();
130
141
  element.addEventListener('quantic__submitfollowup', handler);
131
142
 
132
- const input = element.shadowRoot.querySelector(selectors.input);
133
- input.value = '';
134
-
135
- const submitButton = element.shadowRoot.querySelector(
136
- selectors.submitButton
137
- );
138
- submitButton.click();
143
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
144
+ textarea.value = '';
145
+ element.shadowRoot.querySelector(selectors.submitButton).click();
139
146
 
140
147
  expect(handler).not.toHaveBeenCalled();
141
148
  });
142
149
  });
143
150
 
144
- describe('focus and blur CSS class toggling', () => {
145
- it('should add the focused class when the input is focused', async () => {
151
+ describe('expandable input behaviour', () => {
152
+ it('should expand and add focused class on focus', async () => {
146
153
  const element = createTestComponent();
147
154
  await flushPromises();
148
155
 
149
- const input = element.shadowRoot.querySelector(selectors.input);
150
- input.dispatchEvent(new CustomEvent('focus'));
156
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
157
+ textarea.dispatchEvent(new CustomEvent('focus'));
151
158
  await flushPromises();
152
159
 
153
- const container = element.shadowRoot.querySelector(
154
- selectors.inputContainer
155
- );
160
+ const expander = element.shadowRoot.querySelector(selectors.expander);
161
+ const container = element.shadowRoot.querySelector(selectors.container);
162
+ expect(expander.classList).toContain(expandedClass);
156
163
  expect(container.classList).toContain(
157
- 'follow-up-input__input-container--focused'
164
+ 'follow-up-input__container--focused'
158
165
  );
159
166
  });
160
167
 
161
- it('should remove the focused class when the input is blurred', async () => {
168
+ it('should collapse and remove focused class on blur', async () => {
162
169
  const element = createTestComponent();
163
170
  await flushPromises();
164
171
 
165
- const input = element.shadowRoot.querySelector(selectors.input);
166
- input.dispatchEvent(new CustomEvent('focus'));
172
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
173
+ textarea.dispatchEvent(new CustomEvent('focus'));
167
174
  await flushPromises();
168
175
 
169
- input.dispatchEvent(new CustomEvent('blur'));
176
+ textarea.dispatchEvent(new CustomEvent('blur'));
170
177
  await flushPromises();
171
178
 
172
- const container = element.shadowRoot.querySelector(
173
- selectors.inputContainer
174
- );
179
+ const expander = element.shadowRoot.querySelector(selectors.expander);
180
+ const container = element.shadowRoot.querySelector(selectors.container);
181
+ expect(expander.classList).not.toContain(expandedClass);
175
182
  expect(container.classList).not.toContain(
176
- 'follow-up-input__input-container--focused'
183
+ 'follow-up-input__container--focused'
177
184
  );
178
185
  });
186
+
187
+ it('should sync replica text on input', async () => {
188
+ const element = createTestComponent();
189
+ await flushPromises();
190
+
191
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
192
+ const expander = element.shadowRoot.querySelector(selectors.expander);
193
+
194
+ textarea.value = 'multi\nline\ntext';
195
+ textarea.dispatchEvent(new CustomEvent('input'));
196
+ await flushPromises();
197
+
198
+ expect(expander.dataset.replicatedValue).toBe('multi\nline\ntext');
199
+ });
200
+
201
+ it('should clear replica text after submit', async () => {
202
+ const element = createTestComponent();
203
+ await flushPromises();
204
+
205
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
206
+ const expander = element.shadowRoot.querySelector(selectors.expander);
207
+
208
+ textarea.value = 'some text';
209
+ textarea.dispatchEvent(new CustomEvent('input'));
210
+ await flushPromises();
211
+ expect(expander.dataset.replicatedValue).toBe('some text');
212
+
213
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
214
+ await flushPromises();
215
+
216
+ expect(expander.dataset.replicatedValue).toBeUndefined();
217
+ });
218
+
219
+ it('should collapse the textarea when the Escape key is pressed', async () => {
220
+ const element = createTestComponent();
221
+ await flushPromises();
222
+
223
+ const textarea = element.shadowRoot.querySelector(selectors.textarea);
224
+ textarea.blur = jest.fn();
225
+ textarea.dispatchEvent(new CustomEvent('focus'));
226
+ await flushPromises();
227
+
228
+ textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape'}));
229
+ await flushPromises();
230
+
231
+ expect(textarea.blur).toHaveBeenCalled();
232
+ });
179
233
  });
180
234
  });
@@ -1,17 +1,65 @@
1
- :host {
2
- --slds-c-input-shadow: none;
1
+ .follow-up-input__container {
2
+ min-height: calc(2.5rem + 2px);
3
3
  }
4
4
 
5
- .follow-up-input__input {
5
+ .follow-up-input__container--focused {
6
+ border-color: var(--lwc-brandAccessible, #0176d3);
7
+ }
8
+
9
+ .follow-up-input__expander {
10
+ display: grid;
11
+ overflow: hidden;
12
+ margin-right: 2.5rem;
13
+ }
14
+
15
+ .follow-up-input__expander::after {
16
+ content: attr(data-replicated-value) ' ';
17
+ visibility: hidden;
18
+ }
19
+
20
+ .follow-up-input__expander::after,
21
+ .follow-up-input__textarea {
22
+ grid-area: 1 / 1 / 2 / 2;
23
+ resize: none;
24
+ overflow: hidden;
25
+ white-space: nowrap;
6
26
  border: none;
7
- box-shadow: none;
8
27
  outline: none;
9
- width: 100%;
10
- --slds-c-input-color-border: transparent;
11
- --slds-c-input-shadow-focus: transparent;
12
- --slds-c-input-spacing-border: 0px;
28
+ background: transparent;
29
+ padding: 0.5rem 0.75rem;
30
+ font: inherit;
31
+ min-height: 2.5rem;
13
32
  }
14
33
 
15
- .follow-up-input__input-container.follow-up-input__input-container--focused {
16
- border-color: var(--lwc-brandAccessible, #0176d3);
17
- }
34
+ .follow-up-input__expander--expanded {
35
+ position: absolute;
36
+ bottom: -1px;
37
+ left: -1px;
38
+ right: -1px;
39
+ z-index: 10;
40
+ overflow: visible;
41
+ margin-right: 0;
42
+ background-color: var(--lwc-colorBackground, #fff);
43
+ border: 1px solid var(--lwc-brandAccessible, #0176d3);
44
+ border-radius: 0.25rem;
45
+ }
46
+
47
+ .follow-up-input__expander--expanded::after,
48
+ .follow-up-input__expander--expanded .follow-up-input__textarea {
49
+ white-space: pre-wrap;
50
+ overflow-y: auto;
51
+ max-height: 8rem;
52
+ padding-right: 2.5rem;
53
+ scrollbar-width: none;
54
+ }
55
+
56
+ .follow-up-input__expander--expanded .follow-up-input__textarea::-webkit-scrollbar {
57
+ display: none;
58
+ }
59
+
60
+ .follow-up-input__submit-button {
61
+ position: absolute;
62
+ right: 0.25rem;
63
+ bottom: 0.25rem;
64
+ z-index: 15;
65
+ }
@@ -1,23 +1,24 @@
1
1
  <template>
2
2
  <div class={inputContainerClasses}>
3
- <lightning-input
4
- class="slds-col slds-grow follow-up-input__input"
5
- type="text"
6
- variant="label-hidden"
7
- label={labels.askFollowUp}
8
- placeholder={labels.askFollowUp}
9
- name="ask-followup"
10
- lwc:ref="askFollowUpInput"
11
- onfocus={handleFocus}
12
- onblur={handleBlur}
13
- onkeydown={handleKeyDown}
14
- ></lightning-input>
3
+ <div class="follow-up-input__expander slds-grow" lwc:ref="expander">
4
+ <textarea
5
+ class="follow-up-input__textarea"
6
+ lwc:ref="askFollowUpInput"
7
+ rows="1"
8
+ placeholder={labels.askFollowUp}
9
+ aria-label={labels.askFollowUp}
10
+ onfocus={handleFocus}
11
+ onblur={handleBlur}
12
+ oninput={handleInput}
13
+ onkeydown={handleKeyDown}
14
+ ></textarea>
15
+ </div>
15
16
  <lightning-button-icon
16
17
  disabled={submitButtonDisabled}
17
18
  onclick={handleSubmitFollowUp}
18
19
  icon-name="utility:arrowup"
19
20
  variant="brand"
20
- class="slds-col slds-grow-none slds-align_absolute-center"
21
+ class="follow-up-input__submit-button"
21
22
  name="submit-follow-up"
22
23
  title={labels.submitFollowUp}
23
24
  aria-label={labels.submitFollowUp}
@@ -33,10 +33,16 @@ export default class QuanticGeneratedAnswerFollowUpInput extends LightningElemen
33
33
  return;
34
34
  }
35
35
 
36
- if (event.key === keys.ENTER) {
36
+ if (event.key === keys.ENTER && !event.shiftKey) {
37
37
  event.preventDefault();
38
38
  this.handleSubmitFollowUp();
39
39
  }
40
+
41
+ if (event.key === keys.ESC) {
42
+ event.stopPropagation();
43
+ event.preventDefault();
44
+ this.refs.askFollowUpInput.blur();
45
+ }
40
46
  }
41
47
 
42
48
  handleSubmitFollowUp() {
@@ -48,14 +54,46 @@ export default class QuanticGeneratedAnswerFollowUpInput extends LightningElemen
48
54
  }
49
55
  this.sendSubmitFollowUpEvent();
50
56
  this.refs.askFollowUpInput.value = '';
57
+ this.syncTextWithReplica();
58
+ this.collapse();
51
59
  }
52
60
 
53
61
  handleFocus() {
54
62
  this._focused = true;
63
+ this.syncTextWithReplica();
64
+ this.expand();
55
65
  }
56
66
 
57
67
  handleBlur() {
58
68
  this._focused = false;
69
+ this.collapse();
70
+ }
71
+
72
+ handleInput() {
73
+ this.expand();
74
+ this.syncTextWithReplica();
75
+ }
76
+
77
+ /**
78
+ * Syncs the textarea value with the expander's replicated value for seamless CSS transitions.
79
+ */
80
+ syncTextWithReplica() {
81
+ const expander = this.refs.expander;
82
+ if (expander) {
83
+ expander.dataset.replicatedValue = this.refs.askFollowUpInput.value;
84
+ }
85
+ }
86
+
87
+ expand() {
88
+ this.refs.expander?.classList.add('follow-up-input__expander--expanded');
89
+ }
90
+
91
+ collapse() {
92
+ const expander = this.refs.expander;
93
+ if (expander) {
94
+ expander.classList.remove('follow-up-input__expander--expanded');
95
+ delete expander.dataset.replicatedValue;
96
+ }
59
97
  }
60
98
 
61
99
  /**
@@ -74,6 +112,6 @@ export default class QuanticGeneratedAnswerFollowUpInput extends LightningElemen
74
112
  }
75
113
 
76
114
  get inputContainerClasses() {
77
- return `follow-up-input__input-container slds-box slds-grid slds-box_xx-small ${this._focused ? 'follow-up-input__input-container--focused' : ''}`;
115
+ return `follow-up-input__container slds-is-relative slds-grid slds-box slds-p-around_none ${this._focused ? 'follow-up-input__container--focused' : ''}`;
78
116
  }
79
117
  }