@elliemae/ds-chat 2.0.1 → 2.1.0-rc.10

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 (31) hide show
  1. package/cjs/ChatDataTestids.js +2 -1
  2. package/cjs/parts/chat-composer/ChatContainerComposer.js +14 -8
  3. package/cjs/parts/chat-composer/props.js +2 -0
  4. package/cjs/parts/chat-container/ChatContainer.js +27 -23
  5. package/cjs/parts/chat-container/styled.js +1 -1
  6. package/cjs/parts/chat-container-messages-list/ChatContainerMessagesList.js +65 -35
  7. package/cjs/parts/chat-sidebar/SideBarChat.js +2 -2
  8. package/cjs/parts/sidebar-button/SidebarButton.js +2 -2
  9. package/esm/ChatDataTestids.js +2 -1
  10. package/esm/parts/chat-composer/ChatContainerComposer.js +14 -8
  11. package/esm/parts/chat-composer/props.js +2 -0
  12. package/esm/parts/chat-container/ChatContainer.js +27 -23
  13. package/esm/parts/chat-container/styled.js +1 -1
  14. package/esm/parts/chat-container-messages-list/ChatContainerMessagesList.js +63 -33
  15. package/esm/parts/chat-sidebar/SideBarChat.js +2 -2
  16. package/esm/parts/sidebar-button/SidebarButton.js +2 -2
  17. package/package.json +11 -11
  18. package/types/ChatDataTestids.d.ts +1 -0
  19. package/types/parts/chat-card/ChatCard.d.ts +6 -6
  20. package/types/parts/chat-card/props.d.ts +6 -6
  21. package/types/parts/chat-composer/ChatContainerComposer.d.ts +3 -0
  22. package/types/parts/chat-composer/styled.d.ts +3 -155
  23. package/types/parts/chat-container/ChatContainer.d.ts +6 -6
  24. package/types/parts/chat-container-messages-list/ChatContainerMessagesList.d.ts +6 -6
  25. package/types/parts/message-delimiter/MessageDelimiter.d.ts +4 -4
  26. package/types/parts/message-delimiter/props.d.ts +4 -4
  27. package/types/parts/system-message/SystemMessage.d.ts +2 -2
  28. package/types/parts/system-message/props.d.ts +2 -2
  29. package/types/parts/tile-button/TileButton.d.ts +2 -2
  30. package/types/parts/tile-button/props.d.ts +2 -2
  31. package/types/tests/utils.d.ts +1 -27
@@ -21,7 +21,8 @@ const ChatDataTestIds = {
21
21
  SYSTEM_MSG_TIME: 'chat-system-message-time',
22
22
  BUBBLE: 'ds-chat-bubble',
23
23
  BUBBLE_TITLE: 'chat-bubble-title',
24
- BUBBLE_BODY: 'chat-bubble-body'
24
+ BUBBLE_BODY: 'chat-bubble-body',
25
+ BANNER: 'ds-banner-container'
25
26
  };
26
27
 
27
28
  exports.ChatDataTestIds = ChatDataTestIds;
@@ -28,9 +28,9 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
28
28
 
29
29
  var _PaperAirplane, _Grid;
30
30
 
31
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
31
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
32
32
 
33
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
33
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
34
34
 
35
35
  const ChatComposer = props => {
36
36
  var _input$current;
@@ -48,10 +48,12 @@ const ChatComposer = props => {
48
48
  placeholder,
49
49
  inputMaxLength,
50
50
  maxLengthMessage,
51
+ ariaMaxLengthMessage,
51
52
  buttonDisabled,
52
53
  dataTestid,
53
54
  actionRef
54
55
  } = props;
56
+ const COMPOSER_MIN_HEIGHT = 32;
55
57
  const input = React__default["default"].useRef();
56
58
  const inputSize = React__default["default"].useRef();
57
59
  const inputSend = React__default["default"].useRef();
@@ -62,10 +64,10 @@ const ChatComposer = props => {
62
64
  var _inputSize$current, _inputSize$current2, _inputSize$current3, _inputSize$current4;
63
65
 
64
66
  const newHeight = ((_inputSize$current = inputSize.current) === null || _inputSize$current === void 0 ? void 0 : _inputSize$current.scrollHeight) > internalMaxHeight ? internalMaxHeight : (_inputSize$current2 = inputSize.current) === null || _inputSize$current2 === void 0 ? void 0 : _inputSize$current2.scrollHeight;
65
- onResize(newHeight);
67
+ if (newHeight !== height && newHeight > COMPOSER_MIN_HEIGHT) onResize(newHeight);
66
68
  setHeight(newHeight);
67
69
  setShowScroll(((_inputSize$current3 = inputSize.current) === null || _inputSize$current3 === void 0 ? void 0 : _inputSize$current3.scrollHeight) - ((_inputSize$current4 = inputSize.current) === null || _inputSize$current4 === void 0 ? void 0 : _inputSize$current4.clientHeight) > 5);
68
- }, [inputValue, internalMaxHeight, onResize]);
70
+ }, [inputValue, internalMaxHeight, height, onResize]);
69
71
  React__default["default"].useEffect(() => {
70
72
  if (actionRef && actionRef.current) {
71
73
  actionRef.current.focusToComposer = () => {
@@ -92,6 +94,9 @@ const ChatComposer = props => {
92
94
  "data-testid": dataTestid
93
95
  }, void 0, /*#__PURE__*/_jsx__default["default"](dsGrid.Grid, {
94
96
  cols: ['1fr', '24px'],
97
+ style: {
98
+ height: heightProps.height
99
+ },
95
100
  justifyContent: "center",
96
101
  alignItems: "flex-end",
97
102
  gutter: "xxs"
@@ -105,7 +110,9 @@ const ChatComposer = props => {
105
110
  onKeyDown: onKeyDown,
106
111
  placeholder: placeholder,
107
112
  "aria-label": "Message to send",
108
- "data-testid": "chat-composer-textarea"
113
+ "data-testid": "chat-composer-textarea",
114
+ name: "chat-composer-textarea",
115
+ id: "chat-composer-textarea"
109
116
  }), /*#__PURE__*/_jsx__default["default"](dsGrid.Grid, {
110
117
  height: "32px",
111
118
  alignItems: "center"
@@ -132,8 +139,7 @@ const ChatComposer = props => {
132
139
  width: (_input$current = input.current) === null || _input$current === void 0 ? void 0 : _input$current.clientWidth
133
140
  },
134
141
  onChange: handleChange,
135
- value: inputValue // maxLength={inputMaxLength}
136
-
142
+ value: inputValue
137
143
  }), /*#__PURE__*/_jsx__default["default"](dsGrid.Grid, {
138
144
  cols: ['1fr', '24px'],
139
145
  justifyContent: "flex-end",
@@ -146,7 +152,7 @@ const ChatComposer = props => {
146
152
  }, void 0, inputMaxLength && hasError ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
147
153
  children: [/*#__PURE__*/_jsx__default["default"](styled.StyledCounterErrorA11y, {
148
154
  role: "alert"
149
- }, void 0, maxLengthMessage || "You have exceeded the character limit by ".concat(inputLength - inputMaxLength)), maxLengthMessage || "Please limit to less than ".concat(inputMaxLength, " characters. ")]
155
+ }, void 0, ariaMaxLengthMessage || "You have entered ".concat(inputLength, " characters and have exceeded the limit by ").concat(inputLength - inputMaxLength, ". Please limit to less than ").concat(inputMaxLength, " characters. ")), maxLengthMessage || "Please limit to less than ".concat(inputMaxLength, " characters. ")]
150
156
  }) : '', inputMaxLength ? " ".concat(inputLength, " / ").concat(inputMaxLength) : ''), _Grid || (_Grid = /*#__PURE__*/_jsx__default["default"](dsGrid.Grid, {}))));
151
157
  };
152
158
 
@@ -8,6 +8,7 @@ var lodash = require('lodash');
8
8
  const defaultComposerPros = {
9
9
  placeholder: 'Type your message',
10
10
  inputValue: '',
11
+ ariaMaxLengthMessage: '',
11
12
  onChange: lodash.noop,
12
13
  onResize: lodash.noop,
13
14
  onSend: lodash.noop,
@@ -24,6 +25,7 @@ const defaultComposerPros = {
24
25
  const composerProps = {
25
26
  placeholder: reactDesc.PropTypes.string.description('Input Placeholder').defaultValue(defaultComposerPros.placeholder),
26
27
  inputValue: reactDesc.PropTypes.string.description('Input value').defaultValue(defaultComposerPros.inputValue),
28
+ ariaMaxLengthMessage: reactDesc.PropTypes.string.description('Aria message for Max length message when exceeded').defaultValue(defaultComposerPros.maxLengthMessage),
27
29
  maxLengthMessage: reactDesc.PropTypes.string.description('Max length message').defaultValue(defaultComposerPros.maxLengthMessage),
28
30
  onChange: reactDesc.PropTypes.func.description('Called when the user types').defaultValue(defaultComposerPros.onChange),
29
31
  onResize: reactDesc.PropTypes.func.description('Called the input changes his height').defaultValue(defaultComposerPros.onResize),
@@ -29,14 +29,14 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
29
29
  var DSIndeterminateProgressIndicator__default = /*#__PURE__*/_interopDefaultLegacy(DSIndeterminateProgressIndicator);
30
30
  var DSBanner__default = /*#__PURE__*/_interopDefaultLegacy(DSBanner);
31
31
 
32
- var _DSIndeterminateProgr, _StyledIndicatorConta;
32
+ var _DSIndeterminateProgr;
33
33
 
34
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
34
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
35
35
 
36
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
36
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
37
37
 
38
38
  const ChatContainer = props$1 => {
39
- var _containerRef$current;
39
+ var _messagesListProps$me2, _containerRef$current;
40
40
 
41
41
  useValidateProps.useValidateProps(props$1, props.containerProps);
42
42
  const {
@@ -67,18 +67,16 @@ const ChatContainer = props$1 => {
67
67
  });
68
68
  const onResize = React__default["default"].useCallback(height => {
69
69
  if (onComposerResize) onComposerResize(height);
70
-
71
- if (height > 30) {
72
- /*
70
+ /*
73
71
  setTimeout is used to equal the animation duration from the
74
72
  composer text area when increase its size
75
73
  */
76
- setTimeout(() => {
77
- actionRef.current.scrollToIndex(messagesListProps.messages.length - 1, {
78
- align: 'start'
79
- });
80
- }, 50);
81
- }
74
+
75
+ setTimeout(() => {
76
+ actionRef.current.scrollToIndex(messagesListProps.messages.length - 1, {
77
+ align: 'start'
78
+ });
79
+ }, 50);
82
80
  }, [onComposerResize, messagesListProps.messages, actionRef]);
83
81
  const Container = device === 'desktop' ? styled.StyledChatContainerContent : styled.MobileStyledChatContainerContent;
84
82
  const handleTabs = React__default["default"].useCallback(e => {
@@ -86,17 +84,23 @@ const ChatContainer = props$1 => {
86
84
  const ref = actionRef || listRef;
87
85
 
88
86
  if (e.shiftKey && e.key === 'Tab') {
89
- e.preventDefault();
87
+ var _messagesListProps$me;
88
+
89
+ if (((_messagesListProps$me = messagesListProps.messages) === null || _messagesListProps$me === void 0 ? void 0 : _messagesListProps$me.length) > 0) {
90
+ e.preventDefault();
91
+
92
+ if (['top', 'bottom'].includes(bannerPosition)) {
93
+ bannerRef.current.focusOnWrapper();
94
+ } else {
95
+ var _ref$current;
90
96
 
91
- if (['top', 'bottom'].includes(bannerPosition)) {
92
- bannerRef.current.focusOnWrapper();
93
- } else {
94
- const last = ref.current.getMessagesInView().pop();
95
- ref.current.focusToIndexWithoutScroll(last);
97
+ const last = ref.current.getMessagesInView().pop();
98
+ (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.focusToIndexWithoutScroll(last);
99
+ }
96
100
  }
97
101
  }
98
102
  }
99
- }, [actionRef, onComposerKeyDown, bannerPosition]); // Map actions
103
+ }, [actionRef, onComposerKeyDown, bannerPosition, (_messagesListProps$me2 = messagesListProps.messages) === null || _messagesListProps$me2 === void 0 ? void 0 : _messagesListProps$me2.length]); // Map actions
100
104
 
101
105
  React__default["default"].useEffect(() => {
102
106
  if (actionRef && actionRef.current) {
@@ -146,15 +150,15 @@ const ChatContainer = props$1 => {
146
150
  isOpen: true,
147
151
  type: bannerProps.type || DSBanner.BANNER_TYPES.INFO,
148
152
  actionRef: bannerRef
149
- })), sendingMessages && sendingMessages.length > 0 ? _StyledIndicatorConta || (_StyledIndicatorConta = /*#__PURE__*/_jsx__default["default"](styled.StyledIndicatorContainer, {
153
+ })), sendingMessages && sendingMessages.length > 0 ? /*#__PURE__*/_jsx__default["default"](styled.StyledIndicatorContainer, {
150
154
  isLoading: "bottom",
151
155
  linear: true,
152
156
  "data-testid": "ds-chat-loading-indicator"
153
157
  }, void 0, /*#__PURE__*/_jsx__default["default"](DSIndeterminateProgressIndicator__default["default"], {
154
158
  processing: true,
155
- title: "Loading",
159
+ title: sendingText,
156
160
  lineOnly: true
157
- }))) : null), /*#__PURE__*/jsxRuntime.jsx(ChatContainerComposer.ChatComposer, _objectSpread(_objectSpread({}, composerProps), {}, {
161
+ })) : null), /*#__PURE__*/jsxRuntime.jsx(ChatContainerComposer.ChatComposer, _objectSpread(_objectSpread({}, composerProps), {}, {
158
162
  onKeyDown: handleTabs,
159
163
  onResize: onResize,
160
164
  maxHeight: (((_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.clientHeight) || 0) / 2,
@@ -18,7 +18,7 @@ const StyledChatContainerContent = /*#__PURE__*/styled__default["default"](dsGri
18
18
  })(["height:100%;min-width:", "px;overflow:hidden;background:", ";position:relative;"], CONTAINER_WIDTH, props => props.theme.colors.neutral['050']);
19
19
  const StyledIndicatorContainer = /*#__PURE__*/styled__default["default"].div.withConfig({
20
20
  componentId: "sc-d732wo-1"
21
- })(["transition:0.4s ease-in-out;position:absolute;visibility:hidden;pointer-events:none;width:100%;padding:0 ", ";left:0;right:0;background:", ";", " ", " & div,a{font-size:13px;}"], props => !props.linear ? props.theme.space.xxs : 0, props => props.theme.colors.neutral['000'], props => props.isLoading === 'top' ? "\n top: -41px;\n transform: translate(0, 41px);\n visibility: visible;\n pointer-events: auto\n " : '', props => props.isLoading === 'bottom' ? "\n bottom: -41px;\n transform: translate(0, -41px);\n visibility: visible;\n pointer-events: auto;\n " : '');
21
+ })(["transition:0.4s ease-in-out;position:absolute;visibility:hidden;pointer-events:none;width:100%;padding:0 ", ";left:0;right:0;background:", ";", " ", " & div,a{font-size:13px;}"], props => !props.linear ? props.theme.space.xxs : 0, props => props.theme.colors.neutral['000'], props => props.isLoading === 'top' ? "\n top: -41px;\n transform: translate(0, 41px);\n visibility: visible;\n pointer-events: auto;\n " : '', props => props.isLoading === 'bottom' ? "\n bottom: -41px;\n transform: translate(0, -41px);\n visibility: visible;\n pointer-events: auto;\n " : '');
22
22
  const MobileStyledChatContainerContent = /*#__PURE__*/styled__default["default"](StyledChatContainerContent).withConfig({
23
23
  componentId: "sc-d732wo-2"
24
24
  })(["", ",", "{font-size:16px;}", "{font-size:13px;}", "{background-color:#fff;box-shadow:-0 1px 3px rgba(53,60,70,0.8);}", ",", "{font-size:16px;text-align:left;}", "{font-size:13px;}", "{font-size:16px;}", "{font-size:16px;}"], styled$1.StyledTitleLeftBubble, styled$1.StyleBodyWrapper, styled$1.StyledTitleRightBubble, style.Wrapper, style.Title, style.Message, style.Time, styled$2.StyledComposerInput, StyledIndicatorContainer);
@@ -19,13 +19,13 @@ var React = require('react');
19
19
  var reactDesc = require('react-desc');
20
20
  var reactVirtual = require('react-virtual');
21
21
  var DSButton = require('@elliemae/ds-button');
22
+ var lodash = require('lodash');
22
23
  var ChatBubble = require('../bubble/ChatBubble.js');
23
24
  var props$1 = require('../bubble/props.js');
24
25
  var MessageDelimiter = require('../message-delimiter/MessageDelimiter.js');
25
26
  var SystemMessage = require('../system-message/SystemMessage.js');
26
27
  var styled = require('./styled.js');
27
28
  var props = require('./props.js');
28
- var useValidateProps = require('./config/useValidateProps.js');
29
29
  var jsxRuntime = require('react/jsx-runtime');
30
30
 
31
31
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -35,9 +35,9 @@ var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_definePropert
35
35
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
36
36
  var DSButton__default = /*#__PURE__*/_interopDefaultLegacy(DSButton);
37
37
 
38
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
38
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
39
39
 
40
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
40
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
41
41
 
42
42
  const getPadding = _ref => {
43
43
  let {
@@ -53,8 +53,7 @@ const getPadding = _ref => {
53
53
  return padding;
54
54
  };
55
55
 
56
- const ChatContainerMessagesList = props$2 => {
57
- useValidateProps.useValidateProps(props$2, props.listProps);
56
+ const ChatContainerMessagesList = props => {
58
57
  const {
59
58
  sendingText,
60
59
  bannerPosition,
@@ -66,7 +65,8 @@ const ChatContainerMessagesList = props$2 => {
66
65
  hasMoreItems,
67
66
  isLoading,
68
67
  bannerRef
69
- } = props$2;
68
+ } = props;
69
+ const pendingOnScroll = React__default["default"].useRef(false);
70
70
  const loadMoreRef = React__default["default"].useRef(null);
71
71
  const virtualListRef = React__default["default"].useRef(); // estimateSize should not be really required given what was stated on
72
72
  // https://github.com/tannerlinsley/react-virtual/issues/23
@@ -86,9 +86,16 @@ const ChatContainerMessagesList = props$2 => {
86
86
  })), {}, {
87
87
  estimateSize: React__default["default"].useCallback(() => 80, [])
88
88
  }));
89
- const onScrollStop = React__default["default"].useCallback(() => {
89
+ const debouncedScroll = React__default["default"].useMemo(() => lodash.debounce(() => {
90
90
  var _virtualListRef$curre;
91
91
 
92
+ if (document.visibilityState === 'hidden') {
93
+ pendingOnScroll.current = true;
94
+ return [];
95
+ }
96
+
97
+ if (!virtualListRef.current) return [];
98
+ pendingOnScroll.current = false;
92
99
  const {
93
100
  bottom,
94
101
  top
@@ -97,15 +104,15 @@ const ChatContainerMessagesList = props$2 => {
97
104
  const indexList = [];
98
105
  list.forEach(item => {
99
106
  const {
100
- top: itemTop,
101
- bottom: itemBottom
107
+ top: itemTop
102
108
  } = item.getBoundingClientRect();
103
109
  const itemPadding = 10;
104
- if (itemTop + itemPadding < bottom && itemBottom - itemPadding > top) indexList.push(item.dataset.index);
110
+ if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index);
105
111
  });
106
112
  if (onScrollEnds) onScrollEnds(indexList);
107
113
  return indexList;
108
- }, [onScrollEnds]);
114
+ }, 500), [onScrollEnds]);
115
+ const onScrollStop = React__default["default"].useCallback(debouncedScroll, [debouncedScroll]);
109
116
  const onlyFocus = React__default["default"].useCallback(index => {
110
117
  setTimeout(() => {
111
118
  virtualListRef.current.querySelector("[data-index=\"".concat(index, "\"]")).focus();
@@ -117,7 +124,8 @@ const ChatContainerMessagesList = props$2 => {
117
124
  };
118
125
  vScroll(index, b);
119
126
  onlyFocus(index);
120
- }, [onlyFocus, vScroll]);
127
+ onScrollStop();
128
+ }, [onScrollStop, onlyFocus, vScroll]);
121
129
  React__default["default"].useEffect(() => {
122
130
  if (actionRef && actionRef.current) {
123
131
  actionRef.current.scrollToIndex = function (a) {
@@ -125,9 +133,11 @@ const ChatContainerMessagesList = props$2 => {
125
133
  align: 'center'
126
134
  };
127
135
  vScroll(a, b);
136
+ onScrollStop();
128
137
  };
129
138
 
130
139
  actionRef.current.getMessagesInView = onScrollStop;
140
+ onScrollStop(); // init useMemo due to debounce use.
131
141
 
132
142
  actionRef.current.focusToIndex = function (a) {
133
143
  let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
@@ -138,7 +148,7 @@ const ChatContainerMessagesList = props$2 => {
138
148
 
139
149
  actionRef.current.focusToIndexWithoutScroll = onlyFocus;
140
150
 
141
- actionRef.current.focusToList = a => {
151
+ actionRef.current.focusToList = () => {
142
152
  var _virtualListRef$curre2;
143
153
 
144
154
  (_virtualListRef$curre2 = virtualListRef.current) === null || _virtualListRef$curre2 === void 0 ? void 0 : _virtualListRef$curre2.focus();
@@ -155,7 +165,17 @@ const ChatContainerMessagesList = props$2 => {
155
165
  switch (key) {
156
166
  case 'ArrowUp':
157
167
  e.preventDefault();
158
- if (index > 0) virtualListRef.current.querySelector("[data-index=\"".concat(index - 1, "\"]")).focus();
168
+
169
+ if (index > 0) {
170
+ var _virtualListRef$curre3;
171
+
172
+ ((_virtualListRef$curre3 = virtualListRef.current) === null || _virtualListRef$curre3 === void 0 ? void 0 : _virtualListRef$curre3.querySelector("[data-index=\"".concat(index - 1, "\"]"))).focus();
173
+ } else if (hasMoreItems === 'top') {
174
+ var _loadMoreRef$current;
175
+
176
+ (_loadMoreRef$current = loadMoreRef.current) === null || _loadMoreRef$current === void 0 ? void 0 : _loadMoreRef$current.focus();
177
+ }
178
+
159
179
  break;
160
180
 
161
181
  case 'ArrowDown':
@@ -178,31 +198,26 @@ const ChatContainerMessagesList = props$2 => {
178
198
  break;
179
199
 
180
200
  case 'Tab':
181
- e.preventDefault();
182
-
183
201
  if (hasMoreItems === 'bottom' && !e.shiftKey) {
184
- var _loadMoreRef$current;
185
-
186
- (_loadMoreRef$current = loadMoreRef.current) === null || _loadMoreRef$current === void 0 ? void 0 : _loadMoreRef$current.focus();
187
- } else if (hasMoreItems === 'top' && e.shiftKey) {
188
202
  var _loadMoreRef$current2;
189
203
 
204
+ e.preventDefault();
190
205
  (_loadMoreRef$current2 = loadMoreRef.current) === null || _loadMoreRef$current2 === void 0 ? void 0 : _loadMoreRef$current2.focus();
191
- } else if (!e.shiftKey) {
206
+ } else if (hasMoreItems === 'top' && e.shiftKey) ; else if (!e.shiftKey) {
192
207
  if (bannerPosition) {
208
+ e.preventDefault();
193
209
  bannerRef.current.focusOnWrapper();
194
- } else {
195
- actionRef.current.focusToComposer();
196
210
  }
197
211
  } else {
198
- var _virtualListRef$curre3;
212
+ var _virtualListRef$curre4;
199
213
 
200
- (_virtualListRef$curre3 = virtualListRef.current) === null || _virtualListRef$curre3 === void 0 ? void 0 : _virtualListRef$curre3.focus();
214
+ e.preventDefault();
215
+ (_virtualListRef$curre4 = virtualListRef.current) === null || _virtualListRef$curre4 === void 0 ? void 0 : _virtualListRef$curre4.focus();
201
216
  }
202
217
 
203
218
  break;
204
219
  }
205
- }, [actionRef, hasMoreItems, messages.length, bannerPosition, scrollAndFocus]);
220
+ }, [bannerRef, hasMoreItems, messages.length, bannerPosition, scrollAndFocus]);
206
221
  const handleListKey = React__default["default"].useCallback(e => {
207
222
  const {
208
223
  key
@@ -211,12 +226,22 @@ const ChatContainerMessagesList = props$2 => {
211
226
  switch (key) {
212
227
  case 'ArrowUp':
213
228
  e.preventDefault();
214
- onlyFocus(onScrollStop().shift());
229
+
230
+ if (document.activeElement !== loadMoreRef.current) {
231
+ onlyFocus(onScrollStop().shift());
232
+ }
233
+
215
234
  break;
216
235
 
217
236
  case 'ArrowDown':
218
237
  e.preventDefault();
219
- onlyFocus(onScrollStop().pop());
238
+
239
+ if (document.activeElement === loadMoreRef.current) {
240
+ virtualListRef.current.querySelector("[data-index=\"0\"]").focus();
241
+ } else {
242
+ onlyFocus(onScrollStop().pop());
243
+ }
244
+
220
245
  break;
221
246
 
222
247
  case 'Home':
@@ -249,15 +274,18 @@ const ChatContainerMessagesList = props$2 => {
249
274
  e.preventDefault();
250
275
  actionRef.current.focusToComposer();
251
276
  } else {
252
- var _virtualListRef$curre4;
277
+ var _virtualListRef$curre5;
253
278
 
254
279
  e.preventDefault();
255
- (_virtualListRef$curre4 = virtualListRef.current) === null || _virtualListRef$curre4 === void 0 ? void 0 : _virtualListRef$curre4.focus();
280
+ (_virtualListRef$curre5 = virtualListRef.current) === null || _virtualListRef$curre5 === void 0 ? void 0 : _virtualListRef$curre5.focus();
256
281
  }
257
282
 
258
283
  break;
259
284
  }
260
285
  }, [actionRef, hasMoreItems, messages.length, onScrollStop, onlyFocus, scrollAndFocus]);
286
+ const checkPendingOnScroll = React__default["default"].useCallback(() => {
287
+ if (pendingOnScroll.current === true) onScrollStop();
288
+ }, [onScrollStop]);
261
289
  React__default["default"].useEffect(() => {
262
290
  let handlerCallback = null;
263
291
  const localVirtualRef = virtualListRef.current;
@@ -271,11 +299,13 @@ const ChatContainerMessagesList = props$2 => {
271
299
  virtualListRef.current.addEventListener('scroll', onScroll);
272
300
  }
273
301
 
302
+ document.addEventListener('visibilitychange', checkPendingOnScroll);
274
303
  return () => {
275
304
  if (handlerCallback) clearTimeout(handlerCallback);
276
305
  if (onScrollEnds) localVirtualRef.removeEventListener('scroll', onScroll);
306
+ document.removeEventListener('visibilitychange', checkPendingOnScroll);
277
307
  };
278
- }, [onScrollStop, onScrollEnds]);
308
+ }, [onScrollStop, onScrollEnds, checkPendingOnScroll]);
279
309
  const render = React__default["default"].useMemo(() => virtualItems.map(virtualItem => {
280
310
  const {
281
311
  index,
@@ -296,14 +326,14 @@ const ChatContainerMessagesList = props$2 => {
296
326
  "data-index": index,
297
327
  style: style,
298
328
  ref: measureRef,
299
- tabIndex: 0,
329
+ tabIndex: -1,
300
330
  onKeyDown: handleKey,
301
331
  role: "listitem",
302
332
  children: /*#__PURE__*/_jsx__default["default"](styled.StyledWrapperListItem, {
303
333
  type: row.type
304
334
  }, void 0, row.type === props$1.BUBBLE_TYPES.SENDER || row.type === props$1.BUBBLE_TYPES.RECIPIENT ?
305
335
  /*#__PURE__*/
306
- // eslint-disable-next-line
336
+ // eslint-disable-next-line eslint-comments/no-unlimited-disable
307
337
  jsxRuntime.jsx(ChatBubble.ChatBubble, _objectSpread(_objectSpread({}, row), {}, {
308
338
  helpMessage: isSending ? sendingText : row.helpMessage
309
339
  })) : null, row.type === props$1.BUBBLE_TYPES.DELIMITER ? /*#__PURE__*/jsxRuntime.jsx(MessageDelimiter.MessageDelimiter, _objectSpread({}, row)) : null, row.type === props$1.BUBBLE_TYPES.SYSTEM ? /*#__PURE__*/jsxRuntime.jsx(SystemMessage.SystemMessage, _objectSpread({}, row)) : null)
@@ -319,7 +349,7 @@ const ChatContainerMessagesList = props$2 => {
319
349
  onKeyDown: handleListKey,
320
350
  children: /*#__PURE__*/_jsx__default["default"](styled.StyledChatContainerContentListScroll, {
321
351
  height: "".concat(totalSize, "px")
322
- }, void 0, render, !isLoading && hasMoreItems ? /*#__PURE__*/_jsx__default["default"](styled.StyledLoadMoreContainer, {
352
+ }, void 0, !isLoading && hasMoreItems ? /*#__PURE__*/_jsx__default["default"](styled.StyledLoadMoreContainer, {
323
353
  hasMoreItems: hasMoreItems
324
354
  }, void 0, /*#__PURE__*/_jsx__default["default"](DSButton__default["default"], {
325
355
  labelText: "Load More",
@@ -327,7 +357,7 @@ const ChatContainerMessagesList = props$2 => {
327
357
  onClick: getMoreMessages,
328
358
  "data-testid": "ds-chat-load-more-btn",
329
359
  innerRef: loadMoreRef
330
- })) : null)
360
+ })) : null, render)
331
361
  }));
332
362
  };
333
363
 
@@ -28,9 +28,9 @@ var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_definePropert
28
28
  var _jsx__default = /*#__PURE__*/_interopDefaultLegacy(_jsx);
29
29
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
30
30
 
31
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
31
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
32
32
 
33
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
33
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
34
34
 
35
35
  const FooterChat = _ref => {
36
36
  let {
@@ -24,9 +24,9 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
24
24
 
25
25
  const _excluded = ["label", "dsId", "onClick", "Icon"];
26
26
 
27
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
27
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
28
28
 
29
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
29
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
30
30
  const SidebarButton = _ref => {
31
31
  let {
32
32
  label,
@@ -17,7 +17,8 @@ const ChatDataTestIds = {
17
17
  SYSTEM_MSG_TIME: 'chat-system-message-time',
18
18
  BUBBLE: 'ds-chat-bubble',
19
19
  BUBBLE_TITLE: 'chat-bubble-title',
20
- BUBBLE_BODY: 'chat-bubble-body'
20
+ BUBBLE_BODY: 'chat-bubble-body',
21
+ BANNER: 'ds-banner-container'
21
22
  };
22
23
 
23
24
  export { ChatDataTestIds };
@@ -18,9 +18,9 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
18
18
 
19
19
  var _PaperAirplane, _Grid;
20
20
 
21
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
21
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
22
22
 
23
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
23
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
24
24
 
25
25
  const ChatComposer = props => {
26
26
  var _input$current;
@@ -38,10 +38,12 @@ const ChatComposer = props => {
38
38
  placeholder,
39
39
  inputMaxLength,
40
40
  maxLengthMessage,
41
+ ariaMaxLengthMessage,
41
42
  buttonDisabled,
42
43
  dataTestid,
43
44
  actionRef
44
45
  } = props;
46
+ const COMPOSER_MIN_HEIGHT = 32;
45
47
  const input = React.useRef();
46
48
  const inputSize = React.useRef();
47
49
  const inputSend = React.useRef();
@@ -52,10 +54,10 @@ const ChatComposer = props => {
52
54
  var _inputSize$current, _inputSize$current2, _inputSize$current3, _inputSize$current4;
53
55
 
54
56
  const newHeight = ((_inputSize$current = inputSize.current) === null || _inputSize$current === void 0 ? void 0 : _inputSize$current.scrollHeight) > internalMaxHeight ? internalMaxHeight : (_inputSize$current2 = inputSize.current) === null || _inputSize$current2 === void 0 ? void 0 : _inputSize$current2.scrollHeight;
55
- onResize(newHeight);
57
+ if (newHeight !== height && newHeight > COMPOSER_MIN_HEIGHT) onResize(newHeight);
56
58
  setHeight(newHeight);
57
59
  setShowScroll(((_inputSize$current3 = inputSize.current) === null || _inputSize$current3 === void 0 ? void 0 : _inputSize$current3.scrollHeight) - ((_inputSize$current4 = inputSize.current) === null || _inputSize$current4 === void 0 ? void 0 : _inputSize$current4.clientHeight) > 5);
58
- }, [inputValue, internalMaxHeight, onResize]);
60
+ }, [inputValue, internalMaxHeight, height, onResize]);
59
61
  React.useEffect(() => {
60
62
  if (actionRef && actionRef.current) {
61
63
  actionRef.current.focusToComposer = () => {
@@ -82,6 +84,9 @@ const ChatComposer = props => {
82
84
  "data-testid": dataTestid
83
85
  }, void 0, /*#__PURE__*/_jsx(Grid, {
84
86
  cols: ['1fr', '24px'],
87
+ style: {
88
+ height: heightProps.height
89
+ },
85
90
  justifyContent: "center",
86
91
  alignItems: "flex-end",
87
92
  gutter: "xxs"
@@ -95,7 +100,9 @@ const ChatComposer = props => {
95
100
  onKeyDown: onKeyDown,
96
101
  placeholder: placeholder,
97
102
  "aria-label": "Message to send",
98
- "data-testid": "chat-composer-textarea"
103
+ "data-testid": "chat-composer-textarea",
104
+ name: "chat-composer-textarea",
105
+ id: "chat-composer-textarea"
99
106
  }), /*#__PURE__*/_jsx(Grid, {
100
107
  height: "32px",
101
108
  alignItems: "center"
@@ -122,8 +129,7 @@ const ChatComposer = props => {
122
129
  width: (_input$current = input.current) === null || _input$current === void 0 ? void 0 : _input$current.clientWidth
123
130
  },
124
131
  onChange: handleChange,
125
- value: inputValue // maxLength={inputMaxLength}
126
-
132
+ value: inputValue
127
133
  }), /*#__PURE__*/_jsx(Grid, {
128
134
  cols: ['1fr', '24px'],
129
135
  justifyContent: "flex-end",
@@ -136,7 +142,7 @@ const ChatComposer = props => {
136
142
  }, void 0, inputMaxLength && hasError ? /*#__PURE__*/jsxs(Fragment, {
137
143
  children: [/*#__PURE__*/_jsx(StyledCounterErrorA11y, {
138
144
  role: "alert"
139
- }, void 0, maxLengthMessage || "You have exceeded the character limit by ".concat(inputLength - inputMaxLength)), maxLengthMessage || "Please limit to less than ".concat(inputMaxLength, " characters. ")]
145
+ }, void 0, ariaMaxLengthMessage || "You have entered ".concat(inputLength, " characters and have exceeded the limit by ").concat(inputLength - inputMaxLength, ". Please limit to less than ").concat(inputMaxLength, " characters. ")), maxLengthMessage || "Please limit to less than ".concat(inputMaxLength, " characters. ")]
140
146
  }) : '', inputMaxLength ? " ".concat(inputLength, " / ").concat(inputMaxLength) : ''), _Grid || (_Grid = /*#__PURE__*/_jsx(Grid, {}))));
141
147
  };
142
148
 
@@ -4,6 +4,7 @@ import { noop } from 'lodash';
4
4
  const defaultComposerPros = {
5
5
  placeholder: 'Type your message',
6
6
  inputValue: '',
7
+ ariaMaxLengthMessage: '',
7
8
  onChange: noop,
8
9
  onResize: noop,
9
10
  onSend: noop,
@@ -20,6 +21,7 @@ const defaultComposerPros = {
20
21
  const composerProps = {
21
22
  placeholder: PropTypes.string.description('Input Placeholder').defaultValue(defaultComposerPros.placeholder),
22
23
  inputValue: PropTypes.string.description('Input value').defaultValue(defaultComposerPros.inputValue),
24
+ ariaMaxLengthMessage: PropTypes.string.description('Aria message for Max length message when exceeded').defaultValue(defaultComposerPros.maxLengthMessage),
23
25
  maxLengthMessage: PropTypes.string.description('Max length message').defaultValue(defaultComposerPros.maxLengthMessage),
24
26
  onChange: PropTypes.func.description('Called when the user types').defaultValue(defaultComposerPros.onChange),
25
27
  onResize: PropTypes.func.description('Called the input changes his height').defaultValue(defaultComposerPros.onResize),