andy-widget-react 2.3.1 → 2.3.2
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/README.md +1 -1
- package/dist/index.cjs +29 -9
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +29 -9
- package/dist/index.esm.js.map +1 -0
- package/package.json +2 -2
- package/src/AndyChat.tsx +6 -5
- package/src/SupportChat.tsx +2 -2
package/README.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1102,6 +1102,17 @@ const generateSessionId = () => {
|
|
|
1102
1102
|
}
|
|
1103
1103
|
};
|
|
1104
1104
|
|
|
1105
|
+
const HTML_ESCAPES = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Escape a value for HTML element content and quoted attribute values.
|
|
1109
|
+
* Use it on every value interpolated into an `innerHTML` template; it
|
|
1110
|
+
* stringifies exactly as `${value}` would.
|
|
1111
|
+
* @param {unknown} value - The value to escape
|
|
1112
|
+
* @returns {string} The escaped text
|
|
1113
|
+
*/
|
|
1114
|
+
const escapeHtml = value => String(value).replace(/[&<>"']/g, character => HTML_ESCAPES[character]);
|
|
1115
|
+
|
|
1105
1116
|
/**
|
|
1106
1117
|
* Sanitize URL to prevent XSS attacks
|
|
1107
1118
|
* @param {string} url - The URL to sanitize
|
|
@@ -1124,6 +1135,12 @@ const sanitizeUrl = url => {
|
|
|
1124
1135
|
return trimmedUrl
|
|
1125
1136
|
}
|
|
1126
1137
|
|
|
1138
|
+
// Root-relative paths stay on the host site. `//`, `/\` and the tabs or
|
|
1139
|
+
// newlines browsers strip from URLs could turn one into another host.
|
|
1140
|
+
if (/^\/(?![/\\])[^\t\n\r]*$/.test(trimmedUrl)) {
|
|
1141
|
+
return trimmedUrl
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1127
1144
|
// If no protocol specified, assume https for regular URLs
|
|
1128
1145
|
if (!lowerUrl.includes(':') && !lowerUrl.startsWith('//')) {
|
|
1129
1146
|
return 'https://' + trimmedUrl
|
|
@@ -1134,17 +1151,19 @@ const sanitizeUrl = url => {
|
|
|
1134
1151
|
};
|
|
1135
1152
|
|
|
1136
1153
|
/**
|
|
1137
|
-
* Parse markdown text to HTML
|
|
1154
|
+
* Parse markdown text to HTML. The text is escaped first, so any HTML in it
|
|
1155
|
+
* renders as text and the result is safe for `innerHTML`.
|
|
1138
1156
|
* @param {string} text - The markdown text to parse
|
|
1139
1157
|
* @returns {string} The parsed HTML
|
|
1140
1158
|
*/
|
|
1141
1159
|
const parseMarkdown = text => {
|
|
1142
1160
|
if (!text) return ''
|
|
1143
1161
|
|
|
1144
|
-
let html = text;
|
|
1162
|
+
let html = escapeHtml(text);
|
|
1145
1163
|
|
|
1146
1164
|
// Handle links first (before bold/italic to avoid conflicts)
|
|
1147
|
-
// Match [text](url) format
|
|
1165
|
+
// Match [text](url) format. Both parts are already escaped, so a quote
|
|
1166
|
+
// cannot leave the href attribute.
|
|
1148
1167
|
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, linkText, url) => {
|
|
1149
1168
|
const sanitizedUrl = sanitizeUrl(url);
|
|
1150
1169
|
const isExternal = sanitizedUrl.startsWith('http://') || sanitizedUrl.startsWith('https://');
|
|
@@ -4114,7 +4133,7 @@ const SupportPanel = ({ support, lang, orientation = 'right', initialOpen = fals
|
|
|
4114
4133
|
const errorText = state.error === 'ticket_resolved' ? strings.resolvedReply : ['expired', 'unknown_key', 'malformed', 'authentication_required', 'invalid_signature'].includes(state.error || '') ? strings.auth : state.error === 'permission_denied' ? strings.denied : strings.error;
|
|
4115
4134
|
const promise = state.ticket?.replyPromise || state.config?.replyPromise;
|
|
4116
4135
|
const promiseText = !promise ? null : promise.minutes === promise.businessDayMinutes ? strings.businessDay : promise.minutes % 60 === 0 ? `${promise.minutes / 60} ${strings.hours}` : `${promise.minutes} ${strings.minutes}`;
|
|
4117
|
-
return jsxRuntime.jsx("div", { ref: host, className: `andy-support-host andy-support-host--${orientation}`, children: portal && ReactDOM.createPortal(jsxRuntime.jsxs("div", { className: 'andy-support', "data-private": true, "data-ph-no-capture": true, "data-sentry-block": true, lang: replyLanguage, children: [!open && jsxRuntime.jsxs("button", { type: 'button', className: 'andy-support__launcher', title: tooltip, onClick: () => setOpen(true), children: [jsxRuntime.jsxs("span", { children: [strings.support, " \u00B7 ", title, " ", state.unreadCount > 0 && unread] }), jsxRuntime.jsx("span", { "aria-hidden": 'true', children: "\u2197" })] }), open && jsxRuntime.jsxs("section", { className: 'andy-support__panel', role: 'dialog', "aria-label": `${strings.support} · ${title}`, children: [jsxRuntime.jsxs("header", { className: 'andy-support__header', children: [state.view !== 'conversation' && jsxRuntime.jsx("button", { type: 'button', "aria-label": strings.back, onClick: () => state.view === 'request' ? void controller?.showRequests() : controller?.back(), children: "\u2039" }), jsxRuntime.jsx("span", { className: 'andy-support__mark', "aria-hidden": 'true', children: title.slice(0, 1) }), jsxRuntime.jsxs("div", { className: 'andy-support__identity', children: [jsxRuntime.jsx("strong", { children: title }), jsxRuntime.jsx("small", { children: strings.support })] }), jsxRuntime.jsx("button", { type: 'button', "aria-label": strings.menu, "aria-expanded": menu, disabled: !state.config, onClick: () => setMenu(!menu), children: "\u00B7\u00B7\u00B7" }), jsxRuntime.jsx("button", { type: 'button', "aria-label": strings.close, onClick: () => setOpen(false), children: "\u00D7" }), menu && jsxRuntime.jsxs("nav", { className: 'andy-support__menu', "aria-label": strings.menu, children: [jsxRuntime.jsx("button", { type: 'button', onClick: () => choose(() => controller?.newConversation()), children: strings.new }), jsxRuntime.jsx("button", { type: 'button', onClick: () => choose(escalate), children: strings.team }), jsxRuntime.jsxs("button", { type: 'button', onClick: () => choose(() => void controller?.showRequests()), children: [strings.requests, " ", state.unreadCount > 0 && unread] })] })] }), jsxRuntime.jsxs("div", { className: 'andy-support__content', ref: messages, children: [state.loading && jsxRuntime.jsx("p", { role: 'status', children: strings.loading }), state.view === 'conversation' && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [state.messages.map((message, index) => jsxRuntime.jsx("div", { className: `andy-support__message andy-support__message--${message.role}`, children: message.content }, index)), state.config && state.messages.length === 1 && jsxRuntime.jsx("div", { className: 'andy-support__questions', children: state.config.questions.map(question => jsxRuntime.jsx("button", { type: 'button', disabled: state.busy, onClick: () => void controller?.send(question), children: question }, question)) }), state.busy && jsxRuntime.jsx("p", { className: 'andy-support__muted', role: 'status', children: "\u00B7\u00B7\u00B7" }), state.messages.length > 1 && !state.busy && jsxRuntime.jsxs("button", { type: 'button', className: 'andy-support__secondary', onClick: escalate, children: [strings.team, " \u2197"] })] }), state.view === 'form' && jsxRuntime.jsxs("form", { className: 'andy-support__form', onSubmit: event => { event.preventDefault(); void controller?.submit(subject, body, replyLanguage); }, children: [jsxRuntime.jsx("h2", { children: strings.team }), jsxRuntime.jsxs("label", { children: [strings.subject, jsxRuntime.jsx("input", { required: true, maxLength: 200, value: state.submission?.subject ?? subject, readOnly: !!state.submission, disabled: state.busy, onChange: event => setSubject(event.target.value) })] }), jsxRuntime.jsxs("label", { children: [strings.detail, jsxRuntime.jsx("textarea", { required: true, maxLength: 20000, rows: 5, value: state.submission?.body ?? body, readOnly: !!state.submission, disabled: state.busy, onChange: event => setBody(event.target.value) })] }), jsxRuntime.jsxs("details", { className: 'andy-support__transcript', children: [jsxRuntime.jsxs("summary", { children: [strings.notice, " \u00B7 ", state.transcript.length, " ", state.transcript.length === 1 ? strings.transcriptSingular : strings.transcript] }), state.transcript.map((message, index) => jsxRuntime.jsx("p", { children: message.content }, index))] }), jsxRuntime.jsx("p", { className: 'andy-support__muted', children: strings.consent }), jsxRuntime.jsx("button", { type: 'submit', className: 'andy-support__primary', disabled: state.busy || !subject.trim() || !body.trim(), children: state.busy ? strings.loading : strings.submit })] }), state.view === 'receipt' && state.ticket && jsxRuntime.jsxs("div", { className: 'andy-support__receipt', children: [jsxRuntime.jsx("span", { className: 'andy-support__check', "aria-hidden": 'true', children: "\u2713" }), jsxRuntime.jsx("h2", { children: strings.receipt }), jsxRuntime.jsxs("strong", { children: ["#", state.ticket.number] }), jsxRuntime.jsx("p", { children: state.ticket.subject }), promiseText && jsxRuntime.jsxs("p", { children: [strings.promise, " ", jsxRuntime.jsx("strong", { children: promiseText }), "."] }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-support__primary', onClick: () => void controller?.showRequests(), children: strings.requests })] }), state.view === 'requests' && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h2", { children: strings.requests }), state.tickets.map(ticketRow), !state.busy && !state.error && !state.tickets.length && jsxRuntime.jsx("p", { className: 'andy-support__muted', children: strings.empty })] }), state.view === 'request' && state.ticket && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("h2", { children: ["#", state.ticket.number, " \u00B7 ", state.ticket.subject] }), jsxRuntime.jsxs("p", { className: 'andy-support__muted', children: [strings[state.ticket.status], state.ticket.reopened && ` · ${strings.reopened}`] }), state.entries.filter(entry => ['requester_message', 'public_reply'].includes(entry.kind)).map(entry => jsxRuntime.jsxs("article", { className: 'andy-support__entry', children: [jsxRuntime.jsx("strong", { children: entry.authorName }), jsxRuntime.jsx("p", { children: entry.body })] }, entry.id)), state.ticket.status === 'resolved' && !reopening && jsxRuntime.jsxs("div", { className: 'andy-support__request-actions', children: [jsxRuntime.jsx("button", { type: 'button', className: 'andy-support__primary', onClick: () => setReopening(true), children: strings.reopen }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-support__secondary', onClick: newProblem, children: strings.otherProblem })] })] }), state.error && jsxRuntime.jsxs("div", { className: 'andy-support__error', role: 'alert', children: [jsxRuntime.jsx("p", { children: errorText }), (!state.config || state.view === 'form' || state.view === 'requests' || (state.view === 'request' && state.error !== 'ticket_resolved' && (selectedTicketId || support.ticketId))) && jsxRuntime.jsx("button", { type: 'button', onClick: retry, disabled: state.busy, children: strings.retry })] })] }), state.view === 'conversation' && jsxRuntime.jsxs("form", { className: 'andy-support__composer', onSubmit: event => { event.preventDefault(); send(); }, children: [jsxRuntime.jsx("input", { "aria-label": strings.placeholder, placeholder: strings.placeholder, value: draft, maxLength: 10000, disabled: !state.config, onChange: event => setDraft(event.target.value) }), jsxRuntime.jsx("button", { type: 'submit', "aria-label": strings.send, disabled: state.busy || !state.config || !draft.trim(), children: "\u2191" })] }), state.view === 'request' && state.ticket && (state.ticket.status !== 'resolved' || reopening) && jsxRuntime.jsxs("form", { className: 'andy-support__followup', onSubmit: event => { event.preventDefault(); void followup(); }, children: [jsxRuntime.jsxs("label", { children: [reopening ? strings.reopening : strings.reply, jsxRuntime.jsx("textarea", { rows: 3, maxLength: 20000, required: true, value: state.followup?.body ?? replyDraft, readOnly: !!state.followup, disabled: state.busy, onChange: event => setReplyDraft(event.target.value) })] }), jsxRuntime.jsx("button", { type: 'submit', className: 'andy-support__primary', disabled: state.busy || !replyDraft.trim(), children: state.busy ? strings.loading : reopening ? strings.reopen : strings.send })] }), jsxRuntime.jsxs("footer", { className: 'andy-support__footer', children: [jsxRuntime.jsx("span", { children: strings.powered }), state.config?.branding.footer.map(link => jsxRuntime.jsx("a", { href: link.url, target: '_blank', rel: 'noopener noreferrer', children: link.label }, link.url))] })] })] }), portal) });
|
|
4136
|
+
return jsxRuntime.jsx("div", { ref: host, className: `andy-support-host andy-support-host--${orientation}`, children: portal && ReactDOM.createPortal(jsxRuntime.jsxs("div", { className: 'andy-support', "data-private": true, "data-ph-no-capture": true, "data-sentry-block": true, lang: replyLanguage, children: [!open && jsxRuntime.jsxs("button", { type: 'button', className: 'andy-support__launcher', title: tooltip, onClick: () => setOpen(true), children: [jsxRuntime.jsxs("span", { children: [strings.support, " \u00B7 ", title, " ", state.unreadCount > 0 && unread] }), jsxRuntime.jsx("span", { "aria-hidden": 'true', children: "\u2197" })] }), open && jsxRuntime.jsxs("section", { className: 'andy-support__panel', role: 'dialog', "aria-label": `${strings.support} · ${title}`, children: [jsxRuntime.jsxs("header", { className: 'andy-support__header', children: [state.view !== 'conversation' && jsxRuntime.jsx("button", { type: 'button', "aria-label": strings.back, onClick: () => state.view === 'request' ? void controller?.showRequests() : controller?.back(), children: "\u2039" }), jsxRuntime.jsx("span", { className: 'andy-support__mark', "aria-hidden": 'true', children: title.slice(0, 1) }), jsxRuntime.jsxs("div", { className: 'andy-support__identity', children: [jsxRuntime.jsx("strong", { children: title }), jsxRuntime.jsx("small", { children: strings.support })] }), jsxRuntime.jsx("button", { type: 'button', "aria-label": strings.menu, "aria-expanded": menu, disabled: !state.config, onClick: () => setMenu(!menu), children: "\u00B7\u00B7\u00B7" }), jsxRuntime.jsx("button", { type: 'button', "aria-label": strings.close, onClick: () => setOpen(false), children: "\u00D7" }), menu && jsxRuntime.jsxs("nav", { className: 'andy-support__menu', "aria-label": strings.menu, children: [jsxRuntime.jsx("button", { type: 'button', onClick: () => choose(() => controller?.newConversation()), children: strings.new }), jsxRuntime.jsx("button", { type: 'button', onClick: () => choose(escalate), children: strings.team }), jsxRuntime.jsxs("button", { type: 'button', onClick: () => choose(() => void controller?.showRequests()), children: [strings.requests, " ", state.unreadCount > 0 && unread] })] })] }), jsxRuntime.jsxs("div", { className: 'andy-support__content', ref: messages, children: [state.loading && jsxRuntime.jsx("p", { role: 'status', children: strings.loading }), state.view === 'conversation' && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [state.messages.map((message, index) => jsxRuntime.jsx("div", { className: `andy-support__message andy-support__message--${message.role}`, children: message.content }, index)), state.config && state.messages.length === 1 && jsxRuntime.jsx("div", { className: 'andy-support__questions', children: state.config.questions.map(question => jsxRuntime.jsx("button", { type: 'button', disabled: state.busy, onClick: () => void controller?.send(question), children: question }, question)) }), state.busy && jsxRuntime.jsx("p", { className: 'andy-support__muted', role: 'status', children: "\u00B7\u00B7\u00B7" }), state.messages.length > 1 && !state.busy && jsxRuntime.jsxs("button", { type: 'button', className: 'andy-support__secondary', onClick: escalate, children: [strings.team, " \u2197"] })] }), state.view === 'form' && jsxRuntime.jsxs("form", { className: 'andy-support__form', onSubmit: event => { event.preventDefault(); void controller?.submit(subject, body, replyLanguage); }, children: [jsxRuntime.jsx("h2", { children: strings.team }), jsxRuntime.jsxs("label", { children: [strings.subject, jsxRuntime.jsx("input", { required: true, maxLength: 200, value: state.submission?.subject ?? subject, readOnly: !!state.submission, disabled: state.busy, onChange: event => setSubject(event.target.value) })] }), jsxRuntime.jsxs("label", { children: [strings.detail, jsxRuntime.jsx("textarea", { required: true, maxLength: 20000, rows: 5, value: state.submission?.body ?? body, readOnly: !!state.submission, disabled: state.busy, onChange: event => setBody(event.target.value) })] }), jsxRuntime.jsxs("details", { className: 'andy-support__transcript', children: [jsxRuntime.jsxs("summary", { children: [strings.notice, " \u00B7 ", state.transcript.length, " ", state.transcript.length === 1 ? strings.transcriptSingular : strings.transcript] }), state.transcript.map((message, index) => jsxRuntime.jsx("p", { children: message.content }, index))] }), jsxRuntime.jsx("p", { className: 'andy-support__muted', children: strings.consent }), jsxRuntime.jsx("button", { type: 'submit', className: 'andy-support__primary', disabled: state.busy || !subject.trim() || !body.trim(), children: state.busy ? strings.loading : strings.submit })] }), state.view === 'receipt' && state.ticket && jsxRuntime.jsxs("div", { className: 'andy-support__receipt', children: [jsxRuntime.jsx("span", { className: 'andy-support__check', "aria-hidden": 'true', children: "\u2713" }), jsxRuntime.jsx("h2", { children: strings.receipt }), jsxRuntime.jsxs("strong", { children: ["#", state.ticket.number] }), jsxRuntime.jsx("p", { children: state.ticket.subject }), promiseText && jsxRuntime.jsxs("p", { children: [strings.promise, " ", jsxRuntime.jsx("strong", { children: promiseText }), "."] }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-support__primary', onClick: () => void controller?.showRequests(), children: strings.requests })] }), state.view === 'requests' && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h2", { children: strings.requests }), state.tickets.map(ticketRow), !state.busy && !state.error && !state.tickets.length && jsxRuntime.jsx("p", { className: 'andy-support__muted', children: strings.empty })] }), state.view === 'request' && state.ticket && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("h2", { children: ["#", state.ticket.number, " \u00B7 ", state.ticket.subject] }), jsxRuntime.jsxs("p", { className: 'andy-support__muted', children: [strings[state.ticket.status], state.ticket.reopened && ` · ${strings.reopened}`] }), state.entries.filter(entry => ['requester_message', 'public_reply'].includes(entry.kind)).map(entry => jsxRuntime.jsxs("article", { className: 'andy-support__entry', children: [jsxRuntime.jsx("strong", { children: entry.authorName }), jsxRuntime.jsx("p", { children: entry.body })] }, entry.id)), state.ticket.status === 'resolved' && !reopening && jsxRuntime.jsxs("div", { className: 'andy-support__request-actions', children: [jsxRuntime.jsx("button", { type: 'button', className: 'andy-support__primary', onClick: () => setReopening(true), children: strings.reopen }), jsxRuntime.jsx("button", { type: 'button', className: 'andy-support__secondary', onClick: newProblem, children: strings.otherProblem })] })] }), state.error && jsxRuntime.jsxs("div", { className: 'andy-support__error', role: 'alert', children: [jsxRuntime.jsx("p", { children: errorText }), (!state.config || state.view === 'form' || state.view === 'requests' || (state.view === 'request' && state.error !== 'ticket_resolved' && (selectedTicketId || support.ticketId))) && jsxRuntime.jsx("button", { type: 'button', onClick: retry, disabled: state.busy, children: strings.retry })] })] }), state.view === 'conversation' && jsxRuntime.jsxs("form", { className: 'andy-support__composer', onSubmit: event => { event.preventDefault(); send(); }, children: [jsxRuntime.jsx("input", { "aria-label": strings.placeholder, placeholder: strings.placeholder, value: draft, maxLength: 10000, disabled: !state.config, onChange: event => setDraft(event.target.value) }), jsxRuntime.jsx("button", { type: 'submit', "aria-label": strings.send, disabled: state.busy || !state.config || !draft.trim(), children: "\u2191" })] }), state.view === 'request' && state.ticket && (state.ticket.status !== 'resolved' || reopening) && jsxRuntime.jsxs("form", { className: 'andy-support__followup', onSubmit: event => { event.preventDefault(); void followup(); }, children: [jsxRuntime.jsxs("label", { children: [reopening ? strings.reopening : strings.reply, jsxRuntime.jsx("textarea", { rows: 3, maxLength: 20000, required: true, value: state.followup?.body ?? replyDraft, readOnly: !!state.followup, disabled: state.busy, onChange: event => setReplyDraft(event.target.value) })] }), jsxRuntime.jsx("button", { type: 'submit', className: 'andy-support__primary', disabled: state.busy || !replyDraft.trim(), children: state.busy ? strings.loading : reopening ? strings.reopen : strings.send })] }), jsxRuntime.jsxs("footer", { className: 'andy-support__footer', children: [jsxRuntime.jsx("span", { children: strings.powered }), state.config?.branding.footer.map(link => jsxRuntime.jsx("a", { href: sanitizeUrl(link.url), target: '_blank', rel: 'noopener noreferrer', children: link.label }, link.url))] })] })] }), portal) });
|
|
4118
4137
|
};
|
|
4119
4138
|
/** A host identity change also destroys local drafts and menu state before the next render. */
|
|
4120
4139
|
const SupportChat = props => jsxRuntime.jsx(SupportPanel, { ...props }, JSON.stringify([props.support.installationId, props.support.contextKey, props.support.apiBaseUrl]));
|
|
@@ -4657,7 +4676,7 @@ const SalesAndyChat = ({ embedId, tooltip, name, headline, description, welcomeM
|
|
|
4657
4676
|
bubble.className = 'andy-chat-bubble';
|
|
4658
4677
|
bubble.setAttribute('aria-label', strings.openChat);
|
|
4659
4678
|
const tooltipHTML = tooltip
|
|
4660
|
-
? `<span class="andy-chat-bubble__tooltip" role="tooltip">${tooltip}</span>`
|
|
4679
|
+
? `<span class="andy-chat-bubble__tooltip" role="tooltip">${escapeHtml(tooltip)}</span>`
|
|
4661
4680
|
: '';
|
|
4662
4681
|
bubble.innerHTML = `${CHAT_BUBBLE_DEFAULT_ICON}${tooltipHTML}`;
|
|
4663
4682
|
shadowRef.current.appendChild(bubble);
|
|
@@ -4682,7 +4701,7 @@ const SalesAndyChat = ({ embedId, tooltip, name, headline, description, welcomeM
|
|
|
4682
4701
|
bubble.classList.add('andy-chat-bubble--loaded');
|
|
4683
4702
|
}
|
|
4684
4703
|
const tooltipHTML = !isOpen && tooltip && !isPillStyle
|
|
4685
|
-
? `<span class="andy-chat-bubble__tooltip" role="tooltip">${tooltip}</span>`
|
|
4704
|
+
? `<span class="andy-chat-bubble__tooltip" role="tooltip">${escapeHtml(tooltip)}</span>`
|
|
4686
4705
|
: '';
|
|
4687
4706
|
const configUseBrandColor = config?.useBrandColor ?? true;
|
|
4688
4707
|
const isDarkTheme = config?.theme === 'dark';
|
|
@@ -4695,13 +4714,13 @@ const SalesAndyChat = ({ embedId, tooltip, name, headline, description, welcomeM
|
|
|
4695
4714
|
}
|
|
4696
4715
|
else if (isPillStyle && displayLabel) {
|
|
4697
4716
|
bubble.innerHTML = `
|
|
4698
|
-
<span class="andy-chat-bubble__label">${displayLabel}</span>
|
|
4699
|
-
<img src="${bubbleLogoUrl}" alt="Chat" class="andy-chat-bubble__icon--pill" style="${darkModeIconStyle}" />
|
|
4717
|
+
<span class="andy-chat-bubble__label">${escapeHtml(displayLabel)}</span>
|
|
4718
|
+
<img src="${escapeHtml(bubbleLogoUrl)}" alt="Chat" class="andy-chat-bubble__icon--pill" style="${darkModeIconStyle}" />
|
|
4700
4719
|
`;
|
|
4701
4720
|
}
|
|
4702
4721
|
else {
|
|
4703
4722
|
if (config?.logoUrl) {
|
|
4704
|
-
bubble.innerHTML = `<img src="${config.logoUrl}" alt="Chatbot Logo" class="andy-chat-bubble__logo" style="${darkModeIconStyle}" />${tooltipHTML}`;
|
|
4723
|
+
bubble.innerHTML = `<img src="${escapeHtml(config.logoUrl)}" alt="Chatbot Logo" class="andy-chat-bubble__logo" style="${darkModeIconStyle}" />${tooltipHTML}`;
|
|
4705
4724
|
}
|
|
4706
4725
|
else {
|
|
4707
4726
|
const defaultIconWithStyle = CHAT_BUBBLE_DEFAULT_ICON.replace('class="andy-chat-bubble__icon"', `class="andy-chat-bubble__icon" style="${darkModeIconStyle}"`);
|
|
@@ -5206,3 +5225,4 @@ exports.theme = theme;
|
|
|
5206
5225
|
exports.typography = typography;
|
|
5207
5226
|
exports.useAndyChat = useAndyChat;
|
|
5208
5227
|
exports.zIndex = zIndex;
|
|
5228
|
+
//# sourceMappingURL=index.cjs.map
|