@seamly/web-ui 19.1.1 → 20.0.0-beta.1
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/CHANGELOG.md +625 -0
- package/build/dist/lib/components.js +2 -1
- package/build/dist/lib/components.min.js +1 -1
- package/build/dist/lib/index.debug.js +183 -128
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.debug.min.js.LICENSE.txt +45 -25
- package/build/dist/lib/index.js +7290 -7753
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/index.min.js.LICENSE.txt +0 -5
- package/build/dist/lib/standalone.js +5785 -6255
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/standalone.min.js.LICENSE.txt +0 -5
- package/build/dist/lib/style-guide.js +10834 -4971
- package/build/dist/lib/style-guide.min.js +2 -1
- package/build/dist/lib/style-guide.min.js.LICENSE.txt +9 -0
- package/build/dist/lib/styles.css +1 -1
- package/package.json +1 -2
- package/src/icons/icon_file-32.svg +1 -1
- package/src/javascripts/api/errors/seamly-base-error.js +7 -0
- package/src/javascripts/api/index.js +48 -37
- package/src/javascripts/api/producer.js +5 -1
- package/src/javascripts/config.js +1 -5
- package/src/javascripts/domains/app/actions.js +22 -5
- package/src/javascripts/domains/config/actions.js +3 -0
- package/src/javascripts/domains/config/reducer.js +9 -0
- package/src/javascripts/domains/errors/index.js +5 -4
- package/src/javascripts/domains/forms/hooks.js +3 -1
- package/src/javascripts/domains/forms/provider.js +12 -0
- package/src/javascripts/domains/forms/reducer.js +2 -0
- package/src/javascripts/domains/i18n/hooks.js +2 -1
- package/src/javascripts/domains/i18n/reducer.js +2 -0
- package/src/javascripts/domains/interrupt/reducer.js +2 -2
- package/src/javascripts/domains/options/middleware.js +15 -31
- package/src/javascripts/domains/store/index.js +2 -1
- package/src/javascripts/domains/store/state-reducer.js +3 -8
- package/src/javascripts/domains/translations/components/options-dialog/form.js +1 -1
- package/src/javascripts/domains/translations/components/options-dialog/index.js +15 -1
- package/src/javascripts/domains/translations/reducer.js +2 -0
- package/src/javascripts/domains/visibility/actions.js +1 -1
- package/src/javascripts/domains/visibility/hooks.js +10 -8
- package/src/javascripts/domains/visibility/utils.js +1 -2
- package/src/javascripts/index.js +5 -3
- package/src/javascripts/lib/css.js +7 -1
- package/src/javascripts/lib/engine/index.js +4 -3
- package/src/javascripts/lib/external-api/index.js +38 -29
- package/src/javascripts/package/components.js +2 -1
- package/src/javascripts/style-guide/components/app.js +1 -1
- package/src/javascripts/style-guide/components/static-core.js +18 -4
- package/src/javascripts/style-guide/states.js +203 -298
- package/src/javascripts/ui/components/chat-app.js +1 -1
- package/src/javascripts/ui/components/conversation/component-filter.js +6 -0
- package/src/javascripts/ui/components/conversation/event/carousel-component/index.js +8 -1
- package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js +2 -3
- package/src/javascripts/ui/components/conversation/event/conversation-suggestions.js +70 -0
- package/src/javascripts/ui/components/conversation/event/participant.js +2 -5
- package/src/javascripts/ui/components/conversation/event/splash.js +26 -0
- package/src/javascripts/ui/components/conversation/event/text.js +1 -2
- package/src/javascripts/ui/components/core/seamly-core.js +12 -9
- package/src/javascripts/ui/components/core/seamly-event-subscriber.js +4 -10
- package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +1 -8
- package/src/javascripts/ui/components/entry/entry-container.js +5 -3
- package/src/javascripts/ui/components/entry/text-entry/index.js +7 -1
- package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +5 -1
- package/src/javascripts/ui/components/entry/toggle-button.js +4 -2
- package/src/javascripts/ui/components/entry/upload/file-upload-form.js +1 -1
- package/src/javascripts/ui/components/form-controls/error.js +6 -2
- package/src/javascripts/ui/components/form-controls/form.js +26 -3
- package/src/javascripts/ui/components/layout/app-frame.js +24 -15
- package/src/javascripts/ui/components/layout/chat-frame.js +0 -2
- package/src/javascripts/ui/components/layout/modal-wrapper.js +0 -80
- package/src/javascripts/ui/components/layout/pre-chat-messages.js +45 -0
- package/src/javascripts/ui/components/options/options-frame.js +9 -4
- package/src/javascripts/ui/components/options/options.js +1 -4
- package/src/javascripts/ui/components/options/transcript/index.js +15 -1
- package/src/javascripts/ui/components/options/transcript/transcript-form.js +1 -1
- package/src/javascripts/ui/components/suggestions/index.js +174 -0
- package/src/javascripts/ui/components/suggestions/suggestions-item.js +40 -0
- package/src/javascripts/ui/components/suggestions/suggestions-list.js +24 -0
- package/src/javascripts/ui/components/view/app-view.js +21 -0
- package/src/javascripts/ui/components/view/deprecated-view.js +30 -0
- package/src/javascripts/ui/components/view/index.js +27 -0
- package/src/javascripts/ui/components/view/inline-view.js +45 -0
- package/src/javascripts/ui/components/view/window-view/collapse-button.js +20 -0
- package/src/javascripts/ui/components/view/window-view/index.js +82 -0
- package/src/javascripts/ui/components/view/window-view/window-open-button.js +68 -0
- package/src/javascripts/ui/components/widgets/lightbox.js +7 -2
- package/src/javascripts/ui/hooks/component-helper-hooks.js +0 -9
- package/src/javascripts/ui/hooks/seamly-hooks.js +0 -1
- package/src/javascripts/ui/hooks/seamly-state-hooks.js +28 -4
- package/src/javascripts/ui/hooks/use-seamly-chat.js +12 -3
- package/src/javascripts/ui/hooks/use-seamly-commands.js +4 -31
- package/src/javascripts/ui/utils/seamly-utils.js +2 -14
- package/src/stylesheets/1-settings/_animations.scss +0 -6
- package/src/stylesheets/1-settings/_config.scss +34 -35
- package/src/stylesheets/2-tools/_functions.scss +0 -5
- package/src/stylesheets/2-tools/_mixins.scss +4 -16
- package/src/stylesheets/3-app/_app.scss +78 -135
- package/src/stylesheets/4-base/_a11y.scss +0 -3
- package/src/stylesheets/4-base/_elements.scss +0 -11
- package/src/stylesheets/4-base/_formelements.scss +4 -14
- package/src/stylesheets/5-components/_avatar.scss +2 -44
- package/src/stylesheets/5-components/_buttons.scss +6 -45
- package/src/stylesheets/5-components/_chat-status.scss +14 -38
- package/src/stylesheets/5-components/_choice-prompt.scss +33 -2
- package/src/stylesheets/5-components/_collapse-button.scss +16 -0
- package/src/stylesheets/5-components/_conversation.scss +26 -2
- package/src/stylesheets/5-components/_disclaimer.scss +10 -12
- package/src/stylesheets/5-components/_divider.scss +7 -4
- package/src/stylesheets/5-components/_error.scss +1 -1
- package/src/stylesheets/5-components/_form.scss +9 -0
- package/src/stylesheets/5-components/_icon.scss +10 -1
- package/src/stylesheets/5-components/_idle.scss +0 -8
- package/src/stylesheets/5-components/_input.scss +14 -20
- package/src/stylesheets/5-components/_interrupt.scss +0 -2
- package/src/stylesheets/5-components/_loader.scss +0 -32
- package/src/stylesheets/5-components/_message-author.scss +40 -0
- package/src/stylesheets/5-components/_message-body.scss +194 -0
- package/src/stylesheets/5-components/_message-card.scss +55 -0
- package/src/stylesheets/5-components/_message-carousel.scss +143 -0
- package/src/stylesheets/5-components/_message-count.scss +11 -28
- package/src/stylesheets/5-components/_message-cta.scss +23 -0
- package/src/stylesheets/5-components/_message-info.scss +11 -0
- package/src/stylesheets/5-components/_message-translation-info.scss +17 -0
- package/src/stylesheets/5-components/_message.scss +13 -364
- package/src/stylesheets/5-components/_modal.scss +28 -58
- package/src/stylesheets/5-components/_notification.scss +0 -5
- package/src/stylesheets/5-components/_options.scss +27 -42
- package/src/stylesheets/5-components/_pre-chat-messages.scss +30 -0
- package/src/stylesheets/5-components/_prompt.scss +0 -8
- package/src/stylesheets/5-components/_skip-link.scss +3 -3
- package/src/stylesheets/5-components/_suggestions.scss +96 -0
- package/src/stylesheets/5-components/_unstarted.scss +50 -0
- package/src/stylesheets/5-components/_upload.scss +26 -28
- package/src/stylesheets/5-components/_window-open-button.scss +39 -0
- package/src/stylesheets/6-webui-only/_hover.scss +151 -0
- package/src/stylesheets/6-webui-only/_scrollbar.scss +31 -0
- package/src/stylesheets/7-deprecated/1-settings/_animations.scss +43 -0
- package/src/stylesheets/7-deprecated/1-settings/_config.scss +105 -0
- package/src/stylesheets/7-deprecated/2-tools/_functions.scss +22 -0
- package/src/stylesheets/7-deprecated/2-tools/_mixins.scss +77 -0
- package/src/stylesheets/7-deprecated/3-app/_app.scss +214 -0
- package/src/stylesheets/7-deprecated/4-base/_a11y.scss +14 -0
- package/src/stylesheets/7-deprecated/4-base/_elements.scss +21 -0
- package/src/stylesheets/7-deprecated/4-base/_formelements.scss +57 -0
- package/src/stylesheets/{5-components → 7-deprecated/5-components}/_agent-info.scss +0 -0
- package/src/stylesheets/7-deprecated/5-components/_avatar.scss +64 -0
- package/src/stylesheets/7-deprecated/5-components/_buttons.scss +94 -0
- package/src/stylesheets/{5-components → 7-deprecated/5-components}/_card.scss +0 -0
- package/src/stylesheets/{5-components → 7-deprecated/5-components}/_carousel.scss +0 -0
- package/src/stylesheets/7-deprecated/5-components/_character-limit.scss +36 -0
- package/src/stylesheets/{5-components/_cobrowsing.scss → 7-deprecated/5-components/_chat-status.scss} +18 -16
- package/src/stylesheets/7-deprecated/5-components/_choice-prompt.scss +27 -0
- package/src/stylesheets/7-deprecated/5-components/_collapse-button.scss +17 -0
- package/src/stylesheets/7-deprecated/5-components/_conversation.scss +44 -0
- package/src/stylesheets/7-deprecated/5-components/_disclaimer.scss +36 -0
- package/src/stylesheets/7-deprecated/5-components/_divider.scss +91 -0
- package/src/stylesheets/7-deprecated/5-components/_error.scss +24 -0
- package/src/stylesheets/{5-components → 7-deprecated/5-components}/_faq.scss +8 -3
- package/src/stylesheets/{5-components → 7-deprecated/5-components}/_header-controls.scss +0 -0
- package/src/stylesheets/7-deprecated/5-components/_icon.scss +4 -0
- package/src/stylesheets/7-deprecated/5-components/_idle.scss +61 -0
- package/src/stylesheets/7-deprecated/5-components/_input.scss +78 -0
- package/src/stylesheets/7-deprecated/5-components/_interrupt.scss +35 -0
- package/src/stylesheets/7-deprecated/5-components/_loader.scss +78 -0
- package/src/stylesheets/7-deprecated/5-components/_message-count.scss +41 -0
- package/src/stylesheets/7-deprecated/5-components/_message.scss +385 -0
- package/src/stylesheets/7-deprecated/5-components/_modal.scss +138 -0
- package/src/stylesheets/7-deprecated/5-components/_notification.scss +20 -0
- package/src/stylesheets/7-deprecated/5-components/_options.scss +286 -0
- package/src/stylesheets/7-deprecated/5-components/_prompt.scss +44 -0
- package/src/stylesheets/7-deprecated/5-components/_skip-link.scss +21 -0
- package/src/stylesheets/{5-components → 7-deprecated/5-components}/_svg-graphic.scss +0 -0
- package/src/stylesheets/7-deprecated/5-components/_upload.scss +213 -0
- package/src/stylesheets/deprecated-view.scss +64 -0
- package/src/stylesheets/styles-webui-only.scss +3 -0
- package/src/stylesheets/styles.scss +15 -25
- package/webpack/config.site.js +4 -0
- package/webpack/defaults.js +5 -0
- package/src/.DS_Store +0 -0
- package/src/javascripts/ui/components/conversation/event/hooks/use-text-rendering.js +0 -35
- package/src/javascripts/ui/components/faq/faq.js +0 -162
- package/src/javascripts/ui/components/layout/view.js +0 -36
- package/src/javascripts/ui/components/options/cobrowsing.js +0 -110
- package/src/javascripts/ui/components/warnings/cobrowsing-active-frame.js +0 -29
- package/src/javascripts/ui/components/warnings/cobrowsing-active.js +0 -33
- package/src/stylesheets/5-components/_modal_mode.scss +0 -108
|
@@ -8,17 +8,20 @@ import Video from './event/video'
|
|
|
8
8
|
import Divider from './event/divider'
|
|
9
9
|
import Translation from './event/translation'
|
|
10
10
|
import Participant from './event/participant'
|
|
11
|
+
import Splash from './event/splash'
|
|
11
12
|
import Upload from './event/upload'
|
|
12
13
|
import Cta from './event/cta'
|
|
13
14
|
import TimeIndicator from './event/divider/variants/time-indicator'
|
|
14
15
|
import CarouselMessage from './event/carousel-message'
|
|
15
16
|
import CardMessage from './event/card-message'
|
|
17
|
+
import ConversationSuggestions from './event/conversation-suggestions'
|
|
16
18
|
|
|
17
19
|
const eventTypeMapping = {
|
|
18
20
|
message: {
|
|
19
21
|
choice_prompt: ChoicePrompt,
|
|
20
22
|
text: Text,
|
|
21
23
|
image: Image,
|
|
24
|
+
splash: Splash,
|
|
22
25
|
video: Video,
|
|
23
26
|
upload: Upload,
|
|
24
27
|
cta: Cta,
|
|
@@ -34,6 +37,9 @@ const eventTypeMapping = {
|
|
|
34
37
|
participant: {
|
|
35
38
|
participant: Participant,
|
|
36
39
|
},
|
|
40
|
+
service_data: {
|
|
41
|
+
suggestion: ConversationSuggestions,
|
|
42
|
+
},
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
const ComponentFilter = ({ children }) => {
|
|
@@ -8,6 +8,9 @@ import CarouselMessageSlide from '../carousel-message/components/slide'
|
|
|
8
8
|
|
|
9
9
|
const defaultGetItemKey = (item, idx, prefix) => `${prefix}${idx}`
|
|
10
10
|
const defaultGetItemLabel = (item) => item.label
|
|
11
|
+
const preventScroll = ({ target }) => {
|
|
12
|
+
target.scrollLeft = 0
|
|
13
|
+
}
|
|
11
14
|
|
|
12
15
|
export default function CarouselComponent({
|
|
13
16
|
currentIndex: originalIndex,
|
|
@@ -51,7 +54,10 @@ export default function CarouselComponent({
|
|
|
51
54
|
role="group"
|
|
52
55
|
aria-roledescription="carousel"
|
|
53
56
|
>
|
|
54
|
-
<div
|
|
57
|
+
<div
|
|
58
|
+
className={className('carousel__slides-wrapper')}
|
|
59
|
+
onScroll={preventScroll}
|
|
60
|
+
>
|
|
55
61
|
<div
|
|
56
62
|
id={carouselItemsId}
|
|
57
63
|
className={className('carousel__slides')}
|
|
@@ -78,6 +84,7 @@ export default function CarouselComponent({
|
|
|
78
84
|
item={item}
|
|
79
85
|
items={items}
|
|
80
86
|
currentIndex={currentIndex}
|
|
87
|
+
index={idx}
|
|
81
88
|
isActive={isActive}
|
|
82
89
|
/>
|
|
83
90
|
</div>
|
package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js
CHANGED
|
@@ -5,18 +5,17 @@ import CardComponent from '../../card-component'
|
|
|
5
5
|
export default function CarouselMessageSlide({
|
|
6
6
|
item: slide,
|
|
7
7
|
items,
|
|
8
|
-
|
|
8
|
+
index,
|
|
9
9
|
isActive,
|
|
10
10
|
}) {
|
|
11
11
|
const { t } = useI18n()
|
|
12
|
-
|
|
13
12
|
return (
|
|
14
13
|
<div
|
|
15
14
|
className={className('carousel-item', `carousel-item--${slide.type}`)}
|
|
16
15
|
role="group"
|
|
17
16
|
aria-roledescription="slide"
|
|
18
17
|
aria-label={t('carousel.slide.label', {
|
|
19
|
-
index:
|
|
18
|
+
index: index + 1,
|
|
20
19
|
total: items.length,
|
|
21
20
|
})}
|
|
22
21
|
>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useCallback } from 'preact/hooks'
|
|
2
|
+
import { className } from '../../../../lib/css'
|
|
3
|
+
import { actionTypes } from '../../../utils/seamly-utils'
|
|
4
|
+
import { useI18n } from '../../../../domains/i18n'
|
|
5
|
+
import { useTranslatedEventData } from '../../../../domains/translations'
|
|
6
|
+
import MessageContainer from '../message-container'
|
|
7
|
+
import { useSeamlyCommands } from '../../../hooks/seamly-hooks'
|
|
8
|
+
import SuggestionsList from '../../suggestions/suggestions-list'
|
|
9
|
+
|
|
10
|
+
export const useSuggestions = (event) => {
|
|
11
|
+
const { payload } = event
|
|
12
|
+
const [suggestions] = useTranslatedEventData(event)
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
suggestions,
|
|
16
|
+
payload,
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ConversationSuggestions = ({ event, ...props }) => {
|
|
21
|
+
const { t } = useI18n()
|
|
22
|
+
const headingText = t('suggestions.headingText')
|
|
23
|
+
const footerText = t('suggestions.footerText')
|
|
24
|
+
const { sendAction, addMessageBubble } = useSeamlyCommands()
|
|
25
|
+
const { suggestions, payload } = useSuggestions(event)
|
|
26
|
+
const handleClick = useCallback(
|
|
27
|
+
({ id, question }) => {
|
|
28
|
+
// @todo Refactor to 'suggestionclick'
|
|
29
|
+
sendAction({
|
|
30
|
+
type: actionTypes.custom,
|
|
31
|
+
originMessage: payload.id,
|
|
32
|
+
body: {
|
|
33
|
+
type: 'faqclick',
|
|
34
|
+
body: {
|
|
35
|
+
faqId: id,
|
|
36
|
+
faqQuestion: question,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
addMessageBubble(question)
|
|
42
|
+
},
|
|
43
|
+
[payload, sendAction, addMessageBubble],
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className={className('suggestions', 'suggestions--conversation')}>
|
|
48
|
+
{headingText && (
|
|
49
|
+
<h2 className={className('suggestions__heading')}>{headingText}</h2>
|
|
50
|
+
)}
|
|
51
|
+
<MessageContainer
|
|
52
|
+
type="suggestions"
|
|
53
|
+
showParticipant={false}
|
|
54
|
+
event={event}
|
|
55
|
+
{...props}
|
|
56
|
+
>
|
|
57
|
+
<SuggestionsList
|
|
58
|
+
className="suggestions__list--conversation"
|
|
59
|
+
onClickSuggestion={handleClick}
|
|
60
|
+
suggestions={suggestions}
|
|
61
|
+
/>
|
|
62
|
+
{footerText && (
|
|
63
|
+
<p className={className('suggestions__footer')}>{footerText}</p>
|
|
64
|
+
)}
|
|
65
|
+
</MessageContainer>
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default ConversationSuggestions
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useMemo } from 'preact/hooks'
|
|
2
|
-
import Mustache from 'mustache'
|
|
3
2
|
import parseBody from '../../../../lib/parse-body'
|
|
4
3
|
import EventDivider from '../event-divider'
|
|
5
4
|
import { useTranslatedEventData } from '../../../../domains/translations'
|
|
@@ -12,10 +11,8 @@ const Participant = ({ event }) => {
|
|
|
12
11
|
const [introduction] = useTranslatedEventData(event)
|
|
13
12
|
|
|
14
13
|
const intro = useMemo(() => {
|
|
15
|
-
return introduction
|
|
16
|
-
|
|
17
|
-
: undefined
|
|
18
|
-
}, [introduction, participant])
|
|
14
|
+
return introduction ? parseBody(introduction) : undefined
|
|
15
|
+
}, [introduction])
|
|
19
16
|
|
|
20
17
|
if (!intro) {
|
|
21
18
|
return null
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import parseBody from '../../../../lib/parse-body'
|
|
2
|
+
import useEventLinkClickHandler from './hooks/use-event-link-click-handler'
|
|
3
|
+
import MessageContainer from '../message-container'
|
|
4
|
+
import { useTranslatedEventData } from '../../../../domains/translations'
|
|
5
|
+
|
|
6
|
+
const Splash = ({ event, ...props }) => {
|
|
7
|
+
const { payload } = event
|
|
8
|
+
const [body] = useTranslatedEventData(event)
|
|
9
|
+
const eventClick = useEventLinkClickHandler(payload.id)
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<MessageContainer
|
|
13
|
+
type="splash"
|
|
14
|
+
event={event}
|
|
15
|
+
onClick={eventClick}
|
|
16
|
+
{...props}
|
|
17
|
+
bodyProps={{
|
|
18
|
+
dangerouslySetInnerHTML: {
|
|
19
|
+
__html: parseBody(body.text),
|
|
20
|
+
},
|
|
21
|
+
}}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default Splash
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useMemo } from 'preact/hooks'
|
|
2
2
|
import parseBody from '../../../../lib/parse-body'
|
|
3
3
|
import useEventLinkClickHandler from './hooks/use-event-link-click-handler'
|
|
4
|
-
import { parseRichText } from './hooks/use-text-rendering'
|
|
5
4
|
import MessageContainer from '../message-container'
|
|
6
5
|
import { useTranslatedEventData } from '../../../../domains/translations'
|
|
7
6
|
|
|
@@ -14,7 +13,7 @@ const Text = ({ event, ...props }) => {
|
|
|
14
13
|
return {
|
|
15
14
|
bodyProps: {
|
|
16
15
|
dangerouslySetInnerHTML: {
|
|
17
|
-
__html:
|
|
16
|
+
__html: parseBody(body.text),
|
|
18
17
|
},
|
|
19
18
|
},
|
|
20
19
|
}
|
|
@@ -11,6 +11,7 @@ import SeamlyFileUpload from './seamly-file-upload'
|
|
|
11
11
|
import { SeamlyEventBusContext, SeamlyApiContext } from './seamly-api-context'
|
|
12
12
|
import { StoreProvider } from '../../../domains/redux'
|
|
13
13
|
import { catchError } from '../../../domains/errors'
|
|
14
|
+
import ComponentFilter from '../conversation/component-filter'
|
|
14
15
|
|
|
15
16
|
const SeamlyCore = ({ store, children, config, eventBus, api }) => {
|
|
16
17
|
useErrorBoundary((error) => store.dispatch(catchError(error)))
|
|
@@ -19,15 +20,17 @@ const SeamlyCore = ({ store, children, config, eventBus, api }) => {
|
|
|
19
20
|
<SeamlyEventBusContext.Provider value={eventBus}>
|
|
20
21
|
<SeamlyApiContext.Provider value={api}>
|
|
21
22
|
<SeamlyLiveRegion>
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
<ComponentFilter>
|
|
24
|
+
<SeamlyInitializer config={config} />
|
|
25
|
+
<SeamlyEventSubscriber eventBus={eventBus} />
|
|
26
|
+
<SeamlyReadState />
|
|
27
|
+
<SeamlyNewNotifications />
|
|
28
|
+
<SeamlyIdleDetachCounter />
|
|
29
|
+
<SeamlyActivityMonitor>
|
|
30
|
+
<SeamlyInstanceFunctionsLoader />
|
|
31
|
+
<SeamlyFileUpload>{children}</SeamlyFileUpload>
|
|
32
|
+
</SeamlyActivityMonitor>
|
|
33
|
+
</ComponentFilter>
|
|
31
34
|
</SeamlyLiveRegion>
|
|
32
35
|
</SeamlyApiContext.Provider>
|
|
33
36
|
</SeamlyEventBusContext.Provider>
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
import SeamlyGeneralError from '../../../api/errors/seamly-general-error'
|
|
13
13
|
import SeamlySessionExpiredError from '../../../api/errors/seamly-session-expired-error'
|
|
14
14
|
import SeamlyOfflineError from '../../../api/errors/seamly-offline-error'
|
|
15
|
-
import
|
|
16
|
-
import
|
|
15
|
+
import * as InterruptActions from '../../../domains/interrupt/actions'
|
|
16
|
+
import * as AppActions from '../../../domains/app/actions'
|
|
17
17
|
|
|
18
18
|
const {
|
|
19
19
|
ADD_EVENT,
|
|
@@ -103,6 +103,7 @@ const SeamlyEventSubscriber = ({ eventBus }) => {
|
|
|
103
103
|
switch (payload.type) {
|
|
104
104
|
case 'text':
|
|
105
105
|
case 'choice_prompt':
|
|
106
|
+
case 'splash':
|
|
106
107
|
case 'image':
|
|
107
108
|
case 'upload':
|
|
108
109
|
case 'video':
|
|
@@ -138,21 +139,14 @@ const SeamlyEventSubscriber = ({ eventBus }) => {
|
|
|
138
139
|
case 'system':
|
|
139
140
|
if (payload.type === 'service_changed') {
|
|
140
141
|
const { serviceSettings, ...eventPayload } = payload
|
|
141
|
-
const {
|
|
142
|
+
const { uploads, entry } = serviceSettings
|
|
142
143
|
|
|
143
|
-
dispatch({
|
|
144
|
-
type: SET_FEATURE_ENABLED_STATE,
|
|
145
|
-
key: featureKeys.cobrowsing,
|
|
146
|
-
enabled: !!(cobrowsing && cobrowsing.enabled),
|
|
147
|
-
})
|
|
148
144
|
dispatch({
|
|
149
145
|
type: SET_FEATURE_ENABLED_STATE,
|
|
150
146
|
key: featureKeys.uploads,
|
|
151
147
|
enabled: !!(uploads && uploads.enabled),
|
|
152
148
|
})
|
|
153
149
|
|
|
154
|
-
setUserSelectedOption(featureKeys.cobrowsing, false)
|
|
155
|
-
|
|
156
150
|
dispatch({
|
|
157
151
|
type: SET_SERVICE_ENTRY_METADATA,
|
|
158
152
|
entryMeta: entry,
|
|
@@ -86,14 +86,7 @@ const SeamlyInstanceFunctionsLoader = () => {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
onActivityHandler()
|
|
89
|
-
|
|
90
|
-
config.layoutMode === 'inline' &&
|
|
91
|
-
visibilityState === visibilityStates.minimized
|
|
92
|
-
) {
|
|
93
|
-
console.warn('Inline chat windows cannot be minimized.')
|
|
94
|
-
} else {
|
|
95
|
-
setVisibility(visibilityState)
|
|
96
|
-
}
|
|
89
|
+
setVisibility(visibilityState)
|
|
97
90
|
},
|
|
98
91
|
[config?.api],
|
|
99
92
|
)
|
|
@@ -15,8 +15,10 @@ import TextEntry from './text-entry'
|
|
|
15
15
|
import UploadToggle from './upload-toggle'
|
|
16
16
|
import Upload from './upload'
|
|
17
17
|
import { useConfig } from '../../../domains/config'
|
|
18
|
+
import { useVisibility } from '../../../domains/visibility'
|
|
18
19
|
|
|
19
20
|
const EntryContainer = () => {
|
|
21
|
+
const { isOpen } = useVisibility()
|
|
20
22
|
const entryContainer = useRef(null)
|
|
21
23
|
const { hasCountdown } = useSeamlyIdleDetachCountdown()
|
|
22
24
|
const [showCountdown, setShowCountDown] = useState(hasCountdown)
|
|
@@ -88,9 +90,9 @@ const EntryContainer = () => {
|
|
|
88
90
|
: []),
|
|
89
91
|
])}
|
|
90
92
|
>
|
|
91
|
-
{renderEntry !== entryTypes.upload &&
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
{renderEntry !== entryTypes.upload &&
|
|
94
|
+
accountAllowsUploads &&
|
|
95
|
+
isOpen && <UploadToggle />}
|
|
94
96
|
<EntryComponent />
|
|
95
97
|
</div>
|
|
96
98
|
</div>
|
|
@@ -6,10 +6,12 @@ import {
|
|
|
6
6
|
} from '../../../hooks/seamly-hooks'
|
|
7
7
|
import { FormProvider } from '../../../../domains/forms'
|
|
8
8
|
import TextEntryForm from './text-entry-form'
|
|
9
|
+
import { useVisibility, visibilityStates } from '../../../../domains/visibility'
|
|
9
10
|
|
|
10
11
|
const controlName = 'userText'
|
|
11
12
|
|
|
12
13
|
export default function TextEntry({ ...props }) {
|
|
14
|
+
const { isOpen, setVisibility } = useVisibility()
|
|
13
15
|
const skipLinkId = useSkiplink()
|
|
14
16
|
const focusSkipLinkTarget = useSkiplinkTargetFocusing()
|
|
15
17
|
const { sendMessage } = useSeamlyCommands()
|
|
@@ -18,8 +20,12 @@ export default function TextEntry({ ...props }) {
|
|
|
18
20
|
sendMessage({ body: values[controlName] })
|
|
19
21
|
updateControlValue(controlName, '')
|
|
20
22
|
focusSkipLinkTarget()
|
|
23
|
+
|
|
24
|
+
if (!isOpen) {
|
|
25
|
+
setVisibility(visibilityStates.open)
|
|
26
|
+
}
|
|
21
27
|
},
|
|
22
|
-
[sendMessage, focusSkipLinkTarget],
|
|
28
|
+
[sendMessage, focusSkipLinkTarget, isOpen, setVisibility],
|
|
23
29
|
)
|
|
24
30
|
|
|
25
31
|
return (
|
|
@@ -65,7 +65,11 @@ export default function TextEntryForm({ controlName, skipLinkId }) {
|
|
|
65
65
|
}, [setBlockAutoEntrySwitch, hasValue])
|
|
66
66
|
|
|
67
67
|
return (
|
|
68
|
-
<Form
|
|
68
|
+
<Form
|
|
69
|
+
className={className('entry-form')}
|
|
70
|
+
disableValidationClasses
|
|
71
|
+
noValidate="true"
|
|
72
|
+
>
|
|
69
73
|
<div
|
|
70
74
|
className={className([
|
|
71
75
|
'input--text__container',
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
import { useInterrupt } from '../../../domains/interrupt'
|
|
13
13
|
import { useVisibility } from '../../../domains/visibility'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// Deprecated Toggle Button, should be removed once it is removed from clients
|
|
16
|
+
const DeprecatedToggleButton = ({ onOpenChat }) => {
|
|
16
17
|
const { t } = useI18n()
|
|
17
18
|
const titleId = useGeneratedId()
|
|
18
19
|
const { isOpen } = useVisibility()
|
|
@@ -55,6 +56,7 @@ const ToggleButton = ({ onOpenChat }) => {
|
|
|
55
56
|
focusIfContained(headerCollapseButtonId)
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
|
|
58
60
|
return (
|
|
59
61
|
<div className={className('toggle-button')}>
|
|
60
62
|
<div id={titleId}>
|
|
@@ -81,4 +83,4 @@ const ToggleButton = ({ onOpenChat }) => {
|
|
|
81
83
|
)
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
export default
|
|
86
|
+
export default DeprecatedToggleButton
|
|
@@ -19,7 +19,7 @@ export default function FileInputForm({
|
|
|
19
19
|
const selectedFileName = hasFile ? fileList[0].name : ''
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
|
-
<Form className={className('
|
|
22
|
+
<Form className={className('upload-form')}>
|
|
23
23
|
<FileInput
|
|
24
24
|
name={controlName}
|
|
25
25
|
id={skiplinkId}
|
|
@@ -10,9 +10,13 @@ export default function Error({ id, error }) {
|
|
|
10
10
|
}, [])
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<div
|
|
13
|
+
<div
|
|
14
|
+
className={className('error')}
|
|
15
|
+
aria-live="assertive"
|
|
16
|
+
aria-atomic="true"
|
|
17
|
+
>
|
|
14
18
|
{isAvailable && error && (
|
|
15
|
-
<span id={id} className={className('
|
|
19
|
+
<span id={id} className={className('error__message')}>
|
|
16
20
|
<Icon name="error" size="16" />
|
|
17
21
|
{error}
|
|
18
22
|
</span>
|
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
import { useForm } from '../../../domains/forms'
|
|
2
|
+
import { className } from '../../../lib/css'
|
|
2
3
|
|
|
3
|
-
function Form({
|
|
4
|
-
|
|
4
|
+
function Form({
|
|
5
|
+
className: givenClassName,
|
|
6
|
+
disableValidationClasses,
|
|
7
|
+
...props
|
|
8
|
+
}) {
|
|
9
|
+
const { handleSubmit, isValid, isSubmitted } = useForm()
|
|
5
10
|
|
|
6
|
-
|
|
11
|
+
const formClasses = ['form']
|
|
12
|
+
|
|
13
|
+
if (!disableValidationClasses && isSubmitted) {
|
|
14
|
+
formClasses.push('form--submitted')
|
|
15
|
+
|
|
16
|
+
if (isValid) {
|
|
17
|
+
formClasses.push('form--valid')
|
|
18
|
+
} else {
|
|
19
|
+
formClasses.push('form--invalid')
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<form
|
|
25
|
+
onSubmit={handleSubmit}
|
|
26
|
+
className={className([...formClasses, givenClassName])}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
7
30
|
}
|
|
8
31
|
|
|
9
32
|
export default Form
|
|
@@ -5,20 +5,24 @@ import {
|
|
|
5
5
|
useSeamlyLayoutMode,
|
|
6
6
|
useSeamlyContainerElement,
|
|
7
7
|
} from '../../hooks/seamly-hooks'
|
|
8
|
-
import Faq from '../faq/faq'
|
|
9
8
|
import { useConfig } from '../../../domains/config'
|
|
10
9
|
import { useUserHasResponded } from '../../../domains/app'
|
|
11
10
|
import { useI18n } from '../../../domains/i18n'
|
|
12
11
|
import { useVisibility, visibilityStates } from '../../../domains/visibility'
|
|
12
|
+
import Suggestions from '../suggestions'
|
|
13
13
|
|
|
14
|
-
const AppFrame = ({
|
|
14
|
+
const AppFrame = ({
|
|
15
|
+
children,
|
|
16
|
+
className: givenClassName = '',
|
|
17
|
+
isDeprecated,
|
|
18
|
+
}) => {
|
|
15
19
|
const [, setSeamlyContainerElement] = useSeamlyContainerElement()
|
|
16
20
|
const { isOpen, isVisible, setVisibility } = useVisibility()
|
|
17
|
-
const { zIndex,
|
|
18
|
-
const {
|
|
21
|
+
const { zIndex, namespace, layoutMode } = useConfig()
|
|
22
|
+
const { isInline } = useSeamlyLayoutMode()
|
|
19
23
|
const appContainerClassNames = useSeamlyAppContainerClassNames()
|
|
20
24
|
const userResponded = useUserHasResponded()
|
|
21
|
-
const { locale } = useI18n()
|
|
25
|
+
const { locale, t } = useI18n()
|
|
22
26
|
|
|
23
27
|
const containerElementRef = useCallback(
|
|
24
28
|
(container) => {
|
|
@@ -39,9 +43,20 @@ const AppFrame = ({ children }) => {
|
|
|
39
43
|
return undefined
|
|
40
44
|
}, [locale])
|
|
41
45
|
|
|
42
|
-
const
|
|
46
|
+
const baseClassName = isDeprecated ? 'app--deprecated' : 'app'
|
|
47
|
+
const defaultClassNames = [
|
|
48
|
+
`app--layout-${layoutMode}`,
|
|
49
|
+
`namespace--${namespace}`,
|
|
50
|
+
]
|
|
43
51
|
|
|
44
|
-
|
|
52
|
+
const classNames = [
|
|
53
|
+
baseClassName,
|
|
54
|
+
...defaultClassNames,
|
|
55
|
+
...appContainerClassNames,
|
|
56
|
+
givenClassName,
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
if (!isOpen && layoutMode !== 'app') {
|
|
45
60
|
classNames.push('app--collapsed')
|
|
46
61
|
}
|
|
47
62
|
|
|
@@ -56,26 +71,20 @@ const AppFrame = ({ children }) => {
|
|
|
56
71
|
}
|
|
57
72
|
}
|
|
58
73
|
|
|
59
|
-
const onClickHandler = (e) => {
|
|
60
|
-
if (isModal) {
|
|
61
|
-
e.stopPropagation()
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
74
|
return (
|
|
66
75
|
isVisible && (
|
|
67
76
|
<section
|
|
68
77
|
className={className(classNames)}
|
|
69
78
|
onKeyDown={onKeyDownHandler}
|
|
70
|
-
onClick={onClickHandler}
|
|
71
79
|
lang={blockLang}
|
|
72
80
|
tabIndex="-1"
|
|
73
81
|
ref={containerElementRef}
|
|
74
82
|
style={{ zIndex }}
|
|
75
83
|
data-nosnippet
|
|
84
|
+
aria-label={t('app.srLabel')}
|
|
76
85
|
>
|
|
77
86
|
<div className={className('app-wrapper')}>{children}</div>
|
|
78
|
-
{
|
|
87
|
+
{layoutMode === 'inline' && isOpen && <Suggestions isAside={true} />}
|
|
79
88
|
</section>
|
|
80
89
|
)
|
|
81
90
|
)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { className } from '../../../lib/css'
|
|
2
|
-
import CobrowsingActiveFrame from '../warnings/cobrowsing-active-frame'
|
|
3
2
|
import AppOptions from '../app-options'
|
|
4
3
|
import { ChatStatus as TranslationsChatStatus } from '../../../domains/translations'
|
|
5
4
|
import { useInterrupt } from '../../../domains/interrupt'
|
|
@@ -21,7 +20,6 @@ function ChatFrame({ children, interruptComponent: InterruptComponent }) {
|
|
|
21
20
|
|
|
22
21
|
return (
|
|
23
22
|
<>
|
|
24
|
-
<CobrowsingActiveFrame />
|
|
25
23
|
<TranslationsChatStatus />
|
|
26
24
|
<div className={className('app__container')}>{getContent()}</div>
|
|
27
25
|
<AppOptions />
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'preact/hooks'
|
|
2
|
-
import { createFocusTrap } from 'focus-trap'
|
|
3
|
-
import InOutTransition, {
|
|
4
|
-
transitionStartStates,
|
|
5
|
-
} from '../widgets/in-out-transition'
|
|
6
|
-
import { useSeamlyLayoutMode } from '../../hooks/seamly-hooks'
|
|
7
|
-
import { useI18n } from '../../../domains/i18n'
|
|
8
|
-
import { className } from '../../../lib/css'
|
|
9
|
-
import { createAriaHider } from '../../utils/general-utils'
|
|
10
|
-
import { useVisibility, visibilityStates } from '../../../domains/visibility'
|
|
11
|
-
|
|
12
|
-
const ModalWrapper = ({ children }) => {
|
|
13
|
-
const { t } = useI18n()
|
|
14
|
-
const { isModal } = useSeamlyLayoutMode()
|
|
15
|
-
const { isOpen, setVisibility } = useVisibility()
|
|
16
|
-
const container = useRef(null)
|
|
17
|
-
const focusTrap = useRef(null)
|
|
18
|
-
|
|
19
|
-
const onInTransitionCompleteHandler = () => {
|
|
20
|
-
focusTrap.current = createFocusTrap(container.current)
|
|
21
|
-
focusTrap.current.activate()
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const onOutTransitionCompleteHandler = () => {
|
|
25
|
-
if (focusTrap.current) {
|
|
26
|
-
focusTrap.current.deactivate()
|
|
27
|
-
focusTrap.current = null
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
if (!isModal) {
|
|
33
|
-
return null
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let disposeAriaHider
|
|
37
|
-
|
|
38
|
-
if (isOpen) {
|
|
39
|
-
disposeAriaHider = createAriaHider()
|
|
40
|
-
// As the chat window is housed in a container we have to remove the
|
|
41
|
-
// aria-hidden the aria hider places on the container.
|
|
42
|
-
container.current.parentElement.removeAttribute('aria-hidden')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return () => {
|
|
46
|
-
if (disposeAriaHider) {
|
|
47
|
-
disposeAriaHider()
|
|
48
|
-
disposeAriaHider = null
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}, [isOpen, isModal])
|
|
52
|
-
|
|
53
|
-
const onClickHandler = () => {
|
|
54
|
-
setVisibility(visibilityStates.minimized)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return isModal ? (
|
|
58
|
-
<InOutTransition
|
|
59
|
-
isActive={isOpen}
|
|
60
|
-
transitionStartState={transitionStartStates.rendered}
|
|
61
|
-
onInTransitionComplete={onInTransitionCompleteHandler}
|
|
62
|
-
onOutTransitionComplete={onOutTransitionCompleteHandler}
|
|
63
|
-
>
|
|
64
|
-
<div
|
|
65
|
-
className={className('modal-overlay')}
|
|
66
|
-
role="dialog"
|
|
67
|
-
aria-modal="true"
|
|
68
|
-
aria-label={t('window.srModalLayoutLabel')}
|
|
69
|
-
onClick={onClickHandler}
|
|
70
|
-
ref={container}
|
|
71
|
-
>
|
|
72
|
-
{children}
|
|
73
|
-
</div>
|
|
74
|
-
</InOutTransition>
|
|
75
|
-
) : (
|
|
76
|
-
children
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export default ModalWrapper
|