@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.
Files changed (32) hide show
  1. package/lib/cjs/components/AIComponents/Response/Response.mdx +41 -0
  2. package/lib/cjs/components/AIComponents/Response/Response.stories.d.ts +8 -0
  3. package/lib/cjs/components/AIComponents/Response/Response.stories.js +18 -6
  4. package/lib/cjs/components/AIComponents/Response/Response.test.jsx +13 -7
  5. package/lib/cjs/components/AIComponents/Response/ResponseList.js +4 -8
  6. package/lib/cjs/components/AIComponents/Response/ResponseLoader.d.ts +4 -0
  7. package/lib/cjs/components/AIComponents/Response/ResponseLoader.js +34 -0
  8. package/lib/cjs/components/AIComponents/Response/ResponseMarkdown/MarkdownTextContainer.js +1 -1
  9. package/lib/cjs/components/AIComponents/Response/ResponseMarkdown/ResponseMarkdown.d.ts +1 -0
  10. package/lib/cjs/components/AIComponents/Response/ResponseMarkdown/ResponseMarkdown.js +13 -2
  11. package/lib/cjs/components/AIComponents/Response/ResponseText.js +4 -2
  12. package/lib/cjs/components/Text/Text.stories.js +1 -2
  13. package/lib/cjs/hooks/useTypeAnimation/useTypeAnimation.d.ts +2 -1
  14. package/lib/cjs/hooks/useTypeAnimation/useTypeAnimation.js +26 -10
  15. package/lib/cjs/hooks/useTypeAnimation/useTypeAnimation.test.js +4 -3
  16. package/lib/cjs/styles/themes/next-gen/next-gen.d.ts +4 -0
  17. package/lib/cjs/styles/themes/next-gen/variants/response.d.ts +4 -0
  18. package/lib/cjs/styles/themes/next-gen/variants/response.js +6 -2
  19. package/lib/cjs/styles/themes/next-gen/variants/variants.d.ts +4 -0
  20. package/lib/components/AIComponents/Response/Response.mdx +41 -0
  21. package/lib/components/AIComponents/Response/Response.stories.js +16 -4
  22. package/lib/components/AIComponents/Response/Response.test.jsx +13 -7
  23. package/lib/components/AIComponents/Response/ResponseList.js +4 -8
  24. package/lib/components/AIComponents/Response/ResponseLoader.js +21 -0
  25. package/lib/components/AIComponents/Response/ResponseMarkdown/MarkdownTextContainer.js +1 -1
  26. package/lib/components/AIComponents/Response/ResponseMarkdown/ResponseMarkdown.js +11 -1
  27. package/lib/components/AIComponents/Response/ResponseText.js +4 -2
  28. package/lib/components/Text/Text.stories.js +1 -2
  29. package/lib/hooks/useTypeAnimation/useTypeAnimation.js +26 -10
  30. package/lib/hooks/useTypeAnimation/useTypeAnimation.test.js +4 -3
  31. package/lib/styles/themes/next-gen/variants/response.js +6 -2
  32. 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: _Response["default"]
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 = 40;
48
- return (0, _react2.jsx)(_Response["default"], {
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)(_Response["default"], {
80
- delay: 20
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 < defaultProps.text.length + 1; i += 1) {
112
+ for (let i = 1; i < splitText.length + 1; i += 1) {
111
113
  act(() => { jest.advanceTimersByTime(100); });
112
- expect(screen.queryByText(defaultProps.text.slice(0, i))).toBeInTheDocument();
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 < headingText.length + 1; i += 1) {
125
+ for (let i = 1; i < splitText.length + 1; i += 1) {
122
126
  act(() => { jest.advanceTimersByTime(100); });
123
- expect(screen.queryByText(headingText.slice(0, i))).toBeInTheDocument();
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 < (listItem1.length * 3) + 1; i += 1) {
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(nextText.slice(0, i))).toBeInTheDocument();
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
- asProp = props.as;
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,4 @@
1
+ import React from 'react';
2
+ import { LoaderProps } from '../../../types';
3
+ declare const ResponseLoader: React.ForwardRefExoticComponent<LoaderProps & React.RefAttributes<HTMLDivElement>>;
4
+ export default ResponseLoader;
@@ -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 === markdown.props.children.length) {
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;
@@ -5,6 +5,7 @@ declare const useTypeAnimation: ({ shouldStartAnimation, text, delay, setAnimati
5
5
  setAnimationIndex: any;
6
6
  animationIndex: any;
7
7
  }) => {
8
- currentText: string;
8
+ currentText: any;
9
+ isLoading: boolean;
9
10
  };
10
11
  export default useTypeAnimation;
@@ -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
- currentText = _useState2[0],
21
- setCurrentText = _useState2[1];
22
- var _useState3 = (0, _react.useState)(0),
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 && text && currentIndex < text.length) {
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 (text && currentIndex === text.length) {
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: 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 < text.length; i += 1) {
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"])(text).call(text, 0, i + 1));
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: 'outside'
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 Response from './Response';
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 = 40;
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: 20
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 < defaultProps.text.length + 1; i += 1) {
112
+ for (let i = 1; i < splitText.length + 1; i += 1) {
111
113
  act(() => { jest.advanceTimersByTime(100); });
112
- expect(screen.queryByText(defaultProps.text.slice(0, i))).toBeInTheDocument();
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 < headingText.length + 1; i += 1) {
125
+ for (let i = 1; i < splitText.length + 1; i += 1) {
122
126
  act(() => { jest.advanceTimersByTime(100); });
123
- expect(screen.queryByText(headingText.slice(0, i))).toBeInTheDocument();
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 < (listItem1.length * 3) + 1; i += 1) {
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(nextText.slice(0, i))).toBeInTheDocument();
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
- asProp = props.as;
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 === markdown.props.children.length) {
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
- currentText = _useState2[0],
13
- setCurrentText = _useState2[1];
14
- var _useState3 = useState(0),
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 && text && currentIndex < text.length) {
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 (text && currentIndex === text.length) {
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: 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 < text.length; i += 1) {
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(text).call(text, 0, i + 1));
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: 'outside'
67
+ listStylePosition: 'initial',
68
+ flexDirection: 'row'
65
69
  };
66
70
  export default {
67
71
  iconWrapper: iconWrapper,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pingux/astro",
3
- "version": "2.114.0",
3
+ "version": "2.115.0-alpha.0",
4
4
  "description": "React component library for Ping Identity's design system",
5
5
  "repository": {
6
6
  "type": "git",