@vendorflow/components 2.0.38 → 2.0.42

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.
@@ -77,31 +77,51 @@ var DefaultLoader = (0, react_2.forwardRef)(function (_a, ref) {
77
77
  (0, react_1.jsx)(material_1.CircularProgress, { size: "1.5rem", disableShrink: true })));
78
78
  });
79
79
  function useInfiniteScroll(_a) {
80
- var _b, _c;
80
+ var _b, _c, _d, _e;
81
81
  var scrollParent = _a.scrollParent, scrollBody = _a.scrollBody, isLoading = _a.isLoading, isFetching = _a.isFetching, isReverse = _a.isReverse, hasNextPage = _a.hasNextPage, fetchNextPage = _a.fetchNextPage;
82
82
  var prevPosition = (0, react_2.useRef)();
83
83
  var observer = (0, react_2.useRef)();
84
+ var _f = __read((0, react_2.useState)(false), 2), isScrollInit = _f[0], setScrollInit = _f[1];
85
+ var _g = __read((0, react_2.useState)(false), 2), isScrollLoad = _g[0], setScrollLoad = _g[1];
84
86
  var hasScrollbar = (0, react_2.useMemo)(function () {
85
87
  if (scrollParent.current && scrollBody.current) {
86
88
  return scrollBody.current.clientHeight > scrollParent.current.clientHeight;
87
89
  }
88
90
  return false;
89
91
  }, [(_b = scrollParent.current) === null || _b === void 0 ? void 0 : _b.clientHeight, (_c = scrollBody.current) === null || _c === void 0 ? void 0 : _c.clientHeight]);
92
+ // Ensures that when the chat initializes, it will scroll to the bottom
90
93
  (0, react_2.useEffect)(function () {
91
- var _a, _b;
92
94
  if (!isLoading && hasScrollbar) {
93
- console.log('scrolling to start!');
94
- console.log('scroll parent height: ', (_a = scrollParent.current) === null || _a === void 0 ? void 0 : _a.clientHeight);
95
- console.log('scroll body height: ', (_b = scrollBody.current) === null || _b === void 0 ? void 0 : _b.clientHeight);
96
95
  prevPosition.current = null;
96
+ setScrollLoad(false);
97
97
  scrollToStart();
98
98
  }
99
99
  }, [isLoading, hasScrollbar]);
100
+ // If a fetch happens that was not started by a scroll action (aka fetchNextPage),
101
+ // then this will track the prevPosition
102
+ (0, react_2.useEffect)(function () {
103
+ if (!isScrollLoad && scrollBody.current && isFetching) {
104
+ prevPosition.current = scrollBody.current.clientHeight;
105
+ }
106
+ }, [isFetching, isScrollLoad, (_d = scrollBody.current) === null || _d === void 0 ? void 0 : _d.clientHeight]);
107
+ // This will potentially scroll the page to the start when the page loads new data that did not
108
+ // originate from a fetchNextPage action
109
+ (0, react_2.useEffect)(function () {
110
+ if (!isScrollLoad &&
111
+ isReverse &&
112
+ scrollBody.current &&
113
+ prevPosition.current != null &&
114
+ scrollBody.current.clientHeight - prevPosition.current <= 200) {
115
+ prevPosition.current = null;
116
+ scrollToStart();
117
+ }
118
+ }, [isScrollLoad, (_e = scrollBody.current) === null || _e === void 0 ? void 0 : _e.clientHeight]);
100
119
  function scrollToStart() {
101
120
  var _a;
102
121
  var scrollHeight = (scrollBody.current || { scrollHeight: 0 }).scrollHeight;
103
122
  var scrollToValue = isReverse ? scrollHeight : 0;
104
123
  (_a = scrollParent.current) === null || _a === void 0 ? void 0 : _a.scrollTo(0, scrollToValue);
124
+ setScrollInit(true);
105
125
  }
106
126
  // this callback is used and fired based on the state of the element it is attached to
107
127
  return (0, react_2.useCallback)(function (node) {
@@ -113,25 +133,27 @@ function useInfiniteScroll(_a) {
113
133
  }
114
134
  observer.current = new IntersectionObserver(function (entries) {
115
135
  if (entries[0].isIntersecting && hasNextPage && fetchNextPage) {
116
- if (scrollBody.current && isReverse) {
136
+ if (scrollBody.current && isReverse && isScrollInit) {
117
137
  // save the last element, so that we can scroll to it after the new data loads in
118
138
  prevPosition.current = scrollBody.current.clientHeight;
119
139
  }
120
140
  // load the next page
121
141
  fetchNextPage();
142
+ setScrollLoad(true);
122
143
  }
123
144
  }, {
124
145
  root: (scrollParent === null || scrollParent === void 0 ? void 0 : scrollParent.current) || null,
125
146
  threshold: 1.0,
126
147
  });
127
148
  if (node) {
128
- if (isReverse && scrollParent.current && prevPosition.current != null) {
149
+ if (isReverse && scrollParent.current && prevPosition.current != null && isScrollLoad) {
129
150
  // If we had a prev position, then we want to scroll to it
130
151
  scrollParent.current.scrollTo(0, scrollBody.current.clientHeight - prevPosition.current);
131
152
  prevPosition.current = null;
153
+ setScrollLoad(false);
132
154
  }
133
155
  observer.current.observe(node);
134
156
  }
135
- }, [isLoading, isFetching, isReverse, hasNextPage, fetchNextPage, scrollParent, scrollBody]);
157
+ }, [isLoading, isFetching, isReverse, hasNextPage, fetchNextPage, scrollParent, scrollBody, isScrollInit, isScrollLoad]);
136
158
  }
137
159
  var templateObject_1, templateObject_2, templateObject_3, templateObject_4;
@@ -12,7 +12,6 @@ export interface ChatInterfaceProps {
12
12
  handleSend: (message: string) => Promise<boolean>;
13
13
  className?: string;
14
14
  style?: any;
15
- submitting: boolean;
16
15
  placeholder?: string;
17
16
  hasNextPage?: boolean;
18
17
  fetchNextPage?: () => Promise<any> | any;
@@ -20,6 +19,8 @@ export interface ChatInterfaceProps {
20
19
  isLoading: boolean;
21
20
  /** Determines if a data fetch is happening */
22
21
  isFetching: boolean;
22
+ /** Determines if a message submission is happening */
23
+ isSubmitting: boolean;
23
24
  colors?: {
24
25
  user: string;
25
26
  others: string;
@@ -27,4 +28,4 @@ export interface ChatInterfaceProps {
27
28
  /** Needs to take a ref that is used to determine the height of the input component */
28
29
  renderInputComponent?: (ref: Ref<HTMLDivElement>) => ReactNode;
29
30
  }
30
- export default function ChatInterface({ userId, messages, fetchNextPage, handleSend, hasNextPage, className, style, submitting, placeholder, isLoading, isFetching, colors, renderInputComponent, }: ChatInterfaceProps): JSX.Element;
31
+ export default function ChatInterface({ userId, messages, fetchNextPage, handleSend, hasNextPage, className, style, isSubmitting, placeholder, isLoading, isFetching, colors, renderInputComponent, }: ChatInterfaceProps): JSX.Element;
@@ -67,7 +67,7 @@ var react_measure_1 = __importDefault(require("react-measure"));
67
67
  var MessageInput_1 = __importDefault(require("./MessageInput"));
68
68
  var MessageThread_1 = __importDefault(require("./MessageThread"));
69
69
  function ChatInterface(_a) {
70
- var userId = _a.userId, messages = _a.messages, fetchNextPage = _a.fetchNextPage, handleSend = _a.handleSend, hasNextPage = _a.hasNextPage, className = _a.className, style = _a.style, submitting = _a.submitting, placeholder = _a.placeholder, isLoading = _a.isLoading, isFetching = _a.isFetching, colors = _a.colors, renderInputComponent = _a.renderInputComponent;
70
+ var userId = _a.userId, messages = _a.messages, fetchNextPage = _a.fetchNextPage, handleSend = _a.handleSend, hasNextPage = _a.hasNextPage, className = _a.className, style = _a.style, isSubmitting = _a.isSubmitting, placeholder = _a.placeholder, isLoading = _a.isLoading, isFetching = _a.isFetching, colors = _a.colors, renderInputComponent = _a.renderInputComponent;
71
71
  var _b = __read((0, react_2.useState)(''), 2), message = _b[0], setMessage = _b[1];
72
72
  var _c = __read((0, react_2.useState)(-1), 2), inputHeight = _c[0], setInputHeight = _c[1];
73
73
  function handleClickSend() {
@@ -102,7 +102,7 @@ function ChatInterface(_a) {
102
102
  var measureRef = _a.measureRef;
103
103
  return ((0, react_1.jsx)(react_2.Fragment, null,
104
104
  (0, react_1.jsx)(MessageThread_1.default, { userId: userId, messages: messages, inputHeight: inputHeight, hasNextPage: hasNextPage, fetchNextPage: fetchNextPage, isLoading: isLoading, isFetching: isFetching, colors: colors }),
105
- renderInputComponent ? (renderInputComponent(measureRef)) : ((0, react_1.jsx)(MessageInput_1.default, { ref: measureRef, handleClickSend: handleClickSend, message: message, setMessage: setMessage, submitting: submitting, placeholder: placeholder }))));
105
+ renderInputComponent ? (renderInputComponent(measureRef)) : ((0, react_1.jsx)(MessageInput_1.default, { ref: measureRef, handleClickSend: handleClickSend, message: message, setMessage: setMessage, isSubmitting: isSubmitting, placeholder: placeholder }))));
106
106
  })));
107
107
  }
108
108
  exports.default = ChatInterface;
@@ -44,7 +44,7 @@ var ChatInterface_1 = __importDefault(require("./ChatInterface"));
44
44
  function ChatInterface() {
45
45
  var _a = __read((0, react_2.useState)(true), 2), isLoading = _a[0], setLoading = _a[1];
46
46
  var _b = __read((0, react_2.useState)(true), 2), isFetching = _b[0], setFetching = _b[1];
47
- var _c = __read((0, react_2.useState)(false), 2), submitting = _c[0], setSubmitting = _c[1];
47
+ var _c = __read((0, react_2.useState)(false), 2), isSubmitting = _c[0], setSubmitting = _c[1];
48
48
  var _d = __read((0, react_2.useState)([]), 2), messages = _d[0], setMessages = _d[1];
49
49
  var _e = __read((0, react_2.useState)(true), 2), hasMore = _e[0], setHasMore = _e[1];
50
50
  (0, react_2.useEffect)(function () {
@@ -85,12 +85,15 @@ function ChatInterface() {
85
85
  setTimeout(function () {
86
86
  setMessages(__spreadArray(__spreadArray([], __read(messages), false), __read(generateMessagePage()), false));
87
87
  setFetching(false);
88
- }, 1000);
88
+ }, 100);
89
89
  }
90
90
  function handleSend(message) {
91
91
  setSubmitting(true);
92
+ setFetching(true);
92
93
  return new Promise(function (resolve) {
93
94
  setTimeout(function () {
95
+ setSubmitting(false);
96
+ setFetching(false);
94
97
  setMessages(__spreadArray([
95
98
  {
96
99
  id: generateId(),
@@ -100,13 +103,12 @@ function ChatInterface() {
100
103
  content: message,
101
104
  }
102
105
  ], __read(messages), false));
103
- setSubmitting(false);
104
106
  resolve(true);
105
107
  }, 500);
106
108
  });
107
109
  }
108
- return ((0, react_1.jsx)("div", { css: (0, react_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n border: 1px solid #ededed;\n height: 50rem;\n "], ["\n border: 1px solid #ededed;\n height: 50rem;\n "]))) },
109
- (0, react_1.jsx)(ChatInterface_1.default, { userId: "user1", messages: messages, handleSend: handleSend, submitting: submitting, fetchNextPage: loadMore, hasNextPage: hasMore, isLoading: isLoading, isFetching: isFetching })));
110
+ return ((0, react_1.jsx)("div", { css: (0, react_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n border: 1px solid #ededed;\n height: 30rem;\n "], ["\n border: 1px solid #ededed;\n height: 30rem;\n "]))) },
111
+ (0, react_1.jsx)(ChatInterface_1.default, { userId: "user1", messages: messages, handleSend: handleSend, fetchNextPage: loadMore, hasNextPage: hasMore, isLoading: isLoading, isFetching: isFetching, isSubmitting: isSubmitting })));
110
112
  }
111
113
  exports.ChatInterface = ChatInterface;
112
114
  var templateObject_1;
@@ -1,10 +1,9 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- interface Props {
2
+ import { ChatInterfaceProps } from './ChatInterface';
3
+ interface Props extends Pick<ChatInterfaceProps, 'isSubmitting' | 'placeholder'> {
3
4
  handleClickSend: () => Promise<void>;
4
5
  message: string;
5
- placeholder?: string;
6
6
  setMessage: Dispatch<SetStateAction<string>>;
7
- submitting: boolean;
8
7
  }
9
8
  declare const MessageInput: import("react").ForwardRefExoticComponent<Props & import("react").RefAttributes<HTMLDivElement>>;
10
9
  export default MessageInput;
@@ -15,7 +15,7 @@ var react_textarea_autosize_1 = __importDefault(require("react-textarea-autosize
15
15
  var material_1 = require("@mui/material");
16
16
  var icons_material_1 = require("@mui/icons-material");
17
17
  var MessageInput = (0, react_2.forwardRef)(function (_a, ref) {
18
- var handleClickSend = _a.handleClickSend, message = _a.message, placeholder = _a.placeholder, setMessage = _a.setMessage, submitting = _a.submitting;
18
+ var handleClickSend = _a.handleClickSend, message = _a.message, placeholder = _a.placeholder, setMessage = _a.setMessage, isSubmitting = _a.isSubmitting;
19
19
  function handleOnChange(_a) {
20
20
  var value = _a.target.value;
21
21
  setMessage(value);
@@ -42,7 +42,7 @@ var MessageInput = (0, react_2.forwardRef)(function (_a, ref) {
42
42
  var _a, _b;
43
43
  return (0, react_1.css)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',\n 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n resize: none;\n width: calc(100% - 3.5rem);\n outline: 0 none transparent;\n font-size: 16px;\n margin: 0.5rem;\n padding: 0.5rem;\n box-sizing: border-box;\n border-radius: 5px;\n border-color: ", ";\n "], ["\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',\n 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n resize: none;\n width: calc(100% - 3.5rem);\n outline: 0 none transparent;\n font-size: 16px;\n margin: 0.5rem;\n padding: 0.5rem;\n box-sizing: border-box;\n border-radius: 5px;\n border-color: ", ";\n "])), ((_b = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.primary) === null || _b === void 0 ? void 0 : _b.main) || 'hsl(0, 0%, 89%)');
44
44
  }, placeholder: placeholder || 'Type your message here...', value: message, onChange: handleOnChange, onKeyDown: handleOnKeyDown, minRows: 3, maxRows: 8 }),
45
- (0, react_1.jsx)("div", { css: (0, react_1.css)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n height: 2rem;\n width: 2rem;\n padding-right: ", ";\n "], ["\n height: 2rem;\n width: 2rem;\n padding-right: ", ";\n "])), submitting ? '0.5rem' : '0.25rem') }, submitting ? ((0, react_1.jsx)(material_1.CircularProgress, { size: "2rem" })) : ((0, react_1.jsx)(material_1.IconButton, { css: (0, react_1.css)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n height: 100%;\n width: 100%;\n "], ["\n height: 100%;\n width: 100%;\n "]))), onClick: handleOnClickSend, disabled: submitting },
45
+ (0, react_1.jsx)("div", { css: (0, react_1.css)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n height: 2rem;\n width: 2rem;\n padding-right: ", ";\n "], ["\n height: 2rem;\n width: 2rem;\n padding-right: ", ";\n "])), isSubmitting ? '0.5rem' : '0.25rem') }, isSubmitting ? ((0, react_1.jsx)(material_1.CircularProgress, { size: "2rem" })) : ((0, react_1.jsx)(material_1.IconButton, { css: (0, react_1.css)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n height: 100%;\n width: 100%;\n "], ["\n height: 100%;\n width: 100%;\n "]))), onClick: handleOnClickSend, disabled: isSubmitting },
46
46
  (0, react_1.jsx)(icons_material_1.Send, null))))));
47
47
  });
48
48
  exports.default = MessageInput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vendorflow/components",
3
- "version": "2.0.38",
3
+ "version": "2.0.42",
4
4
  "description": "React components for vendorflow",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",