botframework-webchat-fluent-theme 4.17.1 → 4.18.1-hotfix.20260127.b53acdf

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 (96) hide show
  1. package/dist/botframework-webchat-fluent-theme.css.map +1 -1
  2. package/dist/botframework-webchat-fluent-theme.d.mts +23 -5
  3. package/dist/botframework-webchat-fluent-theme.d.ts +23 -5
  4. package/dist/botframework-webchat-fluent-theme.development.css.map +1 -1
  5. package/dist/botframework-webchat-fluent-theme.development.js +11 -1
  6. package/dist/botframework-webchat-fluent-theme.development.js.map +1 -1
  7. package/dist/botframework-webchat-fluent-theme.js +1 -1
  8. package/dist/botframework-webchat-fluent-theme.js.map +1 -1
  9. package/dist/botframework-webchat-fluent-theme.mjs +1 -1
  10. package/dist/botframework-webchat-fluent-theme.mjs.map +1 -1
  11. package/dist/botframework-webchat-fluent-theme.production.min.css.map +1 -1
  12. package/dist/botframework-webchat-fluent-theme.production.min.js +11 -1
  13. package/dist/botframework-webchat-fluent-theme.production.min.js.map +1 -1
  14. package/package.json +27 -26
  15. package/src/bundle.ts +2 -0
  16. package/src/components/activity/ActivityDecorator.module.css +432 -0
  17. package/src/components/activity/ActivityDecorator.tsx +26 -0
  18. package/src/components/activity/ActivityLoader.module.css +10 -0
  19. package/src/components/activity/ActivityLoader.tsx +21 -0
  20. package/src/components/activity/CopilotMessageHeader.module.css +38 -0
  21. package/src/components/activity/CopilotMessageHeader.tsx +49 -0
  22. package/src/components/activity/index.ts +2 -0
  23. package/src/components/activity/private/isAIGeneratedActivity.ts +5 -0
  24. package/src/components/activity/private/useActivityAuthor.ts +16 -0
  25. package/src/components/activity/private/useActivityStyleOptions.ts +19 -0
  26. package/src/components/assets/AssetComposer.tsx +37 -0
  27. package/src/components/assets/AssetName.ts +1 -0
  28. package/src/components/assets/SlidingDots.tsx +61 -0
  29. package/src/components/assets/private/Context.ts +24 -0
  30. package/src/components/assets/private/useAssetURL.ts +12 -0
  31. package/src/components/assets/private/useContext.ts +8 -0
  32. package/src/components/dropZone/DropZone.module.css +3 -4
  33. package/src/components/dropZone/DropZone.tsx +41 -6
  34. package/src/components/linerActivity/index.ts +2 -0
  35. package/src/components/linerActivity/private/LinerActivity.tsx +20 -0
  36. package/src/components/linerActivity/private/LinerMessageActivity.module.css +28 -0
  37. package/src/components/linerActivity/private/isLinerMessageActivity.ts +7 -0
  38. package/src/components/preChatActivity/PreChatMessageActivity.module.css +56 -0
  39. package/src/components/preChatActivity/PreChatMessageActivity.tsx +60 -0
  40. package/src/components/preChatActivity/StarterPromptsCardAction.module.css +126 -0
  41. package/src/components/preChatActivity/StarterPromptsCardAction.tsx +75 -0
  42. package/src/components/preChatActivity/StarterPromptsToolbar.module.css +18 -0
  43. package/src/components/preChatActivity/StarterPromptsToolbar.tsx +47 -0
  44. package/src/components/preChatActivity/index.tsx +2 -0
  45. package/src/components/preChatActivity/isPreChatMessageActivity.ts +7 -0
  46. package/src/components/sendBox/Attachments.module.css +1 -1
  47. package/src/components/sendBox/Attachments.tsx +5 -4
  48. package/src/components/sendBox/ErrorMessage.tsx +15 -4
  49. package/src/components/sendBox/SendBox.module.css +21 -6
  50. package/src/components/sendBox/SendBox.tsx +95 -56
  51. package/src/components/sendBox/TextArea.module.css +27 -8
  52. package/src/components/sendBox/TextArea.tsx +60 -31
  53. package/src/components/sendBox/Toolbar.module.css +15 -7
  54. package/src/components/sendBox/Toolbar.tsx +17 -7
  55. package/src/components/sendBox/index.tsx +1 -1
  56. package/src/components/sendBox/private/useSubmitError.ts +17 -4
  57. package/src/components/sendBox/private/useTranscriptNavigation.ts +53 -0
  58. package/src/components/suggestedActions/AccessibleButton.tsx +15 -13
  59. package/src/components/suggestedActions/SuggestedAction.module.css +14 -13
  60. package/src/components/suggestedActions/SuggestedAction.tsx +7 -4
  61. package/src/components/suggestedActions/SuggestedActions.module.css +2 -3
  62. package/src/components/suggestedActions/SuggestedActions.tsx +49 -46
  63. package/src/components/telephoneKeypad/private/Button.module.css +2 -3
  64. package/src/components/telephoneKeypad/private/Button.tsx +1 -5
  65. package/src/components/telephoneKeypad/private/TelephoneKeypad.module.css +0 -1
  66. package/src/components/telephoneKeypad/private/TelephoneKeypad.tsx +4 -8
  67. package/src/components/telephoneKeypad/types.ts +1 -1
  68. package/src/components/theme/Theme.module.css +665 -15
  69. package/src/components/theme/Theme.tsx +4 -3
  70. package/src/components/typingIndicator/SlidingDotsTypingIndicator.module.css +12 -0
  71. package/src/components/typingIndicator/SlidingDotsTypingIndicator.tsx +19 -0
  72. package/src/env.d.ts +1 -7
  73. package/src/external.umd/botframework-webchat-api/decorator.ts +1 -0
  74. package/src/external.umd/botframework-webchat-component/decorator.ts +1 -0
  75. package/src/external.umd/botframework-webchat-component/index.ts +5 -0
  76. package/src/external.umd/botframework-webchat-component/internal.ts +1 -0
  77. package/src/icons/AddDocumentIcon.tsx +8 -16
  78. package/src/icons/AttachmentIcon.tsx +8 -16
  79. package/src/icons/InfoSmallIcon.tsx +7 -15
  80. package/src/icons/SendIcon.tsx +7 -15
  81. package/src/icons/TelephoneKeypadIcon.tsx +7 -15
  82. package/src/index.ts +2 -4
  83. package/src/private/FluentThemeProvider.tsx +91 -10
  84. package/src/private/VariantComposer.ts +29 -0
  85. package/src/private/createComposer.tsx +16 -0
  86. package/src/private/useVariants.ts +7 -0
  87. package/src/styles/createStyles.ts +5 -0
  88. package/src/styles/index.ts +3 -2
  89. package/src/styles/useStyles.ts +2 -19
  90. package/src/styles/useVariantClassName.ts +16 -0
  91. package/src/testIds.ts +3 -0
  92. package/src/tsconfig.json +12 -10
  93. package/src/types/PropsOf.ts +2 -5
  94. package/src/external.umd/botframework-webchat-component.ts +0 -4
  95. package/src/styles/injectStyle.ts +0 -9
  96. /package/src/external.umd/{botframework-webchat-api.ts → botframework-webchat-api/index.ts} +0 -0
@@ -1,11 +1,12 @@
1
1
  import React, { type ReactNode } from 'react';
2
2
  import cx from 'classnames';
3
3
  import styles from './Theme.module.css';
4
- import { useStyles } from '../../styles';
4
+ import { useStyles, useVariantClassName } from '../../styles';
5
5
 
6
6
  export const rootClassName = 'webchat-fluent';
7
7
 
8
- export default function WebchatTheme(props: Readonly<{ readonly children: ReactNode | undefined }>) {
8
+ export default function Theme(props: Readonly<{ readonly children: ReactNode | undefined }>) {
9
9
  const classNames = useStyles(styles);
10
- return <div className={cx(rootClassName, classNames['theme'])}>{props.children}</div>;
10
+ const variantClassName = useVariantClassName(styles);
11
+ return <div className={cx(rootClassName, classNames['theme'], variantClassName)}>{props.children}</div>;
11
12
  }
@@ -0,0 +1,12 @@
1
+ :global(.webchat-fluent) .sliding-dots-typing-indicator {
2
+ align-self: start;
3
+ display: flex;
4
+ flex: none;
5
+ height: 16px;
6
+ margin: auto var(--webchat-spacingHorizontalMNudge);
7
+ }
8
+
9
+ :global(.webchat-fluent) .sliding-dots-typing-indicator__image {
10
+ height: 6px;
11
+ width: auto;
12
+ }
@@ -0,0 +1,19 @@
1
+ import { testIds } from 'botframework-webchat-component';
2
+ import { useStyles } from 'botframework-webchat-styles/react';
3
+ import cx from 'classnames';
4
+ import React, { memo } from 'react';
5
+
6
+ import SlidingDots from '../assets/SlidingDots';
7
+ import styles from './SlidingDotsTypingIndicator.module.css';
8
+
9
+ function SlidingDotsTypingIndicator() {
10
+ const classNames = useStyles(styles);
11
+
12
+ return (
13
+ <div className={classNames['sliding-dots-typing-indicator']} data-testid={testIds.typingIndicator}>
14
+ <SlidingDots className={cx(classNames['sliding-dots-typing-indicator__image'])} />
15
+ </div>
16
+ );
17
+ }
18
+
19
+ export default memo(SlidingDotsTypingIndicator);
package/src/env.d.ts CHANGED
@@ -1,7 +1 @@
1
- // CSS modules
2
- type CSSModuleClasses = { readonly [key: string]: any };
3
-
4
- declare module '*.module.css' {
5
- const classes: CSSModuleClasses;
6
- export default classes;
7
- }
1
+ /// <reference types="botframework-webchat-styles/env" />
@@ -0,0 +1 @@
1
+ module.exports = (globalThis as any).WebChat.decorator;
@@ -0,0 +1 @@
1
+ module.exports = (globalThis as any).WebChat.decorator;
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ Components: (globalThis as any).WebChat.Components,
3
+ hooks: (globalThis as any).WebChat.hooks,
4
+ testIds: (globalThis as any).WebChat.testIds
5
+ };
@@ -0,0 +1 @@
1
+ module.exports = (globalThis as any).WebChat.internal;
@@ -1,21 +1,13 @@
1
+ import { Components } from 'botframework-webchat-component';
2
+ import cx from 'classnames';
1
3
  import React, { memo } from 'react';
2
4
 
3
- function AddDocumentIcon(props: Readonly<{ readonly className?: string }>) {
4
- return (
5
- <svg
6
- aria-hidden="true"
7
- className={props.className}
8
- height="1em"
9
- viewBox="0 0 20 20"
10
- width="1em"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- d="M6 2a2 2 0 0 0-2 2v5.2c.32-.08.66-.15 1-.18V4a1 1 0 0 1 1-1h4v3.5c0 .83.67 1.5 1.5 1.5H15v8a1 1 0 0 1-1 1h-3.6c-.18.36-.4.7-.66 1H14a2 2 0 0 0 2-2V7.41c0-.4-.16-.78-.44-1.06l-3.91-3.91A1.5 1.5 0 0 0 10.59 2H6Zm8.8 5h-3.3a.5.5 0 0 1-.5-.5V3.2L14.8 7ZM10 14.5a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0Zm-4-2a.5.5 0 0 0-1 0V14H3.5a.5.5 0 0 0 0 1H5v1.5a.5.5 0 0 0 1 0V15h1.5a.5.5 0 0 0 0-1H6v-1.5Z"
15
- fill="currentColor"
16
- />
17
- </svg>
18
- );
5
+ const { MonochromeImageMasker } = Components;
6
+
7
+ const addDocumentIcon = `data:image/svg+xml;utf8,${encodeURIComponent('<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6 2a2 2 0 0 0-2 2v5.2c.32-.08.66-.15 1-.18V4a1 1 0 0 1 1-1h4v3.5c0 .83.67 1.5 1.5 1.5H15v8a1 1 0 0 1-1 1h-3.6c-.18.36-.4.7-.66 1H14a2 2 0 0 0 2-2V7.41c0-.4-.16-.78-.44-1.06l-3.91-3.91A1.5 1.5 0 0 0 10.59 2H6Zm8.8 5h-3.3a.5.5 0 0 1-.5-.5V3.2L14.8 7ZM10 14.5a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0Zm-4-2a.5.5 0 0 0-1 0V14H3.5a.5.5 0 0 0 0 1H5v1.5a.5.5 0 0 0 1 0V15h1.5a.5.5 0 0 0 0-1H6v-1.5Z"/></svg>')}`;
8
+
9
+ function AddDocumentIcon(props: Readonly<{ className?: string }>) {
10
+ return <MonochromeImageMasker className={cx('icon__add-document', props.className)} src={addDocumentIcon} />;
19
11
  }
20
12
 
21
13
  export default memo(AddDocumentIcon);
@@ -1,21 +1,13 @@
1
+ import { Components } from 'botframework-webchat-component';
2
+ import cx from 'classnames';
1
3
  import React, { memo } from 'react';
2
4
 
3
- function AttachmentIcon(props: Readonly<{ readonly className?: string }>) {
4
- return (
5
- <svg
6
- aria-hidden="true"
7
- className={props.className}
8
- height="1em"
9
- viewBox="0 0 20 20"
10
- width="1em"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- d="m4.83 10.48 5.65-5.65a3 3 0 0 1 4.25 4.24L8 15.8a1.5 1.5 0 0 1-2.12-2.12l6-6.01a.5.5 0 1 0-.7-.71l-6 6.01a2.5 2.5 0 0 0 3.53 3.54l6.71-6.72a4 4 0 1 0-5.65-5.66L4.12 9.78a.5.5 0 0 0 .7.7Z"
15
- fill="currentColor"
16
- />
17
- </svg>
18
- );
5
+ const { MonochromeImageMasker } = Components;
6
+
7
+ const attachmentIcon = `data:image/svg+xml;utf8,${encodeURIComponent('<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m4.83 10.48 5.65-5.65a3 3 0 0 1 4.25 4.24L8 15.8a1.5 1.5 0 0 1-2.12-2.12l6-6.01a.5.5 0 1 0-.7-.71l-6 6.01a2.5 2.5 0 0 0 3.53 3.54l6.71-6.72a4 4 0 1 0-5.65-5.66L4.12 9.78a.5.5 0 0 0 .7.7Z"/></svg>')}`;
8
+
9
+ function AttachmentIcon(props: Readonly<{ className?: string }>) {
10
+ return <MonochromeImageMasker className={cx('icon__attachment', props.className)} src={attachmentIcon} />;
19
11
  }
20
12
 
21
13
  export default memo(AttachmentIcon);
@@ -1,21 +1,13 @@
1
+ import { Components } from 'botframework-webchat-component';
2
+ import cx from 'classnames';
1
3
  import React, { memo } from 'react';
2
4
 
5
+ const { MonochromeImageMasker } = Components;
6
+
7
+ const infoSmallIcon = `data:image/svg+xml;utf8,${encodeURIComponent('<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8.5 7.5a.5.5 0 1 0-1 0v3a.5.5 0 0 0 1 0v-3Zm.25-2a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1ZM2 8a6 6 0 1 1 12 0A6 6 0 0 1 2 8Z"/></svg>')}`;
8
+
3
9
  function InfoSmallIcon(props: Readonly<{ readonly className?: string }>) {
4
- return (
5
- <svg
6
- aria-hidden="true"
7
- className={props.className}
8
- height="1em"
9
- viewBox="0 0 16 16"
10
- width="1em"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- d="M8.5 7.5a.5.5 0 1 0-1 0v3a.5.5 0 0 0 1 0v-3Zm.25-2a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1ZM2 8a6 6 0 1 1 12 0A6 6 0 0 1 2 8Z"
15
- fill="currentColor"
16
- />
17
- </svg>
18
- );
10
+ return <MonochromeImageMasker className={cx('icon__info--small', props.className)} src={infoSmallIcon} />;
19
11
  }
20
12
 
21
13
  export default memo(InfoSmallIcon);
@@ -1,21 +1,13 @@
1
+ import { Components } from 'botframework-webchat-component';
2
+ import cx from 'classnames';
1
3
  import React, { memo } from 'react';
2
4
 
5
+ const { MonochromeImageMasker } = Components;
6
+
7
+ const sendIcon = `data:image/svg+xml;utf8,${encodeURIComponent('<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.18 2.11a.5.5 0 0 1 .54-.06l15 7.5a.5.5 0 0 1 0 .9l-15 7.5a.5.5 0 0 1-.7-.58L3.98 10 2.02 2.63a.5.5 0 0 1 .16-.52Zm2.7 8.39-1.61 6.06L16.38 10 3.27 3.44 4.88 9.5h6.62a.5.5 0 1 1 0 1H4.88Z"/></svg>')}`;
8
+
3
9
  function SendIcon(props: Readonly<{ readonly className?: string }>) {
4
- return (
5
- <svg
6
- aria-hidden="true"
7
- className={props.className}
8
- height="1em"
9
- viewBox="0 0 20 20"
10
- width="1em"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- d="M2.18 2.11a.5.5 0 0 1 .54-.06l15 7.5a.5.5 0 0 1 0 .9l-15 7.5a.5.5 0 0 1-.7-.58L3.98 10 2.02 2.63a.5.5 0 0 1 .16-.52Zm2.7 8.39-1.61 6.06L16.38 10 3.27 3.44 4.88 9.5h6.62a.5.5 0 1 1 0 1H4.88Z"
15
- fill="currentColor"
16
- />
17
- </svg>
18
- );
10
+ return <MonochromeImageMasker className={cx('icon__send', props.className)} src={sendIcon} />;
19
11
  }
20
12
 
21
13
  export default memo(SendIcon);
@@ -1,21 +1,13 @@
1
+ import { Components } from 'botframework-webchat-component';
2
+ import cx from 'classnames';
1
3
  import React, { memo } from 'react';
2
4
 
5
+ const { MonochromeImageMasker } = Components;
6
+
7
+ const telephoneKeypadIcon = `data:image/svg+xml;utf8,${encodeURIComponent('<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6 5.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Zm0 4a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM7.25 12a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM10 5.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM11.25 8a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM10 13.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM11.25 16a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM14 5.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM15.25 8a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM14 13.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Z"/></svg>')}`;
8
+
3
9
  function TelephoneKeypadIcon(props: Readonly<{ readonly className?: string }>) {
4
- return (
5
- <svg
6
- aria-hidden="true"
7
- className={props.className}
8
- height="1em"
9
- viewBox="0 0 20 20"
10
- width="1em"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- d="M6 5.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Zm0 4a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM7.25 12a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM10 5.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM11.25 8a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM10 13.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM11.25 16a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM14 5.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5ZM15.25 8a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0ZM14 13.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Z"
15
- fill="currentColor"
16
- />
17
- </svg>
18
- );
10
+ return <MonochromeImageMasker className={cx('icon__telephone-keypad', props.className)} src={telephoneKeypadIcon} />;
19
11
  }
20
12
 
21
13
  export default memo(TelephoneKeypadIcon);
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { injectMetaTag } from 'inject-meta-tag';
2
2
 
3
+ import { SendBox as FluentSendBox } from './components/sendBox/index';
3
4
  import FluentThemeProvider from './private/FluentThemeProvider';
4
- import { injectStyle } from './styles';
5
5
  import testIds from './testIds';
6
6
 
7
7
  const buildTool = process.env['build_tool'];
@@ -15,6 +15,4 @@ injectMetaTag(
15
15
  `version=${process.env['npm_package_version']}; build-tool=${process.env['build_tool']}; module-format=${process.env['module_format']}`
16
16
  );
17
17
 
18
- injectStyle();
19
-
20
- export { FluentThemeProvider, buildInfo, testIds };
18
+ export { FluentThemeProvider, FluentSendBox, buildInfo, testIds };
@@ -1,22 +1,103 @@
1
+ import { type ActivityMiddleware, type StyleOptions, type TypingIndicatorMiddleware } from 'botframework-webchat-api';
2
+ import {
3
+ DecoratorComposer,
4
+ DecoratorMiddleware,
5
+ type DecoratorMiddlewareInit,
6
+ type DecoratorMiddlewareTypes
7
+ } from 'botframework-webchat-api/decorator';
1
8
  import { Components } from 'botframework-webchat-component';
9
+ import { WebChatDecorator } from 'botframework-webchat-component/decorator';
2
10
  import React, { memo, type ReactNode } from 'react';
3
11
 
12
+ import { ActivityDecorator } from '../components/activity';
13
+ import ActivityLoader from '../components/activity/ActivityLoader';
14
+ import AssetComposer from '../components/assets/AssetComposer';
15
+ import { isLinerMessageActivity, LinerMessageActivity } from '../components/linerActivity';
16
+ import { isPreChatMessageActivity, PreChatMessageActivity } from '../components/preChatActivity';
17
+ import { PrimarySendBox } from '../components/sendBox';
4
18
  import { TelephoneKeypadProvider } from '../components/telephoneKeypad';
5
19
  import { WebChatTheme } from '../components/theme';
6
- import { SendBox } from '../components/sendBox';
20
+ import SlidingDotsTypingIndicator from '../components/typingIndicator/SlidingDotsTypingIndicator';
21
+ import { createStyles } from '../styles';
22
+ import VariantComposer, { VariantList } from './VariantComposer';
7
23
 
8
24
  const { ThemeProvider } = Components;
9
25
 
10
- type Props = Readonly<{ children?: ReactNode | undefined }>;
26
+ type FluentThemeProviderProps = Readonly<{
27
+ children?: ReactNode | undefined;
28
+ variant?: VariantList | undefined;
29
+ }>;
11
30
 
12
- const sendBoxMiddleware = [() => () => () => SendBox];
31
+ const activityMiddleware: readonly ActivityMiddleware[] = Object.freeze([
32
+ () =>
33
+ next =>
34
+ (...args) => {
35
+ const activity = args[0]?.activity;
13
36
 
14
- const FluentThemeProvider = ({ children }: Props) => (
15
- <WebChatTheme>
16
- <TelephoneKeypadProvider>
17
- <ThemeProvider sendBoxMiddleware={sendBoxMiddleware}>{children}</ThemeProvider>
18
- </TelephoneKeypadProvider>
19
- </WebChatTheme>
20
- );
37
+ // TODO: Should show pre-chat only when it is the very first message in the chat history.
38
+ if (isPreChatMessageActivity(activity)) {
39
+ return () => <PreChatMessageActivity activity={activity} />;
40
+ }
41
+
42
+ if (isLinerMessageActivity(activity)) {
43
+ return () => <LinerMessageActivity activity={activity} />;
44
+ }
45
+
46
+ const renderActivity = next(...args);
47
+
48
+ return renderActivity
49
+ ? (...args) => <ActivityDecorator activity={activity}>{renderActivity(...args)}</ActivityDecorator>
50
+ : renderActivity;
51
+ }
52
+ ]);
53
+
54
+ const sendBoxMiddleware = [() => () => () => PrimarySendBox];
55
+
56
+ const decoratorMiddleware: readonly DecoratorMiddleware[] = Object.freeze([
57
+ (init: DecoratorMiddlewareInit) =>
58
+ init === 'activity border' &&
59
+ ((next => request =>
60
+ request.livestreamingState === 'preparing'
61
+ ? ActivityLoader
62
+ : next(request)) satisfies DecoratorMiddlewareTypes['activity border'])
63
+ ]);
64
+
65
+ const styles = createStyles();
66
+
67
+ const fluentStyleOptions: StyleOptions = Object.freeze({
68
+ feedbackActionsPlacement: 'activity-actions'
69
+ });
70
+
71
+ const typingIndicatorMiddleware = Object.freeze([
72
+ () =>
73
+ next =>
74
+ (...args) =>
75
+ args[0].visible ? <SlidingDotsTypingIndicator /> : next(...args)
76
+ ] satisfies TypingIndicatorMiddleware[]);
77
+
78
+ function FluentThemeProvider({ children, variant = 'fluent' }: FluentThemeProviderProps) {
79
+ return (
80
+ <VariantComposer variant={variant}>
81
+ <WebChatTheme>
82
+ <TelephoneKeypadProvider>
83
+ <ThemeProvider
84
+ activityMiddleware={activityMiddleware}
85
+ sendBoxMiddleware={sendBoxMiddleware}
86
+ styleOptions={fluentStyleOptions}
87
+ styles={styles}
88
+ typingIndicatorMiddleware={typingIndicatorMiddleware}
89
+ >
90
+ <AssetComposer>
91
+ <WebChatDecorator>
92
+ <DecoratorComposer middleware={decoratorMiddleware}>{children}</DecoratorComposer>
93
+ </WebChatDecorator>
94
+ </AssetComposer>
95
+ </ThemeProvider>
96
+ </TelephoneKeypadProvider>
97
+ </WebChatTheme>
98
+ </VariantComposer>
99
+ );
100
+ }
21
101
 
22
102
  export default memo(FluentThemeProvider);
103
+ export { type FluentThemeProviderProps };
@@ -0,0 +1,29 @@
1
+ import { createContext } from 'react';
2
+
3
+ import createComposer from './createComposer';
4
+
5
+ type VariantName = 'fluent' | 'copilot' | '';
6
+
7
+ export type VariantList = `${VariantName}`;
8
+
9
+ export type VariantContextType = {
10
+ variant: VariantList;
11
+ };
12
+
13
+ export const VariantContext = createContext<VariantContextType>(
14
+ new Proxy(
15
+ {},
16
+ {
17
+ get() {
18
+ throw new Error('Unable to use VariantContext without VariantComposer');
19
+ }
20
+ }
21
+ ) as unknown as VariantContextType
22
+ );
23
+
24
+ const VariantComposer = createComposer<VariantContextType>(VariantContext, {
25
+ defaults: { variant: '' },
26
+ displayName: 'VariantComposer'
27
+ });
28
+
29
+ export default VariantComposer;
@@ -0,0 +1,16 @@
1
+ import React, { type Context, memo, type ReactNode, useMemo } from 'react';
2
+
3
+ export default function createComposer<
4
+ C,
5
+ P extends { children?: ReactNode | undefined } = Partial<C> & { children?: ReactNode | undefined }
6
+ >({ Provider }: Context<C>, { defaults, displayName }: Readonly<{ defaults: Readonly<C>; displayName: string }>) {
7
+ const Composer = ({ children, ...props }: Readonly<P>) => {
8
+ const value = useMemo(() => Object.freeze({ ...defaults, ...props }), [props]);
9
+
10
+ return <Provider value={value}>{children}</Provider>;
11
+ };
12
+
13
+ Composer.displayName = displayName;
14
+
15
+ return memo(Composer);
16
+ }
@@ -0,0 +1,7 @@
1
+ import { useContext, useMemo } from 'react';
2
+ import { VariantContext } from './VariantComposer';
3
+
4
+ export default function useVariants() {
5
+ const { variant } = useContext(VariantContext);
6
+ return useMemo(() => variant.split(' '), [variant]);
7
+ }
@@ -0,0 +1,5 @@
1
+ import { makeCreateStyles } from 'botframework-webchat-styles';
2
+
3
+ export const fluentStyleContent = '@--FLUENT-STYLES-CONTENT--@';
4
+
5
+ export default makeCreateStyles(fluentStyleContent);
@@ -1,4 +1,5 @@
1
- import injectStyle from './injectStyle';
1
+ import createStyles from './createStyles';
2
2
  import useStyles from './useStyles';
3
+ import useVariantClassName from './useVariantClassName';
3
4
 
4
- export { injectStyle, useStyles };
5
+ export { createStyles, useStyles, useVariantClassName };
@@ -1,19 +1,2 @@
1
- import { useMemo } from 'react';
2
-
3
- function useStyles<T extends CSSModuleClasses>(styles: T): T {
4
- // @ts-expect-error: entries/fromEntries don't allow to specify keys type
5
- return useMemo(
6
- () =>
7
- Object.freeze(
8
- Object.fromEntries(
9
- Object.entries(styles).map(([baseClassName, resultClassName]) => [
10
- baseClassName,
11
- `${baseClassName} ${resultClassName}`
12
- ])
13
- )
14
- ),
15
- [styles]
16
- );
17
- }
18
-
19
- export default useStyles;
1
+ // TODO: refactor after initial approval gained
2
+ export { useStyles as default } from 'botframework-webchat-styles/react';
@@ -0,0 +1,16 @@
1
+ import { useMemo } from 'react';
2
+ import useVariants from '../private/useVariants';
3
+ import useStyles from './useStyles';
4
+
5
+ export default function useVariantClassName<T extends CSSModuleClasses>(styles: T): string {
6
+ const classNames = useStyles(styles);
7
+ const variants = useVariants();
8
+ return useMemo(
9
+ () =>
10
+ variants
11
+ .map(variant => classNames[`variant-${variant}`])
12
+ .filter(value => value)
13
+ .join(' '),
14
+ [classNames, variants]
15
+ );
16
+ }
package/src/testIds.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  const testIds = {
2
+ preChatMessageActivityStarterPromptsCardAction: 'pre-chat message activity starter prompts card action',
3
+ sendBoxContainer: 'send box container',
2
4
  sendBoxDropZone: 'send box drop zone',
3
5
  sendBoxSendButton: 'send box send button',
6
+ sendBoxSuggestedAction: 'send box suggested action',
4
7
  sendBoxTextBox: 'send box text area',
5
8
  sendBoxTelephoneKeypadButton1: `send box telephone keypad button 1`,
6
9
  sendBoxTelephoneKeypadButton2: `send box telephone keypad button 2`,
package/src/tsconfig.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
- "compilerOptions": {
3
- "allowSyntheticDefaultImports": true,
4
- "checkJs": false,
5
- "jsx": "react",
6
- "moduleResolution": "Bundler",
7
- "skipLibCheck": true,
8
- "target": "ESNext",
9
- "plugins": [{ "name": "typescript-plugin-css-modules" }]
10
- },
11
- "extends": "@tsconfig/strictest/tsconfig.json"
2
+ "compilerOptions": {
3
+ "allowSyntheticDefaultImports": true,
4
+ "checkJs": false,
5
+ "jsx": "react",
6
+ "moduleResolution": "Bundler",
7
+ "skipLibCheck": true,
8
+ "target": "ESNext"
9
+ },
10
+ "extends": [
11
+ "@tsconfig/strictest/tsconfig.json",
12
+ "botframework-webchat-styles/tsconfig.json"
13
+ ]
12
14
  }
@@ -1,7 +1,4 @@
1
1
  import { type ComponentType, type MemoExoticComponent } from 'react';
2
2
 
3
- export type PropsOf<T> = T extends ComponentType<infer P>
4
- ? P
5
- : T extends MemoExoticComponent<ComponentType<infer P>>
6
- ? P
7
- : never;
3
+ export type PropsOf<T> =
4
+ T extends ComponentType<infer P> ? P : T extends MemoExoticComponent<ComponentType<infer P>> ? P : never;
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- Components: (globalThis as any).WebChat.Components,
3
- hooks: (globalThis as any).WebChat.hooks
4
- };
@@ -1,9 +0,0 @@
1
- export const injectedStyles = '@--INJECTED-STYLES-CONTENT--@';
2
-
3
- export default function injectStyles() {
4
- if (globalThis.document) {
5
- const style = document.createElement('style');
6
- style.append(document.createTextNode(injectedStyles));
7
- document.head.appendChild(style);
8
- }
9
- }