@constructor-io/constructorio-ui-pia 2.4.0 → 2.6.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.
- package/dist/constructorio-ui-pia-bundled.js +60 -60
- package/lib/cjs/components/CioPia/CioPia.js +10 -5
- package/lib/cjs/components/Input/Input.js +2 -2
- package/lib/cjs/components/PiaConversation/PiaConversation.js +4 -4
- package/lib/cjs/components/PiaConversation/PiaModal.js +8 -4
- package/lib/cjs/hooks/useAnswerResults.js +2 -4
- package/lib/cjs/hooks/useCioPia.js +5 -1
- package/lib/cjs/hooks/useConversation.js +61 -15
- package/lib/cjs/hooks/useViewportCallbacks.js +50 -0
- package/lib/cjs/stories/assets/storybook-styles.css +89 -0
- package/lib/cjs/utils/contentTransformers.js +8 -2
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/components/CioPia/CioPia.js +10 -5
- package/lib/mjs/components/Input/Input.js +2 -2
- package/lib/mjs/components/PiaConversation/PiaConversation.js +4 -4
- package/lib/mjs/components/PiaConversation/PiaModal.js +8 -4
- package/lib/mjs/hooks/useAnswerResults.js +3 -5
- package/lib/mjs/hooks/useCioPia.js +5 -1
- package/lib/mjs/hooks/useConversation.js +60 -15
- package/lib/mjs/hooks/useViewportCallbacks.js +45 -0
- package/lib/mjs/stories/assets/storybook-styles.css +89 -0
- package/lib/mjs/utils/contentTransformers.js +7 -2
- package/lib/mjs/version.js +1 -1
- package/lib/types/components/Input/Input.d.ts +2 -1
- package/lib/types/components/PiaConversation/PiaConversation.d.ts +4 -1
- package/lib/types/components/PiaConversation/PiaModal.d.ts +4 -1
- package/lib/types/hooks/mocks/MockConstructorIOClient.d.ts +1 -1
- package/lib/types/hooks/useCioPia.d.ts +1 -0
- package/lib/types/hooks/useConversation.d.ts +4 -1
- package/lib/types/hooks/useViewportCallbacks.d.ts +9 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/types.d.ts +18 -2
- package/lib/types/utils/contentTransformers.d.ts +26 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
1
2
|
import useAnswerResults from './useAnswerResults';
|
|
2
3
|
import useCioClient from './useCioClient';
|
|
3
4
|
import useSuggestedQuestions from './useSuggestedQuestions';
|
|
4
5
|
export default function useCioPia(props) {
|
|
5
|
-
const { apiKey, itemId, variationId, threadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
|
|
6
|
+
const { apiKey, itemId, variationId, threadId: providedThreadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
|
|
7
|
+
const [generatedThreadId] = useState(() => crypto.randomUUID());
|
|
8
|
+
const threadId = providedThreadId || generatedThreadId;
|
|
6
9
|
const defaultClient = useCioClient({ apiKey });
|
|
7
10
|
const client = providedClient || defaultClient;
|
|
8
11
|
const suggestedQuestions = useSuggestedQuestions({
|
|
@@ -20,6 +23,7 @@ export default function useCioPia(props) {
|
|
|
20
23
|
formatImageUrl,
|
|
21
24
|
});
|
|
22
25
|
return {
|
|
26
|
+
threadId,
|
|
23
27
|
suggestedQuestions,
|
|
24
28
|
answers,
|
|
25
29
|
};
|
|
@@ -1,22 +1,45 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
export default function useConversation({ pia, itemId, isConversation, callbacks, }) {
|
|
3
|
-
const { suggestedQuestions, answers } = pia;
|
|
3
|
+
const { suggestedQuestions, answers, threadId } = pia;
|
|
4
4
|
const { getAnswer } = answers;
|
|
5
|
+
const context = useMemo(() => ({ itemId, threadId }), [itemId, threadId]);
|
|
5
6
|
const [currentQuestion, setCurrentQuestion] = useState('');
|
|
6
7
|
const [displayedQuestions, setDisplayedQuestions] = useState([]);
|
|
7
8
|
const [conversationHistory, setConversationHistory] = useState([]);
|
|
8
9
|
const entryIdRef = useRef(0);
|
|
9
10
|
const prevAnswerValueRef = useRef(answers.data?.value);
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
const callbacksRef = useRef(callbacks);
|
|
12
|
+
const contextRef = useRef(context);
|
|
13
|
+
const lastQuestionRef = useRef('');
|
|
14
|
+
const lastSourceRef = useRef('user');
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
callbacksRef.current = callbacks;
|
|
17
|
+
}, [callbacks]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
contextRef.current = context;
|
|
20
|
+
}, [context]);
|
|
21
|
+
const submitQuestion = useCallback((question, source) => {
|
|
22
|
+
lastSourceRef.current = source;
|
|
23
|
+
lastQuestionRef.current = question;
|
|
12
24
|
setCurrentQuestion(question);
|
|
13
25
|
getAnswer(question);
|
|
14
26
|
if (isConversation) {
|
|
15
27
|
entryIdRef.current += 1;
|
|
16
28
|
const id = entryIdRef.current;
|
|
17
|
-
setConversationHistory((prev) => [...prev, { id, question, answer: '' }]);
|
|
29
|
+
setConversationHistory((prev) => [...prev, { id, question, answer: '', source }]);
|
|
18
30
|
}
|
|
19
|
-
}, [getAnswer, isConversation
|
|
31
|
+
}, [getAnswer, isConversation]);
|
|
32
|
+
const handleSubmitQuestion = useCallback((question) => {
|
|
33
|
+
callbacksRef.current?.onQuestionSubmit?.(question, contextRef.current, 'user');
|
|
34
|
+
submitQuestion(question, 'user');
|
|
35
|
+
}, [submitQuestion]);
|
|
36
|
+
const handleQuestionClick = useCallback((question) => {
|
|
37
|
+
callbacksRef.current?.onQuestionSubmit?.(question, contextRef.current, 'suggestion');
|
|
38
|
+
submitQuestion(question, 'suggestion');
|
|
39
|
+
}, [submitQuestion]);
|
|
40
|
+
const handleInputFocus = useCallback(() => {
|
|
41
|
+
callbacksRef.current?.onFocus?.(contextRef.current);
|
|
42
|
+
}, []);
|
|
20
43
|
const resetState = useCallback(() => {
|
|
21
44
|
setCurrentQuestion('');
|
|
22
45
|
setDisplayedQuestions(suggestedQuestions.data);
|
|
@@ -38,22 +61,41 @@ export default function useConversation({ pia, itemId, isConversation, callbacks
|
|
|
38
61
|
}, [answers.data]);
|
|
39
62
|
useEffect(() => {
|
|
40
63
|
const answerValue = answers.data?.value ?? '';
|
|
41
|
-
if (!
|
|
64
|
+
if (!answerValue)
|
|
42
65
|
return;
|
|
43
66
|
if (answerValue === prevAnswerValueRef.current)
|
|
44
67
|
return;
|
|
45
68
|
prevAnswerValueRef.current = answerValue;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
69
|
+
const answerThreadId = answers.data?.thread_id;
|
|
70
|
+
const qnaResultId = answers.data?.qna_result_id;
|
|
71
|
+
if (isConversation) {
|
|
72
|
+
setConversationHistory((prev) => {
|
|
73
|
+
if (prev.length === 0)
|
|
74
|
+
return prev;
|
|
75
|
+
const updated = [...prev];
|
|
76
|
+
updated[updated.length - 1] = {
|
|
77
|
+
...updated[updated.length - 1],
|
|
78
|
+
answer: answerValue,
|
|
79
|
+
items: answers.items,
|
|
80
|
+
threadId: answerThreadId,
|
|
81
|
+
qnaResultId,
|
|
82
|
+
};
|
|
83
|
+
callbacksRef.current?.onAnswer?.(updated, contextRef.current);
|
|
84
|
+
return updated;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const entry = {
|
|
89
|
+
id: entryIdRef.current,
|
|
90
|
+
question: lastQuestionRef.current,
|
|
52
91
|
answer: answerValue,
|
|
92
|
+
source: lastSourceRef.current,
|
|
53
93
|
items: answers.items,
|
|
94
|
+
threadId: answerThreadId,
|
|
95
|
+
qnaResultId,
|
|
54
96
|
};
|
|
55
|
-
|
|
56
|
-
}
|
|
97
|
+
callbacksRef.current?.onAnswer?.([entry], contextRef.current);
|
|
98
|
+
}
|
|
57
99
|
}, [isConversation, answers.data, answers.items]);
|
|
58
100
|
const currentAnswer = answers.data?.value ?? '';
|
|
59
101
|
const currentItems = answers.items ?? null;
|
|
@@ -67,7 +109,10 @@ export default function useConversation({ pia, itemId, isConversation, callbacks
|
|
|
67
109
|
currentItems,
|
|
68
110
|
isLoading,
|
|
69
111
|
error,
|
|
112
|
+
context,
|
|
70
113
|
handleSubmitQuestion,
|
|
114
|
+
handleQuestionClick,
|
|
115
|
+
handleInputFocus,
|
|
71
116
|
resetState,
|
|
72
117
|
};
|
|
73
118
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
export default function useViewportCallbacks({ callbacks, context, }) {
|
|
3
|
+
const callbacksRef = useRef(callbacks);
|
|
4
|
+
const contextRef = useRef(context);
|
|
5
|
+
const hasBeenVisibleRef = useRef(false);
|
|
6
|
+
const hasFiredOutOfViewRef = useRef(false);
|
|
7
|
+
const observerRef = useRef(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
callbacksRef.current = callbacks;
|
|
10
|
+
}, [callbacks]);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
contextRef.current = context;
|
|
13
|
+
}, [context]);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
return () => {
|
|
16
|
+
observerRef.current?.disconnect();
|
|
17
|
+
};
|
|
18
|
+
}, []);
|
|
19
|
+
const containerRef = useCallback((node) => {
|
|
20
|
+
if (observerRef.current) {
|
|
21
|
+
observerRef.current.disconnect();
|
|
22
|
+
observerRef.current = null;
|
|
23
|
+
}
|
|
24
|
+
if (!node)
|
|
25
|
+
return;
|
|
26
|
+
hasBeenVisibleRef.current = false;
|
|
27
|
+
hasFiredOutOfViewRef.current = false;
|
|
28
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
29
|
+
if (entry.isIntersecting && !hasBeenVisibleRef.current) {
|
|
30
|
+
hasBeenVisibleRef.current = true;
|
|
31
|
+
callbacksRef.current?.onView?.(contextRef.current);
|
|
32
|
+
}
|
|
33
|
+
else if (!entry.isIntersecting &&
|
|
34
|
+
hasBeenVisibleRef.current &&
|
|
35
|
+
!hasFiredOutOfViewRef.current) {
|
|
36
|
+
hasFiredOutOfViewRef.current = true;
|
|
37
|
+
callbacksRef.current?.onOutOfView?.(contextRef.current);
|
|
38
|
+
observer.disconnect();
|
|
39
|
+
}
|
|
40
|
+
}, { threshold: 0.5 });
|
|
41
|
+
observer.observe(node);
|
|
42
|
+
observerRef.current = observer;
|
|
43
|
+
}, []);
|
|
44
|
+
return { containerRef };
|
|
45
|
+
}
|
|
@@ -110,3 +110,92 @@ div.badge-wrapper code {
|
|
|
110
110
|
background: #d8e8fd;
|
|
111
111
|
color: #3c70bf;
|
|
112
112
|
}
|
|
113
|
+
|
|
114
|
+
.cio-flow-diagram {
|
|
115
|
+
display: flex;
|
|
116
|
+
flex-direction: column;
|
|
117
|
+
gap: 4px;
|
|
118
|
+
margin: 24px 0 0;
|
|
119
|
+
font-family: system-ui, sans-serif;
|
|
120
|
+
font-size: 14px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.cio-flow-diagram .flow-step {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: 12px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.cio-flow-diagram .flow-box {
|
|
130
|
+
padding: 10px 16px;
|
|
131
|
+
border-radius: 8px;
|
|
132
|
+
min-width: 220px;
|
|
133
|
+
text-align: center;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.cio-flow-diagram .flow-box--consumer {
|
|
137
|
+
background: #eff6ff;
|
|
138
|
+
border: 1px solid #bfdbfe;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.cio-flow-diagram .flow-box--internal {
|
|
142
|
+
background: #f5f3ff;
|
|
143
|
+
border: 1px solid #ddd6fe;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.cio-flow-diagram .flow-box--output {
|
|
147
|
+
background: #f0fdf4;
|
|
148
|
+
border: 1px solid #bbf7d0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.cio-flow-diagram .flow-arrow {
|
|
152
|
+
margin-left: 110px;
|
|
153
|
+
color: #9ca3af;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.cio-flow-diagram .flow-label {
|
|
157
|
+
font-size: 12px;
|
|
158
|
+
color: #9ca3af;
|
|
159
|
+
font-style: italic;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.cio-flow-diagram .flow-callback {
|
|
163
|
+
font-size: 12px;
|
|
164
|
+
color: #059669;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.cio-flow-diagram .flow-box-subtitle {
|
|
168
|
+
font-size: 12px;
|
|
169
|
+
color: #6b7280;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.cio-flow-legend {
|
|
173
|
+
display: flex;
|
|
174
|
+
gap: 16px;
|
|
175
|
+
margin: 32px 0 16px;
|
|
176
|
+
font-size: 12px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.cio-flow-legend .legend-swatch {
|
|
180
|
+
display: inline-block;
|
|
181
|
+
width: 12px;
|
|
182
|
+
height: 12px;
|
|
183
|
+
border-radius: 3px;
|
|
184
|
+
margin-right: 4px;
|
|
185
|
+
vertical-align: middle;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.cio-flow-legend .legend-swatch--consumer {
|
|
189
|
+
background: #eff6ff;
|
|
190
|
+
border: 1px solid #bfdbfe;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.cio-flow-legend .legend-swatch--internal {
|
|
194
|
+
background: #f5f3ff;
|
|
195
|
+
border: 1px solid #ddd6fe;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.cio-flow-legend .legend-swatch--output {
|
|
199
|
+
background: #f0fdf4;
|
|
200
|
+
border: 1px solid #bbf7d0;
|
|
201
|
+
}
|
|
@@ -8,9 +8,14 @@ export function sanitizeHtml(html) {
|
|
|
8
8
|
return '';
|
|
9
9
|
return DOMPurify.sanitize(html, purifyConfig);
|
|
10
10
|
}
|
|
11
|
-
export function renderMarkdown(content) {
|
|
11
|
+
export function renderMarkdown(content, options) {
|
|
12
12
|
if (!content)
|
|
13
13
|
return '';
|
|
14
|
-
const html = marked.parse(content, { async: false });
|
|
14
|
+
const html = marked.parse(content, { async: false, breaks: true });
|
|
15
|
+
if (options?.sanitize) {
|
|
16
|
+
const purifier = DOMPurify(window);
|
|
17
|
+
const config = { ...purifyConfig, FORBID_TAGS: [...(purifyConfig.FORBID_TAGS ?? [])] };
|
|
18
|
+
return options.sanitize(purifier, html, { config });
|
|
19
|
+
}
|
|
15
20
|
return DOMPurify.sanitize(html, purifyConfig);
|
|
16
21
|
}
|
package/lib/mjs/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '2.
|
|
1
|
+
export default '2.6.3';
|
|
@@ -6,7 +6,8 @@ interface InputProps {
|
|
|
6
6
|
/** @deprecated Use the `translations` prop instead. */
|
|
7
7
|
placeholder?: string;
|
|
8
8
|
onSubmit: (value: string) => void;
|
|
9
|
+
onFocus?: () => void;
|
|
9
10
|
translations?: Translations;
|
|
10
11
|
}
|
|
11
|
-
declare function Input({ value: providedValue, placeholder, disabled, onSubmit, translations, }: InputProps): React.JSX.Element;
|
|
12
|
+
declare function Input({ value: providedValue, placeholder, disabled, onSubmit, onFocus, translations, }: InputProps): React.JSX.Element;
|
|
12
13
|
export default Input;
|
|
@@ -4,5 +4,8 @@ import { ConversationHistoryProps } from '../ConversationHistory/ConversationHis
|
|
|
4
4
|
export interface PiaConversationProps extends ConversationHistoryProps {
|
|
5
5
|
displayedQuestions: Question[];
|
|
6
6
|
handleSubmitQuestion: (question: string) => void;
|
|
7
|
+
handleQuestionClick: (question: string) => void;
|
|
8
|
+
containerRef?: (node: HTMLDivElement | null) => void;
|
|
9
|
+
onInputFocus?: () => void;
|
|
7
10
|
}
|
|
8
|
-
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, }: PiaConversationProps): React.JSX.Element;
|
|
11
|
+
export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, onInputFocus, }: PiaConversationProps): React.JSX.Element;
|
|
@@ -3,10 +3,13 @@ import { Translations, Question, CioPiaComponentOverrides } from '../../types';
|
|
|
3
3
|
interface PiaModalProps {
|
|
4
4
|
initialQuestions: Question[];
|
|
5
5
|
handleSubmitQuestion: (question: string) => void;
|
|
6
|
+
handleQuestionClick: (question: string) => void;
|
|
7
|
+
containerRef?: (node: HTMLDivElement | null) => void;
|
|
6
8
|
isLoading: boolean;
|
|
7
9
|
componentOverrides?: CioPiaComponentOverrides;
|
|
8
10
|
translations?: Translations;
|
|
11
|
+
onInputFocus?: () => void;
|
|
9
12
|
onClose?: () => void;
|
|
10
13
|
}
|
|
11
|
-
export default function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, componentOverrides, translations, onClose, children, }: PropsWithChildren<PiaModalProps>): React.JSX.Element;
|
|
14
|
+
export default function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, isLoading, componentOverrides, translations, onInputFocus, onClose, children, }: PropsWithChildren<PiaModalProps>): React.JSX.Element;
|
|
12
15
|
export {};
|
|
@@ -2,7 +2,7 @@ import { ConstructorClientOptions } from '@constructor-io/constructorio-client-j
|
|
|
2
2
|
import { Recommendations, Browse, Search, Tracker, Quizzes } from '@constructor-io/constructorio-client-javascript/lib/types/constructorio';
|
|
3
3
|
import MockAgent from './agent';
|
|
4
4
|
declare class MockConstructorIOClient {
|
|
5
|
-
|
|
5
|
+
options: ConstructorClientOptions;
|
|
6
6
|
search: Search;
|
|
7
7
|
browse: Browse;
|
|
8
8
|
recommendations: Recommendations;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Callbacks, ConversationEntry, Question, Item } from '../types';
|
|
1
|
+
import { Callbacks, ConversationEntry, PiaCallbackContext, Question, Item } from '../types';
|
|
2
2
|
import { UseCioPiaReturn } from './useCioPia';
|
|
3
3
|
export interface UseConversationProps {
|
|
4
4
|
pia: UseCioPiaReturn;
|
|
@@ -14,7 +14,10 @@ export interface UseConversationReturn {
|
|
|
14
14
|
currentItems: Item[] | null;
|
|
15
15
|
isLoading: boolean;
|
|
16
16
|
error: Error | null;
|
|
17
|
+
context: PiaCallbackContext;
|
|
17
18
|
handleSubmitQuestion: (question: string) => void;
|
|
19
|
+
handleQuestionClick: (question: string) => void;
|
|
20
|
+
handleInputFocus: () => void;
|
|
18
21
|
resetState: () => void;
|
|
19
22
|
}
|
|
20
23
|
export default function useConversation({ pia, itemId, isConversation, callbacks, }: UseConversationProps): UseConversationReturn;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Callbacks, PiaCallbackContext } from '../types';
|
|
2
|
+
export interface UseViewportCallbacksProps {
|
|
3
|
+
callbacks?: Callbacks;
|
|
4
|
+
context: PiaCallbackContext;
|
|
5
|
+
}
|
|
6
|
+
export interface UseViewportCallbacksReturn {
|
|
7
|
+
containerRef: (node: HTMLDivElement | null) => void;
|
|
8
|
+
}
|
|
9
|
+
export default function useViewportCallbacks({ callbacks, context, }: UseViewportCallbacksProps): UseViewportCallbacksReturn;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import CioPia from './components/CioPia';
|
|
|
2
2
|
export { default as CioPia } from './components/CioPia';
|
|
3
3
|
export type { CioPiaProps } from './components/CioPia';
|
|
4
4
|
export { sanitizeHtml, renderMarkdown } from './utils/contentTransformers';
|
|
5
|
+
export type { RenderMarkdownOptions, SanitizeOptions } from './utils/contentTransformers';
|
|
5
6
|
export * from './types';
|
|
6
7
|
export default CioPia;
|
package/lib/types/types.d.ts
CHANGED
|
@@ -60,13 +60,26 @@ export type Translations = {
|
|
|
60
60
|
'Learn More.'?: string;
|
|
61
61
|
'Ask about this product'?: string;
|
|
62
62
|
};
|
|
63
|
+
export type QuestionSource = 'user' | 'suggestion';
|
|
64
|
+
export interface PiaCallbackContext {
|
|
65
|
+
itemId: string;
|
|
66
|
+
threadId: string;
|
|
67
|
+
}
|
|
63
68
|
export interface Callbacks {
|
|
64
|
-
/** Called when a question is submitted (
|
|
65
|
-
onQuestionSubmit?: (question: string) => void;
|
|
69
|
+
/** Called when a question is submitted (typed or suggested question clicked). */
|
|
70
|
+
onQuestionSubmit?: (question: string, context: PiaCallbackContext, source: QuestionSource) => void;
|
|
66
71
|
/** Called when a product card in the carousel is clicked. */
|
|
67
72
|
onProductCardClick?: (item: Item) => void;
|
|
68
73
|
/** Called when the user submits positive or negative feedback on an answer. */
|
|
69
74
|
onFeedback?: (type: FeedbackType) => void;
|
|
75
|
+
/** Called when a new answer is received. Passes the full conversation history. */
|
|
76
|
+
onAnswer?: (history: ConversationEntry[], context: PiaCallbackContext) => void;
|
|
77
|
+
/** Called when the user focuses the input field. */
|
|
78
|
+
onFocus?: (context: PiaCallbackContext) => void;
|
|
79
|
+
/** Called when the widget enters the viewport. */
|
|
80
|
+
onView?: (context: PiaCallbackContext) => void;
|
|
81
|
+
/** Called when the widget leaves the viewport. */
|
|
82
|
+
onOutOfView?: (context: PiaCallbackContext) => void;
|
|
70
83
|
}
|
|
71
84
|
/** Formatter functions for transforming data before display. */
|
|
72
85
|
export interface Formatters {
|
|
@@ -82,7 +95,10 @@ export interface ConversationEntry {
|
|
|
82
95
|
id: number;
|
|
83
96
|
question: string;
|
|
84
97
|
answer: string;
|
|
98
|
+
source: QuestionSource;
|
|
85
99
|
items?: Item[] | null;
|
|
100
|
+
threadId?: string;
|
|
101
|
+
qnaResultId?: string;
|
|
86
102
|
}
|
|
87
103
|
/**
|
|
88
104
|
* Render props passed to CioPia children function
|
|
@@ -1,2 +1,27 @@
|
|
|
1
|
+
import DOMPurify from 'dompurify';
|
|
2
|
+
export interface SanitizeOptions {
|
|
3
|
+
config: DOMPurify.Config;
|
|
4
|
+
}
|
|
5
|
+
/** Options for {@link renderMarkdown}. */
|
|
6
|
+
export interface RenderMarkdownOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Override the default DOMPurify sanitization step.
|
|
9
|
+
* Called with an isolated DOMPurify instance, the parsed HTML string,
|
|
10
|
+
* and an options object containing the default config. Must return the sanitized HTML string.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* sanitize: (purifier, html, { config }) => {
|
|
14
|
+
* purifier.addHook('uponSanitizeAttribute', (node, event) => {
|
|
15
|
+
* if (node.tagName === 'A' && event.attrName === 'href') {
|
|
16
|
+
* if (/^javascript:window\.openChat\(\)$/.test(event.attrValue)) {
|
|
17
|
+
* event.forceKeepAttr = true;
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* });
|
|
21
|
+
* return purifier.sanitize(html, config);
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
sanitize?: (purifier: typeof DOMPurify, html: string, options: SanitizeOptions) => string;
|
|
25
|
+
}
|
|
1
26
|
export declare function sanitizeHtml(html: string): string;
|
|
2
|
-
export declare function renderMarkdown(content: string): string;
|
|
27
|
+
export declare function renderMarkdown(content: string, options?: RenderMarkdownOptions): string;
|
package/lib/types/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "2.
|
|
1
|
+
declare const _default: "2.6.3";
|
|
2
2
|
export default _default;
|
package/package.json
CHANGED