@elliemae/ds-chat 2.1.0-rc.0 → 2.1.0-rc.4

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.
@@ -92,6 +92,9 @@ const ChatComposer = props => {
92
92
  "data-testid": dataTestid
93
93
  }, void 0, /*#__PURE__*/_jsx__default["default"](dsGrid.Grid, {
94
94
  cols: ['1fr', '24px'],
95
+ style: {
96
+ height: heightProps.height
97
+ },
95
98
  justifyContent: "center",
96
99
  alignItems: "flex-end",
97
100
  gutter: "xxs"
@@ -132,8 +135,7 @@ const ChatComposer = props => {
132
135
  width: (_input$current = input.current) === null || _input$current === void 0 ? void 0 : _input$current.clientWidth
133
136
  },
134
137
  onChange: handleChange,
135
- value: inputValue // maxLength={inputMaxLength}
136
-
138
+ value: inputValue
137
139
  }), /*#__PURE__*/_jsx__default["default"](dsGrid.Grid, {
138
140
  cols: ['1fr', '24px'],
139
141
  justifyContent: "flex-end",
@@ -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 => {
@@ -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,6 +19,7 @@ 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');
@@ -67,6 +68,7 @@ const ChatContainerMessagesList = props$2 => {
67
68
  isLoading,
68
69
  bannerRef
69
70
  } = props$2;
71
+ const pendingOnScroll = React__default["default"].useRef(false);
70
72
  const loadMoreRef = React__default["default"].useRef(null);
71
73
  const virtualListRef = React__default["default"].useRef(); // estimateSize should not be really required given what was stated on
72
74
  // https://github.com/tannerlinsley/react-virtual/issues/23
@@ -86,9 +88,15 @@ const ChatContainerMessagesList = props$2 => {
86
88
  })), {}, {
87
89
  estimateSize: React__default["default"].useCallback(() => 80, [])
88
90
  }));
89
- const onScrollStop = React__default["default"].useCallback(() => {
91
+ const debouncedScroll = React__default["default"].useMemo(() => lodash.debounce(() => {
90
92
  var _virtualListRef$curre;
91
93
 
94
+ if (document.visibilityState === 'hidden') {
95
+ pendingOnScroll.current = true;
96
+ return [];
97
+ }
98
+
99
+ pendingOnScroll.current = false;
92
100
  const {
93
101
  bottom,
94
102
  top
@@ -97,15 +105,15 @@ const ChatContainerMessagesList = props$2 => {
97
105
  const indexList = [];
98
106
  list.forEach(item => {
99
107
  const {
100
- top: itemTop,
101
- bottom: itemBottom
108
+ top: itemTop
102
109
  } = item.getBoundingClientRect();
103
110
  const itemPadding = 10;
104
- if (itemTop + itemPadding < bottom && itemBottom - itemPadding > top) indexList.push(item.dataset.index);
111
+ if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index);
105
112
  });
106
113
  if (onScrollEnds) onScrollEnds(indexList);
107
114
  return indexList;
108
- }, [onScrollEnds]);
115
+ }, 500), [onScrollEnds]);
116
+ const onScrollStop = React__default["default"].useCallback(debouncedScroll, [debouncedScroll]);
109
117
  const onlyFocus = React__default["default"].useCallback(index => {
110
118
  setTimeout(() => {
111
119
  virtualListRef.current.querySelector("[data-index=\"".concat(index, "\"]")).focus();
@@ -117,7 +125,8 @@ const ChatContainerMessagesList = props$2 => {
117
125
  };
118
126
  vScroll(index, b);
119
127
  onlyFocus(index);
120
- }, [onlyFocus, vScroll]);
128
+ onScrollStop();
129
+ }, [onScrollStop, onlyFocus, vScroll]);
121
130
  React__default["default"].useEffect(() => {
122
131
  if (actionRef && actionRef.current) {
123
132
  actionRef.current.scrollToIndex = function (a) {
@@ -125,6 +134,7 @@ const ChatContainerMessagesList = props$2 => {
125
134
  align: 'center'
126
135
  };
127
136
  vScroll(a, b);
137
+ onScrollStop();
128
138
  };
129
139
 
130
140
  actionRef.current.getMessagesInView = onScrollStop;
@@ -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();
@@ -222,9 +232,7 @@ const ChatContainerMessagesList = props$2 => {
222
232
  case 'ArrowUp':
223
233
  e.preventDefault();
224
234
 
225
- if (document.activeElement === loadMoreRef.current) {
226
- scrollAndFocus(messages.length - 1);
227
- } else {
235
+ if (document.activeElement !== loadMoreRef.current) {
228
236
  onlyFocus(onScrollStop().shift());
229
237
  }
230
238
 
@@ -232,7 +240,13 @@ const ChatContainerMessagesList = props$2 => {
232
240
 
233
241
  case 'ArrowDown':
234
242
  e.preventDefault();
235
- onlyFocus(onScrollStop().pop());
243
+
244
+ if (document.activeElement === loadMoreRef.current) {
245
+ virtualListRef.current.querySelector("[data-index=\"0\"]").focus();
246
+ } else {
247
+ onlyFocus(onScrollStop().pop());
248
+ }
249
+
236
250
  break;
237
251
 
238
252
  case 'Home':
@@ -274,6 +288,9 @@ const ChatContainerMessagesList = props$2 => {
274
288
  break;
275
289
  }
276
290
  }, [actionRef, hasMoreItems, messages.length, onScrollStop, onlyFocus, scrollAndFocus]);
291
+ const checkPendingOnScroll = React__default["default"].useCallback(() => {
292
+ if (pendingOnScroll.current === true) onScrollStop();
293
+ }, [onScrollStop]);
277
294
  React__default["default"].useEffect(() => {
278
295
  let handlerCallback = null;
279
296
  const localVirtualRef = virtualListRef.current;
@@ -287,11 +304,13 @@ const ChatContainerMessagesList = props$2 => {
287
304
  virtualListRef.current.addEventListener('scroll', onScroll);
288
305
  }
289
306
 
307
+ document.addEventListener('visibilitychange', checkPendingOnScroll);
290
308
  return () => {
291
309
  if (handlerCallback) clearTimeout(handlerCallback);
292
310
  if (onScrollEnds) localVirtualRef.removeEventListener('scroll', onScroll);
311
+ document.removeEventListener('visibilitychange', checkPendingOnScroll);
293
312
  };
294
- }, [onScrollStop, onScrollEnds]);
313
+ }, [onScrollStop, onScrollEnds, checkPendingOnScroll]);
295
314
  const render = React__default["default"].useMemo(() => virtualItems.map(virtualItem => {
296
315
  const {
297
316
  index,
@@ -82,6 +82,9 @@ const ChatComposer = props => {
82
82
  "data-testid": dataTestid
83
83
  }, void 0, /*#__PURE__*/_jsx(Grid, {
84
84
  cols: ['1fr', '24px'],
85
+ style: {
86
+ height: heightProps.height
87
+ },
85
88
  justifyContent: "center",
86
89
  alignItems: "flex-end",
87
90
  gutter: "xxs"
@@ -122,8 +125,7 @@ const ChatComposer = props => {
122
125
  width: (_input$current = input.current) === null || _input$current === void 0 ? void 0 : _input$current.clientWidth
123
126
  },
124
127
  onChange: handleChange,
125
- value: inputValue // maxLength={inputMaxLength}
126
-
128
+ value: inputValue
127
129
  }), /*#__PURE__*/_jsx(Grid, {
128
130
  cols: ['1fr', '24px'],
129
131
  justifyContent: "flex-end",
@@ -55,18 +55,16 @@ const ChatContainer = props => {
55
55
  });
56
56
  const onResize = React.useCallback(height => {
57
57
  if (onComposerResize) onComposerResize(height);
58
-
59
- if (height > 30) {
60
- /*
58
+ /*
61
59
  setTimeout is used to equal the animation duration from the
62
60
  composer text area when increase its size
63
61
  */
64
- setTimeout(() => {
65
- actionRef.current.scrollToIndex(messagesListProps.messages.length - 1, {
66
- align: 'start'
67
- });
68
- }, 50);
69
- }
62
+
63
+ setTimeout(() => {
64
+ actionRef.current.scrollToIndex(messagesListProps.messages.length - 1, {
65
+ align: 'start'
66
+ });
67
+ }, 50);
70
68
  }, [onComposerResize, messagesListProps.messages, actionRef]);
71
69
  const Container = device === 'desktop' ? StyledChatContainerContent : MobileStyledChatContainerContent;
72
70
  const handleTabs = React.useCallback(e => {
@@ -10,7 +10,7 @@ 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
- })(["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 " : '');
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
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);
@@ -15,6 +15,7 @@ import React from 'react';
15
15
  import { describe } from 'react-desc';
16
16
  import { useVirtual } from 'react-virtual';
17
17
  import DSButton from '@elliemae/ds-button';
18
+ import { debounce } from 'lodash';
18
19
  import { ChatBubble } from '../bubble/ChatBubble.js';
19
20
  import { BUBBLE_TYPES } from '../bubble/props.js';
20
21
  import { MessageDelimiter } from '../message-delimiter/MessageDelimiter.js';
@@ -56,6 +57,7 @@ const ChatContainerMessagesList = props => {
56
57
  isLoading,
57
58
  bannerRef
58
59
  } = props;
60
+ const pendingOnScroll = React.useRef(false);
59
61
  const loadMoreRef = React.useRef(null);
60
62
  const virtualListRef = React.useRef(); // estimateSize should not be really required given what was stated on
61
63
  // https://github.com/tannerlinsley/react-virtual/issues/23
@@ -75,9 +77,15 @@ const ChatContainerMessagesList = props => {
75
77
  })), {}, {
76
78
  estimateSize: React.useCallback(() => 80, [])
77
79
  }));
78
- const onScrollStop = React.useCallback(() => {
80
+ const debouncedScroll = React.useMemo(() => debounce(() => {
79
81
  var _virtualListRef$curre;
80
82
 
83
+ if (document.visibilityState === 'hidden') {
84
+ pendingOnScroll.current = true;
85
+ return [];
86
+ }
87
+
88
+ pendingOnScroll.current = false;
81
89
  const {
82
90
  bottom,
83
91
  top
@@ -86,15 +94,15 @@ const ChatContainerMessagesList = props => {
86
94
  const indexList = [];
87
95
  list.forEach(item => {
88
96
  const {
89
- top: itemTop,
90
- bottom: itemBottom
97
+ top: itemTop
91
98
  } = item.getBoundingClientRect();
92
99
  const itemPadding = 10;
93
- if (itemTop + itemPadding < bottom && itemBottom - itemPadding > top) indexList.push(item.dataset.index);
100
+ if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index);
94
101
  });
95
102
  if (onScrollEnds) onScrollEnds(indexList);
96
103
  return indexList;
97
- }, [onScrollEnds]);
104
+ }, 500), [onScrollEnds]);
105
+ const onScrollStop = React.useCallback(debouncedScroll, [debouncedScroll]);
98
106
  const onlyFocus = React.useCallback(index => {
99
107
  setTimeout(() => {
100
108
  virtualListRef.current.querySelector("[data-index=\"".concat(index, "\"]")).focus();
@@ -106,7 +114,8 @@ const ChatContainerMessagesList = props => {
106
114
  };
107
115
  vScroll(index, b);
108
116
  onlyFocus(index);
109
- }, [onlyFocus, vScroll]);
117
+ onScrollStop();
118
+ }, [onScrollStop, onlyFocus, vScroll]);
110
119
  React.useEffect(() => {
111
120
  if (actionRef && actionRef.current) {
112
121
  actionRef.current.scrollToIndex = function (a) {
@@ -114,6 +123,7 @@ const ChatContainerMessagesList = props => {
114
123
  align: 'center'
115
124
  };
116
125
  vScroll(a, b);
126
+ onScrollStop();
117
127
  };
118
128
 
119
129
  actionRef.current.getMessagesInView = onScrollStop;
@@ -127,7 +137,7 @@ const ChatContainerMessagesList = props => {
127
137
 
128
138
  actionRef.current.focusToIndexWithoutScroll = onlyFocus;
129
139
 
130
- actionRef.current.focusToList = a => {
140
+ actionRef.current.focusToList = () => {
131
141
  var _virtualListRef$curre2;
132
142
 
133
143
  (_virtualListRef$curre2 = virtualListRef.current) === null || _virtualListRef$curre2 === void 0 ? void 0 : _virtualListRef$curre2.focus();
@@ -211,9 +221,7 @@ const ChatContainerMessagesList = props => {
211
221
  case 'ArrowUp':
212
222
  e.preventDefault();
213
223
 
214
- if (document.activeElement === loadMoreRef.current) {
215
- scrollAndFocus(messages.length - 1);
216
- } else {
224
+ if (document.activeElement !== loadMoreRef.current) {
217
225
  onlyFocus(onScrollStop().shift());
218
226
  }
219
227
 
@@ -221,7 +229,13 @@ const ChatContainerMessagesList = props => {
221
229
 
222
230
  case 'ArrowDown':
223
231
  e.preventDefault();
224
- onlyFocus(onScrollStop().pop());
232
+
233
+ if (document.activeElement === loadMoreRef.current) {
234
+ virtualListRef.current.querySelector("[data-index=\"0\"]").focus();
235
+ } else {
236
+ onlyFocus(onScrollStop().pop());
237
+ }
238
+
225
239
  break;
226
240
 
227
241
  case 'Home':
@@ -263,6 +277,9 @@ const ChatContainerMessagesList = props => {
263
277
  break;
264
278
  }
265
279
  }, [actionRef, hasMoreItems, messages.length, onScrollStop, onlyFocus, scrollAndFocus]);
280
+ const checkPendingOnScroll = React.useCallback(() => {
281
+ if (pendingOnScroll.current === true) onScrollStop();
282
+ }, [onScrollStop]);
266
283
  React.useEffect(() => {
267
284
  let handlerCallback = null;
268
285
  const localVirtualRef = virtualListRef.current;
@@ -276,11 +293,13 @@ const ChatContainerMessagesList = props => {
276
293
  virtualListRef.current.addEventListener('scroll', onScroll);
277
294
  }
278
295
 
296
+ document.addEventListener('visibilitychange', checkPendingOnScroll);
279
297
  return () => {
280
298
  if (handlerCallback) clearTimeout(handlerCallback);
281
299
  if (onScrollEnds) localVirtualRef.removeEventListener('scroll', onScroll);
300
+ document.removeEventListener('visibilitychange', checkPendingOnScroll);
282
301
  };
283
- }, [onScrollStop, onScrollEnds]);
302
+ }, [onScrollStop, onScrollEnds, checkPendingOnScroll]);
284
303
  const render = React.useMemo(() => virtualItems.map(virtualItem => {
285
304
  const {
286
305
  index,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-chat",
3
- "version": "2.1.0-rc.0",
3
+ "version": "2.1.0-rc.4",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Chat",
6
6
  "module": "./esm/index.js",
@@ -305,15 +305,15 @@
305
305
  "generateSubmodules": true
306
306
  },
307
307
  "dependencies": {
308
- "@elliemae/ds-banner": "2.1.0-rc.0",
309
- "@elliemae/ds-button": "2.1.0-rc.0",
310
- "@elliemae/ds-grid": "2.1.0-rc.0",
311
- "@elliemae/ds-icons": "2.1.0-rc.0",
312
- "@elliemae/ds-indeterminate-progress-indicator": "2.1.0-rc.0",
313
- "@elliemae/ds-props-helpers": "2.1.0-rc.0",
314
- "@elliemae/ds-system": "2.1.0-rc.0",
315
- "@elliemae/ds-tooltip": "2.1.0-rc.0",
316
- "@elliemae/ds-truncated-tooltip-text": "2.1.0-rc.0",
308
+ "@elliemae/ds-banner": "2.1.0-rc.4",
309
+ "@elliemae/ds-button": "2.1.0-rc.4",
310
+ "@elliemae/ds-grid": "2.1.0-rc.4",
311
+ "@elliemae/ds-icons": "2.1.0-rc.4",
312
+ "@elliemae/ds-indeterminate-progress-indicator": "2.1.0-rc.4",
313
+ "@elliemae/ds-props-helpers": "2.1.0-rc.4",
314
+ "@elliemae/ds-system": "2.1.0-rc.4",
315
+ "@elliemae/ds-tooltip": "2.1.0-rc.4",
316
+ "@elliemae/ds-truncated-tooltip-text": "2.1.0-rc.4",
317
317
  "prop-types": "~15.7.2",
318
318
  "react-desc": "~4.1.2",
319
319
  "react-virtual": "~2.3.2"