botframework-webchat-component 4.14.0 → 4.15.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 (453) hide show
  1. package/.eslintrc.yml +4 -106
  2. package/.prettierrc.yml +1 -1
  3. package/lib/Activity/Bubble.js +2 -2
  4. package/lib/Activity/CarouselFilmStrip.js +3 -3
  5. package/lib/Activity/CarouselFilmStripAttachment.js +2 -2
  6. package/lib/Activity/CarouselLayout.js +5 -5
  7. package/lib/Activity/Speak.js +6 -6
  8. package/lib/Activity/StackedLayout.d.ts.map +1 -1
  9. package/lib/Activity/StackedLayout.js +3 -3
  10. package/lib/Assets/TypingAnimation.js +2 -2
  11. package/lib/Attachment/AudioAttachment.js +2 -2
  12. package/lib/Attachment/AudioContent.js +2 -2
  13. package/lib/Attachment/FileAttachment.js +2 -2
  14. package/lib/Attachment/FileContent.d.ts.map +1 -1
  15. package/lib/Attachment/FileContent.js +12 -2
  16. package/lib/Attachment/HTMLVideoContent.js +2 -2
  17. package/lib/Attachment/ImageContent.js +2 -2
  18. package/lib/Attachment/TextContent.js +2 -2
  19. package/lib/Attachment/VideoAttachment.js +2 -2
  20. package/lib/Attachment/VideoContent.js +1 -1
  21. package/lib/Attachment/VimeoContent.js +2 -2
  22. package/lib/Attachment/YouTubeContent.js +2 -2
  23. package/lib/Avatar/ImageAvatar.js +2 -2
  24. package/lib/Avatar/InitialsAvatar.js +2 -2
  25. package/lib/BasicConnectivityStatus.js +2 -2
  26. package/lib/BasicSendBox.js +3 -3
  27. package/lib/BasicToast.js +4 -4
  28. package/lib/BasicToaster.js +8 -5
  29. package/lib/BasicTranscript.d.ts +7 -0
  30. package/lib/BasicTranscript.d.ts.map +1 -0
  31. package/lib/BasicTranscript.js +387 -729
  32. package/lib/BasicTypingIndicator.d.ts +2 -1
  33. package/lib/BasicTypingIndicator.d.ts.map +1 -1
  34. package/lib/BasicTypingIndicator.js +13 -5
  35. package/lib/BasicWebChat.js +2 -2
  36. package/lib/Composer.d.ts.map +1 -1
  37. package/lib/Composer.js +42 -35
  38. package/lib/ConnectivityStatus/Assets/ErrorNotificationIcon.js +2 -2
  39. package/lib/ConnectivityStatus/Assets/SpinnerAnimation.js +2 -2
  40. package/lib/ConnectivityStatus/Assets/WarningNotificationIcon.js +2 -2
  41. package/lib/ConnectivityStatus/Connected.js +1 -1
  42. package/lib/ConnectivityStatus/Connecting.js +4 -4
  43. package/lib/ConnectivityStatus/FailedToConnect.js +2 -2
  44. package/lib/ConnectivityStatus/JavaScriptError.js +2 -2
  45. package/lib/Dictation.js +4 -4
  46. package/lib/ErrorBox.js +2 -2
  47. package/lib/Middleware/Activity/createCoreMiddleware.d.ts.map +1 -1
  48. package/lib/Middleware/Activity/createCoreMiddleware.js +1 -1
  49. package/lib/Middleware/ActivityStatus/AbsoluteTime.js +1 -1
  50. package/lib/Middleware/ActivityStatus/RelativeTime.js +1 -1
  51. package/lib/Middleware/ActivityStatus/SendStatus/SendFailedRetry.js +3 -3
  52. package/lib/Middleware/ActivityStatus/SendStatus/SendStatus.js +5 -5
  53. package/lib/Middleware/ActivityStatus/Timestamp.js +2 -2
  54. package/lib/Middleware/ActivityStatus/createSendStatusMiddleware.js +21 -16
  55. package/lib/Middleware/ActivityStatus/createTimestampMiddleware.js +1 -1
  56. package/lib/Middleware/Attachment/createCoreMiddleware.js +2 -5
  57. package/lib/Middleware/AttachmentForScreenReader/AudioAttachment.js +1 -1
  58. package/lib/Middleware/AttachmentForScreenReader/FileAttachment.js +1 -1
  59. package/lib/Middleware/AttachmentForScreenReader/ImageAttachment.js +1 -1
  60. package/lib/Middleware/AttachmentForScreenReader/TextAttachment.js +1 -1
  61. package/lib/Middleware/AttachmentForScreenReader/VideoAttachment.js +1 -1
  62. package/lib/Middleware/AttachmentForScreenReader/createCoreMiddleware.d.ts.map +1 -1
  63. package/lib/Middleware/AttachmentForScreenReader/createCoreMiddleware.js +1 -1
  64. package/lib/Middleware/Avatar/createCoreMiddleware.d.ts.map +1 -1
  65. package/lib/Middleware/Avatar/createCoreMiddleware.js +3 -4
  66. package/lib/Middleware/CardAction/createCoreMiddleware.js +10 -3
  67. package/lib/Middleware/GroupActivities/createCoreMiddleware.js +1 -1
  68. package/lib/Middleware/ScrollToEndButton/ScrollToEndButton.js +2 -2
  69. package/lib/Middleware/ScrollToEndButton/createScrollToEndButtonMiddleware.d.ts.map +1 -1
  70. package/lib/Middleware/ScrollToEndButton/createScrollToEndButtonMiddleware.js +1 -1
  71. package/lib/Middleware/Toast/createCoreMiddleware.d.ts.map +1 -1
  72. package/lib/Middleware/Toast/createCoreMiddleware.js +1 -1
  73. package/lib/Middleware/TypingIndicator/createCoreMiddleware.d.ts.map +1 -1
  74. package/lib/Middleware/TypingIndicator/createCoreMiddleware.js +9 -7
  75. package/lib/ReactWebChat.js +5 -3
  76. package/lib/ScreenReaderActivity.js +17 -8
  77. package/lib/ScreenReaderText.d.ts +9 -0
  78. package/lib/ScreenReaderText.d.ts.map +1 -0
  79. package/lib/ScreenReaderText.js +22 -8
  80. package/lib/SendBox/Assets/SendIcon.js +2 -2
  81. package/lib/SendBox/AutoResizeTextArea.js +4 -4
  82. package/lib/SendBox/DictationInterims.js +3 -3
  83. package/lib/SendBox/IconButton.d.ts +11 -0
  84. package/lib/SendBox/IconButton.d.ts.map +1 -0
  85. package/lib/SendBox/IconButton.js +27 -7
  86. package/lib/SendBox/MicrophoneButton.js +5 -5
  87. package/lib/SendBox/SendButton.js +5 -5
  88. package/lib/SendBox/SuggestedAction.d.ts +17 -0
  89. package/lib/SendBox/SuggestedAction.d.ts.map +1 -0
  90. package/lib/SendBox/SuggestedAction.js +28 -19
  91. package/lib/SendBox/SuggestedActions.d.ts.map +1 -1
  92. package/lib/SendBox/SuggestedActions.js +33 -12
  93. package/lib/SendBox/TextBox.js +6 -6
  94. package/lib/SendBox/UploadButton.js +6 -6
  95. package/lib/Styles/StyleSet/BasicTranscript.d.ts +13 -5
  96. package/lib/Styles/StyleSet/BasicTranscript.d.ts.map +1 -1
  97. package/lib/Styles/StyleSet/BasicTranscript.js +21 -9
  98. package/lib/Styles/StyleSet/Bubble.d.ts.map +1 -1
  99. package/lib/Styles/StyleSet/Bubble.js +2 -2
  100. package/lib/Styles/StyleSet/CarouselFilmStrip.d.ts.map +1 -1
  101. package/lib/Styles/StyleSet/CarouselFilmStrip.js +2 -2
  102. package/lib/Styles/StyleSet/CarouselFilmStripAttachment.d.ts.map +1 -1
  103. package/lib/Styles/StyleSet/CarouselFilmStripAttachment.js +2 -2
  104. package/lib/Styles/StyleSet/KeyboardHelp.d.ts +123 -0
  105. package/lib/Styles/StyleSet/KeyboardHelp.d.ts.map +1 -0
  106. package/lib/Styles/StyleSet/KeyboardHelp.js +145 -0
  107. package/lib/Styles/StyleSet/ScrollToEndButton.d.ts +1 -1
  108. package/lib/Styles/StyleSet/ScrollToEndButton.js +2 -2
  109. package/lib/Styles/StyleSet/SendBoxButton.d.ts +56 -10
  110. package/lib/Styles/StyleSet/SendBoxButton.d.ts.map +1 -1
  111. package/lib/Styles/StyleSet/SendBoxButton.js +76 -12
  112. package/lib/Styles/StyleSet/SendBoxTextBox.d.ts +1 -1
  113. package/lib/Styles/StyleSet/SendBoxTextBox.d.ts.map +1 -1
  114. package/lib/Styles/StyleSet/SendBoxTextBox.js +3 -3
  115. package/lib/Styles/StyleSet/StackedLayout.d.ts.map +1 -1
  116. package/lib/Styles/StyleSet/StackedLayout.js +1 -1
  117. package/lib/Styles/StyleSet/SuggestedAction.d.ts +73 -28
  118. package/lib/Styles/StyleSet/SuggestedAction.d.ts.map +1 -1
  119. package/lib/Styles/StyleSet/SuggestedAction.js +116 -41
  120. package/lib/Styles/StyleSet/SuggestedActions.d.ts +13 -6
  121. package/lib/Styles/StyleSet/SuggestedActions.d.ts.map +1 -1
  122. package/lib/Styles/StyleSet/SuggestedActions.js +13 -6
  123. package/lib/Styles/createStyleSet.d.ts +323 -54
  124. package/lib/Styles/createStyleSet.d.ts.map +1 -1
  125. package/lib/Styles/createStyleSet.js +5 -2
  126. package/lib/Styles/mirrorStyle.js +13 -4
  127. package/lib/Toast/NotificationIcon.js +7 -3
  128. package/lib/Toast/createToastMiddleware.d.ts.map +1 -1
  129. package/lib/Toast/createToastMiddleware.js +1 -1
  130. package/lib/Transcript/ActivityRow.d.ts +9 -0
  131. package/lib/Transcript/ActivityRow.d.ts.map +1 -0
  132. package/lib/Transcript/ActivityRow.js +157 -0
  133. package/lib/Transcript/ActivityTextAlt.js +57 -0
  134. package/lib/Transcript/FocusTrap.d.ts +8 -0
  135. package/lib/Transcript/FocusTrap.d.ts.map +1 -0
  136. package/lib/Transcript/FocusTrap.js +74 -0
  137. package/lib/Transcript/KeyboardHelp.d.ts +4 -0
  138. package/lib/Transcript/KeyboardHelp.d.ts.map +1 -0
  139. package/lib/Transcript/KeyboardHelp.js +550 -0
  140. package/lib/Transcript/LiveRegionTranscript.d.ts +8 -0
  141. package/lib/Transcript/LiveRegionTranscript.d.ts.map +1 -0
  142. package/lib/Transcript/LiveRegionTranscript.js +214 -0
  143. package/lib/Transcript/types.d.ts +2 -0
  144. package/lib/Transcript/types.d.ts.map +1 -0
  145. package/lib/Transcript/types.js +2 -0
  146. package/lib/Transcript/useActivityAccessibleName.d.ts +4 -0
  147. package/lib/Transcript/useActivityAccessibleName.d.ts.map +1 -0
  148. package/lib/Transcript/useActivityAccessibleName.js +97 -0
  149. package/lib/Utils/AccessKeySink/Surface.js +7 -5
  150. package/lib/Utils/AccessibleButton.d.ts +11 -0
  151. package/lib/Utils/AccessibleButton.d.ts.map +1 -0
  152. package/lib/Utils/AccessibleButton.js +15 -8
  153. package/lib/Utils/AccessibleInputText.js +6 -4
  154. package/lib/Utils/AccessibleTextArea.js +6 -4
  155. package/lib/Utils/CroppedImage.js +2 -2
  156. package/lib/Utils/Fade.js +2 -2
  157. package/lib/Utils/FocusRedirector.d.ts +9 -0
  158. package/lib/Utils/FocusRedirector.d.ts.map +1 -0
  159. package/lib/Utils/FocusRedirector.js +18 -15
  160. package/lib/Utils/InlineMarkdown.js +17 -10
  161. package/lib/Utils/TypeFocusSink/FocusBox.js +6 -4
  162. package/lib/Utils/TypeFocusSink/getTabIndex.js +1 -1
  163. package/lib/Utils/TypeFocusSink/inputtableKey.d.ts +2 -0
  164. package/lib/Utils/TypeFocusSink/inputtableKey.d.ts.map +1 -0
  165. package/lib/Utils/TypeFocusSink/inputtableKey.js +5 -2
  166. package/lib/Utils/TypeFocusSink/navigableEvent.js +1 -1
  167. package/lib/Utils/activityAltText.d.ts +8 -0
  168. package/lib/Utils/activityAltText.d.ts.map +1 -0
  169. package/lib/Utils/activityAltText.js +2 -2
  170. package/lib/Utils/addTargetBlankToHyperlinksMarkdown.js +1 -1
  171. package/lib/Utils/createCustomEvent.js +9 -3
  172. package/lib/Utils/debounce.js +1 -1
  173. package/lib/Utils/detectBrowser.js +4 -2
  174. package/lib/Utils/downscaleImageToDataURL/downscaleImageToDataURLUsingWorker.js +3 -3
  175. package/lib/Utils/downscaleImageToDataURL/index.js +2 -2
  176. package/lib/Utils/filterMap.js +1 -1
  177. package/lib/Utils/findAncestor.js +17 -0
  178. package/lib/Utils/getActivityUniqueId.js +4 -2
  179. package/lib/Utils/intersectionOf.d.ts +5 -0
  180. package/lib/Utils/intersectionOf.d.ts.map +1 -0
  181. package/lib/Utils/intersectionOf.js +17 -2
  182. package/lib/Utils/isZeroOrPositive.d.ts +5 -0
  183. package/lib/Utils/isZeroOrPositive.d.ts.map +1 -0
  184. package/lib/Utils/isZeroOrPositive.js +4 -1
  185. package/lib/Utils/mapMap.js +10 -3
  186. package/lib/Utils/readDataURIToBlob.js +3 -3
  187. package/lib/Utils/scrollIntoViewWithBlockNearest.d.ts +7 -0
  188. package/lib/Utils/scrollIntoViewWithBlockNearest.d.ts.map +1 -0
  189. package/lib/Utils/scrollIntoViewWithBlockNearest.js +48 -0
  190. package/lib/Utils/shallowEquals.js +7 -3
  191. package/lib/Utils/supportPseudoClass.d.ts +2 -0
  192. package/lib/Utils/supportPseudoClass.d.ts.map +1 -0
  193. package/lib/Utils/supportPseudoClass.js +23 -0
  194. package/lib/Utils/tabbableElements.d.ts +2 -0
  195. package/lib/Utils/tabbableElements.d.ts.map +1 -0
  196. package/lib/Utils/tabbableElements.js +2 -2
  197. package/lib/connectToWebChat.js +17 -7
  198. package/lib/hooks/index.js +24 -24
  199. package/lib/hooks/internal/BypassSpeechSynthesisPonyfill.js +100 -41
  200. package/lib/hooks/internal/UITracker.js +2 -2
  201. package/lib/hooks/internal/useChanged.js +8 -1
  202. package/lib/hooks/internal/useDispatchScrollPosition.js +3 -7
  203. package/lib/hooks/internal/useDispatchTranscriptFocusByActivityKey.d.ts +2 -0
  204. package/lib/hooks/internal/useDispatchTranscriptFocusByActivityKey.d.ts.map +1 -0
  205. package/lib/hooks/internal/useDispatchTranscriptFocusByActivityKey.js +15 -0
  206. package/lib/hooks/internal/useEnterKeyHint.js +1 -1
  207. package/lib/hooks/internal/useFocusVisible.d.ts +3 -0
  208. package/lib/hooks/internal/useFocusVisible.d.ts.map +1 -0
  209. package/lib/hooks/internal/useFocusVisible.js +48 -0
  210. package/lib/hooks/internal/useForceRender.js +2 -2
  211. package/lib/hooks/internal/useForceRenderAtInterval.js +2 -2
  212. package/lib/hooks/internal/useInternalRenderMarkdownInline.js +1 -1
  213. package/lib/hooks/internal/useLocalizeAccessKey.js +2 -2
  214. package/lib/hooks/internal/useMemoWithPrevious.d.ts +3 -0
  215. package/lib/hooks/internal/useMemoWithPrevious.d.ts.map +1 -0
  216. package/lib/hooks/internal/useMemoWithPrevious.js +22 -0
  217. package/lib/hooks/internal/useMemoize.d.ts +14 -0
  218. package/lib/hooks/internal/useMemoize.d.ts.map +1 -0
  219. package/lib/hooks/internal/useMemoize.js +12 -3
  220. package/lib/hooks/internal/useNavigatorPlatform.js +1 -1
  221. package/lib/hooks/internal/useNonce.js +1 -1
  222. package/lib/hooks/internal/useObserveFocusVisible.d.ts +3 -0
  223. package/lib/hooks/internal/useObserveFocusVisible.d.ts.map +1 -0
  224. package/lib/hooks/internal/useObserveFocusVisible.js +208 -0
  225. package/lib/hooks/internal/usePrevious.d.ts +2 -0
  226. package/lib/hooks/internal/usePrevious.d.ts.map +1 -0
  227. package/lib/hooks/internal/usePrevious.js +18 -0
  228. package/lib/hooks/internal/useRegisterFocusSendBox.js +1 -1
  229. package/lib/hooks/internal/useRegisterFocusTranscript.js +1 -1
  230. package/lib/hooks/internal/useRegisterScrollRelative.js +1 -1
  231. package/lib/hooks/internal/useRegisterScrollTo.js +1 -1
  232. package/lib/hooks/internal/useRegisterScrollToEnd.js +1 -1
  233. package/lib/hooks/internal/useReplaceEmoticon.js +2 -2
  234. package/lib/hooks/internal/useResumeAudioContext.js +2 -2
  235. package/lib/hooks/internal/useScrollRelative.js +1 -1
  236. package/lib/hooks/internal/useSettableDictateAbortable.js +1 -1
  237. package/lib/hooks/internal/useStateRef.d.ts +3 -0
  238. package/lib/hooks/internal/useStateRef.d.ts.map +1 -0
  239. package/lib/hooks/internal/useStateRef.js +40 -0
  240. package/lib/hooks/internal/useSuggestedActionsAccessKey.js +1 -1
  241. package/lib/hooks/internal/useValueRef.d.ts +3 -0
  242. package/lib/hooks/internal/useValueRef.d.ts.map +1 -0
  243. package/lib/hooks/internal/useValueRef.js +25 -0
  244. package/lib/hooks/useDictateAbortable.js +2 -2
  245. package/lib/hooks/useFocus.d.ts +1 -1
  246. package/lib/hooks/useFocus.d.ts.map +1 -1
  247. package/lib/hooks/useFocus.js +1 -1
  248. package/lib/hooks/useObserveScrollPosition.js +2 -2
  249. package/lib/hooks/useObserveTranscriptFocus.js +2 -2
  250. package/lib/hooks/useRenderMarkdownAsHTML.d.ts.map +1 -1
  251. package/lib/hooks/useRenderMarkdownAsHTML.js +2 -2
  252. package/lib/hooks/useScrollTo.d.ts.map +1 -1
  253. package/lib/hooks/useScrollTo.js +1 -1
  254. package/lib/hooks/useScrollToEnd.d.ts.map +1 -1
  255. package/lib/hooks/useScrollToEnd.js +1 -1
  256. package/lib/hooks/useSendFiles.js +3 -3
  257. package/lib/index.d.ts +10 -0
  258. package/lib/index.d.ts.map +1 -1
  259. package/lib/index.js +20 -18
  260. package/lib/providers/ActivityTree/ActivityTreeComposer.d.ts +5 -0
  261. package/lib/providers/ActivityTree/ActivityTreeComposer.d.ts.map +1 -0
  262. package/lib/providers/ActivityTree/ActivityTreeComposer.js +86 -0
  263. package/lib/providers/ActivityTree/private/Context.d.ts +9 -0
  264. package/lib/providers/ActivityTree/private/Context.d.ts.map +1 -0
  265. package/lib/providers/ActivityTree/private/Context.js +13 -0
  266. package/lib/providers/ActivityTree/private/types.d.ts +10 -0
  267. package/lib/providers/ActivityTree/private/types.d.ts.map +1 -0
  268. package/lib/providers/ActivityTree/private/types.js +2 -0
  269. package/lib/providers/ActivityTree/private/useActivitiesWithRenderer.d.ts +4 -0
  270. package/lib/providers/ActivityTree/private/useActivitiesWithRenderer.d.ts.map +1 -0
  271. package/lib/providers/ActivityTree/private/useActivitiesWithRenderer.js +58 -0
  272. package/lib/providers/ActivityTree/private/useActivityTreeWithRenderer.d.ts +5 -0
  273. package/lib/providers/ActivityTree/private/useActivityTreeWithRenderer.d.ts.map +1 -0
  274. package/lib/providers/ActivityTree/private/useActivityTreeWithRenderer.js +166 -0
  275. package/lib/providers/ActivityTree/private/useContext.d.ts +3 -0
  276. package/lib/providers/ActivityTree/private/useContext.d.ts.map +1 -0
  277. package/lib/providers/ActivityTree/private/useContext.js +24 -0
  278. package/lib/providers/ActivityTree/useActivityTreeWithRenderer.d.ts +8 -0
  279. package/lib/providers/ActivityTree/useActivityTreeWithRenderer.d.ts.map +1 -0
  280. package/lib/providers/ActivityTree/useActivityTreeWithRenderer.js +17 -0
  281. package/lib/providers/LiveRegionTwin/LiveRegionTwinComposer.d.ts +35 -0
  282. package/lib/providers/LiveRegionTwin/LiveRegionTwinComposer.d.ts.map +1 -0
  283. package/lib/providers/LiveRegionTwin/LiveRegionTwinComposer.js +156 -0
  284. package/lib/providers/LiveRegionTwin/private/Context.d.ts +10 -0
  285. package/lib/providers/LiveRegionTwin/private/Context.d.ts.map +1 -0
  286. package/lib/providers/LiveRegionTwin/private/Context.js +13 -0
  287. package/lib/providers/LiveRegionTwin/private/LiveRegionTwinContainer.d.ts +11 -0
  288. package/lib/providers/LiveRegionTwin/private/LiveRegionTwinContainer.d.ts.map +1 -0
  289. package/lib/providers/LiveRegionTwin/private/LiveRegionTwinContainer.js +86 -0
  290. package/lib/providers/LiveRegionTwin/private/types.d.ts +8 -0
  291. package/lib/providers/LiveRegionTwin/private/types.d.ts.map +1 -0
  292. package/lib/providers/LiveRegionTwin/private/types.js +2 -0
  293. package/lib/providers/LiveRegionTwin/private/useContext.d.ts +3 -0
  294. package/lib/providers/LiveRegionTwin/private/useContext.d.ts.map +1 -0
  295. package/lib/providers/LiveRegionTwin/private/useContext.js +24 -0
  296. package/lib/providers/LiveRegionTwin/private/useMarkAllAsRenderedEffect.d.ts +2 -0
  297. package/lib/providers/LiveRegionTwin/private/useMarkAllAsRenderedEffect.d.ts.map +1 -0
  298. package/lib/providers/LiveRegionTwin/private/useMarkAllAsRenderedEffect.js +24 -0
  299. package/lib/providers/LiveRegionTwin/private/useStaticElementEntries.d.ts +3 -0
  300. package/lib/providers/LiveRegionTwin/private/useStaticElementEntries.d.ts.map +1 -0
  301. package/lib/providers/LiveRegionTwin/private/useStaticElementEntries.js +15 -0
  302. package/lib/providers/LiveRegionTwin/useQueueStaticElement.d.ts +8 -0
  303. package/lib/providers/LiveRegionTwin/useQueueStaticElement.d.ts.map +1 -0
  304. package/lib/providers/LiveRegionTwin/useQueueStaticElement.js +20 -0
  305. package/lib/providers/TranscriptFocus/TranscriptFocusComposer.d.ts +7 -0
  306. package/lib/providers/TranscriptFocus/TranscriptFocusComposer.d.ts.map +1 -0
  307. package/lib/providers/TranscriptFocus/TranscriptFocusComposer.js +184 -0
  308. package/lib/providers/TranscriptFocus/private/Context.d.ts +12 -0
  309. package/lib/providers/TranscriptFocus/private/Context.d.ts.map +1 -0
  310. package/lib/providers/TranscriptFocus/private/Context.js +13 -0
  311. package/lib/providers/TranscriptFocus/private/useContext.d.ts +2 -0
  312. package/lib/providers/TranscriptFocus/private/useContext.d.ts.map +1 -0
  313. package/lib/providers/TranscriptFocus/private/useContext.js +24 -0
  314. package/lib/providers/TranscriptFocus/useActiveDescendantId.d.ts +2 -0
  315. package/lib/providers/TranscriptFocus/useActiveDescendantId.d.ts.map +1 -0
  316. package/lib/providers/TranscriptFocus/useActiveDescendantId.js +15 -0
  317. package/lib/providers/TranscriptFocus/useFocusByActivityKey.d.ts +8 -0
  318. package/lib/providers/TranscriptFocus/useFocusByActivityKey.d.ts.map +1 -0
  319. package/lib/providers/TranscriptFocus/useFocusByActivityKey.js +21 -0
  320. package/lib/providers/TranscriptFocus/useFocusRelativeActivity.d.ts +2 -0
  321. package/lib/providers/TranscriptFocus/useFocusRelativeActivity.d.ts.map +1 -0
  322. package/lib/providers/TranscriptFocus/useFocusRelativeActivity.js +15 -0
  323. package/lib/providers/TranscriptFocus/useFocusedActivityKey.d.ts +2 -0
  324. package/lib/providers/TranscriptFocus/useFocusedActivityKey.d.ts.map +1 -0
  325. package/lib/providers/TranscriptFocus/useFocusedActivityKey.js +15 -0
  326. package/lib/providers/TranscriptFocus/useFocusedExplicitly.d.ts +2 -0
  327. package/lib/providers/TranscriptFocus/useFocusedExplicitly.d.ts.map +1 -0
  328. package/lib/providers/TranscriptFocus/useFocusedExplicitly.js +15 -0
  329. package/lib/providers/TranscriptFocus/useGetDescendantIdByActivityKey.d.ts +2 -0
  330. package/lib/providers/TranscriptFocus/useGetDescendantIdByActivityKey.d.ts.map +1 -0
  331. package/lib/providers/TranscriptFocus/useGetDescendantIdByActivityKey.js +15 -0
  332. package/package.json +25 -33
  333. package/src/Activity/CarouselFilmStrip.js +2 -3
  334. package/src/Activity/CarouselFilmStripAttachment.js +0 -1
  335. package/src/Activity/StackedLayout.tsx +10 -9
  336. package/src/Attachment/FileAttachment.js +1 -1
  337. package/src/Attachment/FileContent.tsx +12 -0
  338. package/src/BasicToaster.js +9 -5
  339. package/src/BasicTranscript.tsx +898 -0
  340. package/src/BasicTypingIndicator.tsx +3 -2
  341. package/src/Composer.tsx +41 -29
  342. package/src/Dictation.js +4 -3
  343. package/src/Middleware/Activity/createCoreMiddleware.tsx +50 -44
  344. package/src/Middleware/ActivityStatus/createSendStatusMiddleware.js +10 -6
  345. package/src/Middleware/ActivityStatus/createTimestampMiddleware.js +10 -8
  346. package/src/Middleware/Attachment/createCoreMiddleware.tsx +28 -28
  347. package/src/Middleware/AttachmentForScreenReader/createCoreMiddleware.tsx +25 -23
  348. package/src/Middleware/Avatar/createCoreMiddleware.tsx +9 -8
  349. package/src/Middleware/CardAction/createCoreMiddleware.js +50 -41
  350. package/src/Middleware/GroupActivities/createCoreMiddleware.js +6 -4
  351. package/src/Middleware/ScrollToEndButton/createScrollToEndButtonMiddleware.ts +11 -9
  352. package/src/Middleware/Toast/createCoreMiddleware.tsx +12 -10
  353. package/src/Middleware/TypingIndicator/createCoreMiddleware.tsx +8 -2
  354. package/src/ScreenReaderActivity.js +20 -6
  355. package/src/{ScreenReaderText.js → ScreenReaderText.tsx} +27 -9
  356. package/src/SendBox/{IconButton.js → IconButton.tsx} +19 -3
  357. package/src/SendBox/{SuggestedAction.js → SuggestedAction.tsx} +72 -35
  358. package/src/SendBox/SuggestedActions.tsx +64 -21
  359. package/src/Styles/StyleSet/BasicTranscript.ts +34 -20
  360. package/src/Styles/StyleSet/Bubble.ts +0 -1
  361. package/src/Styles/StyleSet/CarouselFilmStrip.ts +12 -10
  362. package/src/Styles/StyleSet/CarouselFilmStripAttachment.ts +4 -3
  363. package/src/Styles/StyleSet/KeyboardHelp.ts +157 -0
  364. package/src/Styles/StyleSet/ScrollToEndButton.ts +1 -1
  365. package/src/Styles/StyleSet/SendBoxButton.ts +84 -13
  366. package/src/Styles/StyleSet/SendBoxTextBox.ts +1 -2
  367. package/src/Styles/StyleSet/StackedLayout.ts +13 -11
  368. package/src/Styles/StyleSet/SuggestedAction.ts +129 -42
  369. package/src/Styles/StyleSet/SuggestedActions.ts +13 -5
  370. package/src/Styles/createStyleSet.ts +2 -1
  371. package/src/Styles/mirrorStyle.js +10 -2
  372. package/src/Toast/NotificationIcon.js +4 -1
  373. package/src/Toast/createToastMiddleware.tsx +4 -1
  374. package/src/Transcript/ActivityRow.tsx +124 -0
  375. package/src/Transcript/ActivityTextAlt.tsx +32 -0
  376. package/src/Transcript/FocusTrap.tsx +64 -0
  377. package/src/Transcript/KeyboardHelp.tsx +282 -0
  378. package/src/Transcript/LiveRegionTranscript.tsx +181 -0
  379. package/src/Transcript/types.ts +1 -0
  380. package/src/Transcript/useActivityAccessibleName.ts +85 -0
  381. package/src/Utils/{AccessibleButton.js → AccessibleButton.tsx} +19 -4
  382. package/src/Utils/{FocusRedirector.js → FocusRedirector.tsx} +21 -8
  383. package/src/Utils/InlineMarkdown.js +18 -2
  384. package/src/Utils/TypeFocusSink/FocusBox.js +4 -4
  385. package/src/Utils/TypeFocusSink/inputtableKey.ts +5 -1
  386. package/src/Utils/createCustomEvent.js +7 -1
  387. package/src/Utils/detectBrowser.js +2 -1
  388. package/src/Utils/findAncestor.ts +12 -0
  389. package/src/Utils/getActivityUniqueId.ts +5 -0
  390. package/src/Utils/intersectionOf.ts +14 -0
  391. package/src/Utils/isZeroOrPositive.ts +7 -0
  392. package/src/Utils/mapMap.js +7 -1
  393. package/src/Utils/scrollIntoViewWithBlockNearest.ts +20 -0
  394. package/src/Utils/shallowEquals.js +8 -1
  395. package/src/Utils/supportPseudoClass.ts +17 -0
  396. package/src/Utils/{tabbableElements.js → tabbableElements.ts} +6 -5
  397. package/src/connectToWebChat.js +11 -4
  398. package/src/hooks/internal/BypassSpeechSynthesisPonyfill.js +70 -17
  399. package/src/hooks/internal/useChanged.ts +17 -0
  400. package/src/hooks/internal/useDispatchScrollPosition.js +1 -3
  401. package/src/hooks/internal/useDispatchTranscriptFocusByActivityKey.ts +5 -0
  402. package/src/hooks/internal/useFocusVisible.ts +22 -0
  403. package/src/hooks/internal/useMemoWithPrevious.ts +16 -0
  404. package/src/hooks/internal/useMemoize.spec.js +1 -1
  405. package/src/hooks/internal/useMemoize.ts +53 -0
  406. package/src/hooks/internal/useObserveFocusVisible.ts +252 -0
  407. package/src/hooks/internal/usePrevious.ts +12 -0
  408. package/src/hooks/internal/useScrollRelative.js +4 -3
  409. package/src/hooks/internal/useStateRef.ts +31 -0
  410. package/src/hooks/internal/useValueRef.ts +22 -0
  411. package/src/hooks/useFocus.ts +1 -1
  412. package/src/hooks/useRenderMarkdownAsHTML.ts +4 -5
  413. package/src/hooks/useScrollTo.ts +4 -3
  414. package/src/hooks/useScrollToEnd.ts +4 -3
  415. package/src/index.ts +0 -1
  416. package/src/providers/ActivityTree/ActivityTreeComposer.tsx +74 -0
  417. package/src/providers/ActivityTree/private/Context.ts +12 -0
  418. package/src/providers/ActivityTree/private/types.ts +12 -0
  419. package/src/providers/ActivityTree/private/useActivitiesWithRenderer.ts +66 -0
  420. package/src/providers/ActivityTree/private/useActivityTreeWithRenderer.ts +140 -0
  421. package/src/providers/ActivityTree/private/useContext.ts +15 -0
  422. package/src/providers/ActivityTree/useActivityTreeWithRenderer.ts +16 -0
  423. package/src/providers/LiveRegionTwin/LiveRegionTwinComposer.tsx +154 -0
  424. package/src/providers/LiveRegionTwin/private/Context.ts +15 -0
  425. package/src/providers/LiveRegionTwin/private/LiveRegionTwinContainer.tsx +64 -0
  426. package/src/providers/LiveRegionTwin/private/types.ts +10 -0
  427. package/src/providers/LiveRegionTwin/private/useContext.ts +15 -0
  428. package/src/providers/LiveRegionTwin/private/useMarkAllAsRenderedEffect.ts +13 -0
  429. package/src/providers/LiveRegionTwin/private/useStaticElementEntries.ts +7 -0
  430. package/src/providers/LiveRegionTwin/useQueueStaticElement.ts +12 -0
  431. package/src/providers/TranscriptFocus/TranscriptFocusComposer.tsx +180 -0
  432. package/src/providers/TranscriptFocus/private/Context.ts +16 -0
  433. package/src/providers/TranscriptFocus/private/useContext.ts +13 -0
  434. package/src/providers/TranscriptFocus/useActiveDescendantId.ts +5 -0
  435. package/src/providers/TranscriptFocus/useFocusByActivityKey.ts +14 -0
  436. package/src/providers/TranscriptFocus/useFocusRelativeActivity.ts +5 -0
  437. package/src/providers/TranscriptFocus/useFocusedActivityKey.ts +5 -0
  438. package/src/providers/TranscriptFocus/useFocusedExplicitly.ts +5 -0
  439. package/src/providers/TranscriptFocus/useGetDescendantIdByActivityKey.ts +5 -0
  440. package/.eslintignore +0 -1
  441. package/lib/Utils/findLastIndex.js +0 -32
  442. package/lib/hooks/internal/useAcknowledgedActivity.js +0 -90
  443. package/lib/hooks/internal/useDispatchTranscriptFocus.js +0 -19
  444. package/src/BasicTranscript.js +0 -1140
  445. package/src/Utils/findLastIndex.js +0 -11
  446. package/src/Utils/findLastIndex.spec.js +0 -31
  447. package/src/Utils/getActivityUniqueId.js +0 -3
  448. package/src/Utils/intersectionOf.js +0 -11
  449. package/src/Utils/isZeroOrPositive.js +0 -4
  450. package/src/hooks/internal/useAcknowledgedActivity.js +0 -65
  451. package/src/hooks/internal/useChanged.js +0 -10
  452. package/src/hooks/internal/useDispatchTranscriptFocus.js +0 -7
  453. package/src/hooks/internal/useMemoize.js +0 -37
@@ -4,14 +4,16 @@ import ScrollToEndButton from './ScrollToEndButton';
4
4
 
5
5
  export default function createScrollToEndButtonMiddleware(): ScrollToEndButtonMiddleware[] {
6
6
  return [
7
- () => () => ({ atEnd, styleOptions: { scrollToEndButtonBehavior }, unread }) =>
8
- !scrollToEndButtonBehavior
9
- ? // Don't show the button when it is set to false.
10
- false
11
- : scrollToEndButtonBehavior === 'any'
12
- ? // Show when the scroll view is not at the end, regardless of number of unread activities.
13
- !atEnd && ScrollToEndButton
14
- : // Show when the scroll view is not at the end of the transcript, and there are new/unread activities.
15
- !atEnd && unread && ScrollToEndButton
7
+ () =>
8
+ () =>
9
+ ({ atEnd, styleOptions: { scrollToEndButtonBehavior }, unread }) =>
10
+ !scrollToEndButtonBehavior
11
+ ? // Don't show the button when it is set to false.
12
+ false
13
+ : scrollToEndButtonBehavior === 'any'
14
+ ? // Show when the scroll view is not at the end, regardless of number of unread activities.
15
+ !atEnd && ScrollToEndButton
16
+ : // Show when the scroll view is not at the end of the transcript, and there are new/unread activities.
17
+ !atEnd && unread && ScrollToEndButton
16
18
  ];
17
19
  }
@@ -4,17 +4,19 @@ import createToastMiddleware from '../../Toast/createToastMiddleware';
4
4
 
5
5
  function createCoreMiddleware(): ToastMiddleware[] {
6
6
  return [
7
- () => next => (...args) => {
8
- const [
9
- {
10
- notification: { id }
11
- }
12
- ] = args;
7
+ () =>
8
+ next =>
9
+ (...args) => {
10
+ const [
11
+ {
12
+ notification: { id }
13
+ }
14
+ ] = args;
13
15
 
14
- // We are ignoring "connectivitystatus" notifications, we will render it using <BasicConnectivityStatus> instead.
15
- // If devs want to render it, they can add a middleware.
16
- return id !== 'connectivitystatus' && next(...args);
17
- },
16
+ // We are ignoring "connectivitystatus" notifications, we will render it using <BasicConnectivityStatus> instead.
17
+ // If devs want to render it, they can add a middleware.
18
+ return id !== 'connectivitystatus' && next(...args);
19
+ },
18
20
  createToastMiddleware()
19
21
  ];
20
22
  }
@@ -21,6 +21,12 @@ const DotIndicator = () => {
21
21
 
22
22
  // TODO: [P4] Rename this file or the whole middleware, it looks either too simple or too comprehensive now
23
23
  export default function createCoreMiddleware(): TypingIndicatorMiddleware[] {
24
- /* eslint-disable-next-line react/prop-types */
25
- return [() => () => ({ visible }) => visible && <DotIndicator />];
24
+ return [
25
+ () =>
26
+ () =>
27
+ // This is not a React component.
28
+ // eslint-disable-next-line react/prop-types
29
+ ({ visible }) =>
30
+ visible && <DotIndicator />
31
+ ];
26
32
  }
@@ -9,7 +9,13 @@ import activityAltText from './Utils/activityAltText';
9
9
  import useStyleToEmotionObject from './hooks/internal/useStyleToEmotionObject';
10
10
  import useRenderMarkdownAsHTML from './hooks/useRenderMarkdownAsHTML';
11
11
 
12
- const { useAvatarForBot, useCreateAttachmentForScreenReaderRenderer, useDateFormatter, useLocalizer } = hooks;
12
+ const {
13
+ useAvatarForBot,
14
+ useCreateAttachmentForScreenReaderRenderer,
15
+ useDateFormatter,
16
+ useGetKeyByActivity,
17
+ useLocalizer
18
+ } = hooks;
13
19
 
14
20
  const ROOT_STYLE = {
15
21
  '&.webchat__screen-reader-activity': {
@@ -76,6 +82,7 @@ ScreenReaderAttachments.propTypes = {
76
82
  const ScreenReaderActivity = ({ activity, children, id, renderAttachments }) => {
77
83
  const [{ initials: botInitials }] = useAvatarForBot();
78
84
  const formatDate = useDateFormatter();
85
+ const getKeyByActivity = useGetKeyByActivity();
79
86
  const localize = useLocalizer();
80
87
  const renderMarkdownAsHTML = useRenderMarkdownAsHTML();
81
88
  const rootClassName = useStyleToEmotionObject()(ROOT_STYLE) + '';
@@ -85,24 +92,31 @@ const ScreenReaderActivity = ({ activity, children, id, renderAttachments }) =>
85
92
 
86
93
  const fromUser = role === 'user';
87
94
 
88
- const greetingAlt = (fromUser
89
- ? localize('ACTIVITY_YOU_SAID_ALT')
90
- : localize('ACTIVITY_BOT_SAID_ALT', botInitials || '')
95
+ const greetingAlt = (
96
+ fromUser ? localize('ACTIVITY_YOU_SAID_ALT') : localize('ACTIVITY_BOT_SAID_ALT', botInitials || '')
91
97
  ).replace(/\s{2,}/gu, ' ');
92
98
 
93
99
  const timestampAlt = localize('ACTIVITY_STATUS_SEND_STATUS_ALT_SENT_AT', formatDate(timestamp));
100
+ const labelId = useMemo(
101
+ () => `webchat__screen-reader-activity__label-${getKeyByActivity(activity)}`,
102
+ [activity, getKeyByActivity]
103
+ );
94
104
 
95
105
  return (
96
106
  <article
97
107
  aria-atomic={true}
108
+ // Narrator requires the "aria-labelledby" attribute, otherwise, it will only read "aria-roledescription".
109
+ // However, iOS VoiceOver and NVDA both ignore the "aria-labelledby" and read out the whole content, including timestamp.
110
+ aria-labelledby={labelId}
98
111
  aria-roledescription="message"
99
112
  className={classNames('webchat__screen-reader-activity', rootClassName)}
100
113
  // "id" attribute is used by `aria-labelledby`.
101
114
  // eslint-disable-next-line react/forbid-dom-props
102
115
  id={id}
103
- role="region"
104
116
  >
105
- <p>
117
+ {/* "id" attribute is used by `aria-labelledby`. */}
118
+ {/* eslint-disable-next-line react/forbid-dom-props */}
119
+ <p id={labelId}>
106
120
  <span>{greetingAlt}</span>
107
121
  <span>{textAlt}</span>
108
122
  </p>
@@ -1,7 +1,9 @@
1
1
  /* eslint react/forbid-dom-props: ["off"] */
2
2
 
3
3
  import PropTypes from 'prop-types';
4
- import React from 'react';
4
+ import React, { forwardRef } from 'react';
5
+
6
+ import type { VFC } from 'react';
5
7
 
6
8
  import useStyleToEmotionObject from './hooks/internal/useStyleToEmotionObject';
7
9
 
@@ -21,21 +23,37 @@ const ROOT_STYLE = {
21
23
  width: 1
22
24
  };
23
25
 
24
- const ScreenReaderText = ({ id, text }) => {
25
- const rootClassName = useStyleToEmotionObject()(ROOT_STYLE) + '';
26
-
27
- return (
28
- <div className={rootClassName} id={id}>
29
- {text}
30
- </div>
31
- );
26
+ type ScreenReaderTextProps = {
27
+ 'aria-hidden'?: boolean;
28
+ id?: string;
29
+ text: string;
32
30
  };
33
31
 
32
+ const ScreenReaderText: VFC<ScreenReaderTextProps> = forwardRef<HTMLDivElement, ScreenReaderTextProps>(
33
+ ({ 'aria-hidden': ariaHidden, id, text }, ref) => {
34
+ const rootClassName = useStyleToEmotionObject()(ROOT_STYLE) + '';
35
+
36
+ if (ariaHidden && !id) {
37
+ console.warn(
38
+ 'botframework-webchat assertion: when "aria-hidden" is set, the screen reader text should be read by "aria-labelledby". Thus, "id" must be set.'
39
+ );
40
+ }
41
+
42
+ return (
43
+ <div aria-hidden={ariaHidden} className={rootClassName} id={id} ref={ref}>
44
+ {text}
45
+ </div>
46
+ );
47
+ }
48
+ );
49
+
34
50
  ScreenReaderText.defaultProps = {
51
+ 'aria-hidden': undefined,
35
52
  id: undefined
36
53
  };
37
54
 
38
55
  ScreenReaderText.propTypes = {
56
+ 'aria-hidden': PropTypes.bool,
39
57
  id: PropTypes.string,
40
58
  text: PropTypes.string.isRequired
41
59
  };
@@ -1,16 +1,28 @@
1
1
  import { hooks } from 'botframework-webchat-api';
2
2
  import classNames from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
- import React from 'react';
4
+ import React, { FC, MouseEventHandler, ReactNode, useRef } from 'react';
5
5
 
6
6
  import AccessibleButton from '../Utils/AccessibleButton';
7
+ import useFocusVisible from '../hooks/internal/useFocusVisible';
7
8
  import useStyleSet from '../hooks/useStyleSet';
8
9
 
9
10
  const { useStyleOptions } = hooks;
10
11
 
11
- const IconButton = ({ alt, children, className, disabled, onClick }) => {
12
- const [{ sendBoxButtonAlignment }] = useStyleOptions();
12
+ type IconButtonProps = {
13
+ alt?: string;
14
+ children?: ReactNode;
15
+ className?: string;
16
+ disabled?: boolean;
17
+ onClick?: MouseEventHandler<HTMLButtonElement>;
18
+ };
19
+
20
+ const IconButton: FC<IconButtonProps> = ({ alt, children, className, disabled, onClick }) => {
13
21
  const [{ sendBoxButton: sendBoxButtonStyleSet }] = useStyleSet();
22
+ const [{ sendBoxButtonAlignment }] = useStyleOptions();
23
+ const buttonRef = useRef<HTMLButtonElement>();
24
+
25
+ const [focusVisible] = useFocusVisible(buttonRef);
14
26
 
15
27
  return (
16
28
  <AccessibleButton
@@ -18,16 +30,20 @@ const IconButton = ({ alt, children, className, disabled, onClick }) => {
18
30
  sendBoxButtonStyleSet + '',
19
31
  'webchat__icon-button',
20
32
  {
33
+ 'webchat__icon-button--focus-visible': focusVisible,
21
34
  'webchat__icon-button--stretch': sendBoxButtonAlignment !== 'bottom' && sendBoxButtonAlignment !== 'top'
22
35
  },
23
36
  className + ''
24
37
  )}
25
38
  disabled={disabled}
26
39
  onClick={disabled ? undefined : onClick}
40
+ ref={buttonRef}
27
41
  title={alt}
28
42
  type="button"
29
43
  >
44
+ <div className="webchat__icon-button__shade" />
30
45
  {children}
46
+ <div className="webchat__icon-button__keyboard-focus-indicator" />
31
47
  </AccessibleButton>
32
48
  );
33
49
  };
@@ -1,26 +1,26 @@
1
1
  import { hooks } from 'botframework-webchat-api';
2
2
  import classNames from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
- import React, { useCallback, useRef } from 'react';
4
+ import React, { MouseEventHandler, useCallback, useRef, VFC } from 'react';
5
5
 
6
6
  import AccessibleButton from '../Utils/AccessibleButton';
7
7
  import connectToWebChat from '../connectToWebChat';
8
8
  import useFocus from '../hooks/useFocus';
9
9
  import useFocusAccessKeyEffect from '../Utils/AccessKeySink/useFocusAccessKeyEffect';
10
+ import useFocusVisible from '../hooks/internal/useFocusVisible';
10
11
  import useLocalizeAccessKey from '../hooks/internal/useLocalizeAccessKey';
11
12
  import useScrollToEnd from '../hooks/useScrollToEnd';
12
13
  import useSuggestedActionsAccessKey from '../hooks/internal/useSuggestedActionsAccessKey';
13
14
  import useStyleSet from '../hooks/useStyleSet';
14
15
  import useStyleToEmotionObject from '../hooks/internal/useStyleToEmotionObject';
16
+ import { DirectLineCardAction } from 'botframework-webchat-core';
15
17
 
16
18
  const { useDirection, useDisabled, usePerformCardAction, useStyleOptions, useSuggestedActions } = hooks;
17
19
 
18
20
  const ROOT_STYLE = {
19
21
  '&.webchat__suggested-action': {
20
- '& .webchat__suggested-action__button': {
21
- display: 'flex',
22
- overflow: 'hidden' // Prevent image from leaking; object-fit does not work with IE11
23
- }
22
+ display: 'flex',
23
+ overflow: 'hidden' // Prevent image from leaking; object-fit does not work with IE11
24
24
  }
25
25
  };
26
26
 
@@ -37,7 +37,39 @@ const connectSuggestedAction = (...selectors) =>
37
37
  ...selectors
38
38
  );
39
39
 
40
- const SuggestedAction = ({ buttonText, className, displayText, image, imageAlt, text, textClassName, type, value }) => {
40
+ type SuggestedActionProps = {
41
+ buttonText: string;
42
+ className?: string;
43
+ displayText?: string;
44
+ image?: string;
45
+ imageAlt?: string;
46
+ text?: string;
47
+ textClassName?: string;
48
+ type?:
49
+ | 'call'
50
+ | 'downloadFile'
51
+ | 'imBack'
52
+ | 'messageBack'
53
+ | 'openUrl'
54
+ | 'playAudio'
55
+ | 'playVideo'
56
+ | 'postBack'
57
+ | 'showImage'
58
+ | 'signin';
59
+ value?: any;
60
+ };
61
+
62
+ const SuggestedAction: VFC<SuggestedActionProps> = ({
63
+ buttonText,
64
+ className,
65
+ displayText,
66
+ image,
67
+ imageAlt,
68
+ text,
69
+ textClassName,
70
+ type,
71
+ value
72
+ }) => {
41
73
  const [_, setSuggestedActions] = useSuggestedActions();
42
74
  const [{ suggestedActionsStackedLayoutButtonTextWrap }] = useStyleOptions();
43
75
  const [{ suggestedAction: suggestedActionStyleSet }] = useStyleSet();
@@ -48,12 +80,16 @@ const SuggestedAction = ({ buttonText, className, displayText, image, imageAlt,
48
80
  const focusRef = useRef();
49
81
  const localizeAccessKey = useLocalizeAccessKey();
50
82
  const performCardAction = usePerformCardAction();
51
- const scrollToEnd = useScrollToEnd();
52
83
  const rootClassName = useStyleToEmotionObject()(ROOT_STYLE) + '';
84
+ const scrollToEnd = useScrollToEnd();
53
85
 
54
- const handleClick = useCallback(
86
+ const [focusVisible] = useFocusVisible(focusRef);
87
+
88
+ const handleClick = useCallback<MouseEventHandler<HTMLButtonElement>>(
55
89
  ({ target }) => {
56
- performCardAction({ displayText, text, type, value }, { target });
90
+ // TODO: [P3] #XXX We should not destruct DirectLineCardAction into React props and pass them in. It makes typings difficult.
91
+ // Instead, we should pass a "cardAction" props.
92
+ performCardAction({ displayText, text, type, value } as DirectLineCardAction, { target });
57
93
 
58
94
  // Since "openUrl" action do not submit, the suggested action buttons do not hide after click.
59
95
  type === 'openUrl' && setSuggestedActions([]);
@@ -67,38 +103,37 @@ const SuggestedAction = ({ buttonText, className, displayText, image, imageAlt,
67
103
  useFocusAccessKeyEffect(accessKey, focusRef);
68
104
 
69
105
  return (
70
- <div
106
+ <AccessibleButton
107
+ {...(accessKey ? { 'aria-keyshortcuts': localizeAccessKey(accessKey) } : {})}
71
108
  className={classNames(
72
109
  'webchat__suggested-action',
73
- { 'webchat__suggested-action--rtl': direction === 'rtl' },
110
+ {
111
+ 'webchat__suggested-action--focus-visible': focusVisible,
112
+ 'webchat__suggested-action--rtl': direction === 'rtl',
113
+ 'webchat__suggested-action--wrapping': suggestedActionsStackedLayoutButtonTextWrap
114
+ },
74
115
  rootClassName,
75
116
  suggestedActionStyleSet + '',
76
117
  (className || '') + ''
77
118
  )}
119
+ disabled={disabled}
120
+ onClick={handleClick}
121
+ ref={focusRef}
122
+ type="button"
78
123
  >
79
- <AccessibleButton
80
- {...(accessKey ? { 'aria-keyshortcuts': localizeAccessKey(accessKey) } : {})}
81
- className={classNames('webchat__suggested-action__button', {
82
- 'webchat__suggested-action--wrapping': suggestedActionsStackedLayoutButtonTextWrap
83
- })}
84
- disabled={disabled}
85
- onClick={handleClick}
86
- ref={focusRef}
87
- type="button"
88
- >
89
- {image && (
90
- <img
91
- alt={imageAlt}
92
- className={classNames(
93
- 'webchat__suggested-action__image',
94
- direction === 'rtl' && 'webchat__suggested-action__image--rtl'
95
- )}
96
- src={image}
97
- />
98
- )}
99
- <span className={classNames('webchat__suggested-action__text', (textClassName || '') + '')}>{buttonText}</span>
100
- </AccessibleButton>
101
- </div>
124
+ {image && (
125
+ <img
126
+ alt={imageAlt}
127
+ className={classNames(
128
+ 'webchat__suggested-action__image',
129
+ direction === 'rtl' && 'webchat__suggested-action__image--rtl'
130
+ )}
131
+ src={image}
132
+ />
133
+ )}
134
+ <span className={classNames('webchat__suggested-action__text', (textClassName || '') + '')}>{buttonText}</span>
135
+ <div className="webchat__suggested-action__keyboard-focus-indicator" />
136
+ </AccessibleButton>
102
137
  );
103
138
  };
104
139
 
@@ -109,7 +144,7 @@ SuggestedAction.defaultProps = {
109
144
  imageAlt: undefined,
110
145
  text: '',
111
146
  textClassName: '',
112
- type: '',
147
+ type: undefined,
113
148
  value: undefined
114
149
  };
115
150
 
@@ -121,6 +156,8 @@ SuggestedAction.propTypes = {
121
156
  imageAlt: PropTypes.string,
122
157
  text: PropTypes.string,
123
158
  textClassName: PropTypes.string,
159
+ // TypeScript class is not mappable to PropTypes.
160
+ // @ts-ignore
124
161
  type: PropTypes.string,
125
162
  value: PropTypes.any
126
163
  };
@@ -5,7 +5,7 @@ import { hooks } from 'botframework-webchat-api';
5
5
  import BasicFilm, { createBasicStyleSet as createBasicStyleSetForReactFilm } from 'react-film';
6
6
  import classNames from 'classnames';
7
7
  import PropTypes from 'prop-types';
8
- import React, { FC, useMemo } from 'react';
8
+ import React, { FC, useMemo, useRef } from 'react';
9
9
 
10
10
  import connectToWebChat from '../connectToWebChat';
11
11
  import ScreenReaderText from '../ScreenReaderText';
@@ -151,7 +151,7 @@ const SuggestedActionFlowContainer = ({ children, className, screenReaderText })
151
151
  {!!children && !!React.Children.count(children) && (
152
152
  <div className="webchat__suggested-actions__flow-box">
153
153
  {React.Children.map(children, child => (
154
- <div className="webchat__suggested-actions__item">{child}</div>
154
+ <div className="webchat__suggested-actions__flow-item-box">{child}</div>
155
155
  ))}
156
156
  </div>
157
157
  )}
@@ -209,12 +209,13 @@ SuggestedActionStackedContainer.propTypes = {
209
209
 
210
210
  type SuggestedActionsProps = {
211
211
  className?: string;
212
- suggestedActions?: DirectLineCardAction;
212
+ suggestedActions?: DirectLineCardAction[];
213
213
  };
214
214
 
215
215
  const SuggestedActions: FC<SuggestedActionsProps> = ({ className, suggestedActions = [] }) => {
216
216
  const [{ suggestedActionLayout, suggestedActionsStackedLayoutButtonTextWrap }] = useStyleOptions();
217
217
  const [accessKey] = useSuggestedActionsAccessKey();
218
+ const hideEmptyRef = useRef(true);
218
219
  const localize = useLocalizer();
219
220
  const localizeAccessKey = useLocalizeAccessKey();
220
221
 
@@ -227,24 +228,63 @@ const SuggestedActions: FC<SuggestedActionsProps> = ({ className, suggestedActio
227
228
  : localize('SUGGESTED_ACTIONS_ALT_NO_CONTENT')
228
229
  );
229
230
 
230
- const children = suggestedActions.map(({ displayText, image, imageAltText, text, title, type, value }, index) => (
231
- <SuggestedAction
232
- buttonText={suggestedActionText({ displayText, title, type, value })}
233
- className="webchat__suggested-actions__button"
234
- displayText={displayText}
235
- image={image}
236
- imageAlt={imageAltText}
237
- key={index}
238
- text={text}
239
- textClassName={
240
- suggestedActionLayout === 'stacked' && suggestedActionsStackedLayoutButtonTextWrap
241
- ? 'webchat__suggested-actions__button-text-stacked-text-wrap'
242
- : 'webchat__suggested-actions__button-text'
243
- }
244
- type={type}
245
- value={value}
246
- />
247
- ));
231
+ const children = suggestedActions.map((cardAction, index) => {
232
+ const { displayText, image, imageAltText, text, title, type, value } = cardAction as {
233
+ displayText?: string;
234
+ image?: string;
235
+ imageAltText?: string;
236
+ text?: string;
237
+ title?: string;
238
+ type:
239
+ | 'call'
240
+ | 'downloadFile'
241
+ | 'imBack'
242
+ | 'messageBack'
243
+ | 'openUrl'
244
+ | 'playAudio'
245
+ | 'playVideo'
246
+ | 'postBack'
247
+ | 'showImage'
248
+ | 'signin';
249
+ value?: { [key: string]: any } | string;
250
+ };
251
+
252
+ return (
253
+ <div className="webchat__suggested-actions__item-box" key={index}>
254
+ <SuggestedAction
255
+ buttonText={suggestedActionText({ displayText, title, type, value })}
256
+ className="webchat__suggested-actions__button"
257
+ displayText={displayText}
258
+ image={image}
259
+ imageAlt={imageAltText}
260
+ text={text}
261
+ textClassName={
262
+ suggestedActionLayout === 'stacked' && suggestedActionsStackedLayoutButtonTextWrap
263
+ ? 'webchat__suggested-actions__button-text-stacked-text-wrap'
264
+ : 'webchat__suggested-actions__button-text'
265
+ }
266
+ type={type}
267
+ value={value}
268
+ />
269
+ </div>
270
+ );
271
+ });
272
+
273
+ // (Related to #4021)
274
+ //
275
+ // To improve accessibility UX, if there are no suggested actions, and this container was never shown.
276
+ // Then, avoid rendering the alt-text "Suggested Actions Container: Is empty".
277
+ //
278
+ // This is to reduce the narration of "Is empty".
279
+ //
280
+ // After any suggested actions were shown during the lifetime of this container, then we will
281
+ // continue to start showing "Suggested Actions Container: Is empty" when the container is empty.
282
+ if (!children.length && hideEmptyRef.current) {
283
+ return null;
284
+ }
285
+
286
+ // Otherwise, if we have rendered once, we will continue to render "Is empty".
287
+ hideEmptyRef.current = false;
248
288
 
249
289
  if (suggestedActionLayout === 'flow') {
250
290
  return (
@@ -273,6 +313,9 @@ SuggestedActions.defaultProps = {
273
313
 
274
314
  SuggestedActions.propTypes = {
275
315
  className: PropTypes.string,
316
+
317
+ // TypeScript class is not mappable to PropTypes.func
318
+ // @ts-ignore
276
319
  suggestedActions: PropTypes.arrayOf(
277
320
  PropTypes.shape({
278
321
  displayText: PropTypes.string,
@@ -26,9 +26,12 @@ export default function createBasicTranscriptStyleSet({
26
26
  borderStyle: transcriptActivityVisualKeyboardIndicatorStyle,
27
27
  borderWidth: transcriptActivityVisualKeyboardIndicatorWidth,
28
28
  boxSizing: 'border-box',
29
- height: `calc(100% - ${paddingRegular}px)`,
29
+ height: `calc(100% - ${paddingRegular / 2}px)`,
30
30
  left: 0,
31
- margin: paddingRegular / 2,
31
+ marginBottom: 0,
32
+ marginLeft: paddingRegular / 2,
33
+ marginRight: paddingRegular / 2,
34
+ marginTop: 0,
32
35
  pointerEvents: 'none',
33
36
  position: 'absolute',
34
37
  top: 0,
@@ -36,40 +39,51 @@ export default function createBasicTranscriptStyleSet({
36
39
  }
37
40
  },
38
41
 
39
- '&:focus .webchat__basic-transcript__focus-indicator, .webchat__basic-transcript__terminator:focus + .webchat__basic-transcript__focus-indicator': {
40
- height: '100%',
41
- borderColor: transcriptVisualKeyboardIndicatorColor,
42
- borderStyle: transcriptVisualKeyboardIndicatorStyle,
43
- borderWidth: transcriptVisualKeyboardIndicatorWidth,
44
- boxSizing: 'border-box',
45
- pointerEvents: 'none',
46
- position: 'absolute',
47
- top: 0,
48
- width: '100%'
49
- },
42
+ '&:focus .webchat__basic-transcript__focus-indicator, .webchat__basic-transcript__terminator:focus + .webchat__basic-transcript__focus-indicator':
43
+ {
44
+ height: '100%',
45
+ borderColor: transcriptVisualKeyboardIndicatorColor,
46
+ borderStyle: transcriptVisualKeyboardIndicatorStyle,
47
+ borderWidth: transcriptVisualKeyboardIndicatorWidth,
48
+ boxSizing: 'border-box',
49
+ pointerEvents: 'none',
50
+ position: 'absolute',
51
+ top: 0,
52
+ width: '100%'
53
+ },
50
54
 
51
55
  '& .webchat__basic-transcript__activity': {
52
- paddingTop: paddingRegular,
56
+ paddingTop: paddingRegular / 2,
53
57
  position: 'relative',
54
58
 
59
+ '&:first-child': {
60
+ marginTop: paddingRegular / 2
61
+ },
62
+
55
63
  '&:not(:first-child)': {
56
- marginTop: -paddingRegular
64
+ marginTop: -paddingRegular / 2
57
65
  }
58
66
  },
59
67
 
60
- '& .webchat__basic-transcript__activity-box:not(:empty)': {
61
- paddingBottom: paddingRegular
62
- },
63
-
64
- '& .webchat__basic-transcript__activity-sentinel': {
68
+ // When the activity is focused as active descendant, `scrollIntoView()` will scroll this invisible <div> into view.
69
+ '& .webchat__basic-transcript__activity-active-descendant': {
65
70
  height: '100%',
66
71
  left: 0,
72
+ marginTop: -paddingRegular / 2,
73
+ paddingBottom: paddingRegular / 2,
74
+ // The bounding box is expanded to both top and bottom to scroll focus indicator into view.
75
+ // We should ignore clicks to make sure this expansion don't register click as focus.
76
+ // Otherwise, when clicking on the very bottom edge of the activity, it will focus on next activity instead.
67
77
  pointerEvents: 'none',
68
78
  position: 'absolute',
69
79
  top: 0,
70
80
  width: '100%'
71
81
  },
72
82
 
83
+ '& .webchat__basic-transcript__activity-body:not(:empty)': {
84
+ paddingBottom: paddingRegular
85
+ },
86
+
73
87
  '& .webchat__basic-transcript__terminator': {
74
88
  bottom: 0,
75
89
  height: 0,
@@ -1,4 +1,3 @@
1
- /* eslint-disable prettier/prettier */
2
1
  /* eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2] }] */
3
2
  import { StrictStyleOptions } from 'botframework-webchat-api';
4
3