@seamly/web-ui 20.3.0 → 20.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/build/dist/lib/index.debug.js +61 -94
  2. package/build/dist/lib/index.debug.min.js +1 -1
  3. package/build/dist/lib/index.debug.min.js.LICENSE.txt +4 -16
  4. package/build/dist/lib/index.js +467 -3965
  5. package/build/dist/lib/index.min.js +1 -1
  6. package/build/dist/lib/index.min.js.LICENSE.txt +0 -5
  7. package/build/dist/lib/standalone.js +432 -3865
  8. package/build/dist/lib/standalone.min.js +1 -1
  9. package/build/dist/lib/style-guide.js +267 -191
  10. package/build/dist/lib/style-guide.min.js +1 -1
  11. package/build/dist/lib/styles.css +1 -1
  12. package/package.json +2 -4
  13. package/src/.DS_Store +0 -0
  14. package/src/javascripts/api/index.js +17 -1
  15. package/src/javascripts/domains/config/reducer.js +2 -0
  16. package/src/javascripts/domains/forms/provider.js +14 -6
  17. package/src/javascripts/domains/store/state-reducer.js +1 -0
  18. package/src/javascripts/domains/visibility/actions.js +2 -0
  19. package/src/javascripts/domains/visibility/hooks.js +60 -1
  20. package/src/javascripts/domains/visibility/reducer.js +5 -0
  21. package/src/javascripts/domains/visibility/selectors.js +5 -0
  22. package/src/javascripts/domains/visibility/utils.js +5 -1
  23. package/src/javascripts/index.js +1 -0
  24. package/src/javascripts/style-guide/components/app.js +2 -0
  25. package/src/javascripts/style-guide/states.js +55 -50
  26. package/src/javascripts/ui/components/conversation/conversation.js +9 -10
  27. package/src/javascripts/ui/components/conversation/event/card-component.js +1 -2
  28. package/src/javascripts/ui/components/conversation/event/conversation-suggestions.js +19 -9
  29. package/src/javascripts/ui/components/conversation/event/cta.js +1 -2
  30. package/src/javascripts/ui/components/conversation/event/image.js +11 -3
  31. package/src/javascripts/ui/components/conversation/event/participant.js +2 -11
  32. package/src/javascripts/ui/components/conversation/event/splash.js +1 -3
  33. package/src/javascripts/ui/components/conversation/event/text.js +9 -9
  34. package/src/javascripts/ui/components/entry/text-entry/text-entry-form.js +6 -0
  35. package/src/javascripts/ui/components/layout/chat.js +52 -48
  36. package/src/javascripts/ui/components/suggestions/suggestions-list.js +12 -14
  37. package/src/javascripts/ui/components/view/deprecated-view.js +16 -11
  38. package/src/javascripts/ui/components/view/index.js +2 -2
  39. package/src/javascripts/ui/components/view/inline-view.js +13 -8
  40. package/src/javascripts/ui/hooks/seamly-entry-hooks.js +3 -2
  41. package/src/javascripts/ui/hooks/seamly-state-hooks.js +7 -3
  42. package/src/javascripts/ui/hooks/use-seamly-chat.js +41 -29
  43. package/src/javascripts/ui/hooks/use-seamly-commands.js +16 -4
  44. package/src/javascripts/ui/utils/seamly-utils.js +24 -7
  45. package/src/stylesheets/5-components/_message-count.scss +5 -2
  46. package/CHANGELOG.md +0 -729
  47. package/src/javascripts/lib/parse-body.js +0 -10
  48. package/src/javascripts/ui/components/conversation/event/hooks/use-text-rendering.js +0 -35
@@ -17,6 +17,7 @@ const baseState = {
17
17
  },
18
18
  initialState: {},
19
19
  unreadEvents: 0,
20
+ loadedImageEventIds: [],
20
21
  isLoading: false,
21
22
  idleDetachCountdown: { hasCountdown: false, isActive: false },
22
23
  resumeConversationPrompt: false,
@@ -155,7 +156,6 @@ const infoMessage = {
155
156
  body: {
156
157
  text: 'This is a system generated info message',
157
158
  type: 'text',
158
- variables: {},
159
159
  },
160
160
  fromClient: false,
161
161
  id: randomId(),
@@ -198,7 +198,7 @@ const participantMessage = {
198
198
  participant: {
199
199
  avatar,
200
200
  id: 'agent',
201
- introduction: "You're now talking to {{name}} gimme a minit",
201
+ introduction: "You're now talking to Mrs. Bot gimme a minit",
202
202
  name: 'Mrs. Bot',
203
203
  service: {
204
204
  expose: { map: {}, version: 2 },
@@ -222,7 +222,7 @@ const participantMessageDefaultIcon = {
222
222
  messageStatus: 'received',
223
223
  participant: {
224
224
  id: 'user',
225
- introduction: "You're now talking to {{name}} gimme a minit",
225
+ introduction: "You're now talking to Mrs. Bot gimme a minit",
226
226
  name: 'Mrs. Bot',
227
227
  service: {
228
228
  expose: { map: {}, version: 2 },
@@ -244,7 +244,6 @@ const getCustomMessage = ({ type, data, text }) => ({
244
244
  type,
245
245
  text,
246
246
  data,
247
- variables: {},
248
247
  },
249
248
  participant: 'agent',
250
249
  service: {
@@ -268,7 +267,6 @@ const shortTextMessage = {
268
267
  body: {
269
268
  text: 'What do you want to do?',
270
269
  type: 'text',
271
- variables: {},
272
270
  },
273
271
  fromClient: false,
274
272
  fromHistory: true,
@@ -303,7 +301,8 @@ const ctaMessage = {
303
301
  type: 'message',
304
302
  payload: {
305
303
  body: {
306
- description: 'Thanks for chatting!\n\nMore info about our **products**?',
304
+ description:
305
+ 'Thanks for chatting!\n\nMore info about our <strong>products</strong>?',
307
306
  buttonLink: 'https://seamly.ai',
308
307
  buttonText: 'View website',
309
308
  buttonNewTab: true,
@@ -330,7 +329,6 @@ const longTextMessage = {
330
329
  body: {
331
330
  text: 'What do you want to do? This is a really long message from a bot that has a lot to say about a lot of things. Currently I am contemplating my own bot existence and constantly asking myself who I am. What do you want to do? This is a really long message from a bot that has a lot to say about a lot of things. Currently I am contemplating my own bot existence and constantly asking myself who I am. What do you want to do? This is a really long message from a bot that has a lot to say about a lot of things. Currently I am contemplating my own bot existence and constantly asking myself who I am.',
332
331
  type: 'text',
333
- variables: {},
334
332
  },
335
333
  fromClient: false,
336
334
  fromHistory: true,
@@ -352,9 +350,8 @@ const textMessageBoldItalicUnderline = {
352
350
  type: 'message',
353
351
  payload: {
354
352
  body: {
355
- text: 'Bubble with **bold** *italic* <u>underline</u>',
353
+ text: 'Bubble with <strong>bold</strong> <em>italic</em> <u>underline</u>',
356
354
  type: 'text',
357
- variables: {},
358
355
  },
359
356
  fromClient: false,
360
357
  fromHistory: true,
@@ -376,24 +373,8 @@ const textMessageWithLinks = {
376
373
  type: 'message',
377
374
  payload: {
378
375
  body: {
379
- text: '{{link_1}} and {{link_2}} embedded in text',
376
+ text: '<a href="https://google.com" data-link-id="1">Link in same window</a> and <a href="https://google.com" data-link-id="2" target="_blank">link in new window</a> embedded in text',
380
377
  type: 'text',
381
- variables: {
382
- link_1: {
383
- id: '1',
384
- name: 'Link in same window',
385
- newTab: false,
386
- type: 'link',
387
- url: 'https://google.com',
388
- },
389
- link_2: {
390
- id: '2',
391
- name: 'link in new window',
392
- newTab: true,
393
- type: 'link',
394
- url: 'https://google.com',
395
- },
396
- },
397
378
  },
398
379
  fromClient: false,
399
380
  fromHistory: true,
@@ -415,17 +396,8 @@ const textMessageWithLongLink = {
415
396
  type: 'message',
416
397
  payload: {
417
398
  body: {
418
- text: 'Here is a long link {{link_1}} embedded in text',
399
+ text: 'Here is a long link <a href="https://google.com" data-link-id="1">click me click me please click me yoohoooo please please click me here I am click me now what are you waiting for click me now now now now now click meeeeeeeeeeeeee</a> embedded in text',
419
400
  type: 'text',
420
- variables: {
421
- link_1: {
422
- id: '1',
423
- name: 'click me click me please click me yoohoooo please please click me here I am click me now what are you waiting for click me now now now now now click meeeeeeeeeeeeee',
424
- newTab: false,
425
- type: 'link',
426
- url: 'https://google.com',
427
- },
428
- },
429
401
  },
430
402
  fromClient: false,
431
403
  fromHistory: true,
@@ -449,7 +421,6 @@ const textMesageWithBullets = {
449
421
  body: {
450
422
  text: '<ul>\n<li>Bullets</li>\n<li>bullets</li>\n<li>bullets</li>\n</ul>\n',
451
423
  type: 'text',
452
- variables: {},
453
424
  },
454
425
  fromClient: false,
455
426
  fromHistory: true,
@@ -604,7 +575,6 @@ const userMessage = {
604
575
  body: {
605
576
  text: 'This is what the user typed',
606
577
  type: 'text',
607
- variables: {},
608
578
  },
609
579
  fromClient: true,
610
580
  fromHistory: true,
@@ -623,7 +593,23 @@ const userMessageLong = {
623
593
  body: {
624
594
  text: 'This is what the user typed. And sometimes the user has quite a lot to say and then we get longer lines that need to wrap well and not break the styling so here goes with just such a line right here!!',
625
595
  type: 'text',
626
- variables: {},
596
+ },
597
+ fromClient: true,
598
+ fromHistory: true,
599
+ id: randomId(),
600
+ messageStatus: 'read',
601
+ participant: 'user',
602
+ transactionId: '1cdefea9-7437-4672-bcf8-2c75dc99244c',
603
+ transactionLast: null,
604
+ type: 'text',
605
+ },
606
+ }
607
+ const userMessageWithLinks = {
608
+ type: 'message',
609
+ payload: {
610
+ body: {
611
+ text: '<a href="https://google.com" data-link-id="1">Link in same window</a> and <a href="https://google.com" data-link-id="2" target="_blank">link in new window</a> embedded in text',
612
+ type: 'text',
627
613
  },
628
614
  fromClient: true,
629
615
  fromHistory: true,
@@ -835,7 +821,7 @@ const cardAskText = {
835
821
  },
836
822
  buttonText: 'Ask about pizzas!',
837
823
  description:
838
- 'Pizza Margherita is a **typical Neapolitan pizza**.\n\nIt is made with San Marzano tomatoes, mozzarella cheese, fresh basil, salt, and extra-virgin olive oil.',
824
+ 'Pizza Margherita is a <strong>typical Neapolitan pizza</strong>.\n\nIt is made with San Marzano tomatoes, mozzarella cheese, fresh basil, salt, and extra-virgin olive oil.',
839
825
  image:
840
826
  'https://developers.seamly.ai/clients/web-ui/static/photos/card-square.jpg',
841
827
  title: 'Pizza Margherita',
@@ -854,7 +840,8 @@ const cardNavigate = {
854
840
  type: 'navigate',
855
841
  },
856
842
  buttonText: 'Order now!',
857
- description: 'Pizza Margherita is a **typical Neapolitan pizza**.',
843
+ description:
844
+ 'Pizza Margherita is a <strong>typical Neapolitan pizza</strong>.',
858
845
  image:
859
846
  'https://developers.seamly.ai/clients/web-ui/static/photos/card-landscape.jpg',
860
847
  title: 'Pizza Margherita',
@@ -1092,6 +1079,7 @@ const standardState = {
1092
1079
  longTextMessage,
1093
1080
  userMessage,
1094
1081
  textMessageBoldItalicUnderline,
1082
+ userMessageWithLinks,
1095
1083
  newTopicDivider,
1096
1084
  imageMessage,
1097
1085
  fileDownloadAgentMessage,
@@ -1119,6 +1107,7 @@ const standardState = {
1119
1107
  userMessageLong,
1120
1108
  fileDownloadUserMessage,
1121
1109
  emptyUrlFileDownloadUserMessage,
1110
+ userMessageWithLinks,
1122
1111
  ],
1123
1112
  },
1124
1113
  withParticipants: {
@@ -1196,7 +1185,6 @@ const standardState = {
1196
1185
  body: {
1197
1186
  text: 'Long ago when a dialog started',
1198
1187
  type: 'text',
1199
- variables: {},
1200
1188
  },
1201
1189
  },
1202
1190
  },
@@ -1258,7 +1246,6 @@ const standardState = {
1258
1246
  body: {
1259
1247
  text: 'Long ago when a dialog started',
1260
1248
  type: 'text',
1261
- variables: {},
1262
1249
  },
1263
1250
  },
1264
1251
  },
@@ -1271,7 +1258,6 @@ const standardState = {
1271
1258
  body: {
1272
1259
  text: 'Above me should be a time indicator showing the full date',
1273
1260
  type: 'text',
1274
- variables: {},
1275
1261
  },
1276
1262
  },
1277
1263
  },
@@ -1284,7 +1270,6 @@ const standardState = {
1284
1270
  body: {
1285
1271
  text: 'Another message',
1286
1272
  type: 'text',
1287
- variables: {},
1288
1273
  },
1289
1274
  },
1290
1275
  },
@@ -1297,7 +1282,6 @@ const standardState = {
1297
1282
  body: {
1298
1283
  text: 'And another message',
1299
1284
  type: 'text',
1300
- variables: {},
1301
1285
  },
1302
1286
  },
1303
1287
  },
@@ -1310,7 +1294,6 @@ const standardState = {
1310
1294
  body: {
1311
1295
  text: 'Above me should be a time indicator showing "yesterday"',
1312
1296
  type: 'text',
1313
- variables: {},
1314
1297
  },
1315
1298
  },
1316
1299
  },
@@ -1323,7 +1306,6 @@ const standardState = {
1323
1306
  body: {
1324
1307
  text: 'Another message',
1325
1308
  type: 'text',
1326
- variables: {},
1327
1309
  },
1328
1310
  },
1329
1311
  },
@@ -1336,7 +1318,6 @@ const standardState = {
1336
1318
  body: {
1337
1319
  text: 'And another message',
1338
1320
  type: 'text',
1339
- variables: {},
1340
1321
  },
1341
1322
  },
1342
1323
  },
@@ -1349,7 +1330,6 @@ const standardState = {
1349
1330
  body: {
1350
1331
  text: 'Above me should be a time indicator showing me the dialog continues today',
1351
1332
  type: 'text',
1352
- variables: {},
1353
1333
  },
1354
1334
  },
1355
1335
  },
@@ -1772,6 +1752,30 @@ const inlineInterface = {
1772
1752
  },
1773
1753
  },
1774
1754
  },
1755
+ minimizedInlineCharacterLimit: {
1756
+ category: categoryKeys.minimizedInline,
1757
+ headingText: 'Inline minimized with limited characters',
1758
+ description: '',
1759
+ inline: {
1760
+ ...baseState,
1761
+ config: {
1762
+ ...baseState.config,
1763
+ layoutMode: 'inline',
1764
+ },
1765
+ visibility: {
1766
+ ...baseState.visibility,
1767
+ visibility: visibilityStates.minimized,
1768
+ },
1769
+ entryMeta: {
1770
+ ...baseState.entryMeta,
1771
+ options: {
1772
+ text: {
1773
+ limit: 120,
1774
+ },
1775
+ },
1776
+ },
1777
+ },
1778
+ },
1775
1779
  minimizedInlinePrechat: {
1776
1780
  category: categoryKeys.minimizedInline,
1777
1781
  headingText: 'Inline minimized with pre-chat messages',
@@ -1908,6 +1912,7 @@ const newInterface = {
1908
1912
  description: '',
1909
1913
  ...baseState,
1910
1914
  events: [
1915
+ getCustomMessage(shortTextMessage.payload.body),
1911
1916
  {
1912
1917
  type: 'service_data',
1913
1918
  payload: {
@@ -6,7 +6,7 @@ import {
6
6
  useSkiplink,
7
7
  useSkiplinkTargetFocusing,
8
8
  } from 'ui/hooks/seamly-hooks'
9
- import { useEvents } from 'ui/hooks/seamly-state-hooks'
9
+ import { useEvents, useLoadedImageEventIds } from 'ui/hooks/seamly-state-hooks'
10
10
  import PrivacyDisclaimer from 'ui/components/layout/privacy-disclaimer'
11
11
  import { useVisibility } from 'domains/visibility'
12
12
  import Event from './event/event'
@@ -15,21 +15,20 @@ import ComponentFilter from './component-filter'
15
15
 
16
16
  const Conversation = () => {
17
17
  const { t } = useI18n()
18
- const appBodyContainer = useRef(null)
18
+ const chatBodyContainer = useRef(null)
19
19
  const events = useEvents()
20
20
  const isLoading = useSeamlyIsLoading()
21
21
  const { isOpen } = useVisibility()
22
22
  const skiplinkTargetId = useSkiplink()
23
23
  const focusSkiplinkTarget = useSkiplinkTargetFocusing()
24
+ const loadedImageEventIds = useLoadedImageEventIds()
24
25
 
25
26
  useEffect(() => {
26
- window.requestAnimationFrame(() => {
27
- if (appBodyContainer.current) {
28
- appBodyContainer.current.scrollTop =
29
- appBodyContainer.current.scrollHeight
30
- }
31
- })
32
- }, [events, isLoading, isOpen])
27
+ const containerElement = chatBodyContainer.current
28
+ if (containerElement) {
29
+ containerElement.scrollTop = containerElement.scrollHeight
30
+ }
31
+ }, [events, isLoading, isOpen, loadedImageEventIds])
33
32
 
34
33
  const renderEvents = () => {
35
34
  let prevParticipant = null
@@ -72,7 +71,7 @@ const Conversation = () => {
72
71
  {t('skiplinkText')}
73
72
  </a>
74
73
  )}
75
- <div className={className('chat__body')} ref={appBodyContainer}>
74
+ <div className={className('chat__body')} ref={chatBodyContainer}>
76
75
  <div className={className('conversation__container')}>
77
76
  <PrivacyDisclaimer />
78
77
  <ol className={className('conversation')}>
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useRef } from 'preact/hooks'
2
2
  import { className } from 'lib/css'
3
- import parseBody from 'lib/parse-body'
4
3
  import { useGeneratedId, useSeamlyCommands } from 'ui/hooks/seamly-hooks'
5
4
  import { cardTypes, actionTypes } from 'ui/utils/seamly-utils'
6
5
 
@@ -84,7 +83,7 @@ const CardComponent = ({
84
83
  {description && (
85
84
  <div
86
85
  className={className('card__description')}
87
- dangerouslySetInnerHTML={{ __html: parseBody(description) }}
86
+ dangerouslySetInnerHTML={{ __html: description }}
88
87
  />
89
88
  )}
90
89
  <CardActionComponent
@@ -1,16 +1,17 @@
1
- import { useCallback, useState } from 'preact/hooks'
1
+ import { useCallback, useMemo, useState } from 'preact/hooks'
2
2
  import { className } from 'lib/css'
3
+ import {
4
+ useEvents,
5
+ useSeamlyCommands,
6
+ useSeamlyDispatchContext,
7
+ } from 'ui/hooks/seamly-hooks'
3
8
  import { useI18n } from 'domains/i18n'
4
9
  import { useTranslatedEventData } from 'domains/translations'
5
10
  import { useUserHasResponded } from 'domains/app'
6
11
  import { setHasResponded } from 'domains/app/actions'
7
- import { actionTypes } from '../../../utils/seamly-utils'
8
- import MessageContainer from '../message-container'
9
- import {
10
- useSeamlyCommands,
11
- useSeamlyDispatchContext,
12
- } from '../../../hooks/seamly-hooks'
13
- import SuggestionsList from '../../suggestions/suggestions-list'
12
+ import { actionTypes } from 'ui/utils/seamly-utils'
13
+ import MessageContainer from 'ui/components/conversation/message-container'
14
+ import SuggestionsList from 'ui/components/suggestions/suggestions-list'
14
15
 
15
16
  export const useSuggestions = (event) => {
16
17
  const { payload } = event
@@ -28,11 +29,20 @@ const ConversationSuggestions = ({ event, ...props }) => {
28
29
  const userResponded = useUserHasResponded()
29
30
  const { sendAction, addMessageBubble } = useSeamlyCommands()
30
31
  const { suggestions, payload } = useSuggestions(event)
32
+ const events = useEvents()
31
33
 
32
34
  const { t } = useI18n()
33
35
  const headingText = t('suggestions.headingText')
34
36
  const footerText = t('suggestions.footerText')
35
37
 
38
+ // We check if there is at least one last transaction
39
+ // to avoid rendering the suggestions before prior events are rendered.
40
+ const hasLastTransactionEvent = useMemo(
41
+ () =>
42
+ events.some(({ payload: eventPayload }) => eventPayload?.transactionLast),
43
+ [events],
44
+ )
45
+
36
46
  const handleClick = useCallback(
37
47
  ({ id, question }) => {
38
48
  setIsExpanded(false)
@@ -56,7 +66,7 @@ const ConversationSuggestions = ({ event, ...props }) => {
56
66
  [dispatch, sendAction, payload.id, addMessageBubble],
57
67
  )
58
68
 
59
- if (!isExpanded || userResponded) {
69
+ if (!isExpanded || userResponded || !hasLastTransactionEvent) {
60
70
  return null
61
71
  }
62
72
 
@@ -1,6 +1,5 @@
1
1
  import { useCallback } from 'preact/hooks'
2
2
  import { className } from 'lib/css'
3
- import parseBody from 'lib/parse-body'
4
3
  import { useGeneratedId, useSeamlyCommands } from 'ui/hooks/seamly-hooks'
5
4
  import { actionTypes } from 'ui/utils/seamly-utils'
6
5
  import MessageContainer from 'ui/components/conversation/message-container'
@@ -31,7 +30,7 @@ const Cta = ({ event }) => {
31
30
  <div
32
31
  className={className('cta__content')}
33
32
  id={descriptionId}
34
- dangerouslySetInnerHTML={{ __html: parseBody(body.description) }}
33
+ dangerouslySetInnerHTML={{ __html: body.description }}
35
34
  onClick={eventClick}
36
35
  />
37
36
  <a
@@ -1,12 +1,22 @@
1
1
  import { useState } from 'preact/hooks'
2
2
  import MessageContainer from 'ui/components/conversation/message-container'
3
3
  import { useTranslatedEventData } from 'domains/translations'
4
+ import { useStoreDispatch } from 'domains/redux'
4
5
  import ImageLightbox from './image-lightbox'
6
+ import { seamlyActions } from '../../../utils/seamly-utils'
7
+
8
+ const { SET_LOADED_IMAGE_EVENT_IDS } = seamlyActions
5
9
 
6
10
  const Image = ({ event, descriptorId, ...props }) => {
7
11
  const [body] = useTranslatedEventData(event)
8
12
  const { description, url, isZoomable } = body
9
13
  const [showLighbox, setShowLightbox] = useState(false)
14
+ const dispatch = useStoreDispatch()
15
+
16
+ const handleOnLoad = () => {
17
+ dispatch({ type: SET_LOADED_IMAGE_EVENT_IDS, eventId: event.payload.id })
18
+ setShowLightbox(true)
19
+ }
10
20
 
11
21
  return (
12
22
  <MessageContainer event={event} type="image" {...props}>
@@ -14,9 +24,7 @@ const Image = ({ event, descriptorId, ...props }) => {
14
24
  src={url}
15
25
  id={descriptorId}
16
26
  alt={description}
17
- onLoad={() => {
18
- setShowLightbox(true)
19
- }}
27
+ onLoad={handleOnLoad}
20
28
  />
21
29
  {isZoomable && showLighbox && (
22
30
  <ImageLightbox description={description} url={url} />
@@ -1,6 +1,3 @@
1
- import { useMemo } from 'preact/hooks'
2
- import Mustache from 'mustache'
3
- import parseBody from 'lib/parse-body'
4
1
  import EventDivider from 'ui/components/conversation/event-divider'
5
2
  import { useTranslatedEventData } from 'domains/translations'
6
3
 
@@ -8,13 +5,7 @@ const Participant = ({ event }) => {
8
5
  const { participant } = event.payload
9
6
  const [introduction] = useTranslatedEventData(event)
10
7
 
11
- const intro = useMemo(() => {
12
- return introduction
13
- ? Mustache.render(parseBody(introduction), participant)
14
- : undefined
15
- }, [introduction, participant])
16
-
17
- if (!intro) {
8
+ if (!introduction) {
18
9
  return null
19
10
  }
20
11
 
@@ -23,7 +14,7 @@ const Participant = ({ event }) => {
23
14
  graphicSrc={participant.avatar}
24
15
  graphicType={participant.avatar ? 'avatar' : undefined}
25
16
  iconName={!participant.avatar ? 'balloon' : undefined}
26
- childrenHTML={intro}
17
+ childrenHTML={introduction}
27
18
  dividerType="participant"
28
19
  />
29
20
  )
@@ -1,6 +1,4 @@
1
- import parseBody from '../../../../lib/parse-body'
2
1
  import useEventLinkClickHandler from './hooks/use-event-link-click-handler'
3
- import { parseRichText } from './hooks/use-text-rendering'
4
2
  import MessageContainer from '../message-container'
5
3
  import { useTranslatedEventData } from '../../../../domains/translations'
6
4
 
@@ -17,7 +15,7 @@ const Splash = ({ event, ...props }) => {
17
15
  {...props}
18
16
  bodyProps={{
19
17
  dangerouslySetInnerHTML: {
20
- __html: parseRichText(parseBody(body.text), body.variables),
18
+ __html: body.text,
21
19
  },
22
20
  }}
23
21
  />
@@ -1,28 +1,28 @@
1
1
  import { useMemo } from 'preact/hooks'
2
- import parseBody from 'lib/parse-body'
3
2
  import MessageContainer from 'ui/components/conversation/message-container'
4
3
  import { useTranslatedEventData } from 'domains/translations'
5
4
  import useEventLinkClickHandler from './hooks/use-event-link-click-handler'
6
- import { parseRichText } from './hooks/use-text-rendering'
7
5
 
8
6
  const Text = ({ event, ...props }) => {
9
7
  const [body] = useTranslatedEventData(event)
10
8
  const eventClick = useEventLinkClickHandler(event.payload.id)
11
9
 
12
10
  const containerProps = useMemo(() => {
13
- if (!event.payload.fromClient) {
11
+ if (event.payload.optimisticallyInjected) {
14
12
  return {
15
- bodyProps: {
16
- dangerouslySetInnerHTML: {
17
- __html: parseRichText(parseBody(body.text), body.variables),
18
- },
19
- },
13
+ children: <p>{body.text}</p>,
20
14
  }
21
15
  }
16
+
22
17
  return {
23
- children: <p>{body.text}</p>,
18
+ bodyProps: {
19
+ dangerouslySetInnerHTML: {
20
+ __html: body.text,
21
+ },
22
+ },
24
23
  }
25
24
  }, [body, event])
25
+
26
26
  return (
27
27
  <MessageContainer
28
28
  type="text"
@@ -64,6 +64,11 @@ export default function TextEntryForm({ controlName, skipLinkId }) {
64
64
  }
65
65
  }, [setBlockAutoEntrySwitch, hasValue])
66
66
 
67
+ const handlePointerDown = (event) => {
68
+ // When a message is submitted, the keyboard should be prevented from closing on mobile devices
69
+ event.preventDefault()
70
+ }
71
+
67
72
  return (
68
73
  <Form
69
74
  className={className('entry-form')}
@@ -99,6 +104,7 @@ export default function TextEntryForm({ controlName, skipLinkId }) {
99
104
  <button
100
105
  className={className('button', 'input__submit')}
101
106
  type="submit"
107
+ onPointerDown={handlePointerDown}
102
108
  aria-disabled={!hasValue || reachedCharacterLimit ? 'true' : null}
103
109
  >
104
110
  <Icon name="send" size="32" alt={t('input.sendMessage')} />