@coveo/quantic 3.38.2 → 3.39.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.
@@ -1624,4 +1624,18 @@
1624
1624
  <protected>false</protected>
1625
1625
  <shortDescription>No generated answer available.</shortDescription>
1626
1626
  </labels>
1627
+ <labels>
1628
+ <fullName>quantic_AskFollowUp</fullName>
1629
+ <value>Ask follow-up</value>
1630
+ <language>en_US</language>
1631
+ <protected>false</protected>
1632
+ <shortDescription>Ask follow-up</shortDescription>
1633
+ </labels>
1634
+ <labels>
1635
+ <fullName>quantic_SubmitFollowUp</fullName>
1636
+ <value>Submit follow-up</value>
1637
+ <language>en_US</language>
1638
+ <protected>false</protected>
1639
+ <shortDescription>Submit follow-up</shortDescription>
1640
+ </labels>
1627
1641
  </CustomLabels>
@@ -0,0 +1,180 @@
1
+ import {buildCreateTestComponent, cleanup, flushPromises} from 'c/testUtils';
2
+ import QuanticGeneratedAnswerFollowUpInput from '../quanticGeneratedAnswerFollowUpInput';
3
+
4
+ jest.mock(
5
+ '@salesforce/label/c.quantic_SubmitFollowUp',
6
+ () => ({default: 'Submit follow-up'}),
7
+ {virtual: true}
8
+ );
9
+ jest.mock(
10
+ '@salesforce/label/c.quantic_AskFollowUp',
11
+ () => ({default: 'Ask follow-up'}),
12
+ {virtual: true}
13
+ );
14
+ jest.mock('c/quanticUtils', () => ({
15
+ keys: {ENTER: 'Enter'},
16
+ }));
17
+
18
+ const selectors = {
19
+ input: 'lightning-input',
20
+ submitButton: 'lightning-button-icon',
21
+ inputContainer: '.follow-up-input__input-container',
22
+ };
23
+
24
+ const createTestComponent = buildCreateTestComponent(
25
+ QuanticGeneratedAnswerFollowUpInput,
26
+ 'c-quantic-generated-answer-follow-up-input'
27
+ );
28
+
29
+ describe('c-quantic-generated-answer-follow-up-input', () => {
30
+ afterEach(() => {
31
+ cleanup();
32
+ });
33
+
34
+ it('should render the input and submit button', async () => {
35
+ const element = createTestComponent();
36
+ await flushPromises();
37
+
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();
45
+ });
46
+
47
+ describe('submitting a follow up', () => {
48
+ it('should dispatch #quantic__submitfollowup when pressing Enter', async () => {
49
+ const element = createTestComponent();
50
+ await flushPromises();
51
+
52
+ const handler = jest.fn();
53
+ element.addEventListener('quantic__submitfollowup', handler);
54
+
55
+ const input = element.shadowRoot.querySelector(selectors.input);
56
+ input.value = 'follow up question';
57
+ input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
58
+
59
+ expect(handler).toHaveBeenCalledTimes(1);
60
+ expect(handler.mock.calls[0][0].detail.value).toBe('follow up question');
61
+ });
62
+
63
+ it('should dispatch #quantic__submitfollowup when clicking the submit button', async () => {
64
+ const element = createTestComponent();
65
+ await flushPromises();
66
+
67
+ const handler = jest.fn();
68
+ element.addEventListener('quantic__submitfollowup', handler);
69
+
70
+ const input = element.shadowRoot.querySelector(selectors.input);
71
+ input.value = 'another question';
72
+
73
+ const submitButton = element.shadowRoot.querySelector(
74
+ selectors.submitButton
75
+ );
76
+ submitButton.click();
77
+
78
+ expect(handler).toHaveBeenCalledTimes(1);
79
+ expect(handler.mock.calls[0][0].detail.value).toBe('another question');
80
+ });
81
+
82
+ it('should clear the input and blur it after a successful submit', async () => {
83
+ const element = createTestComponent();
84
+ await flushPromises();
85
+
86
+ const input = element.shadowRoot.querySelector(selectors.input);
87
+ input.value = 'a question';
88
+ input.blur = jest.fn();
89
+
90
+ input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
91
+
92
+ expect(input.value).toBe('');
93
+ });
94
+ });
95
+
96
+ describe('when submission should be blocked', () => {
97
+ it('should not dispatch the event when submitButtonDisabled is true', async () => {
98
+ const element = createTestComponent({submitButtonDisabled: true});
99
+ await flushPromises();
100
+
101
+ const handler = jest.fn();
102
+ element.addEventListener('quantic__submitfollowup', handler);
103
+
104
+ const input = element.shadowRoot.querySelector(selectors.input);
105
+ input.value = 'a question';
106
+ input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
107
+
108
+ expect(handler).not.toHaveBeenCalled();
109
+ });
110
+
111
+ it('should not dispatch the event when input is whitespace only', async () => {
112
+ const element = createTestComponent();
113
+ await flushPromises();
114
+
115
+ const handler = jest.fn();
116
+ element.addEventListener('quantic__submitfollowup', handler);
117
+
118
+ const input = element.shadowRoot.querySelector(selectors.input);
119
+ input.value = ' ';
120
+ input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
121
+
122
+ expect(handler).not.toHaveBeenCalled();
123
+ });
124
+
125
+ it('should not dispatch the event when input is empty', async () => {
126
+ const element = createTestComponent();
127
+ await flushPromises();
128
+
129
+ const handler = jest.fn();
130
+ element.addEventListener('quantic__submitfollowup', handler);
131
+
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();
139
+
140
+ expect(handler).not.toHaveBeenCalled();
141
+ });
142
+ });
143
+
144
+ describe('focus and blur CSS class toggling', () => {
145
+ it('should add the focused class when the input is focused', async () => {
146
+ const element = createTestComponent();
147
+ await flushPromises();
148
+
149
+ const input = element.shadowRoot.querySelector(selectors.input);
150
+ input.dispatchEvent(new CustomEvent('focus'));
151
+ await flushPromises();
152
+
153
+ const container = element.shadowRoot.querySelector(
154
+ selectors.inputContainer
155
+ );
156
+ expect(container.classList).toContain(
157
+ 'follow-up-input__input-container--focused'
158
+ );
159
+ });
160
+
161
+ it('should remove the focused class when the input is blurred', async () => {
162
+ const element = createTestComponent();
163
+ await flushPromises();
164
+
165
+ const input = element.shadowRoot.querySelector(selectors.input);
166
+ input.dispatchEvent(new CustomEvent('focus'));
167
+ await flushPromises();
168
+
169
+ input.dispatchEvent(new CustomEvent('blur'));
170
+ await flushPromises();
171
+
172
+ const container = element.shadowRoot.querySelector(
173
+ selectors.inputContainer
174
+ );
175
+ expect(container.classList).not.toContain(
176
+ 'follow-up-input__input-container--focused'
177
+ );
178
+ });
179
+ });
180
+ });
@@ -0,0 +1,17 @@
1
+ :host {
2
+ --slds-c-input-shadow: none;
3
+ }
4
+
5
+ .follow-up-input__input {
6
+ border: none;
7
+ box-shadow: none;
8
+ 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;
13
+ }
14
+
15
+ .follow-up-input__input-container.follow-up-input__input-container--focused {
16
+ border-color: var(--lwc-brandAccessible, #0176d3);
17
+ }
@@ -0,0 +1,29 @@
1
+ <template>
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>
15
+ <lightning-button-icon
16
+ disabled={submitButtonDisabled}
17
+ onclick={handleSubmitFollowUp}
18
+ icon-name="utility:arrowup"
19
+ variant="brand"
20
+ class="slds-col slds-grow-none slds-align_absolute-center"
21
+ name="submit-follow-up"
22
+ title={labels.submitFollowUp}
23
+ aria-label={labels.submitFollowUp}
24
+ alternative-text={labels.submitFollowUp}
25
+ >
26
+ <label>{labels.submitFollowUp}</label>
27
+ </lightning-button-icon>
28
+ </div>
29
+ </template>
@@ -0,0 +1,79 @@
1
+ import submitFollowUp from '@salesforce/label/c.quantic_SubmitFollowUp';
2
+ import askFollowUp from '@salesforce/label/c.quantic_AskFollowUp';
3
+ import {keys} from 'c/quanticUtils';
4
+ import {api, LightningElement} from 'lwc';
5
+
6
+ /**
7
+ * The `QuanticGeneratedAnswerFollowUpInput` component allows users to submit follow-up questions related to a generated answer.
8
+ * @fires CustomEvent#quantic__submitfollowup
9
+ * @category Internal
10
+ * @example
11
+ * <c-quantic-generated-answer-follow-up-input></c-quantic-generated-answer-follow-up-input>
12
+ */
13
+ export default class QuanticGeneratedAnswerFollowUpInput extends LightningElement {
14
+ labels = {
15
+ submitFollowUp,
16
+ askFollowUp,
17
+ };
18
+
19
+ /**
20
+ * Whether the submit button is disabled.
21
+ * @type {boolean}
22
+ * @defaultValue false
23
+ */
24
+ @api
25
+ submitButtonDisabled = false;
26
+
27
+ /** @type {boolean} */
28
+ _focused = false;
29
+
30
+ handleKeyDown(event) {
31
+ // Let the browser commit IME text before handling shortcuts like Enter during composition.
32
+ if (event.isComposing || event.keyCode === 229) {
33
+ return;
34
+ }
35
+
36
+ if (event.key === keys.ENTER) {
37
+ event.preventDefault();
38
+ this.handleSubmitFollowUp();
39
+ }
40
+ }
41
+
42
+ handleSubmitFollowUp() {
43
+ if (
44
+ this.submitButtonDisabled ||
45
+ this.refs.askFollowUpInput.value.trim() === ''
46
+ ) {
47
+ return;
48
+ }
49
+ this.sendSubmitFollowUpEvent();
50
+ this.refs.askFollowUpInput.value = '';
51
+ }
52
+
53
+ handleFocus() {
54
+ this._focused = true;
55
+ }
56
+
57
+ handleBlur() {
58
+ this._focused = false;
59
+ }
60
+
61
+ /**
62
+ * Sends the "quantic__submitfollowup" event.
63
+ */
64
+ sendSubmitFollowUpEvent() {
65
+ this.dispatchEvent(
66
+ new CustomEvent('quantic__submitfollowup', {
67
+ bubbles: true,
68
+ composed: true,
69
+ detail: {
70
+ value: this.refs.askFollowUpInput.value,
71
+ },
72
+ })
73
+ );
74
+ }
75
+
76
+ 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' : ''}`;
78
+ }
79
+ }
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
3
+ <apiVersion>65.0</apiVersion>
4
+ <isExposed>false</isExposed>
5
+ </LightningComponentBundle>