@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.
Files changed (186) hide show
  1. package/CHANGELOG.md +625 -0
  2. package/build/dist/lib/components.js +2 -1
  3. package/build/dist/lib/components.min.js +1 -1
  4. package/build/dist/lib/index.debug.js +183 -128
  5. package/build/dist/lib/index.debug.min.js +1 -1
  6. package/build/dist/lib/index.debug.min.js.LICENSE.txt +45 -25
  7. package/build/dist/lib/index.js +7290 -7753
  8. package/build/dist/lib/index.min.js +1 -1
  9. package/build/dist/lib/index.min.js.LICENSE.txt +0 -5
  10. package/build/dist/lib/standalone.js +5785 -6255
  11. package/build/dist/lib/standalone.min.js +1 -1
  12. package/build/dist/lib/standalone.min.js.LICENSE.txt +0 -5
  13. package/build/dist/lib/style-guide.js +10834 -4971
  14. package/build/dist/lib/style-guide.min.js +2 -1
  15. package/build/dist/lib/style-guide.min.js.LICENSE.txt +9 -0
  16. package/build/dist/lib/styles.css +1 -1
  17. package/package.json +1 -2
  18. package/src/icons/icon_file-32.svg +1 -1
  19. package/src/javascripts/api/errors/seamly-base-error.js +7 -0
  20. package/src/javascripts/api/index.js +48 -37
  21. package/src/javascripts/api/producer.js +5 -1
  22. package/src/javascripts/config.js +1 -5
  23. package/src/javascripts/domains/app/actions.js +22 -5
  24. package/src/javascripts/domains/config/actions.js +3 -0
  25. package/src/javascripts/domains/config/reducer.js +9 -0
  26. package/src/javascripts/domains/errors/index.js +5 -4
  27. package/src/javascripts/domains/forms/hooks.js +3 -1
  28. package/src/javascripts/domains/forms/provider.js +12 -0
  29. package/src/javascripts/domains/forms/reducer.js +2 -0
  30. package/src/javascripts/domains/i18n/hooks.js +2 -1
  31. package/src/javascripts/domains/i18n/reducer.js +2 -0
  32. package/src/javascripts/domains/interrupt/reducer.js +2 -2
  33. package/src/javascripts/domains/options/middleware.js +15 -31
  34. package/src/javascripts/domains/store/index.js +2 -1
  35. package/src/javascripts/domains/store/state-reducer.js +3 -8
  36. package/src/javascripts/domains/translations/components/options-dialog/form.js +1 -1
  37. package/src/javascripts/domains/translations/components/options-dialog/index.js +15 -1
  38. package/src/javascripts/domains/translations/reducer.js +2 -0
  39. package/src/javascripts/domains/visibility/actions.js +1 -1
  40. package/src/javascripts/domains/visibility/hooks.js +10 -8
  41. package/src/javascripts/domains/visibility/utils.js +1 -2
  42. package/src/javascripts/index.js +5 -3
  43. package/src/javascripts/lib/css.js +7 -1
  44. package/src/javascripts/lib/engine/index.js +4 -3
  45. package/src/javascripts/lib/external-api/index.js +38 -29
  46. package/src/javascripts/package/components.js +2 -1
  47. package/src/javascripts/style-guide/components/app.js +1 -1
  48. package/src/javascripts/style-guide/components/static-core.js +18 -4
  49. package/src/javascripts/style-guide/states.js +203 -298
  50. package/src/javascripts/ui/components/chat-app.js +1 -1
  51. package/src/javascripts/ui/components/conversation/component-filter.js +6 -0
  52. package/src/javascripts/ui/components/conversation/event/carousel-component/index.js +8 -1
  53. package/src/javascripts/ui/components/conversation/event/carousel-message/components/slide.js +2 -3
  54. package/src/javascripts/ui/components/conversation/event/conversation-suggestions.js +70 -0
  55. package/src/javascripts/ui/components/conversation/event/participant.js +2 -5
  56. package/src/javascripts/ui/components/conversation/event/splash.js +26 -0
  57. package/src/javascripts/ui/components/conversation/event/text.js +1 -2
  58. package/src/javascripts/ui/components/core/seamly-core.js +12 -9
  59. package/src/javascripts/ui/components/core/seamly-event-subscriber.js +4 -10
  60. package/src/javascripts/ui/components/core/seamly-instance-functions-loader.js +1 -8
  61. package/src/javascripts/ui/components/entry/entry-container.js +5 -3
  62. package/src/javascripts/ui/components/entry/text-entry/index.js +7 -1
  63. package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +5 -1
  64. package/src/javascripts/ui/components/entry/toggle-button.js +4 -2
  65. package/src/javascripts/ui/components/entry/upload/file-upload-form.js +1 -1
  66. package/src/javascripts/ui/components/form-controls/error.js +6 -2
  67. package/src/javascripts/ui/components/form-controls/form.js +26 -3
  68. package/src/javascripts/ui/components/layout/app-frame.js +24 -15
  69. package/src/javascripts/ui/components/layout/chat-frame.js +0 -2
  70. package/src/javascripts/ui/components/layout/modal-wrapper.js +0 -80
  71. package/src/javascripts/ui/components/layout/pre-chat-messages.js +45 -0
  72. package/src/javascripts/ui/components/options/options-frame.js +9 -4
  73. package/src/javascripts/ui/components/options/options.js +1 -4
  74. package/src/javascripts/ui/components/options/transcript/index.js +15 -1
  75. package/src/javascripts/ui/components/options/transcript/transcript-form.js +1 -1
  76. package/src/javascripts/ui/components/suggestions/index.js +174 -0
  77. package/src/javascripts/ui/components/suggestions/suggestions-item.js +40 -0
  78. package/src/javascripts/ui/components/suggestions/suggestions-list.js +24 -0
  79. package/src/javascripts/ui/components/view/app-view.js +21 -0
  80. package/src/javascripts/ui/components/view/deprecated-view.js +30 -0
  81. package/src/javascripts/ui/components/view/index.js +27 -0
  82. package/src/javascripts/ui/components/view/inline-view.js +45 -0
  83. package/src/javascripts/ui/components/view/window-view/collapse-button.js +20 -0
  84. package/src/javascripts/ui/components/view/window-view/index.js +82 -0
  85. package/src/javascripts/ui/components/view/window-view/window-open-button.js +68 -0
  86. package/src/javascripts/ui/components/widgets/lightbox.js +7 -2
  87. package/src/javascripts/ui/hooks/component-helper-hooks.js +0 -9
  88. package/src/javascripts/ui/hooks/seamly-hooks.js +0 -1
  89. package/src/javascripts/ui/hooks/seamly-state-hooks.js +28 -4
  90. package/src/javascripts/ui/hooks/use-seamly-chat.js +12 -3
  91. package/src/javascripts/ui/hooks/use-seamly-commands.js +4 -31
  92. package/src/javascripts/ui/utils/seamly-utils.js +2 -14
  93. package/src/stylesheets/1-settings/_animations.scss +0 -6
  94. package/src/stylesheets/1-settings/_config.scss +34 -35
  95. package/src/stylesheets/2-tools/_functions.scss +0 -5
  96. package/src/stylesheets/2-tools/_mixins.scss +4 -16
  97. package/src/stylesheets/3-app/_app.scss +78 -135
  98. package/src/stylesheets/4-base/_a11y.scss +0 -3
  99. package/src/stylesheets/4-base/_elements.scss +0 -11
  100. package/src/stylesheets/4-base/_formelements.scss +4 -14
  101. package/src/stylesheets/5-components/_avatar.scss +2 -44
  102. package/src/stylesheets/5-components/_buttons.scss +6 -45
  103. package/src/stylesheets/5-components/_chat-status.scss +14 -38
  104. package/src/stylesheets/5-components/_choice-prompt.scss +33 -2
  105. package/src/stylesheets/5-components/_collapse-button.scss +16 -0
  106. package/src/stylesheets/5-components/_conversation.scss +26 -2
  107. package/src/stylesheets/5-components/_disclaimer.scss +10 -12
  108. package/src/stylesheets/5-components/_divider.scss +7 -4
  109. package/src/stylesheets/5-components/_error.scss +1 -1
  110. package/src/stylesheets/5-components/_form.scss +9 -0
  111. package/src/stylesheets/5-components/_icon.scss +10 -1
  112. package/src/stylesheets/5-components/_idle.scss +0 -8
  113. package/src/stylesheets/5-components/_input.scss +14 -20
  114. package/src/stylesheets/5-components/_interrupt.scss +0 -2
  115. package/src/stylesheets/5-components/_loader.scss +0 -32
  116. package/src/stylesheets/5-components/_message-author.scss +40 -0
  117. package/src/stylesheets/5-components/_message-body.scss +194 -0
  118. package/src/stylesheets/5-components/_message-card.scss +55 -0
  119. package/src/stylesheets/5-components/_message-carousel.scss +143 -0
  120. package/src/stylesheets/5-components/_message-count.scss +11 -28
  121. package/src/stylesheets/5-components/_message-cta.scss +23 -0
  122. package/src/stylesheets/5-components/_message-info.scss +11 -0
  123. package/src/stylesheets/5-components/_message-translation-info.scss +17 -0
  124. package/src/stylesheets/5-components/_message.scss +13 -364
  125. package/src/stylesheets/5-components/_modal.scss +28 -58
  126. package/src/stylesheets/5-components/_notification.scss +0 -5
  127. package/src/stylesheets/5-components/_options.scss +27 -42
  128. package/src/stylesheets/5-components/_pre-chat-messages.scss +30 -0
  129. package/src/stylesheets/5-components/_prompt.scss +0 -8
  130. package/src/stylesheets/5-components/_skip-link.scss +3 -3
  131. package/src/stylesheets/5-components/_suggestions.scss +96 -0
  132. package/src/stylesheets/5-components/_unstarted.scss +50 -0
  133. package/src/stylesheets/5-components/_upload.scss +26 -28
  134. package/src/stylesheets/5-components/_window-open-button.scss +39 -0
  135. package/src/stylesheets/6-webui-only/_hover.scss +151 -0
  136. package/src/stylesheets/6-webui-only/_scrollbar.scss +31 -0
  137. package/src/stylesheets/7-deprecated/1-settings/_animations.scss +43 -0
  138. package/src/stylesheets/7-deprecated/1-settings/_config.scss +105 -0
  139. package/src/stylesheets/7-deprecated/2-tools/_functions.scss +22 -0
  140. package/src/stylesheets/7-deprecated/2-tools/_mixins.scss +77 -0
  141. package/src/stylesheets/7-deprecated/3-app/_app.scss +214 -0
  142. package/src/stylesheets/7-deprecated/4-base/_a11y.scss +14 -0
  143. package/src/stylesheets/7-deprecated/4-base/_elements.scss +21 -0
  144. package/src/stylesheets/7-deprecated/4-base/_formelements.scss +57 -0
  145. package/src/stylesheets/{5-components → 7-deprecated/5-components}/_agent-info.scss +0 -0
  146. package/src/stylesheets/7-deprecated/5-components/_avatar.scss +64 -0
  147. package/src/stylesheets/7-deprecated/5-components/_buttons.scss +94 -0
  148. package/src/stylesheets/{5-components → 7-deprecated/5-components}/_card.scss +0 -0
  149. package/src/stylesheets/{5-components → 7-deprecated/5-components}/_carousel.scss +0 -0
  150. package/src/stylesheets/7-deprecated/5-components/_character-limit.scss +36 -0
  151. package/src/stylesheets/{5-components/_cobrowsing.scss → 7-deprecated/5-components/_chat-status.scss} +18 -16
  152. package/src/stylesheets/7-deprecated/5-components/_choice-prompt.scss +27 -0
  153. package/src/stylesheets/7-deprecated/5-components/_collapse-button.scss +17 -0
  154. package/src/stylesheets/7-deprecated/5-components/_conversation.scss +44 -0
  155. package/src/stylesheets/7-deprecated/5-components/_disclaimer.scss +36 -0
  156. package/src/stylesheets/7-deprecated/5-components/_divider.scss +91 -0
  157. package/src/stylesheets/7-deprecated/5-components/_error.scss +24 -0
  158. package/src/stylesheets/{5-components → 7-deprecated/5-components}/_faq.scss +8 -3
  159. package/src/stylesheets/{5-components → 7-deprecated/5-components}/_header-controls.scss +0 -0
  160. package/src/stylesheets/7-deprecated/5-components/_icon.scss +4 -0
  161. package/src/stylesheets/7-deprecated/5-components/_idle.scss +61 -0
  162. package/src/stylesheets/7-deprecated/5-components/_input.scss +78 -0
  163. package/src/stylesheets/7-deprecated/5-components/_interrupt.scss +35 -0
  164. package/src/stylesheets/7-deprecated/5-components/_loader.scss +78 -0
  165. package/src/stylesheets/7-deprecated/5-components/_message-count.scss +41 -0
  166. package/src/stylesheets/7-deprecated/5-components/_message.scss +385 -0
  167. package/src/stylesheets/7-deprecated/5-components/_modal.scss +138 -0
  168. package/src/stylesheets/7-deprecated/5-components/_notification.scss +20 -0
  169. package/src/stylesheets/7-deprecated/5-components/_options.scss +286 -0
  170. package/src/stylesheets/7-deprecated/5-components/_prompt.scss +44 -0
  171. package/src/stylesheets/7-deprecated/5-components/_skip-link.scss +21 -0
  172. package/src/stylesheets/{5-components → 7-deprecated/5-components}/_svg-graphic.scss +0 -0
  173. package/src/stylesheets/7-deprecated/5-components/_upload.scss +213 -0
  174. package/src/stylesheets/deprecated-view.scss +64 -0
  175. package/src/stylesheets/styles-webui-only.scss +3 -0
  176. package/src/stylesheets/styles.scss +15 -25
  177. package/webpack/config.site.js +4 -0
  178. package/webpack/defaults.js +5 -0
  179. package/src/.DS_Store +0 -0
  180. package/src/javascripts/ui/components/conversation/event/hooks/use-text-rendering.js +0 -35
  181. package/src/javascripts/ui/components/faq/faq.js +0 -162
  182. package/src/javascripts/ui/components/layout/view.js +0 -36
  183. package/src/javascripts/ui/components/options/cobrowsing.js +0 -110
  184. package/src/javascripts/ui/components/warnings/cobrowsing-active-frame.js +0 -29
  185. package/src/javascripts/ui/components/warnings/cobrowsing-active.js +0 -33
  186. package/src/stylesheets/5-components/_modal_mode.scss +0 -108
@@ -1,4 +1,4 @@
1
- import View from './layout/view'
1
+ import View from './view'
2
2
  import SeamlyCore from './core/seamly-core'
3
3
 
4
4
  const ChatApp = (props) => {
@@ -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 className={className('carousel__slides-wrapper')}>
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>
@@ -5,18 +5,17 @@ import CardComponent from '../../card-component'
5
5
  export default function CarouselMessageSlide({
6
6
  item: slide,
7
7
  items,
8
- currentIndex,
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: currentIndex + 1,
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
- ? Mustache.render(parseBody(introduction), participant)
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: parseRichText(parseBody(body.text), body.variables),
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
- <SeamlyInitializer config={config} />
23
- <SeamlyEventSubscriber eventBus={eventBus} />
24
- <SeamlyReadState />
25
- <SeamlyNewNotifications />
26
- <SeamlyIdleDetachCounter />
27
- <SeamlyActivityMonitor>
28
- <SeamlyInstanceFunctionsLoader />
29
- <SeamlyFileUpload>{children}</SeamlyFileUpload>
30
- </SeamlyActivityMonitor>
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 { Actions as InterruptActions } from '../../../domains/interrupt'
16
- import { Actions as AppActions } from '../../../domains/app'
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 { cobrowsing, uploads, entry } = serviceSettings
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
- if (
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 && accountAllowsUploads && (
92
- <UploadToggle />
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 className={className('input', 'input--text')} noValidate="true">
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
- const ToggleButton = ({ onOpenChat }) => {
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 ToggleButton
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('input', 'input--file')}>
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 aria-live="assertive" aria-atomic="true">
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('error')}>
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({ ...props }) {
4
- const { handleSubmit } = useForm()
4
+ function Form({
5
+ className: givenClassName,
6
+ disableValidationClasses,
7
+ ...props
8
+ }) {
9
+ const { handleSubmit, isValid, isSubmitted } = useForm()
5
10
 
6
- return <form onSubmit={handleSubmit} {...props} />
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 = ({ children }) => {
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, showFaq } = useConfig()
18
- const { isModal, isInline } = useSeamlyLayoutMode()
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 classNames = ['app', ...appContainerClassNames]
46
+ const baseClassName = isDeprecated ? 'app--deprecated' : 'app'
47
+ const defaultClassNames = [
48
+ `app--layout-${layoutMode}`,
49
+ `namespace--${namespace}`,
50
+ ]
43
51
 
44
- if (!isOpen) {
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
- {showFaq && <Faq />}
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