@pingux/astro 2.114.0 → 2.115.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/components/AIComponents/Response/Response.mdx +41 -0
- package/lib/cjs/components/AIComponents/Response/Response.stories.d.ts +8 -0
- package/lib/cjs/components/AIComponents/Response/Response.stories.js +18 -6
- package/lib/cjs/components/AIComponents/Response/Response.test.jsx +13 -7
- package/lib/cjs/components/AIComponents/Response/ResponseList.js +4 -8
- package/lib/cjs/components/AIComponents/Response/ResponseLoader.d.ts +4 -0
- package/lib/cjs/components/AIComponents/Response/ResponseLoader.js +34 -0
- package/lib/cjs/components/AIComponents/Response/ResponseMarkdown/MarkdownTextContainer.js +1 -1
- package/lib/cjs/components/AIComponents/Response/ResponseMarkdown/ResponseMarkdown.d.ts +1 -0
- package/lib/cjs/components/AIComponents/Response/ResponseMarkdown/ResponseMarkdown.js +13 -2
- package/lib/cjs/components/AIComponents/Response/ResponseText.js +4 -2
- package/lib/cjs/components/Text/Text.stories.js +1 -2
- package/lib/cjs/hooks/useTypeAnimation/useTypeAnimation.d.ts +2 -1
- package/lib/cjs/hooks/useTypeAnimation/useTypeAnimation.js +26 -10
- package/lib/cjs/hooks/useTypeAnimation/useTypeAnimation.test.js +4 -3
- package/lib/cjs/styles/themes/next-gen/next-gen.d.ts +4 -0
- package/lib/cjs/styles/themes/next-gen/variants/response.d.ts +4 -0
- package/lib/cjs/styles/themes/next-gen/variants/response.js +6 -2
- package/lib/cjs/styles/themes/next-gen/variants/variants.d.ts +4 -0
- package/lib/components/AIComponents/Response/Response.mdx +41 -0
- package/lib/components/AIComponents/Response/Response.stories.js +16 -4
- package/lib/components/AIComponents/Response/Response.test.jsx +13 -7
- package/lib/components/AIComponents/Response/ResponseList.js +4 -8
- package/lib/components/AIComponents/Response/ResponseLoader.js +21 -0
- package/lib/components/AIComponents/Response/ResponseMarkdown/MarkdownTextContainer.js +1 -1
- package/lib/components/AIComponents/Response/ResponseMarkdown/ResponseMarkdown.js +11 -1
- package/lib/components/AIComponents/Response/ResponseText.js +4 -2
- package/lib/components/Text/Text.stories.js +1 -2
- package/lib/hooks/useTypeAnimation/useTypeAnimation.js +26 -10
- package/lib/hooks/useTypeAnimation/useTypeAnimation.test.js +4 -3
- package/lib/styles/themes/next-gen/variants/response.js +6 -2
- package/package.json +1 -1
@@ -0,0 +1,41 @@
|
|
1
|
+
import { Meta } from '@storybook/addon-docs';
|
2
|
+
|
3
|
+
<Meta title="Components/Response" />
|
4
|
+
|
5
|
+
# Response
|
6
|
+
|
7
|
+
The Response component is used to display animated text responses, lists, and attachments in a conversational UI. It supports progressive rendering of text and nested components like toolbars and attachments.
|
8
|
+
|
9
|
+
### Recommended Use
|
10
|
+
|
11
|
+
- Use the Response component to display text responses with typing animations.
|
12
|
+
- Include lists, toolbars, or attachments as part of the response content.
|
13
|
+
|
14
|
+
### Features
|
15
|
+
|
16
|
+
- **Typing Animation**: Text is progressively displayed to simulate typing.
|
17
|
+
- **Nested Components**: Supports nested lists, toolbars, and attachments.
|
18
|
+
- **Customizable**: Delay and animation settings can be adjusted.
|
19
|
+
|
20
|
+
### Required Components
|
21
|
+
|
22
|
+
This component works with the following subcomponents:
|
23
|
+
- [ResponseText](./?path=/docs/components-response-responsetext--docs)
|
24
|
+
- [ResponseList](./?path=/docs/components-response-responselist--docs)
|
25
|
+
- [ResponseToolbar](./?path=/docs/components-response-responsetoolbar--docs)
|
26
|
+
- [ResponseAttachment](./?path=/docs/components-response-responseattachment--docs)
|
27
|
+
|
28
|
+
### Example Usage
|
29
|
+
|
30
|
+
```jsx
|
31
|
+
<Response delay={100}>
|
32
|
+
<ResponseText text="Hello, how can I assist you today?" />
|
33
|
+
<ResponseList as="ul">
|
34
|
+
<ResponseText as="li" text="Option 1: Get help with your account." />
|
35
|
+
<ResponseText as="li" text="Option 2: Learn about our services." />
|
36
|
+
</ResponseList>
|
37
|
+
<ResponseToolbar>
|
38
|
+
<ResponseToolbarIcon title="Copy" icon={CopyIcon} />
|
39
|
+
<ResponseToolbarIcon title="Read Aloud" icon={VolumeHighIcon} />
|
40
|
+
</ResponseToolbar>
|
41
|
+
</Response>
|
@@ -2,6 +2,14 @@ import React from 'react';
|
|
2
2
|
declare const _default: {
|
3
3
|
title: string;
|
4
4
|
component: (props: import("../../../types/response").ResponseProps) => React.JSX.Element;
|
5
|
+
parameters: {
|
6
|
+
docs: {
|
7
|
+
page: () => React.JSX.Element;
|
8
|
+
source: {
|
9
|
+
type: string;
|
10
|
+
};
|
11
|
+
};
|
12
|
+
};
|
5
13
|
};
|
6
14
|
export default _default;
|
7
15
|
export declare const Default: (args: any) => React.JSX.Element;
|
@@ -13,8 +13,10 @@ var _TextIcon = _interopRequireDefault(require("@pingux/mdi-react/TextIcon"));
|
|
13
13
|
var _ThumbDownOutlineIcon = _interopRequireDefault(require("@pingux/mdi-react/ThumbDownOutlineIcon"));
|
14
14
|
var _ThumbUpOutlineIcon = _interopRequireDefault(require("@pingux/mdi-react/ThumbUpOutlineIcon"));
|
15
15
|
var _VolumeHighIcon = _interopRequireDefault(require("@pingux/mdi-react/VolumeHighIcon"));
|
16
|
+
var _storybookDocsLayout = _interopRequireDefault(require("../../../../.storybook/storybookDocsLayout"));
|
17
|
+
var _index = require("../../../index");
|
16
18
|
var _ResponseMarkdown = _interopRequireDefault(require("./ResponseMarkdown/ResponseMarkdown"));
|
17
|
-
var _Response = _interopRequireDefault(require("./Response"));
|
19
|
+
var _Response = _interopRequireDefault(require("./Response.mdx"));
|
18
20
|
var _ResponseAttachment = _interopRequireDefault(require("./ResponseAttachment"));
|
19
21
|
var _ResponseList = _interopRequireDefault(require("./ResponseList"));
|
20
22
|
var _ResponseText = _interopRequireDefault(require("./ResponseText"));
|
@@ -23,7 +25,17 @@ var _ResponseToolbarIcon = _interopRequireDefault(require("./ResponseToolbarIcon
|
|
23
25
|
var _react2 = require("@emotion/react");
|
24
26
|
var _default = {
|
25
27
|
title: 'Ai Components/Response',
|
26
|
-
component:
|
28
|
+
component: _index.Response,
|
29
|
+
parameters: {
|
30
|
+
docs: {
|
31
|
+
page: function page() {
|
32
|
+
return (0, _react2.jsx)(_react["default"].Fragment, null, (0, _react2.jsx)(_Response["default"], null), (0, _react2.jsx)(_storybookDocsLayout["default"], null));
|
33
|
+
},
|
34
|
+
source: {
|
35
|
+
type: 'code'
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
27
39
|
};
|
28
40
|
exports["default"] = _default;
|
29
41
|
var testText = 'Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet';
|
@@ -44,8 +56,8 @@ var Default = function Default(args) {
|
|
44
56
|
title: 'Rephrase Answer',
|
45
57
|
icon: _TextIcon["default"]
|
46
58
|
}];
|
47
|
-
var delay =
|
48
|
-
return (0, _react2.jsx)(
|
59
|
+
var delay = 100;
|
60
|
+
return (0, _react2.jsx)(_index.Response, {
|
49
61
|
delay: delay
|
50
62
|
}, (0, _react2.jsx)(_ResponseText["default"], {
|
51
63
|
text: testText
|
@@ -76,8 +88,8 @@ exports.Default = Default;
|
|
76
88
|
var nestedMarkdown = 'The recent login activity shows successful authentication attempts for the user \"bbludis476@gmail.com\" using the \"BXRetail App\". There were no failed authentication attempts recorded. Here are the details of the successful attempts:\n\n1. **Timestamp:** 2025-02-13T09:25:55.946Z\n - **User:** bbludis476@gmail.com\n - **Action:** User Access Allowed\n - **Status:** SUCCESS\n\n2. **Timestamp:** 2025-02-13T09:25:52.377Z\n - **User:** bbludis476@gmail.com\n - **Action:** User Access Allowed\n - **Status:** SUCCESS';
|
77
89
|
var italics = '*Italics* bbludis476@gmail.com';
|
78
90
|
var MarkdownStory = function MarkdownStory() {
|
79
|
-
return (0, _react2.jsx)(
|
80
|
-
delay:
|
91
|
+
return (0, _react2.jsx)(_index.Response, {
|
92
|
+
delay: 100
|
81
93
|
}, (0, _react2.jsx)(_ResponseText["default"], {
|
82
94
|
text: "Beginning response text"
|
83
95
|
}), (0, _react2.jsx)(_ResponseMarkdown["default"], {
|
@@ -106,10 +106,12 @@ test('component renders', () => {
|
|
106
106
|
test('delay prop works correctly', async () => {
|
107
107
|
getComponent();
|
108
108
|
|
109
|
+
const splitText = defaultProps.text.split(' ');
|
110
|
+
|
109
111
|
expect(screen.queryByText(defaultProps.text)).not.toBeInTheDocument();
|
110
|
-
for (let i = 1; i <
|
112
|
+
for (let i = 1; i < splitText.length + 1; i += 1) {
|
111
113
|
act(() => { jest.advanceTimersByTime(100); });
|
112
|
-
expect(screen.queryByText(
|
114
|
+
expect(screen.queryByText(splitText.slice(0, i).join(' '))).toBeInTheDocument();
|
113
115
|
}
|
114
116
|
expect(screen.queryByText(defaultProps.text)).toBeInTheDocument();
|
115
117
|
});
|
@@ -117,15 +119,19 @@ test('delay prop works correctly', async () => {
|
|
117
119
|
test('delay prop works correctly, with list', async () => {
|
118
120
|
getComponentWithList();
|
119
121
|
|
122
|
+
const splitText = headingText.split(' ');
|
123
|
+
|
120
124
|
expect(screen.queryByText(headingText)).not.toBeInTheDocument();
|
121
|
-
for (let i = 1; i <
|
125
|
+
for (let i = 1; i < splitText.length + 1; i += 1) {
|
122
126
|
act(() => { jest.advanceTimersByTime(100); });
|
123
|
-
expect(screen.queryByText(
|
127
|
+
expect(screen.queryByText(splitText.slice(0, i).join(' '))).toBeInTheDocument();
|
124
128
|
}
|
125
129
|
expect(screen.queryByText(headingText)).toBeInTheDocument();
|
126
130
|
|
131
|
+
const nextTextSplit = nextText.split(' ');
|
132
|
+
|
127
133
|
// advance through the listItems
|
128
|
-
for (let i = 1; i <
|
134
|
+
for (let i = 1; i < 10; i += 1) {
|
129
135
|
act(() => { jest.advanceTimersByTime(100); });
|
130
136
|
}
|
131
137
|
expect(screen.queryByText(nextText)).not.toBeInTheDocument();
|
@@ -133,7 +139,7 @@ test('delay prop works correctly, with list', async () => {
|
|
133
139
|
// ensure that the subsequent text renders correctly
|
134
140
|
for (let i = 1; i < nextText.length + 1; i += 1) {
|
135
141
|
act(() => { jest.advanceTimersByTime(100); });
|
136
|
-
expect(screen.queryByText(
|
142
|
+
expect(screen.queryByText(nextTextSplit.slice(0, i).join(' '))).toBeInTheDocument();
|
137
143
|
}
|
138
144
|
expect(screen.queryByText(nextText)).toBeInTheDocument();
|
139
145
|
});
|
@@ -148,7 +154,7 @@ test('default delay prop works correctly', async () => {
|
|
148
154
|
expect(screen.queryByText(defaultProps.text)).not.toBeInTheDocument();
|
149
155
|
for (let i = 1; i < defaultProps.text.length + 1; i += 1) {
|
150
156
|
act(() => { jest.advanceTimersByTime(10); });
|
151
|
-
expect(screen.queryByText(defaultProps.text.slice(0, i))).toBeInTheDocument();
|
157
|
+
expect(screen.queryByText(defaultProps.text.split(' ').slice(0, i).join(' '))).toBeInTheDocument();
|
152
158
|
}
|
153
159
|
expect(screen.queryByText(defaultProps.text)).toBeInTheDocument();
|
154
160
|
});
|
@@ -27,7 +27,8 @@ var ResponseList = function ResponseList(props) {
|
|
27
27
|
setAnimationIndex = props.setAnimationIndex,
|
28
28
|
shouldStartAnimation = props.shouldStartAnimation,
|
29
29
|
delay = props.delay,
|
30
|
-
|
30
|
+
_props$as = props.as,
|
31
|
+
asProp = _props$as === void 0 ? 'ul' : _props$as;
|
31
32
|
(0, _react.useEffect)(function () {
|
32
33
|
if (children && setAnimationIndex && index === children.length && parentIndex !== undefined) {
|
33
34
|
setAnimationIndex(parentIndex + 1);
|
@@ -46,19 +47,14 @@ var ResponseList = function ResponseList(props) {
|
|
46
47
|
return (0, _react2.jsx)(_index.Box, {
|
47
48
|
as: asProp,
|
48
49
|
variant: "response.list",
|
49
|
-
className: classNames
|
50
|
-
sx: {
|
51
|
-
pl: 'md',
|
52
|
-
listStyleType: 'disc',
|
53
|
-
listStylePosition: 'inside'
|
54
|
-
}
|
50
|
+
className: classNames
|
55
51
|
}, (0, _map["default"])(_react.Children).call(_react.Children, children, function (child, i) {
|
56
52
|
return /*#__PURE__*/_react["default"].cloneElement(child, {
|
57
53
|
shouldStartAnimation: index === i,
|
58
54
|
setAnimationIndex: setIndex,
|
59
55
|
animationIndex: i,
|
60
56
|
delay: delay,
|
61
|
-
isListItem: /*#__PURE__*/_react["default"].isValidElement(child) && child.props.as && child.props.as !== 'p',
|
57
|
+
isListItem: /*#__PURE__*/_react["default"].isValidElement(child) && child.props.as && (child.props.as !== 'p' || child.props.as !== 'span'),
|
62
58
|
parentIndex: index,
|
63
59
|
as: 'li'
|
64
60
|
});
|
@@ -0,0 +1,34 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _typeof = require("@babel/runtime-corejs3/helpers/typeof");
|
4
|
+
var _WeakMap = require("@babel/runtime-corejs3/core-js-stable/weak-map");
|
5
|
+
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
|
6
|
+
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor");
|
7
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
|
8
|
+
_Object$defineProperty(exports, "__esModule", {
|
9
|
+
value: true
|
10
|
+
});
|
11
|
+
exports["default"] = void 0;
|
12
|
+
var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/taggedTemplateLiteral"));
|
13
|
+
var _react = _interopRequireWildcard(require("react"));
|
14
|
+
var _react2 = require("@emotion/react");
|
15
|
+
var _templateObject, _templateObject2;
|
16
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof _WeakMap !== "function") return null; var cacheBabelInterop = new _WeakMap(); var cacheNodeInterop = new _WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
17
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = _Object$defineProperty && _Object$getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? _Object$getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { _Object$defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
18
|
+
var typingPulse = (0, _react2.keyframes)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2["default"])(["\n 0% {\n opacity: 0.25;\n }\n\n 50% {\n opacity: 0.25;\n }\n 80% {\n opacity: 1;\n }\n 100% {\n opacity: 0.25;\n }\n"])));
|
19
|
+
var animationSettingsType = '2s ease-out infinite';
|
20
|
+
var ResponseLoader = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
|
21
|
+
var _props$color = props.color,
|
22
|
+
color = _props$color === void 0 ? 'currentColor' : _props$color;
|
23
|
+
return (0, _react2.jsx)(_react2.ClassNames, null, function (_ref) {
|
24
|
+
var className = _ref.css;
|
25
|
+
return (0, _react2.jsx)("span", {
|
26
|
+
ref: ref,
|
27
|
+
role: "alert",
|
28
|
+
"aria-label": "response is loading",
|
29
|
+
className: className(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2["default"])(["\n animation: ", " ", ";\n background-color: ", ";\n height: .75rem;\n width: .75rem;\n border-radius: 50%;\n display: inline-block;\n margin-left: 4px;\n margin-bottom: -1px;\n "])), typingPulse, animationSettingsType, color)
|
30
|
+
});
|
31
|
+
});
|
32
|
+
});
|
33
|
+
var _default = ResponseLoader;
|
34
|
+
exports["default"] = _default;
|
@@ -67,7 +67,7 @@ var MarkdownTextContainer = function MarkdownTextContainer(props) {
|
|
67
67
|
return (0, _react2.jsx)(_Box["default"], {
|
68
68
|
className: classNames,
|
69
69
|
variant: "response.textWrapper",
|
70
|
-
as: hasNonStringChild ? 'div' : as
|
70
|
+
as: hasNonStringChild && as === 'p' ? 'div' : as
|
71
71
|
}, (0, _react2.jsx)(_Box["default"], {
|
72
72
|
isRow: true
|
73
73
|
}, (0, _map["default"])(_react.Children).call(_react.Children, (0, _slice["default"])(markdownTextChildren).call(markdownTextChildren, 0, index + 1), function (child, i) {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { ResponseMarkdownContextValue } from '../../../../types/response';
|
3
3
|
export declare const ResponseMarkdownContext: React.Context<ResponseMarkdownContextValue>;
|
4
|
+
export declare const countChildren: (_children: any) => number;
|
4
5
|
declare const ResponseMarkdown: (componentProps: any) => React.JSX.Element;
|
5
6
|
export default ResponseMarkdown;
|
@@ -14,7 +14,7 @@ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequ
|
|
14
14
|
_Object$defineProperty(exports, "__esModule", {
|
15
15
|
value: true
|
16
16
|
});
|
17
|
-
exports["default"] = exports.ResponseMarkdownContext = void 0;
|
17
|
+
exports["default"] = exports.countChildren = exports.ResponseMarkdownContext = void 0;
|
18
18
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
|
19
19
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray"));
|
20
20
|
var _react = _interopRequireWildcard(require("react"));
|
@@ -31,6 +31,16 @@ var ResponseMarkdownContext = /*#__PURE__*/(0, _react.createContext)({
|
|
31
31
|
stateIndex: -1
|
32
32
|
});
|
33
33
|
exports.ResponseMarkdownContext = ResponseMarkdownContext;
|
34
|
+
var countChildren = function countChildren(_children) {
|
35
|
+
var count = 0;
|
36
|
+
for (var i = 0; i < _children.length; i += 1) {
|
37
|
+
if (typeof _children[i] !== 'string') {
|
38
|
+
count += 1;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return count;
|
42
|
+
};
|
43
|
+
exports.countChildren = countChildren;
|
34
44
|
var ResponseMarkdown = function ResponseMarkdown(componentProps) {
|
35
45
|
var _useState = (0, _react.useState)(-1),
|
36
46
|
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
|
@@ -135,8 +145,9 @@ var ResponseMarkdown = function ResponseMarkdown(componentProps) {
|
|
135
145
|
}
|
136
146
|
}
|
137
147
|
});
|
148
|
+
var childrenCount = countChildren(markdown.props.children);
|
138
149
|
(0, _react.useEffect)(function () {
|
139
|
-
if (index ===
|
150
|
+
if (index === childrenCount) {
|
140
151
|
setAnimationIndex(parentIndex + 1);
|
141
152
|
}
|
142
153
|
}, [index, markdown.props.children.length]);
|
@@ -12,6 +12,7 @@ var _react = _interopRequireDefault(require("react"));
|
|
12
12
|
var _hooks = require("../../../hooks");
|
13
13
|
var _useTypeAnimation2 = _interopRequireDefault(require("../../../hooks/useTypeAnimation/useTypeAnimation"));
|
14
14
|
var _index = require("../../../index");
|
15
|
+
var _ResponseLoader = _interopRequireDefault(require("./ResponseLoader"));
|
15
16
|
var _react2 = require("@emotion/react");
|
16
17
|
var _excluded = ["delay", "text", "shouldStartAnimation", "setAnimationIndex", "animationIndex", "isListItem", "className"];
|
17
18
|
var ResponseText = function ResponseText(props) {
|
@@ -32,7 +33,8 @@ var ResponseText = function ResponseText(props) {
|
|
32
33
|
shouldStartAnimation: shouldStartAnimation
|
33
34
|
};
|
34
35
|
var _useTypeAnimation = (0, _useTypeAnimation2["default"])(animationProps),
|
35
|
-
currentText = _useTypeAnimation.currentText
|
36
|
+
currentText = _useTypeAnimation.currentText,
|
37
|
+
isLoading = _useTypeAnimation.isLoading;
|
36
38
|
var hasBullet = isListItem === true && currentText.length > 0;
|
37
39
|
var _useStatusClasses = (0, _hooks.useStatusClasses)(className, {
|
38
40
|
hasBullet: hasBullet
|
@@ -43,7 +45,7 @@ var ResponseText = function ResponseText(props) {
|
|
43
45
|
role: isListItem ? 'listitem' : '',
|
44
46
|
variant: "response",
|
45
47
|
className: classNames
|
46
|
-
}), renderText);
|
48
|
+
}), renderText, isLoading && (0, _react2.jsx)(_ResponseLoader["default"], null));
|
47
49
|
};
|
48
50
|
var _default = ResponseText;
|
49
51
|
exports["default"] = _default;
|
@@ -430,8 +430,7 @@ var CustomWidth = function CustomWidth() {
|
|
430
430
|
return (0, _react2.jsx)(_index.Box, {
|
431
431
|
width: 200
|
432
432
|
}, (0, _react2.jsx)(_index.Text, {
|
433
|
-
p: "xl"
|
434
|
-
color: "text.secondary"
|
433
|
+
p: "xl"
|
435
434
|
}, "superlongtextinonelinewithnowhitespacessoitcanbelongerthatanywidth"));
|
436
435
|
};
|
437
436
|
exports.CustomWidth = CustomWidth;
|
@@ -7,6 +7,7 @@ _Object$defineProperty(exports, "__esModule", {
|
|
7
7
|
});
|
8
8
|
exports["default"] = void 0;
|
9
9
|
var _setTimeout2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/set-timeout"));
|
10
|
+
var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice"));
|
10
11
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray"));
|
11
12
|
var _react = require("react");
|
12
13
|
var useTypeAnimation = function useTypeAnimation(_ref) {
|
@@ -15,20 +16,26 @@ var useTypeAnimation = function useTypeAnimation(_ref) {
|
|
15
16
|
delay = _ref.delay,
|
16
17
|
setAnimationIndex = _ref.setAnimationIndex,
|
17
18
|
animationIndex = _ref.animationIndex;
|
18
|
-
var _useState = (0, _react.useState)(''),
|
19
|
+
var _useState = (0, _react.useState)(text.split(' ')),
|
19
20
|
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
|
20
|
-
|
21
|
-
|
22
|
-
var _useState3 = (0, _react.useState)(
|
21
|
+
splitText = _useState2[0],
|
22
|
+
setSplitText = _useState2[1];
|
23
|
+
var _useState3 = (0, _react.useState)(-1),
|
23
24
|
_useState4 = (0, _slicedToArray2["default"])(_useState3, 2),
|
24
25
|
currentIndex = _useState4[0],
|
25
26
|
setCurrentIndex = _useState4[1];
|
27
|
+
var _useState5 = (0, _react.useState)(false),
|
28
|
+
_useState6 = (0, _slicedToArray2["default"])(_useState5, 2),
|
29
|
+
isLoading = _useState6[0],
|
30
|
+
setIsLoading = _useState6[1];
|
26
31
|
(0, _react.useEffect)(function () {
|
27
|
-
if (shouldStartAnimation &&
|
32
|
+
if (shouldStartAnimation && currentIndex < 0) {
|
33
|
+
setCurrentIndex(0);
|
34
|
+
}
|
35
|
+
}, [shouldStartAnimation, currentIndex]);
|
36
|
+
(0, _react.useEffect)(function () {
|
37
|
+
if (shouldStartAnimation && text && currentIndex < splitText.length) {
|
28
38
|
var timeout = (0, _setTimeout2["default"])(function () {
|
29
|
-
setCurrentText(function (prevText) {
|
30
|
-
return prevText + text[currentIndex];
|
31
|
-
});
|
32
39
|
setCurrentIndex(function (prevIndex) {
|
33
40
|
return prevIndex + 1;
|
34
41
|
});
|
@@ -37,15 +44,24 @@ var useTypeAnimation = function useTypeAnimation(_ref) {
|
|
37
44
|
return clearTimeout(timeout);
|
38
45
|
};
|
39
46
|
}
|
40
|
-
if (
|
47
|
+
if (splitText && currentIndex === splitText.length) {
|
41
48
|
setAnimationIndex(animationIndex + 1);
|
42
49
|
}
|
43
50
|
return function () {
|
44
51
|
return null;
|
45
52
|
};
|
46
53
|
}, [currentIndex, delay, text, shouldStartAnimation, setAnimationIndex, animationIndex]);
|
54
|
+
(0, _react.useEffect)(function () {
|
55
|
+
if (splitText.length > 0 && currentIndex > 0 && currentIndex < splitText.length) {
|
56
|
+
setIsLoading(true);
|
57
|
+
} else {
|
58
|
+
setIsLoading(false);
|
59
|
+
}
|
60
|
+
}, [splitText, text, currentIndex]);
|
61
|
+
var indexOrNothing = Math.max(currentIndex, 0);
|
47
62
|
return {
|
48
|
-
currentText:
|
63
|
+
currentText: (0, _slice["default"])(splitText).call(splitText, 0, indexOrNothing).join(' '),
|
64
|
+
isLoading: isLoading
|
49
65
|
};
|
50
66
|
};
|
51
67
|
var _default = useTypeAnimation;
|
@@ -17,8 +17,9 @@ function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (
|
|
17
17
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(source), !0)).call(_context, function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context2 = ownKeys(Object(source))).call(_context2, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
|
18
18
|
var setAnimationIndex = jest.fn();
|
19
19
|
var animationIndex = 0;
|
20
|
-
var text = 'Hello';
|
20
|
+
var text = 'Hello World';
|
21
21
|
var delay = 100;
|
22
|
+
var splitText = text.split(' ');
|
22
23
|
var defaultProps = {
|
23
24
|
text: text,
|
24
25
|
delay: delay,
|
@@ -39,11 +40,11 @@ describe('useTypeAnimation', function () {
|
|
39
40
|
}),
|
40
41
|
result = _renderHook.result;
|
41
42
|
expect(result.current.currentText).toBe('');
|
42
|
-
for (var i = 0; i <
|
43
|
+
for (var i = 0; i < splitText.length; i += 1) {
|
43
44
|
(0, _reactHooks.act)(function () {
|
44
45
|
jest.advanceTimersByTime(delay);
|
45
46
|
});
|
46
|
-
expect(result.current.currentText).toBe((0, _slice["default"])(
|
47
|
+
expect(result.current.currentText).toBe((0, _slice["default"])(splitText).call(splitText, 0, i + 1).join(' '));
|
47
48
|
}
|
48
49
|
expect(result.current.currentText).toBe(text);
|
49
50
|
});
|
@@ -2703,19 +2703,23 @@ declare const _default: {
|
|
2703
2703
|
};
|
2704
2704
|
};
|
2705
2705
|
textWrapper: {
|
2706
|
+
height: string;
|
2706
2707
|
'&.has-bullet': {
|
2707
2708
|
display: string;
|
2709
|
+
height: string;
|
2708
2710
|
};
|
2709
2711
|
'&.has-rendered': {
|
2710
2712
|
display: string;
|
2711
2713
|
};
|
2712
2714
|
'&.has-block': {
|
2715
|
+
maxHeight: string;
|
2713
2716
|
display: string;
|
2714
2717
|
};
|
2715
2718
|
'&::marker': {
|
2716
2719
|
color: string;
|
2717
2720
|
};
|
2718
2721
|
listStylePosition: string;
|
2722
|
+
flexDirection: string;
|
2719
2723
|
};
|
2720
2724
|
};
|
2721
2725
|
skeleton: {
|
@@ -50,19 +50,23 @@ declare const _default: {
|
|
50
50
|
};
|
51
51
|
};
|
52
52
|
textWrapper: {
|
53
|
+
height: string;
|
53
54
|
'&.has-bullet': {
|
54
55
|
display: string;
|
56
|
+
height: string;
|
55
57
|
};
|
56
58
|
'&.has-rendered': {
|
57
59
|
display: string;
|
58
60
|
};
|
59
61
|
'&.has-block': {
|
62
|
+
maxHeight: string;
|
60
63
|
display: string;
|
61
64
|
};
|
62
65
|
'&::marker': {
|
63
66
|
color: string;
|
64
67
|
};
|
65
68
|
listStylePosition: string;
|
69
|
+
flexDirection: string;
|
66
70
|
};
|
67
71
|
};
|
68
72
|
export default _default;
|
@@ -56,19 +56,23 @@ var list = {
|
|
56
56
|
}
|
57
57
|
};
|
58
58
|
var textWrapper = {
|
59
|
+
height: 'fit-content',
|
59
60
|
'&.has-bullet': {
|
60
|
-
display: 'list-item !important'
|
61
|
+
display: 'list-item !important',
|
62
|
+
height: 'fit-content'
|
61
63
|
},
|
62
64
|
'&.has-rendered': {
|
63
65
|
display: 'list-item'
|
64
66
|
},
|
65
67
|
'&.has-block': {
|
68
|
+
maxHeight: 'fit-content',
|
66
69
|
display: 'block'
|
67
70
|
},
|
68
71
|
'&::marker': {
|
69
72
|
color: 'text.primary'
|
70
73
|
},
|
71
|
-
listStylePosition: '
|
74
|
+
listStylePosition: 'initial',
|
75
|
+
flexDirection: 'row'
|
72
76
|
};
|
73
77
|
var _default = {
|
74
78
|
iconWrapper: iconWrapper,
|
@@ -968,19 +968,23 @@ declare const _default: {
|
|
968
968
|
};
|
969
969
|
};
|
970
970
|
textWrapper: {
|
971
|
+
height: string;
|
971
972
|
'&.has-bullet': {
|
972
973
|
display: string;
|
974
|
+
height: string;
|
973
975
|
};
|
974
976
|
'&.has-rendered': {
|
975
977
|
display: string;
|
976
978
|
};
|
977
979
|
'&.has-block': {
|
980
|
+
maxHeight: string;
|
978
981
|
display: string;
|
979
982
|
};
|
980
983
|
'&::marker': {
|
981
984
|
color: string;
|
982
985
|
};
|
983
986
|
listStylePosition: string;
|
987
|
+
flexDirection: string;
|
984
988
|
};
|
985
989
|
};
|
986
990
|
skeleton: {
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { Meta } from '@storybook/addon-docs';
|
2
|
+
|
3
|
+
<Meta title="Components/Response" />
|
4
|
+
|
5
|
+
# Response
|
6
|
+
|
7
|
+
The Response component is used to display animated text responses, lists, and attachments in a conversational UI. It supports progressive rendering of text and nested components like toolbars and attachments.
|
8
|
+
|
9
|
+
### Recommended Use
|
10
|
+
|
11
|
+
- Use the Response component to display text responses with typing animations.
|
12
|
+
- Include lists, toolbars, or attachments as part of the response content.
|
13
|
+
|
14
|
+
### Features
|
15
|
+
|
16
|
+
- **Typing Animation**: Text is progressively displayed to simulate typing.
|
17
|
+
- **Nested Components**: Supports nested lists, toolbars, and attachments.
|
18
|
+
- **Customizable**: Delay and animation settings can be adjusted.
|
19
|
+
|
20
|
+
### Required Components
|
21
|
+
|
22
|
+
This component works with the following subcomponents:
|
23
|
+
- [ResponseText](./?path=/docs/components-response-responsetext--docs)
|
24
|
+
- [ResponseList](./?path=/docs/components-response-responselist--docs)
|
25
|
+
- [ResponseToolbar](./?path=/docs/components-response-responsetoolbar--docs)
|
26
|
+
- [ResponseAttachment](./?path=/docs/components-response-responseattachment--docs)
|
27
|
+
|
28
|
+
### Example Usage
|
29
|
+
|
30
|
+
```jsx
|
31
|
+
<Response delay={100}>
|
32
|
+
<ResponseText text="Hello, how can I assist you today?" />
|
33
|
+
<ResponseList as="ul">
|
34
|
+
<ResponseText as="li" text="Option 1: Get help with your account." />
|
35
|
+
<ResponseText as="li" text="Option 2: Learn about our services." />
|
36
|
+
</ResponseList>
|
37
|
+
<ResponseToolbar>
|
38
|
+
<ResponseToolbarIcon title="Copy" icon={CopyIcon} />
|
39
|
+
<ResponseToolbarIcon title="Read Aloud" icon={VolumeHighIcon} />
|
40
|
+
</ResponseToolbar>
|
41
|
+
</Response>
|
@@ -5,8 +5,10 @@ import TextIcon from '@pingux/mdi-react/TextIcon';
|
|
5
5
|
import ThumbDownOutlineIcon from '@pingux/mdi-react/ThumbDownOutlineIcon';
|
6
6
|
import ThumbUpOutlineIcon from '@pingux/mdi-react/ThumbUpOutlineIcon';
|
7
7
|
import VolumeHighIcon from '@pingux/mdi-react/VolumeHighIcon';
|
8
|
+
import DocsLayout from '../../../../.storybook/storybookDocsLayout';
|
9
|
+
import { Response } from '../../../index';
|
8
10
|
import Markdown from './ResponseMarkdown/ResponseMarkdown';
|
9
|
-
import
|
11
|
+
import ResponseReadme from './Response.mdx';
|
10
12
|
import ResponseAttachment from './ResponseAttachment';
|
11
13
|
import ResponseList from './ResponseList';
|
12
14
|
import ResponseText from './ResponseText';
|
@@ -15,7 +17,17 @@ import ResponseToolbarIcon from './ResponseToolbarIcon';
|
|
15
17
|
import { jsx as ___EmotionJSX } from "@emotion/react";
|
16
18
|
export default {
|
17
19
|
title: 'Ai Components/Response',
|
18
|
-
component: Response
|
20
|
+
component: Response,
|
21
|
+
parameters: {
|
22
|
+
docs: {
|
23
|
+
page: function page() {
|
24
|
+
return ___EmotionJSX(React.Fragment, null, ___EmotionJSX(ResponseReadme, null), ___EmotionJSX(DocsLayout, null));
|
25
|
+
},
|
26
|
+
source: {
|
27
|
+
type: 'code'
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
19
31
|
};
|
20
32
|
var testText = 'Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet';
|
21
33
|
export var Default = function Default(args) {
|
@@ -35,7 +47,7 @@ export var Default = function Default(args) {
|
|
35
47
|
title: 'Rephrase Answer',
|
36
48
|
icon: TextIcon
|
37
49
|
}];
|
38
|
-
var delay =
|
50
|
+
var delay = 100;
|
39
51
|
return ___EmotionJSX(Response, {
|
40
52
|
delay: delay
|
41
53
|
}, ___EmotionJSX(ResponseText, {
|
@@ -67,7 +79,7 @@ var nestedMarkdown = 'The recent login activity shows successful authentication
|
|
67
79
|
var italics = '*Italics* bbludis476@gmail.com';
|
68
80
|
export var MarkdownStory = function MarkdownStory() {
|
69
81
|
return ___EmotionJSX(Response, {
|
70
|
-
delay:
|
82
|
+
delay: 100
|
71
83
|
}, ___EmotionJSX(ResponseText, {
|
72
84
|
text: "Beginning response text"
|
73
85
|
}), ___EmotionJSX(Markdown, {
|
@@ -106,10 +106,12 @@ test('component renders', () => {
|
|
106
106
|
test('delay prop works correctly', async () => {
|
107
107
|
getComponent();
|
108
108
|
|
109
|
+
const splitText = defaultProps.text.split(' ');
|
110
|
+
|
109
111
|
expect(screen.queryByText(defaultProps.text)).not.toBeInTheDocument();
|
110
|
-
for (let i = 1; i <
|
112
|
+
for (let i = 1; i < splitText.length + 1; i += 1) {
|
111
113
|
act(() => { jest.advanceTimersByTime(100); });
|
112
|
-
expect(screen.queryByText(
|
114
|
+
expect(screen.queryByText(splitText.slice(0, i).join(' '))).toBeInTheDocument();
|
113
115
|
}
|
114
116
|
expect(screen.queryByText(defaultProps.text)).toBeInTheDocument();
|
115
117
|
});
|
@@ -117,15 +119,19 @@ test('delay prop works correctly', async () => {
|
|
117
119
|
test('delay prop works correctly, with list', async () => {
|
118
120
|
getComponentWithList();
|
119
121
|
|
122
|
+
const splitText = headingText.split(' ');
|
123
|
+
|
120
124
|
expect(screen.queryByText(headingText)).not.toBeInTheDocument();
|
121
|
-
for (let i = 1; i <
|
125
|
+
for (let i = 1; i < splitText.length + 1; i += 1) {
|
122
126
|
act(() => { jest.advanceTimersByTime(100); });
|
123
|
-
expect(screen.queryByText(
|
127
|
+
expect(screen.queryByText(splitText.slice(0, i).join(' '))).toBeInTheDocument();
|
124
128
|
}
|
125
129
|
expect(screen.queryByText(headingText)).toBeInTheDocument();
|
126
130
|
|
131
|
+
const nextTextSplit = nextText.split(' ');
|
132
|
+
|
127
133
|
// advance through the listItems
|
128
|
-
for (let i = 1; i <
|
134
|
+
for (let i = 1; i < 10; i += 1) {
|
129
135
|
act(() => { jest.advanceTimersByTime(100); });
|
130
136
|
}
|
131
137
|
expect(screen.queryByText(nextText)).not.toBeInTheDocument();
|
@@ -133,7 +139,7 @@ test('delay prop works correctly, with list', async () => {
|
|
133
139
|
// ensure that the subsequent text renders correctly
|
134
140
|
for (let i = 1; i < nextText.length + 1; i += 1) {
|
135
141
|
act(() => { jest.advanceTimersByTime(100); });
|
136
|
-
expect(screen.queryByText(
|
142
|
+
expect(screen.queryByText(nextTextSplit.slice(0, i).join(' '))).toBeInTheDocument();
|
137
143
|
}
|
138
144
|
expect(screen.queryByText(nextText)).toBeInTheDocument();
|
139
145
|
});
|
@@ -148,7 +154,7 @@ test('default delay prop works correctly', async () => {
|
|
148
154
|
expect(screen.queryByText(defaultProps.text)).not.toBeInTheDocument();
|
149
155
|
for (let i = 1; i < defaultProps.text.length + 1; i += 1) {
|
150
156
|
act(() => { jest.advanceTimersByTime(10); });
|
151
|
-
expect(screen.queryByText(defaultProps.text.slice(0, i))).toBeInTheDocument();
|
157
|
+
expect(screen.queryByText(defaultProps.text.split(' ').slice(0, i).join(' '))).toBeInTheDocument();
|
152
158
|
}
|
153
159
|
expect(screen.queryByText(defaultProps.text)).toBeInTheDocument();
|
154
160
|
});
|
@@ -14,7 +14,8 @@ var ResponseList = function ResponseList(props) {
|
|
14
14
|
setAnimationIndex = props.setAnimationIndex,
|
15
15
|
shouldStartAnimation = props.shouldStartAnimation,
|
16
16
|
delay = props.delay,
|
17
|
-
|
17
|
+
_props$as = props.as,
|
18
|
+
asProp = _props$as === void 0 ? 'ul' : _props$as;
|
18
19
|
useEffect(function () {
|
19
20
|
if (children && setAnimationIndex && index === children.length && parentIndex !== undefined) {
|
20
21
|
setAnimationIndex(parentIndex + 1);
|
@@ -33,19 +34,14 @@ var ResponseList = function ResponseList(props) {
|
|
33
34
|
return ___EmotionJSX(Box, {
|
34
35
|
as: asProp,
|
35
36
|
variant: "response.list",
|
36
|
-
className: classNames
|
37
|
-
sx: {
|
38
|
-
pl: 'md',
|
39
|
-
listStyleType: 'disc',
|
40
|
-
listStylePosition: 'inside'
|
41
|
-
}
|
37
|
+
className: classNames
|
42
38
|
}, _mapInstanceProperty(Children).call(Children, children, function (child, i) {
|
43
39
|
return /*#__PURE__*/React.cloneElement(child, {
|
44
40
|
shouldStartAnimation: index === i,
|
45
41
|
setAnimationIndex: setIndex,
|
46
42
|
animationIndex: i,
|
47
43
|
delay: delay,
|
48
|
-
isListItem: /*#__PURE__*/React.isValidElement(child) && child.props.as && child.props.as !== 'p',
|
44
|
+
isListItem: /*#__PURE__*/React.isValidElement(child) && child.props.as && (child.props.as !== 'p' || child.props.as !== 'span'),
|
49
45
|
parentIndex: index,
|
50
46
|
as: 'li'
|
51
47
|
});
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import _taggedTemplateLiteral from "@babel/runtime-corejs3/helpers/esm/taggedTemplateLiteral";
|
2
|
+
var _templateObject, _templateObject2;
|
3
|
+
import React, { forwardRef } from 'react';
|
4
|
+
import { ClassNames, keyframes } from '@emotion/react';
|
5
|
+
import { jsx as ___EmotionJSX } from "@emotion/react";
|
6
|
+
var typingPulse = keyframes(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n 0% {\n opacity: 0.25;\n }\n\n 50% {\n opacity: 0.25;\n }\n 80% {\n opacity: 1;\n }\n 100% {\n opacity: 0.25;\n }\n"])));
|
7
|
+
var animationSettingsType = '2s ease-out infinite';
|
8
|
+
var ResponseLoader = /*#__PURE__*/forwardRef(function (props, ref) {
|
9
|
+
var _props$color = props.color,
|
10
|
+
color = _props$color === void 0 ? 'currentColor' : _props$color;
|
11
|
+
return ___EmotionJSX(ClassNames, null, function (_ref) {
|
12
|
+
var className = _ref.css;
|
13
|
+
return ___EmotionJSX("span", {
|
14
|
+
ref: ref,
|
15
|
+
role: "alert",
|
16
|
+
"aria-label": "response is loading",
|
17
|
+
className: className(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n animation: ", " ", ";\n background-color: ", ";\n height: .75rem;\n width: .75rem;\n border-radius: 50%;\n display: inline-block;\n margin-left: 4px;\n margin-bottom: -1px;\n "])), typingPulse, animationSettingsType, color)
|
18
|
+
});
|
19
|
+
});
|
20
|
+
});
|
21
|
+
export default ResponseLoader;
|
@@ -53,7 +53,7 @@ var MarkdownTextContainer = function MarkdownTextContainer(props) {
|
|
53
53
|
return ___EmotionJSX(Box, {
|
54
54
|
className: classNames,
|
55
55
|
variant: "response.textWrapper",
|
56
|
-
as: hasNonStringChild ? 'div' : as
|
56
|
+
as: hasNonStringChild && as === 'p' ? 'div' : as
|
57
57
|
}, ___EmotionJSX(Box, {
|
58
58
|
isRow: true
|
59
59
|
}, _mapInstanceProperty(Children).call(Children, _sliceInstanceProperty(markdownTextChildren).call(markdownTextChildren, 0, index + 1), function (child, i) {
|
@@ -19,6 +19,15 @@ import { jsx as ___EmotionJSX } from "@emotion/react";
|
|
19
19
|
export var ResponseMarkdownContext = /*#__PURE__*/createContext({
|
20
20
|
stateIndex: -1
|
21
21
|
});
|
22
|
+
export var countChildren = function countChildren(_children) {
|
23
|
+
var count = 0;
|
24
|
+
for (var i = 0; i < _children.length; i += 1) {
|
25
|
+
if (typeof _children[i] !== 'string') {
|
26
|
+
count += 1;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
return count;
|
30
|
+
};
|
22
31
|
var ResponseMarkdown = function ResponseMarkdown(componentProps) {
|
23
32
|
var _useState = useState(-1),
|
24
33
|
_useState2 = _slicedToArray(_useState, 2),
|
@@ -123,8 +132,9 @@ var ResponseMarkdown = function ResponseMarkdown(componentProps) {
|
|
123
132
|
}
|
124
133
|
}
|
125
134
|
});
|
135
|
+
var childrenCount = countChildren(markdown.props.children);
|
126
136
|
useEffect(function () {
|
127
|
-
if (index ===
|
137
|
+
if (index === childrenCount) {
|
128
138
|
setAnimationIndex(parentIndex + 1);
|
129
139
|
}
|
130
140
|
}, [index, markdown.props.children.length]);
|
@@ -5,6 +5,7 @@ import React from 'react';
|
|
5
5
|
import { useStatusClasses } from '../../../hooks';
|
6
6
|
import useTypeAnimation from '../../../hooks/useTypeAnimation/useTypeAnimation';
|
7
7
|
import { Text } from '../../../index';
|
8
|
+
import ResponseLoader from './ResponseLoader';
|
8
9
|
import { jsx as ___EmotionJSX } from "@emotion/react";
|
9
10
|
var ResponseText = function ResponseText(props) {
|
10
11
|
var _props$delay = props.delay,
|
@@ -24,7 +25,8 @@ var ResponseText = function ResponseText(props) {
|
|
24
25
|
shouldStartAnimation: shouldStartAnimation
|
25
26
|
};
|
26
27
|
var _useTypeAnimation = useTypeAnimation(animationProps),
|
27
|
-
currentText = _useTypeAnimation.currentText
|
28
|
+
currentText = _useTypeAnimation.currentText,
|
29
|
+
isLoading = _useTypeAnimation.isLoading;
|
28
30
|
var hasBullet = isListItem === true && currentText.length > 0;
|
29
31
|
var _useStatusClasses = useStatusClasses(className, {
|
30
32
|
hasBullet: hasBullet
|
@@ -35,6 +37,6 @@ var ResponseText = function ResponseText(props) {
|
|
35
37
|
role: isListItem ? 'listitem' : '',
|
36
38
|
variant: "response",
|
37
39
|
className: classNames
|
38
|
-
}), renderText);
|
40
|
+
}), renderText, isLoading && ___EmotionJSX(ResponseLoader, null));
|
39
41
|
};
|
40
42
|
export default ResponseText;
|
@@ -420,8 +420,7 @@ export var CustomWidth = function CustomWidth() {
|
|
420
420
|
return ___EmotionJSX(Box, {
|
421
421
|
width: 200
|
422
422
|
}, ___EmotionJSX(Text, {
|
423
|
-
p: "xl"
|
424
|
-
color: "text.secondary"
|
423
|
+
p: "xl"
|
425
424
|
}, "superlongtextinonelinewithnowhitespacessoitcanbelongerthatanywidth"));
|
426
425
|
};
|
427
426
|
export var CustomStyle = function CustomStyle() {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import _slicedToArray from "@babel/runtime-corejs3/helpers/esm/slicedToArray";
|
2
2
|
import _setTimeout from "@babel/runtime-corejs3/core-js-stable/set-timeout";
|
3
|
+
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
|
3
4
|
import { useEffect, useState } from 'react';
|
4
5
|
var useTypeAnimation = function useTypeAnimation(_ref) {
|
5
6
|
var shouldStartAnimation = _ref.shouldStartAnimation,
|
@@ -7,20 +8,26 @@ var useTypeAnimation = function useTypeAnimation(_ref) {
|
|
7
8
|
delay = _ref.delay,
|
8
9
|
setAnimationIndex = _ref.setAnimationIndex,
|
9
10
|
animationIndex = _ref.animationIndex;
|
10
|
-
var _useState = useState(''),
|
11
|
+
var _useState = useState(text.split(' ')),
|
11
12
|
_useState2 = _slicedToArray(_useState, 2),
|
12
|
-
|
13
|
-
|
14
|
-
var _useState3 = useState(
|
13
|
+
splitText = _useState2[0],
|
14
|
+
setSplitText = _useState2[1];
|
15
|
+
var _useState3 = useState(-1),
|
15
16
|
_useState4 = _slicedToArray(_useState3, 2),
|
16
17
|
currentIndex = _useState4[0],
|
17
18
|
setCurrentIndex = _useState4[1];
|
19
|
+
var _useState5 = useState(false),
|
20
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
21
|
+
isLoading = _useState6[0],
|
22
|
+
setIsLoading = _useState6[1];
|
18
23
|
useEffect(function () {
|
19
|
-
if (shouldStartAnimation &&
|
24
|
+
if (shouldStartAnimation && currentIndex < 0) {
|
25
|
+
setCurrentIndex(0);
|
26
|
+
}
|
27
|
+
}, [shouldStartAnimation, currentIndex]);
|
28
|
+
useEffect(function () {
|
29
|
+
if (shouldStartAnimation && text && currentIndex < splitText.length) {
|
20
30
|
var timeout = _setTimeout(function () {
|
21
|
-
setCurrentText(function (prevText) {
|
22
|
-
return prevText + text[currentIndex];
|
23
|
-
});
|
24
31
|
setCurrentIndex(function (prevIndex) {
|
25
32
|
return prevIndex + 1;
|
26
33
|
});
|
@@ -29,15 +36,24 @@ var useTypeAnimation = function useTypeAnimation(_ref) {
|
|
29
36
|
return clearTimeout(timeout);
|
30
37
|
};
|
31
38
|
}
|
32
|
-
if (
|
39
|
+
if (splitText && currentIndex === splitText.length) {
|
33
40
|
setAnimationIndex(animationIndex + 1);
|
34
41
|
}
|
35
42
|
return function () {
|
36
43
|
return null;
|
37
44
|
};
|
38
45
|
}, [currentIndex, delay, text, shouldStartAnimation, setAnimationIndex, animationIndex]);
|
46
|
+
useEffect(function () {
|
47
|
+
if (splitText.length > 0 && currentIndex > 0 && currentIndex < splitText.length) {
|
48
|
+
setIsLoading(true);
|
49
|
+
} else {
|
50
|
+
setIsLoading(false);
|
51
|
+
}
|
52
|
+
}, [splitText, text, currentIndex]);
|
53
|
+
var indexOrNothing = Math.max(currentIndex, 0);
|
39
54
|
return {
|
40
|
-
currentText:
|
55
|
+
currentText: _sliceInstanceProperty(splitText).call(splitText, 0, indexOrNothing).join(' '),
|
56
|
+
isLoading: isLoading
|
41
57
|
};
|
42
58
|
};
|
43
59
|
export default useTypeAnimation;
|
@@ -14,8 +14,9 @@ import { act, renderHook } from '@testing-library/react-hooks';
|
|
14
14
|
import useTypeAnimation from './useTypeAnimation';
|
15
15
|
var setAnimationIndex = jest.fn();
|
16
16
|
var animationIndex = 0;
|
17
|
-
var text = 'Hello';
|
17
|
+
var text = 'Hello World';
|
18
18
|
var delay = 100;
|
19
|
+
var splitText = text.split(' ');
|
19
20
|
var defaultProps = {
|
20
21
|
text: text,
|
21
22
|
delay: delay,
|
@@ -36,11 +37,11 @@ describe('useTypeAnimation', function () {
|
|
36
37
|
}),
|
37
38
|
result = _renderHook.result;
|
38
39
|
expect(result.current.currentText).toBe('');
|
39
|
-
for (var i = 0; i <
|
40
|
+
for (var i = 0; i < splitText.length; i += 1) {
|
40
41
|
act(function () {
|
41
42
|
jest.advanceTimersByTime(delay);
|
42
43
|
});
|
43
|
-
expect(result.current.currentText).toBe(_sliceInstanceProperty(
|
44
|
+
expect(result.current.currentText).toBe(_sliceInstanceProperty(splitText).call(splitText, 0, i + 1).join(' '));
|
44
45
|
}
|
45
46
|
expect(result.current.currentText).toBe(text);
|
46
47
|
});
|
@@ -49,19 +49,23 @@ var list = {
|
|
49
49
|
}
|
50
50
|
};
|
51
51
|
var textWrapper = {
|
52
|
+
height: 'fit-content',
|
52
53
|
'&.has-bullet': {
|
53
|
-
display: 'list-item !important'
|
54
|
+
display: 'list-item !important',
|
55
|
+
height: 'fit-content'
|
54
56
|
},
|
55
57
|
'&.has-rendered': {
|
56
58
|
display: 'list-item'
|
57
59
|
},
|
58
60
|
'&.has-block': {
|
61
|
+
maxHeight: 'fit-content',
|
59
62
|
display: 'block'
|
60
63
|
},
|
61
64
|
'&::marker': {
|
62
65
|
color: 'text.primary'
|
63
66
|
},
|
64
|
-
listStylePosition: '
|
67
|
+
listStylePosition: 'initial',
|
68
|
+
flexDirection: 'row'
|
65
69
|
};
|
66
70
|
export default {
|
67
71
|
iconWrapper: iconWrapper,
|