@elliemae/ds-chat 2.0.0-alpha.10 → 2.0.0-alpha.14

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 (123) hide show
  1. package/cjs/ChatDataTestids.js +27 -0
  2. package/cjs/parts/bubble/ChatBubble.js +15 -12
  3. package/cjs/parts/bubble/ChatBubbleArrow.js +64 -61
  4. package/cjs/parts/bubble/config/useValidateProps.js +5 -6
  5. package/cjs/parts/bubble/props.js +1 -1
  6. package/cjs/parts/bubble/styled.js +2 -31
  7. package/cjs/parts/chat-card/props.js +2 -2
  8. package/cjs/parts/chat-composer/ChatContainerComposer.js +16 -8
  9. package/cjs/parts/chat-composer/props.js +5 -11
  10. package/cjs/parts/chat-composer/styled.js +4 -4
  11. package/cjs/parts/chat-container/ChatContainer.js +67 -20
  12. package/cjs/parts/chat-container/config/useValidateProps.js +2 -2
  13. package/cjs/parts/chat-container/props.js +7 -13
  14. package/cjs/parts/chat-container/styled.js +2 -2
  15. package/cjs/parts/chat-container-header/ChatContainerHeader.js +3 -3
  16. package/cjs/parts/chat-container-header/helpers.js +31 -0
  17. package/cjs/parts/chat-container-header/styled.js +6 -6
  18. package/cjs/parts/chat-container-messages-list/ChatContainerMessagesList.js +156 -40
  19. package/cjs/parts/chat-container-messages-list/config/useValidateProps.js +2 -2
  20. package/cjs/parts/chat-container-messages-list/props.js +5 -13
  21. package/cjs/parts/chat-container-messages-list/styled.js +2 -6
  22. package/cjs/parts/chat-empty-state/ChatEmptyState.js +2 -3
  23. package/cjs/parts/chat-sidebar/SideBarChat.js +57 -29
  24. package/cjs/parts/chat-sidebar/props.js +11 -1
  25. package/cjs/parts/chat-sidebar/styled.js +2 -2
  26. package/cjs/parts/floating-button/FloatingButton.js +18 -10
  27. package/cjs/parts/floating-button/props.js +6 -2
  28. package/cjs/parts/grid-influencer/styled.js +2 -6
  29. package/cjs/parts/message-delimiter/styled.js +1 -1
  30. package/cjs/parts/sidebar-button/SidebarButton.js +6 -1
  31. package/cjs/parts/sidebar-button/props.js +2 -3
  32. package/cjs/parts/system-message/style.js +1 -1
  33. package/cjs/parts/tile-button/TileButton.js +31 -28
  34. package/cjs/parts/tile-button/props.js +12 -8
  35. package/cjs/parts/tile-button/styled.js +12 -5
  36. package/cjs/styled.js +1 -1
  37. package/esm/ChatDataTestids.js +23 -0
  38. package/esm/parts/bubble/ChatBubble.js +14 -11
  39. package/esm/parts/bubble/ChatBubbleArrow.js +64 -61
  40. package/esm/parts/bubble/config/useValidateProps.js +5 -6
  41. package/esm/parts/bubble/props.js +1 -1
  42. package/esm/parts/bubble/styled.js +2 -31
  43. package/esm/parts/chat-card/props.js +2 -2
  44. package/esm/parts/chat-composer/ChatContainerComposer.js +15 -6
  45. package/esm/parts/chat-composer/props.js +5 -11
  46. package/esm/parts/chat-composer/styled.js +2 -2
  47. package/esm/parts/chat-container/ChatContainer.js +65 -18
  48. package/esm/parts/chat-container/config/useValidateProps.js +2 -2
  49. package/esm/parts/chat-container/props.js +7 -13
  50. package/esm/parts/chat-container/styled.js +2 -2
  51. package/esm/parts/chat-container-header/ChatContainerHeader.js +3 -2
  52. package/esm/parts/chat-container-header/helpers.js +23 -0
  53. package/esm/parts/chat-container-header/styled.js +6 -6
  54. package/esm/parts/chat-container-messages-list/ChatContainerMessagesList.js +154 -38
  55. package/esm/parts/chat-container-messages-list/config/useValidateProps.js +2 -2
  56. package/esm/parts/chat-container-messages-list/props.js +5 -13
  57. package/esm/parts/chat-container-messages-list/styled.js +2 -6
  58. package/esm/parts/chat-empty-state/ChatEmptyState.js +1 -1
  59. package/esm/parts/chat-sidebar/SideBarChat.js +57 -28
  60. package/esm/parts/chat-sidebar/props.js +11 -1
  61. package/esm/parts/chat-sidebar/styled.js +2 -2
  62. package/esm/parts/floating-button/FloatingButton.js +18 -9
  63. package/esm/parts/floating-button/props.js +6 -2
  64. package/esm/parts/grid-influencer/styled.js +2 -6
  65. package/esm/parts/message-delimiter/styled.js +1 -1
  66. package/esm/parts/sidebar-button/SidebarButton.js +6 -1
  67. package/esm/parts/sidebar-button/props.js +1 -1
  68. package/esm/parts/system-message/style.js +1 -1
  69. package/esm/parts/tile-button/TileButton.js +32 -27
  70. package/esm/parts/tile-button/props.js +11 -3
  71. package/esm/parts/tile-button/styled.js +12 -7
  72. package/esm/styled.js +1 -1
  73. package/package.json +29 -6
  74. package/types/ChatDataTestids.d.ts +21 -0
  75. package/types/parts/bubble/ChatBubble.d.ts +18 -5
  76. package/types/parts/bubble/props.d.ts +13 -4
  77. package/types/parts/bubble/styled.d.ts +9 -9
  78. package/types/parts/bubble/tests/ChatBubble.test.d.ts +1 -0
  79. package/types/parts/chat-card/ChatCard.d.ts +24 -4
  80. package/types/parts/chat-card/props.d.ts +19 -3
  81. package/types/parts/chat-card/styled.d.ts +6 -6
  82. package/types/parts/chat-composer/ChatContainerComposer.d.ts +48 -13
  83. package/types/parts/chat-composer/styled.d.ts +117 -24
  84. package/types/parts/chat-composer/tests/ChatContainerComposer.test.d.ts +1 -0
  85. package/types/parts/chat-container/ChatContainer.d.ts +54 -13
  86. package/types/parts/chat-container/config/useValidateProps.d.ts +1 -1
  87. package/types/parts/chat-container/styled.d.ts +4 -4
  88. package/types/parts/chat-container/tests/ChatContainer.test.d.ts +1 -0
  89. package/types/parts/chat-container-header/helpers.d.ts +6 -0
  90. package/types/parts/chat-container-header/styled.d.ts +3 -3
  91. package/types/parts/chat-container-messages-list/ChatContainerMessagesList.d.ts +39 -9
  92. package/types/parts/chat-container-messages-list/config/useValidateProps.d.ts +1 -1
  93. package/types/parts/chat-container-messages-list/styled.d.ts +7 -7
  94. package/types/parts/chat-empty-state/ChatEmptyState.d.ts +12 -3
  95. package/types/parts/chat-empty-state/props.d.ts +7 -2
  96. package/types/parts/chat-empty-state/styled.d.ts +2 -2
  97. package/types/parts/chat-sidebar/SideBarChat.d.ts +39 -9
  98. package/types/parts/chat-sidebar/props.d.ts +39 -9
  99. package/types/parts/chat-sidebar/styled.d.ts +2 -2
  100. package/types/parts/floating-button/FloatingButton.d.ts +11 -2
  101. package/types/parts/floating-button/props.d.ts +13 -1
  102. package/types/parts/floating-button/styled.d.ts +1 -1
  103. package/types/parts/floating-container/styled.d.ts +1 -2
  104. package/types/parts/grid-influencer/styled.d.ts +2 -2
  105. package/types/parts/message-delimiter/MessageDelimiter.d.ts +21 -4
  106. package/types/parts/message-delimiter/props.d.ts +16 -3
  107. package/types/parts/message-delimiter/styled.d.ts +3 -3
  108. package/types/parts/sidebar-button/SidebarButton.d.ts +16 -5
  109. package/types/parts/sidebar-button/props.d.ts +16 -5
  110. package/types/parts/sidebar-button/styled.d.ts +3 -3
  111. package/types/parts/system-message/SystemMessage.d.ts +12 -2
  112. package/types/parts/system-message/props.d.ts +7 -1
  113. package/types/parts/system-message/style.d.ts +5 -5
  114. package/types/parts/tile-button/TileButton.d.ts +66 -17
  115. package/types/parts/tile-button/props.d.ts +64 -16
  116. package/types/parts/tile-button/styled.d.ts +9 -8
  117. package/types/prop-types.d.ts +28 -9
  118. package/types/tests/utils.d.ts +27 -0
  119. package/cjs/package.json +0 -4
  120. package/esm/package.json +0 -4
  121. package/types/parts/chat-composer/props.d.ts +0 -35
  122. package/types/parts/chat-container/props.d.ts +0 -39
  123. package/types/parts/chat-container-messages-list/props.d.ts +0 -23
@@ -1,5 +1,6 @@
1
1
  import { PropTypes } from 'react-desc';
2
2
  import { noop } from 'lodash';
3
+ import { BANNER_TYPES } from '@elliemae/ds-banner';
3
4
  import { defaultProps as defaultProps$1 } from '../chat-container-messages-list/props.js';
4
5
  import { defaultComposerPros } from '../chat-composer/props.js';
5
6
 
@@ -14,13 +15,15 @@ const defaultProps = {
14
15
  getMoreMessages: noop,
15
16
  bannerPosition: undefined,
16
17
  bannerProps: {
18
+ type: BANNER_TYPES.INFO,
17
19
  label: 'Unread Messages',
18
20
  viewLabel: 'View',
19
21
  onView: noop,
20
22
  onClose: noop
21
23
  },
22
24
  sendingMessages: undefined,
23
- sendingText: 'Sending'
25
+ sendingText: 'Sending',
26
+ ariaLabel: 'Chat window'
24
27
  };
25
28
  const containerProps = {
26
29
  messagesListProps: PropTypes.object.description('ChatMessageList props "messages" / "onScrollEnds"').defaultValue(defaultProps.messagesListProps),
@@ -31,20 +34,11 @@ const containerProps = {
31
34
  hasMoreItems: PropTypes.oneOf(['top', 'bottom', undefined]).description('Show Load More button at the `top` or `bottom` of the container'),
32
35
  getMoreMessages: PropTypes.func.description('Called when the user clicks on load more').defaultValue(defaultProps.getMoreMessages),
33
36
  bannerPosition: PropTypes.oneOf(['top', 'bottom', undefined]).description('Show Loading messages indicator at the `top` or `bottom` of the container'),
34
- bannerProps: PropTypes.object.description('Banner configuration').defaultValue(defaultProps.bannerProps),
37
+ bannerProps: PropTypes.object.description("Banner configuration:\n label: string;\n viewLabel: string;\n type: BANNER_TYPES;\n onView: () => void;\n onClose: () => void;\n ").defaultValue(defaultProps.bannerProps),
35
38
  sendingMessages: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)]).description('Array of ids of sending messages').defaultValue(defaultProps.sendingMessages),
36
39
  sendingText: PropTypes.string.description('Label description for messages in sending status').defaultValue(defaultProps.sendingText),
37
- actionRef: PropTypes.object.description(`Reference:
38
- {
39
- scrollToIndex: (n: number) => void,
40
- getMessagesInView: () => number[],
41
- focusToIndex: (n: number) => void,
42
- focusToList: () => void,
43
- focusToComposer: () => void,
44
- focusToSend: () => void,
45
- }
46
-
47
- `).defaultValue(defaultProps.actionRef)
40
+ actionRef: PropTypes.object.description("Reference: \n { \n scrollToIndex: (n: number) => void,\n getMessagesInView: () => number[],\n focusToIndex: (n: number) => void,\n focusToList: () => void,\n focusToComposer: () => void,\n focusToSend: () => void,\n }\n \n ").defaultValue(defaultProps.actionRef),
41
+ ariaLabel: PropTypes.string.description('Aria Label description for chat container').defaultValue(defaultProps.ariaLabel)
48
42
  };
49
43
 
50
44
  export { containerProps, defaultProps };
@@ -10,9 +10,9 @@ const StyledChatContainerContent = /*#__PURE__*/styled(Grid).withConfig({
10
10
  })(["height:100%;min-width:", "px;overflow:hidden;background:", ";position:relative;"], CONTAINER_WIDTH, props => props.theme.colors.neutral['050']);
11
11
  const StyledIndicatorContainer = /*#__PURE__*/styled.div.withConfig({
12
12
  componentId: "sc-d732wo-1"
13
- })(["position:absolute;width:calc(100% + ", ");padding:", ";left:-", ";right:-", ";background:", ";", " ", ""], props => props.theme.space.xxs, props => !props.linear ? props.theme.space.xxs : 0, props => props.theme.space.xxs, props => props.theme.space.xxs, props => props.theme.colors.neutral['000'], props => props.isLoading === 'top' ? 'top: 0;' : '', props => props.isLoading === 'bottom' ? 'bottom: 0;' : '');
13
+ })(["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 " : '');
14
14
  const MobileStyledChatContainerContent = /*#__PURE__*/styled(StyledChatContainerContent).withConfig({
15
15
  componentId: "sc-d732wo-2"
16
- })(["", ",", "{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;}"], StyledTitleLeftBubble, StyleBodyWrapper, StyledTitleRightBubble, Wrapper, Title, Message, Time, StyledComposerInput);
16
+ })(["", ",", "{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;}"], StyledTitleLeftBubble, StyleBodyWrapper, StyledTitleRightBubble, Wrapper, Title, Message, Time, StyledComposerInput, StyledIndicatorContainer);
17
17
 
18
18
  export { CONTAINER_WIDTH, MobileStyledChatContainerContent, StyledChatContainerContent, StyledIndicatorContainer };
@@ -1,7 +1,8 @@
1
1
  import _jsx from '@babel/runtime/helpers/esm/jsx';
2
- import React from 'react';
2
+ import 'react';
3
3
  import { SimpleTruncatedTooltipText } from '@elliemae/ds-truncated-tooltip-text';
4
4
  import { StyledChatContainerContentHeader, StyledChatContainerContentHeaderLabel, StyledChatContainerContentHeaderActions } from './styled.js';
5
+ import { validHeaderChilds } from './helpers.js';
5
6
 
6
7
  const ChatContainerHeader = props => {
7
8
  const {
@@ -21,7 +22,7 @@ const ChatContainerHeader = props => {
21
22
  }, void 0, /*#__PURE__*/_jsx(SimpleTruncatedTooltipText, {
22
23
  value: title
23
24
  })), /*#__PURE__*/_jsx(StyledChatContainerContentHeaderActions, {
24
- cols: React.Children.toArray(children).filter(e => e).map(() => '32px'),
25
+ cols: validHeaderChilds(children),
25
26
  justifyContent: "flex-end",
26
27
  "data-testid": "chat-container-header-children"
27
28
  }, void 0, children));
@@ -0,0 +1,23 @@
1
+ import 'core-js/modules/esnext.async-iterator.map.js';
2
+ import 'core-js/modules/esnext.iterator.map.js';
3
+ import 'core-js/modules/esnext.async-iterator.filter.js';
4
+ import 'core-js/modules/esnext.iterator.constructor.js';
5
+ import 'core-js/modules/esnext.iterator.filter.js';
6
+ import 'core-js/modules/esnext.async-iterator.constructor.js';
7
+ import 'core-js/modules/esnext.async-iterator.to-array.js';
8
+ import 'core-js/modules/esnext.iterator.to-array.js';
9
+ import React from 'react';
10
+
11
+ const validHeaderChilds = children => React.Children.toArray(children).filter(e => {
12
+ if (Array.isArray(e.props.children)) {
13
+ return false;
14
+ }
15
+
16
+ if (e.props.children === undefined && e.$$typeof.toString() === 'Symbol(react.element)') {
17
+ return true;
18
+ }
19
+
20
+ return !!e.props.children;
21
+ }).map(() => '32px');
22
+
23
+ export { validHeaderChilds };
@@ -1,14 +1,14 @@
1
1
  import styled from 'styled-components';
2
2
  import { Grid } from '@elliemae/ds-grid';
3
3
 
4
- const StyledChatContainerContentHeader = /*#__PURE__*/styled(Grid).withConfig({
4
+ const StyledChatContainerContentHeaderActions = /*#__PURE__*/styled(Grid).withConfig({
5
5
  componentId: "sc-jmynvr-0"
6
- })(["width:100%;min-height:48px;border-bottom:1px solid ", ";background:", ";"], props => props.theme.colors.neutral['200'], props => props.theme.colors.neutral['050']);
7
- const StyledChatContainerContentHeaderLabel = /*#__PURE__*/styled(Grid).withConfig({
6
+ })(["max-width:80px;"]);
7
+ const StyledChatContainerContentHeader = /*#__PURE__*/styled(Grid).withConfig({
8
8
  componentId: "sc-jmynvr-1"
9
- })(["justify-content:center;align-items:center;font-weight:bold;font-size:18px;color:", ";"], props => props.theme.colors.neutral['700']);
10
- const StyledChatContainerContentHeaderActions = /*#__PURE__*/styled(Grid).withConfig({
9
+ })(["width:100%;min-height:48px;border-bottom:1px solid ", ";background:", ";", "{& button{background:transparent;}}"], props => props.theme.colors.neutral['200'], props => props.theme.colors.neutral['050'], StyledChatContainerContentHeaderActions);
10
+ const StyledChatContainerContentHeaderLabel = /*#__PURE__*/styled(Grid).withConfig({
11
11
  componentId: "sc-jmynvr-2"
12
- })(["max-width:80px;"]);
12
+ })(["justify-content:center;align-items:center;font-weight:bold;font-size:18px;color:", ";"], props => props.theme.colors.neutral['700']);
13
13
 
14
14
  export { StyledChatContainerContentHeader, StyledChatContainerContentHeaderActions, StyledChatContainerContentHeaderLabel };
@@ -1,9 +1,20 @@
1
+ import 'core-js/modules/esnext.async-iterator.filter.js';
2
+ import 'core-js/modules/esnext.iterator.filter.js';
1
3
  import _jsx from '@babel/runtime/helpers/esm/jsx';
2
4
  import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
5
+ import 'core-js/modules/esnext.async-iterator.some.js';
6
+ import 'core-js/modules/esnext.iterator.constructor.js';
7
+ import 'core-js/modules/esnext.iterator.some.js';
8
+ import 'core-js/modules/esnext.async-iterator.for-each.js';
9
+ import 'core-js/modules/esnext.iterator.for-each.js';
10
+ import 'core-js/modules/esnext.async-iterator.map.js';
11
+ import 'core-js/modules/esnext.iterator.map.js';
12
+ import 'core-js/modules/esnext.async-iterator.find.js';
13
+ import 'core-js/modules/esnext.iterator.find.js';
3
14
  import React from 'react';
4
15
  import { describe } from 'react-desc';
5
16
  import { useVirtual } from 'react-virtual';
6
- import DSButton from '@elliemae/ds-basic/Button';
17
+ import DSButton from '@elliemae/ds-button';
7
18
  import { ChatBubble } from '../bubble/ChatBubble.js';
8
19
  import { BUBBLE_TYPES } from '../bubble/props.js';
9
20
  import { MessageDelimiter } from '../message-delimiter/MessageDelimiter.js';
@@ -17,27 +28,35 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
17
28
 
18
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(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; }
19
30
 
20
- const getPadding = hasMoreItems => {
31
+ const getPadding = _ref => {
32
+ let {
33
+ hasMoreItems,
34
+ bannerPosition,
35
+ isLoading
36
+ } = _ref;
21
37
  const padding = {
22
38
  paddingStart: 0,
23
39
  paddingEnd: -5
24
40
  };
25
- if (hasMoreItems === 'top') padding.paddingStart = 42;else if (hasMoreItems === 'bottom') padding.paddingEnd = 42;
41
+ if ([hasMoreItems, bannerPosition, isLoading].some(item => item === 'top')) padding.paddingStart = 42;else if ([hasMoreItems, bannerPosition, isLoading].some(item => item === 'bottom')) padding.paddingEnd = 42;
26
42
  return padding;
27
43
  };
28
44
 
29
45
  const ChatContainerMessagesList = props => {
30
- useValidateProps(props, ChatContainerMessagesListWithSchema.toTypescript());
46
+ useValidateProps(props, listProps);
31
47
  const {
32
48
  sendingText,
49
+ bannerPosition,
33
50
  sendingMessages,
34
51
  messages,
35
52
  actionRef,
36
53
  onScrollEnds,
37
54
  getMoreMessages,
38
55
  hasMoreItems,
39
- isLoading
56
+ isLoading,
57
+ bannerRef
40
58
  } = props;
59
+ const loadMoreRef = React.useRef(null);
41
60
  const virtualListRef = React.useRef(); // estimateSize should not be really required given what was stated on
42
61
  // https://github.com/tannerlinsley/react-virtual/issues/23
43
62
 
@@ -49,90 +68,185 @@ const ChatContainerMessagesList = props => {
49
68
  size: messages.length,
50
69
  parentRef: virtualListRef,
51
70
  overscan: 15
52
- }, getPadding(hasMoreItems)), {}, {
71
+ }, getPadding({
72
+ hasMoreItems,
73
+ bannerPosition,
74
+ isLoading
75
+ })), {}, {
53
76
  estimateSize: React.useCallback(() => 80, [])
54
77
  }));
55
78
  const onScrollStop = React.useCallback(() => {
79
+ var _virtualListRef$curre;
80
+
56
81
  const {
57
82
  bottom,
58
83
  top
59
- } = virtualListRef.current.getBoundingClientRect();
84
+ } = (_virtualListRef$curre = virtualListRef.current) === null || _virtualListRef$curre === void 0 ? void 0 : _virtualListRef$curre.getBoundingClientRect();
60
85
  const list = virtualListRef.current.querySelectorAll('[data-element="chat-element-list-item"]');
61
86
  const indexList = [];
62
87
  list.forEach(item => {
63
88
  const {
64
- top: itemTop
89
+ top: itemTop,
90
+ bottom: itemBottom
65
91
  } = item.getBoundingClientRect();
66
- if (itemTop < bottom && itemTop > top) indexList.push(item.dataset.index);
92
+ const itemPadding = 10;
93
+ if (itemTop + itemPadding < bottom && itemBottom - itemPadding > top) indexList.push(item.dataset.index);
67
94
  });
68
95
  if (onScrollEnds) onScrollEnds(indexList);
69
96
  return indexList;
70
97
  }, [onScrollEnds]);
71
- const scrollAndFocus = React.useCallback(index => {
72
- vScroll(index, {
73
- align: 'center'
74
- });
98
+ const onlyFocus = React.useCallback(index => {
75
99
  setTimeout(() => {
76
- virtualListRef.current.querySelector(`[data-index="${index}"]`).focus();
100
+ virtualListRef.current.querySelector("[data-index=\"".concat(index, "\"]")).focus();
77
101
  }, 300);
78
- }, [vScroll]);
102
+ }, []);
103
+ const scrollAndFocus = React.useCallback(function (index) {
104
+ let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
105
+ align: 'center'
106
+ };
107
+ vScroll(index, b);
108
+ onlyFocus(index);
109
+ }, [onlyFocus, vScroll]);
79
110
  React.useEffect(() => {
80
111
  if (actionRef && actionRef.current) {
81
- actionRef.current.scrollToIndex = (a, b = {
82
- align: 'center'
83
- }) => {
112
+ actionRef.current.scrollToIndex = function (a) {
113
+ let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
114
+ align: 'center'
115
+ };
84
116
  vScroll(a, b);
85
117
  };
86
118
 
87
119
  actionRef.current.getMessagesInView = onScrollStop;
88
120
 
89
- actionRef.current.focusToIndex = (a, b = {
90
- align: 'center'
91
- }) => {
92
- scrollAndFocus(a);
121
+ actionRef.current.focusToIndex = function (a) {
122
+ let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
123
+ align: 'center'
124
+ };
125
+ scrollAndFocus(a, b);
93
126
  };
94
127
 
95
- actionRef.current.focusToList = (a, b = {
96
- align: 'center'
97
- }) => {
98
- var _virtualListRef$curre;
128
+ actionRef.current.focusToIndexWithoutScroll = onlyFocus;
129
+
130
+ actionRef.current.focusToList = a => {
131
+ var _virtualListRef$curre2;
99
132
 
100
- (_virtualListRef$curre = virtualListRef.current) === null || _virtualListRef$curre === void 0 ? void 0 : _virtualListRef$curre.focus();
133
+ (_virtualListRef$curre2 = virtualListRef.current) === null || _virtualListRef$curre2 === void 0 ? void 0 : _virtualListRef$curre2.focus();
101
134
  };
102
135
  }
103
- }, [actionRef, onScrollStop, scrollAndFocus, vScroll]);
136
+ }, [actionRef, onScrollStop, onlyFocus, scrollAndFocus, vScroll]);
104
137
  const handleKey = React.useCallback(e => {
105
- e.preventDefault();
106
138
  const {
107
139
  key
108
140
  } = e;
109
141
  const index = Number(e.currentTarget.dataset.index);
142
+ e.stopPropagation();
110
143
 
111
144
  switch (key) {
112
145
  case 'ArrowUp':
113
- if (index > 0) virtualListRef.current.querySelector(`[data-index="${index - 1}"]`).focus();
146
+ e.preventDefault();
147
+ if (index > 0) virtualListRef.current.querySelector("[data-index=\"".concat(index - 1, "\"]")).focus();
114
148
  break;
115
149
 
116
150
  case 'ArrowDown':
151
+ e.preventDefault();
152
+
117
153
  if (index < messages.length - 1) {
118
- virtualListRef.current.querySelector(`[data-index="${index + 1}"]`).focus();
154
+ virtualListRef.current.querySelector("[data-index=\"".concat(index + 1, "\"]")).focus();
119
155
  }
120
156
 
121
157
  break;
122
158
 
123
159
  case 'Home':
160
+ e.preventDefault();
124
161
  scrollAndFocus(0);
125
162
  break;
126
163
 
127
164
  case 'End':
165
+ e.preventDefault();
128
166
  scrollAndFocus(messages.length - 1);
129
167
  break;
130
168
 
131
169
  case 'Tab':
132
- actionRef.current.focusToComposer();
170
+ e.preventDefault();
171
+
172
+ if (hasMoreItems === 'bottom' && !e.shiftKey) {
173
+ var _loadMoreRef$current;
174
+
175
+ (_loadMoreRef$current = loadMoreRef.current) === null || _loadMoreRef$current === void 0 ? void 0 : _loadMoreRef$current.focus();
176
+ } else if (hasMoreItems === 'top' && e.shiftKey) {
177
+ var _loadMoreRef$current2;
178
+
179
+ (_loadMoreRef$current2 = loadMoreRef.current) === null || _loadMoreRef$current2 === void 0 ? void 0 : _loadMoreRef$current2.focus();
180
+ } else if (!e.shiftKey) {
181
+ if (bannerPosition) {
182
+ bannerRef.current.focusOnWrapper();
183
+ } else {
184
+ actionRef.current.focusToComposer();
185
+ }
186
+ } else {
187
+ var _virtualListRef$curre3;
188
+
189
+ (_virtualListRef$curre3 = virtualListRef.current) === null || _virtualListRef$curre3 === void 0 ? void 0 : _virtualListRef$curre3.focus();
190
+ }
191
+
192
+ break;
193
+ }
194
+ }, [actionRef, hasMoreItems, messages.length, bannerPosition, scrollAndFocus]);
195
+ const handleListKey = React.useCallback(e => {
196
+ const {
197
+ key
198
+ } = e;
199
+
200
+ switch (key) {
201
+ case 'ArrowUp':
202
+ e.preventDefault();
203
+ onlyFocus(onScrollStop().shift());
204
+ break;
205
+
206
+ case 'ArrowDown':
207
+ e.preventDefault();
208
+ onlyFocus(onScrollStop().pop());
209
+ break;
210
+
211
+ case 'Home':
212
+ e.preventDefault();
213
+ scrollAndFocus(0);
214
+ break;
215
+
216
+ case 'End':
217
+ e.preventDefault();
218
+ scrollAndFocus(messages.length - 1);
219
+ break;
220
+
221
+ case 'Tab':
222
+ if (document.activeElement !== loadMoreRef.current) {
223
+ if (hasMoreItems === 'bottom' && !e.shiftKey) {
224
+ var _loadMoreRef$current3;
225
+
226
+ e.preventDefault();
227
+ (_loadMoreRef$current3 = loadMoreRef.current) === null || _loadMoreRef$current3 === void 0 ? void 0 : _loadMoreRef$current3.focus();
228
+ } else if (hasMoreItems === 'top' && e.shiftKey) {
229
+ var _loadMoreRef$current4;
230
+
231
+ e.preventDefault();
232
+ (_loadMoreRef$current4 = loadMoreRef.current) === null || _loadMoreRef$current4 === void 0 ? void 0 : _loadMoreRef$current4.focus();
233
+ } else if (!e.shiftKey) {
234
+ e.preventDefault();
235
+ actionRef.current.focusToComposer();
236
+ }
237
+ } else if (!e.shiftKey) {
238
+ e.preventDefault();
239
+ actionRef.current.focusToComposer();
240
+ } else {
241
+ var _virtualListRef$curre4;
242
+
243
+ e.preventDefault();
244
+ (_virtualListRef$curre4 = virtualListRef.current) === null || _virtualListRef$curre4 === void 0 ? void 0 : _virtualListRef$curre4.focus();
245
+ }
246
+
133
247
  break;
134
248
  }
135
- }, [actionRef, messages.length, scrollAndFocus]);
249
+ }, [actionRef, hasMoreItems, messages.length, onScrollStop, onlyFocus, scrollAndFocus]);
136
250
  React.useEffect(() => {
137
251
  let handlerCallback = null;
138
252
  const localVirtualRef = virtualListRef.current;
@@ -163,7 +277,7 @@ const ChatContainerMessagesList = props => {
163
277
  position: 'absolute',
164
278
  top: 0,
165
279
  left: 0,
166
- transform: `translateY(${start}px)`,
280
+ transform: "translateY(".concat(start, "px)"),
167
281
  width: '100%'
168
282
  };
169
283
  return /*#__PURE__*/jsx(ListItem, {
@@ -182,7 +296,7 @@ const ChatContainerMessagesList = props => {
182
296
  jsx(ChatBubble, _objectSpread(_objectSpread({}, row), {}, {
183
297
  helpMessage: isSending ? sendingText : row.helpMessage
184
298
  })) : null, row.type === BUBBLE_TYPES.DELIMITER ? /*#__PURE__*/jsx(MessageDelimiter, _objectSpread({}, row)) : null, row.type === BUBBLE_TYPES.SYSTEM ? /*#__PURE__*/jsx(SystemMessage, _objectSpread({}, row)) : null)
185
- }, `ds-chat-bubble-${index}`);
299
+ }, "ds-chat-bubble-".concat(index, "-").concat(row.dsId, "-").concat(row.type));
186
300
  }), [virtualItems, messages, sendingMessages, handleKey, sendingText]);
187
301
  return /*#__PURE__*/_jsx(StyledWrapper, {}, void 0, /*#__PURE__*/jsx(StyledChatContainerContentList, {
188
302
  "data-testid": "chat-thread-container",
@@ -190,15 +304,17 @@ const ChatContainerMessagesList = props => {
190
304
  "aria-live": "polite",
191
305
  ref: virtualListRef,
192
306
  role: "list",
193
- onKeyDown: handleKey,
307
+ onKeyDown: handleListKey,
194
308
  children: /*#__PURE__*/_jsx(StyledChatContainerContentListScroll, {
195
- height: `${totalSize}px`
309
+ height: "".concat(totalSize, "px")
196
310
  }, void 0, render, !isLoading && hasMoreItems ? /*#__PURE__*/_jsx(StyledLoadMoreContainer, {
197
311
  hasMoreItems: hasMoreItems
198
312
  }, void 0, /*#__PURE__*/_jsx(DSButton, {
199
313
  labelText: "Load More",
200
314
  buttonType: "secondary",
201
- onClick: getMoreMessages
315
+ onClick: getMoreMessages,
316
+ "data-testid": "ds-chat-load-more-btn",
317
+ innerRef: loadMoreRef
202
318
  })) : null)
203
319
  }));
204
320
  };
@@ -1,7 +1,7 @@
1
1
  import { useValidateTypescriptPropTypes } from '@elliemae/ds-props-helpers';
2
2
 
3
- const useValidateProps = (props, schema) => {
4
- useValidateTypescriptPropTypes(props, schema);
3
+ const useValidateProps = (props, propTypes) => {
4
+ useValidateTypescriptPropTypes(props, propTypes);
5
5
  };
6
6
 
7
7
  export { useValidateProps };
@@ -7,22 +7,14 @@ const defaultProps = {
7
7
  onScrollEnds: () => [],
8
8
  getMoreMessages: noop,
9
9
  sendingMessages: undefined,
10
- sendingText: 'Sending'
10
+ sendingText: 'Sending',
11
+ bannerPosition: undefined,
12
+ bannerRef: undefined
11
13
  };
12
14
  const listProps = {
13
15
  messages: PropTypes.arrayOf(PropTypes.object).description('The array of out-of-the-box items you want to render inside the ChatMessageList').defaultValue(defaultProps.messages),
14
- actionRef: PropTypes.object.description(`Reference:
15
- {
16
- scrollToIndex: (n: number) => void,
17
- getMessagesInView: () => number[],
18
- focusToIndex: (n: number) => void,
19
- focusToList: () => void,
20
- focusToComposer: () => void,
21
- focusToSend: () => void,
22
- }
23
-
24
- `).defaultValue(defaultProps.actionRef),
25
- onScrollEnds: PropTypes.func.description(`Called when the scroll stops.`),
16
+ actionRef: PropTypes.object.description("Reference: \n { \n scrollToIndex: (n: number) => void,\n getMessagesInView: () => number[],\n focusToIndex: (n: number) => void,\n focusToIndexWithoutScroll: (n: number) => void,\n focusToList: () => void,\n focusToComposer: () => void,\n focusToSend: () => void,\n }\n \n ").defaultValue(defaultProps.actionRef),
17
+ onScrollEnds: PropTypes.func.description("Called when the scroll stops."),
26
18
  isLoading: PropTypes.oneOf(['top', 'bottom', undefined]).description('Keeps the load more space while the loading is in progress'),
27
19
  hasMoreItems: PropTypes.oneOf(['top', 'bottom', undefined]).description('Show Load More button at the `top` or `bottom` of the container'),
28
20
  getMoreMessages: PropTypes.func.description('Called when the user clicks on load more').defaultValue(defaultProps.getMoreMessages),
@@ -8,11 +8,7 @@ const StyledWrapper = /*#__PURE__*/styled.div.withConfig({
8
8
 
9
9
  const StyledWrapperListItem = /*#__PURE__*/styled.div.withConfig({
10
10
  componentId: "sc-1jhprzr-1"
11
- })(["min-width:100%;", ";", ";", ";"], props => props.type === BUBBLE_TYPES.SENDER && `padding: ${props.theme.space.xxs} ${props.theme.space.xxs} 0px 13%
12
- `, props => props.type === BUBBLE_TYPES.RECIPIENT && `padding: ${props.theme.space.xxs} 13% ${props.theme.space.xxs}
13
- ${props.theme.space.xxs}
14
- `, props => props.type === BUBBLE_TYPES.SYSTEM && `padding: ${props.theme.space.xxs} 0px
15
- `);
11
+ })(["min-width:100%;", ";", ";", ";"], props => props.type === BUBBLE_TYPES.SENDER && "padding: ".concat(props.theme.space.xxs, " ").concat(props.theme.space.xxs, " ").concat(props.theme.space.xxs, " 13%\n "), props => props.type === BUBBLE_TYPES.RECIPIENT && "padding: ".concat(props.theme.space.xxs, " 13% ").concat(props.theme.space.xxs, "\n ").concat(props.theme.space.xxs, "\n "), props => props.type === BUBBLE_TYPES.SYSTEM && "padding: ".concat(props.theme.space.xxs, " 0px\n "));
16
12
  const StyledChatContainerContentList = /*#__PURE__*/styled.div.withConfig({
17
13
  componentId: "sc-1jhprzr-2"
18
14
  })(["width:100%;height:100%;padding:", ";padding-bottom:0;overflow-y:auto;overflow-x:hidden;"], props => props.theme.space.xs);
@@ -24,6 +20,6 @@ const StyledLoadMoreContainer = /*#__PURE__*/styled.div.withConfig({
24
20
  })(["position:absolute;width:calc(100% + ", ");padding:", ";left:-", ";right:-", ";display:grid;justify-content:center;align-items:center;", " ", ""], props => props.theme.space.xxs, props => props.theme.space.xxs, props => props.theme.space.xxs, props => props.theme.space.xxs, props => props.hasMoreItems === 'top' ? 'top: 0;' : '', props => props.hasMoreItems === 'bottom' ? 'bottom: 0;' : '');
25
21
  const ListItem = /*#__PURE__*/styled.div.withConfig({
26
22
  componentId: "sc-1jhprzr-5"
27
- })(["&:focus,&:focus-visible{outline:none;&:after{content:'';display:block;position:absolute;pointer-events:none;background:rgba(255,255,255,0.5);width:calc(100% + ", ");height:100%;}}"], props => props.theme.space.xxs);
23
+ })(["&:focus,&:focus-visible{outline:none;&:after{content:'';display:block;position:absolute;top:0;left:-", ";pointer-events:none;border-radius:2px;background-color:#ebedf0;width:calc(100% + 24px);border:2px solid #1e79c2;height:100%;z-index:-1;}}"], props => props.theme.space.xxs);
28
24
 
29
25
  export { ListItem, StyledChatContainerContentList, StyledChatContainerContentListScroll, StyledLoadMoreContainer, StyledWrapper, StyledWrapperListItem };
@@ -3,7 +3,7 @@ import 'core-js/modules/web.url.to-json.js';
3
3
  import { useMemo } from 'react';
4
4
  import { describe } from 'react-desc';
5
5
  import { Grid } from '@elliemae/ds-grid';
6
- import Communications from '@elliemae/ds-icons/Communications';
6
+ import { Communications } from '@elliemae/ds-icons';
7
7
  import { emptyStateProps, defaultProps } from './props.js';
8
8
  import { MessageWrapper, ChatEmptyStateWrapper } from './styled.js';
9
9
  import { useValidateProps } from './config/useValidateProps.js';
@@ -1,34 +1,43 @@
1
1
  import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
2
2
  import _jsx from '@babel/runtime/helpers/esm/jsx';
3
3
  import 'core-js/modules/web.url.to-json.js';
4
- import 'react';
4
+ import 'core-js/modules/esnext.async-iterator.map.js';
5
+ import 'core-js/modules/esnext.iterator.map.js';
6
+ import 'core-js/modules/esnext.async-iterator.filter.js';
7
+ import 'core-js/modules/esnext.iterator.constructor.js';
8
+ import 'core-js/modules/esnext.iterator.filter.js';
9
+ import 'core-js/modules/esnext.async-iterator.for-each.js';
10
+ import 'core-js/modules/esnext.iterator.for-each.js';
11
+ import React from 'react';
5
12
  import { describe } from 'react-desc';
6
- import MenuExpand from '@elliemae/ds-icons/MenuExpand';
7
- import MenuCollapse from '@elliemae/ds-icons/MenuCollapse';
13
+ import { MenuCollapse, MenuExpand } from '@elliemae/ds-icons';
8
14
  import { StyledSideBarContainer, StyledSideBarButtonsContainer } from './styled.js';
9
15
  import { TileButton } from '../tile-button/TileButton.js';
10
16
  import { SidebarButton } from '../sidebar-button/SidebarButton.js';
11
17
  import { chatSidebarProps, defaultProps } from './props.js';
12
18
  import { useValidateProps } from './config/useValidateProps.js';
13
- import { jsx } from 'react/jsx-runtime';
19
+ import { jsxs, jsx } from 'react/jsx-runtime';
14
20
 
15
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; }
16
22
 
17
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; }
18
24
 
19
- const FooterChat = ({
20
- expanded,
21
- onFooterClose,
22
- onFooterExpand,
23
- footerButtonExtraProps
24
- }) => /*#__PURE__*/_jsx(SidebarButton, {
25
- dsId: "sidebar_footer",
26
- label: null,
27
- Icon: !expanded ? MenuCollapse : MenuExpand,
28
- onClick: expanded ? onFooterClose : onFooterExpand,
29
- "aria-pressed": expanded,
30
- "aria-label": footerButtonExtraProps['aria-label']
31
- });
25
+ const FooterChat = _ref => {
26
+ let {
27
+ expanded,
28
+ onFooterClose,
29
+ onFooterExpand,
30
+ footerButtonExtraProps
31
+ } = _ref;
32
+ return /*#__PURE__*/_jsx(SidebarButton, {
33
+ dsId: "sidebar_footer",
34
+ label: null,
35
+ Icon: !expanded ? MenuCollapse : MenuExpand,
36
+ onClick: expanded ? onFooterClose : onFooterExpand,
37
+ "aria-pressed": expanded,
38
+ "aria-label": footerButtonExtraProps['aria-label']
39
+ });
40
+ };
32
41
 
33
42
  const SideBarChat = props => {
34
43
  useValidateProps(props, SideBarChatWithSchema.toJSON());
@@ -38,18 +47,38 @@ const SideBarChat = props => {
38
47
  onFooterClose,
39
48
  onFooterExpand,
40
49
  selectedItem,
41
- footerButtonExtraProps
50
+ footerButtonExtraProps,
51
+ tooltipPlacement,
52
+ enableTooltipWhenIsClosed,
53
+ actionRef
42
54
  } = props;
43
- return /*#__PURE__*/_jsx(StyledSideBarContainer, {
44
- rows: [1, 'auto']
45
- }, void 0, /*#__PURE__*/_jsx(StyledSideBarButtonsContainer, {}, void 0, sidebarItems.map(p => /*#__PURE__*/jsx(TileButton, _objectSpread(_objectSpread({}, p), {}, {
46
- selected: selectedItem === p.dsId
47
- })))), /*#__PURE__*/_jsx(FooterChat, {
48
- expanded: expanded,
49
- onFooterClose: onFooterClose,
50
- onFooterExpand: onFooterExpand,
51
- footerButtonExtraProps: footerButtonExtraProps
52
- }));
55
+ const {
56
+ current: listRef
57
+ } = React.useRef({});
58
+ const registerReference = React.useCallback(ref => {
59
+ if (ref) listRef[ref.dataset.key] = ref;
60
+ }, [listRef]);
61
+ React.useEffect(() => {
62
+ if (actionRef.current.listRef) {
63
+ actionRef.current.listRef = listRef;
64
+ }
65
+ }, [sidebarItems, expanded, actionRef, listRef]);
66
+ return /*#__PURE__*/jsxs(StyledSideBarContainer, {
67
+ rows: [1, 'auto'],
68
+ ref: listRef,
69
+ children: [/*#__PURE__*/_jsx(StyledSideBarButtonsContainer, {}, void 0, sidebarItems.map(p => /*#__PURE__*/jsx(TileButton, _objectSpread(_objectSpread({
70
+ innerRef: registerReference
71
+ }, p), {}, {
72
+ selected: selectedItem === p.dsId,
73
+ tooltipPlacement: tooltipPlacement,
74
+ disableTooltip: enableTooltipWhenIsClosed ? false : !expanded
75
+ }), p.dsId))), /*#__PURE__*/_jsx(FooterChat, {
76
+ expanded: expanded,
77
+ onFooterClose: onFooterClose,
78
+ onFooterExpand: onFooterExpand,
79
+ footerButtonExtraProps: footerButtonExtraProps
80
+ })]
81
+ });
53
82
  };
54
83
 
55
84
  SideBarChat.defaultProps = defaultProps;