botframework-webchat-fluent-theme 4.18.1-main.20250313.cd86ef9 → 4.18.1-main.20250320.abcd9e7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/botframework-webchat-fluent-theme.css.map +1 -1
- package/dist/botframework-webchat-fluent-theme.development.css.map +1 -1
- package/dist/botframework-webchat-fluent-theme.development.js +7 -7
- package/dist/botframework-webchat-fluent-theme.development.js.map +1 -1
- package/dist/botframework-webchat-fluent-theme.js +1 -1
- package/dist/botframework-webchat-fluent-theme.js.map +1 -1
- package/dist/botframework-webchat-fluent-theme.mjs +1 -1
- package/dist/botframework-webchat-fluent-theme.mjs.map +1 -1
- package/dist/botframework-webchat-fluent-theme.production.min.css.map +1 -1
- package/dist/botframework-webchat-fluent-theme.production.min.js +7 -7
- package/dist/botframework-webchat-fluent-theme.production.min.js.map +1 -1
- package/package.json +6 -6
- package/src/components/activity/ActivityLoader.tsx +3 -9
- package/src/components/assets/AssetComposer.tsx +37 -0
- package/src/components/assets/AssetName.ts +1 -0
- package/src/components/assets/SlidingDots.tsx +61 -0
- package/src/components/assets/private/Context.ts +24 -0
- package/src/components/assets/private/useAssetURL.ts +12 -0
- package/src/components/assets/private/useContext.ts +8 -0
- package/src/components/typingIndicator/SlidingDotsTypingIndicator.module.css +11 -0
- package/src/components/typingIndicator/SlidingDotsTypingIndicator.tsx +19 -0
- package/src/external.umd/botframework-webchat-component/index.ts +2 -1
- package/src/private/FluentThemeProvider.tsx +17 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botframework-webchat-fluent-theme",
|
|
3
|
-
"version": "4.18.1-main.
|
|
3
|
+
"version": "4.18.1-main.20250320.abcd9e7",
|
|
4
4
|
"description": "Fluent theme for Bot Framework Web Chat",
|
|
5
5
|
"main": "./dist/botframework-webchat-fluent-theme.js",
|
|
6
6
|
"types": "./dist/botframework-webchat-fluent-theme.d.ts",
|
|
@@ -72,15 +72,15 @@
|
|
|
72
72
|
"@types/math-random": "^1.0.2",
|
|
73
73
|
"@types/node": "^22.13.4",
|
|
74
74
|
"@types/react": "^16.14.62",
|
|
75
|
-
"botframework-webchat-base": "4.18.1-main.
|
|
76
|
-
"botframework-webchat-styles": "4.18.1-main.
|
|
75
|
+
"botframework-webchat-base": "4.18.1-main.20250320.abcd9e7",
|
|
76
|
+
"botframework-webchat-styles": "4.18.1-main.20250320.abcd9e7",
|
|
77
77
|
"tsup": "^8.3.6",
|
|
78
78
|
"typescript": "^5.7.3"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"botframework-webchat-api": "4.18.1-main.
|
|
82
|
-
"botframework-webchat-component": "4.18.1-main.
|
|
83
|
-
"botframework-webchat-core": "4.18.1-main.
|
|
81
|
+
"botframework-webchat-api": "4.18.1-main.20250320.abcd9e7",
|
|
82
|
+
"botframework-webchat-component": "4.18.1-main.20250320.abcd9e7",
|
|
83
|
+
"botframework-webchat-core": "4.18.1-main.20250320.abcd9e7",
|
|
84
84
|
"classnames": "2.5.1",
|
|
85
85
|
"inject-meta-tag": "0.0.1",
|
|
86
86
|
"math-random": "2.0.1",
|
|
@@ -3,23 +3,17 @@ import cx from 'classnames';
|
|
|
3
3
|
import React, { Fragment, memo, type ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
import { useVariantClassName } from '../../styles';
|
|
6
|
+
import SlidingDots from '../assets/SlidingDots';
|
|
6
7
|
import styles from './ActivityLoader.module.css';
|
|
7
8
|
|
|
8
|
-
const loadingAnimationUrl =
|
|
9
|
-
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCA0MDAgMjAiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjAiIHgyPSIxMDAlIiB5MT0iMCIgeTI9IjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAlIj48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJzdG9wLWNvbG9yIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iI2FkNWFlMTsjYWQ1YWUxOyMwRTk0RTE7IzBFOTRFMTsjNjY5ZmMyOyM2NjlmYzI7I2FkNWFlMSIvPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjUwJSI+PGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3RvcC1jb2xvciIgZHVyPSIycyIga2V5VGltZXM9IjA7MC4yOzAuMzM7MC41OzAuNjY7MC44OzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IiNlOTYxOGQ7I2U5NjE4ZDsjNTdBQjgyOyM1N0FCODI7IzYzNzdlMDsjNjM3N2UwOyNlOTYxOGQiLz48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxMDAlIj48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJzdG9wLWNvbG9yIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iI2ZkOWU1ZjsjZmQ5ZTVmOyNDNkMyMjU7I0M2QzIyNTsjOWI4MGVjOyM5YjgwZWM7I2ZkOWU1ZiIvPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48ZyBmaWxsPSJ1cmwoI2EpIj48cmVjdCBoZWlnaHQ9IjIwIiByeD0iMTAiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IngiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuNTswLjY2OzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjI2OzI2OzA7MCIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IndpZHRoIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIyMDsyMDszMDszMDsyMDsyMCIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9Im9wYWNpdHkiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuNTswLjY2OzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjE7MTswOzAiLz48L3JlY3Q+PHJlY3QgaGVpZ2h0PSIyMCIgcng9IjEwIj48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4IiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iNjI7NjI7NzI7NzI7MjY7MjY7MCIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IndpZHRoIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMTA0OzEwNDsyMDsyMDs3MDs3MDsyMCIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9Im9wYWNpdHkiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuODsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIxOzE7MCIvPjwvcmVjdD48cmVjdCBoZWlnaHQ9IjIwIiByeD0iMTAiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IngiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuMjswLjMzOzAuNTswLjY2OzAuODsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIxODI7MTgyOzEwODsxMDg7MTEyOzExMjsyNiIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IndpZHRoIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIyMDsyMDs2MDs2MDsyMDsyMCIvPjwvcmVjdD48cmVjdCBoZWlnaHQ9IjIwIiByeD0iMTAiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IngiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuMjswLjMzOzAuNTswLjY2OzAuODsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIyMTg7MjE4OzE4NDsxODQ7MTQ4OzE0ODs2MiIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IndpZHRoIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iNjA7NjA7ODA7ODA7NDA7NDA7MTA0Ii8+PC9yZWN0PjxyZWN0IGhlaWdodD0iMjAiIHJ4PSIxMCI+PGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ieCIgZHVyPSIycyIga2V5VGltZXM9IjA7MC4yOzAuMzM7MC41OzAuNjY7MC44OzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjI5NDsyOTQ7MjgwOzI4MDsyMDQ7MjA0OzE4MiIvPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IndpZHRoIiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iNDA7NDA7MjA7MjA7ODA7ODA7MjAiLz48L3JlY3Q+PHJlY3QgaGVpZ2h0PSIyMCIgcng9IjEwIj48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4IiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzUwOzM1MDszMTY7MzE2OzMwMDszMDA7MjE4Ii8+PGFuaW1hdGUgYXR0cmlidXRlTmFtZT0id2lkdGgiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuMjswLjMzOzAuNTswLjY2OzAuODsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIyMDsyMDs2MDs2MDsyMDsyMDs2MCIvPjwvcmVjdD48cmVjdCBoZWlnaHQ9IjIwIiByeD0iMTAiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9IngiIGR1cj0iMnMiIGtleVRpbWVzPSIwOzAuMjswLjMzOzAuNTswLjY2OzAuODsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIzODY7Mzg2OzM5MjszOTI7MzM2OzMzNjsyOTQiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ3aWR0aCIgZHVyPSIycyIga2V5VGltZXM9IjA7MC41OzAuNjY7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMjA7MjA7NDA7NDAiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJvcGFjaXR5IiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjU7MC42NjsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdmFsdWVzPSIwOzA7MTsxIi8+PC9yZWN0PjxyZWN0IHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgcng9IjEwIj48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4IiBkdXI9IjJzIiBrZXlUaW1lcz0iMDswLjI7MC4zMzswLjU7MC42NjswLjg7MSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iNDIyOzQyMjs0Mjg7NDI4OzM5MjszOTI7MzUwIi8+PGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ib3BhY2l0eSIgZHVyPSIycyIga2V5VGltZXM9IjA7MC44OzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjA7MDsxIi8+PC9yZWN0PjwvZz48L3N2Zz4=';
|
|
10
|
-
|
|
11
9
|
function FluentActivityLoader({ children }: Readonly<{ children?: ReactNode | undefined }>) {
|
|
12
10
|
const classNames = useStyles(styles);
|
|
13
11
|
const variantClassName = useVariantClassName(classNames);
|
|
12
|
+
|
|
14
13
|
return (
|
|
15
14
|
<Fragment>
|
|
16
15
|
{children}
|
|
17
|
-
<
|
|
18
|
-
alt=""
|
|
19
|
-
className={cx(classNames['activity-loader'], variantClassName)}
|
|
20
|
-
role="presentation"
|
|
21
|
-
src={loadingAnimationUrl}
|
|
22
|
-
/>
|
|
16
|
+
<SlidingDots className={cx(classNames['activity-loader'], variantClassName)} />
|
|
23
17
|
</Fragment>
|
|
24
18
|
);
|
|
25
19
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ContextOf } from 'botframework-webchat-api';
|
|
2
|
+
import React, { memo, useEffect, useMemo, type ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { type AssetName } from './AssetName';
|
|
5
|
+
import Context from './private/Context';
|
|
6
|
+
|
|
7
|
+
type ContextType = ContextOf<typeof Context>;
|
|
8
|
+
|
|
9
|
+
type AssetComposerProps = Readonly<{
|
|
10
|
+
children?: ReactNode | undefined;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
const SLIDING_DOTS_SVG_STRING =
|
|
14
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="400" height="20" viewBox="0 0 400 20"><defs><linearGradient id="a" x1="0" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop offset="0%"><animate attributeName="stop-color" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="#ad5ae1;#ad5ae1;#0E94E1;#0E94E1;#669fc2;#669fc2;#ad5ae1"/></stop><stop offset="50%"><animate attributeName="stop-color" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="#e9618d;#e9618d;#57AB82;#57AB82;#6377e0;#6377e0;#e9618d"/></stop><stop offset="100%"><animate attributeName="stop-color" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="#fd9e5f;#fd9e5f;#C6C225;#C6C225;#9b80ec;#9b80ec;#fd9e5f"/></stop></linearGradient></defs><g fill="url(#a)"><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.5;0.66;1" repeatCount="indefinite" values="26;26;0;0"/><animate attributeName="width" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;1" repeatCount="indefinite" values="20;20;30;30;20;20"/><animate attributeName="opacity" dur="2s" keyTimes="0;0.5;0.66;1" repeatCount="indefinite" values="1;1;0;0"/></rect><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="62;62;72;72;26;26;0"/><animate attributeName="width" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="104;104;20;20;70;70;20"/><animate attributeName="opacity" dur="2s" keyTimes="0;0.8;1" repeatCount="indefinite" values="1;1;0"/></rect><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="182;182;108;108;112;112;26"/><animate attributeName="width" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;1" repeatCount="indefinite" values="20;20;60;60;20;20"/></rect><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="218;218;184;184;148;148;62"/><animate attributeName="width" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="60;60;80;80;40;40;104"/></rect><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="294;294;280;280;204;204;182"/><animate attributeName="width" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="40;40;20;20;80;80;20"/></rect><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="350;350;316;316;300;300;218"/><animate attributeName="width" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="20;20;60;60;20;20;60"/></rect><rect height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="386;386;392;392;336;336;294"/><animate attributeName="width" dur="2s" keyTimes="0;0.5;0.66;1" repeatCount="indefinite" values="20;20;40;40"/><animate attributeName="opacity" dur="2s" keyTimes="0;0.5;0.66;1" repeatCount="indefinite" values="0;0;1;1"/></rect><rect width="20" height="20" rx="10"><animate attributeName="x" dur="2s" keyTimes="0;0.2;0.33;0.5;0.66;0.8;1" repeatCount="indefinite" values="422;422;428;428;392;392;350"/><animate attributeName="opacity" dur="2s" keyTimes="0;0.8;1" repeatCount="indefinite" values="0;0;1"/></rect></g></svg>';
|
|
15
|
+
|
|
16
|
+
const AssetComposer = memo(({ children }: AssetComposerProps) => {
|
|
17
|
+
const slidingDotsURL = useMemo(
|
|
18
|
+
() => URL.createObjectURL(new Blob([SLIDING_DOTS_SVG_STRING], { type: 'image/svg+xml' })),
|
|
19
|
+
[]
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
useEffect(() => () => URL.revokeObjectURL(slidingDotsURL), [slidingDotsURL]);
|
|
23
|
+
|
|
24
|
+
const context = useMemo<ContextType>(
|
|
25
|
+
() =>
|
|
26
|
+
Object.freeze({
|
|
27
|
+
urlStateMap: new Map<AssetName, readonly [URL]>([['sliding dots', Object.freeze([new URL(slidingDotsURL)])]])
|
|
28
|
+
}),
|
|
29
|
+
[slidingDotsURL]
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return <Context.Provider value={context}>{children}</Context.Provider>;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
AssetComposer.displayName = 'AssetComposer';
|
|
36
|
+
|
|
37
|
+
export default AssetComposer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type AssetName = 'sliding dots';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { hooks } from 'botframework-webchat-component';
|
|
2
|
+
import React, { memo, useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import { useRefFrom } from 'use-ref-from';
|
|
4
|
+
|
|
5
|
+
import useAssetURL from './private/useAssetURL';
|
|
6
|
+
|
|
7
|
+
const { useLocalizer, useShouldReduceMotion } = hooks;
|
|
8
|
+
|
|
9
|
+
type SlidingDotsProps = Readonly<{ className: string }>;
|
|
10
|
+
|
|
11
|
+
const SlidingDots = ({ className }: SlidingDotsProps) => {
|
|
12
|
+
const [shouldReduceMotion] = useShouldReduceMotion();
|
|
13
|
+
const [url] = useAssetURL('sliding dots');
|
|
14
|
+
const localize = useLocalizer();
|
|
15
|
+
const objectElementRef = useRef<HTMLObjectElement>(null);
|
|
16
|
+
|
|
17
|
+
const altText = localize('TYPING_INDICATOR_ALT');
|
|
18
|
+
const shouldReduceMotionRef = useRefFrom(shouldReduceMotion);
|
|
19
|
+
|
|
20
|
+
const pauseAnimations = useCallback(() => {
|
|
21
|
+
const contentDocument = objectElementRef.current?.contentDocument;
|
|
22
|
+
const svgElement = contentDocument?.documentElement;
|
|
23
|
+
const { SVGSVGElement } = contentDocument?.defaultView || {};
|
|
24
|
+
|
|
25
|
+
SVGSVGElement && svgElement instanceof SVGSVGElement && svgElement.pauseAnimations();
|
|
26
|
+
}, [objectElementRef]);
|
|
27
|
+
|
|
28
|
+
const unpauseAnimations = useCallback(() => {
|
|
29
|
+
const contentDocument = objectElementRef.current?.contentDocument;
|
|
30
|
+
const svgElement = contentDocument?.documentElement;
|
|
31
|
+
const { SVGSVGElement } = contentDocument?.defaultView || {};
|
|
32
|
+
|
|
33
|
+
SVGSVGElement && svgElement instanceof SVGSVGElement && svgElement.unpauseAnimations();
|
|
34
|
+
}, [objectElementRef]);
|
|
35
|
+
|
|
36
|
+
const pauseOrUnpauseAnimations = useCallback(
|
|
37
|
+
() => (shouldReduceMotionRef.current ? pauseAnimations() : unpauseAnimations()),
|
|
38
|
+
[pauseAnimations, shouldReduceMotionRef, unpauseAnimations]
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
useEffect(pauseOrUnpauseAnimations, [
|
|
42
|
+
pauseOrUnpauseAnimations,
|
|
43
|
+
// Call "pauseOrUnpauseAnimations()" when "shouldReduceMotion" change.
|
|
44
|
+
shouldReduceMotion
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<object
|
|
49
|
+
aria-label={altText}
|
|
50
|
+
className={className}
|
|
51
|
+
data={url.href}
|
|
52
|
+
onLoad={pauseOrUnpauseAnimations}
|
|
53
|
+
ref={objectElementRef}
|
|
54
|
+
type="image/svg+xml"
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
SlidingDots.displayName = 'SlidingDots';
|
|
60
|
+
|
|
61
|
+
export default memo(SlidingDots);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { AssetName } from '../AssetName';
|
|
4
|
+
|
|
5
|
+
type ContextType = Readonly<{
|
|
6
|
+
urlStateMap: ReadonlyMap<AssetName, readonly [URL]>;
|
|
7
|
+
}>;
|
|
8
|
+
|
|
9
|
+
type ContextAsGetter<T extends Record<string, unknown>> =
|
|
10
|
+
T extends Record<infer K, infer V> ? Record<K, { get(): V }> : never;
|
|
11
|
+
|
|
12
|
+
const defaultContextValue: ContextAsGetter<ContextType> = {
|
|
13
|
+
urlStateMap: {
|
|
14
|
+
get() {
|
|
15
|
+
throw new Error('urlMap cannot be used outside of <AssetComposerContext>.');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const Context = createContext<ContextType>(Object.create({}, defaultContextValue));
|
|
21
|
+
|
|
22
|
+
Context.displayName = 'AssetComposerContext';
|
|
23
|
+
|
|
24
|
+
export default Context;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type AssetName } from '../AssetName';
|
|
2
|
+
import useContext from './useContext';
|
|
3
|
+
|
|
4
|
+
export default function useAssetURL(assetName: AssetName): readonly [URL] {
|
|
5
|
+
const urlState = useContext().urlStateMap.get(assetName);
|
|
6
|
+
|
|
7
|
+
if (!urlState) {
|
|
8
|
+
throw new Error(`botframework-webchat-fluent-theme internal: Asset "${assetName}" was not found.`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return urlState;
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
:global(.webchat-fluent) .sliding-dots-typing-indicator {
|
|
2
|
+
align-self: start;
|
|
3
|
+
display: flex;
|
|
4
|
+
height: 16px;
|
|
5
|
+
margin: auto var(--webchat-spacingHorizontalMNudge);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:global(.webchat-fluent) .sliding-dots-typing-indicator__image {
|
|
9
|
+
height: 6px;
|
|
10
|
+
width: auto;
|
|
11
|
+
}
|
|
@@ -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);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ActivityMiddleware, type StyleOptions } from 'botframework-webchat-api';
|
|
1
|
+
import { type ActivityMiddleware, type StyleOptions, type TypingIndicatorMiddleware } from 'botframework-webchat-api';
|
|
2
2
|
import { DecoratorComposer, DecoratorMiddleware } from 'botframework-webchat-api/decorator';
|
|
3
3
|
import { Components } from 'botframework-webchat-component';
|
|
4
4
|
import { WebChatDecorator } from 'botframework-webchat-component/decorator';
|
|
@@ -6,13 +6,15 @@ import React, { memo, type ReactNode } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { ActivityDecorator } from '../components/activity';
|
|
8
8
|
import ActivityLoader from '../components/activity/ActivityLoader';
|
|
9
|
+
import AssetComposer from '../components/assets/AssetComposer';
|
|
10
|
+
import { isLinerMessageActivity, LinerMessageActivity } from '../components/linerActivity';
|
|
9
11
|
import { isPreChatMessageActivity, PreChatMessageActivity } from '../components/preChatActivity';
|
|
10
12
|
import { PrimarySendBox } from '../components/sendBox';
|
|
11
13
|
import { TelephoneKeypadProvider } from '../components/telephoneKeypad';
|
|
12
14
|
import { WebChatTheme } from '../components/theme';
|
|
15
|
+
import SlidingDotsTypingIndicator from '../components/typingIndicator/SlidingDotsTypingIndicator';
|
|
13
16
|
import { createStyles } from '../styles';
|
|
14
17
|
import VariantComposer, { VariantList } from './VariantComposer';
|
|
15
|
-
import { isLinerMessageActivity, LinerMessageActivity } from '../components/linerActivity';
|
|
16
18
|
|
|
17
19
|
const { ThemeProvider } = Components;
|
|
18
20
|
|
|
@@ -55,6 +57,13 @@ const fluentStyleOptions: StyleOptions = Object.freeze({
|
|
|
55
57
|
feedbackActionsPlacement: 'activity-actions'
|
|
56
58
|
});
|
|
57
59
|
|
|
60
|
+
const typingIndicatorMiddleware = Object.freeze([
|
|
61
|
+
() =>
|
|
62
|
+
next =>
|
|
63
|
+
(...args) =>
|
|
64
|
+
args[0].visible ? <SlidingDotsTypingIndicator /> : next(...args)
|
|
65
|
+
] satisfies TypingIndicatorMiddleware[]);
|
|
66
|
+
|
|
58
67
|
const FluentThemeProvider = ({ children, variant = 'fluent' }: Props) => (
|
|
59
68
|
<VariantComposer variant={variant}>
|
|
60
69
|
<WebChatTheme>
|
|
@@ -64,10 +73,13 @@ const FluentThemeProvider = ({ children, variant = 'fluent' }: Props) => (
|
|
|
64
73
|
sendBoxMiddleware={sendBoxMiddleware}
|
|
65
74
|
styleOptions={fluentStyleOptions}
|
|
66
75
|
styles={styles}
|
|
76
|
+
typingIndicatorMiddleware={typingIndicatorMiddleware}
|
|
67
77
|
>
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
|
|
78
|
+
<AssetComposer>
|
|
79
|
+
<WebChatDecorator>
|
|
80
|
+
<DecoratorComposer middleware={decoratorMiddleware}>{children}</DecoratorComposer>
|
|
81
|
+
</WebChatDecorator>
|
|
82
|
+
</AssetComposer>
|
|
71
83
|
</ThemeProvider>
|
|
72
84
|
</TelephoneKeypadProvider>
|
|
73
85
|
</WebChatTheme>
|