Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32202973
D8027.1765114494.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D8027.1765114494.diff
View Options
diff --git a/web/chat/chat-input-text-area.react.js b/web/chat/chat-input-text-area.react.js
--- a/web/chat/chat-input-text-area.react.js
+++ b/web/chat/chat-input-text-area.react.js
@@ -12,8 +12,11 @@
+currentText: string,
+setCurrentText: (text: string) => void,
+onChangePosition: () => void,
+ +maxHeight?: number,
};
+export const defaultMaxHeight = 150;
+
const ChatInputTextArea: React.ComponentType<Props> = React.memo<Props>(
function ChatInputTextArea(props: Props) {
const {
@@ -23,6 +26,7 @@
send,
setCurrentText,
onChangePosition,
+ maxHeight = defaultMaxHeight,
} = props;
const textareaRef = React.useRef(null);
@@ -53,11 +57,11 @@
const textarea = textareaRef.current;
if (textarea) {
textarea.style.height = 'auto';
- const newHeight = Math.min(textarea.scrollHeight, 150);
+ const newHeight = Math.min(textarea.scrollHeight, maxHeight);
textarea.style.height = `${newHeight}px`;
}
onChangePosition();
- }, [onChangePosition]);
+ }, [maxHeight, onChangePosition]);
React.useEffect(() => {
focusAndUpdateText();
diff --git a/web/chat/chat-message-list.react.js b/web/chat/chat-message-list.react.js
--- a/web/chat/chat-message-list.react.js
+++ b/web/chat/chat-message-list.react.js
@@ -28,8 +28,11 @@
useDispatchActionPromise,
} from 'lib/utils/action-utils.js';
+import { defaultMaxHeight } from './chat-input-text-area.react.js';
import css from './chat-message-list.css';
+import type { ScrollToMessageCallback } from './edit-message-provider.js';
import { useEditModalContext } from './edit-message-provider.js';
+import { editBoxHeight, editBoxTopMargin } from './edit-text-message.react.js';
import { MessageListContext } from './message-list-types.js';
import Message from './message.react.js';
import RelationshipPrompt from './relationship-prompt/relationship-prompt.js';
@@ -64,18 +67,39 @@
+clearTooltip: () => mixed,
+oldestMessageServerID: ?string,
+isEditState: boolean,
+ +addScrollToMessageListener: ScrollToMessageCallback => mixed,
+ +removeScrollToMessageListener: ScrollToMessageCallback => mixed,
};
type Snapshot = {
+scrollTop: number,
+scrollHeight: number,
};
-class ChatMessageList extends React.PureComponent<Props> {
+
+type State = {
+ +scrollTimeoutID: ?TimeoutID,
+ +scrollingEndCallback: ?() => mixed,
+};
+
+class ChatMessageList extends React.PureComponent<Props, State> {
container: ?HTMLDivElement;
messageContainer: ?HTMLDivElement;
loadingFromScroll = false;
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ scrollTimeoutID: null,
+ scrollingEndCallback: null,
+ };
+ }
+
componentDidMount() {
this.scrollToBottom();
+ this.props.addScrollToMessageListener(this.scrollToMessage);
+ }
+
+ componentWillUnmount() {
+ this.props.removeScrollToMessageListener(this.scrollToMessage);
}
getSnapshotBeforeUpdate(prevProps: Props) {
@@ -178,6 +202,95 @@
);
};
+ scrollingEndCallbackWrapper = (
+ messageID: string,
+ callback: (maxHeight: number) => mixed,
+ ): (() => mixed) => {
+ return () => {
+ const maxHeight = this.getMaxEditTextAreaHeight(messageID);
+ callback(maxHeight);
+ };
+ };
+
+ scrollToMessage = (
+ messageID: string,
+ callback: (maxHeight: number) => mixed,
+ ) => {
+ const element = document.getElementById(messageID);
+ if (!element) {
+ return;
+ }
+ if (!this.willMessageEditWindowOverflow(messageID)) {
+ const maxHeight = this.getMaxEditTextAreaHeight(messageID);
+ callback(maxHeight);
+ return;
+ }
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ this.setState(
+ {
+ scrollingEndCallback: this.scrollingEndCallbackWrapper(
+ messageID,
+ callback,
+ ),
+ },
+ () => {
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ this.onScroll();
+ },
+ );
+ };
+
+ getMaxEditTextAreaHeight = (messageID: string): number => {
+ const { messageContainer } = this;
+ if (!messageContainer) {
+ return defaultMaxHeight;
+ }
+ const messageElement = document.getElementById(messageID);
+ if (!messageElement) {
+ console.log(`couldn't find the message element`);
+ return defaultMaxHeight;
+ }
+
+ const msgPos = messageElement.getBoundingClientRect();
+ const containerPos = messageContainer.getBoundingClientRect();
+
+ const messageBottom = msgPos.bottom;
+ const containerTop = containerPos.top;
+
+ const maxHeight =
+ messageBottom - containerTop - editBoxHeight - editBoxTopMargin;
+
+ return maxHeight;
+ };
+
+ willMessageEditWindowOverflow(messageID: string) {
+ const { messageContainer } = this;
+ if (!messageContainer) {
+ return false;
+ }
+ const messageElement = document.getElementById(messageID);
+ if (!messageElement) {
+ console.log(`couldn't find the message element`);
+ return false;
+ }
+
+ const msgPos = messageElement.getBoundingClientRect();
+ const containerPos = messageContainer.getBoundingClientRect();
+
+ const messageHeight = msgPos.height;
+ const offset = Math.max(
+ 0,
+ defaultMaxHeight + editBoxHeight - messageHeight,
+ );
+
+ const messageTop = msgPos.top - offset;
+ const messageBottom = msgPos.bottom;
+ const containerTop = containerPos.top;
+ const containerBottom = containerPos.bottom;
+
+ return messageBottom > containerBottom || messageTop < containerTop;
+ }
+
render() {
const { messageListData, threadInfo, inputState } = this.props;
if (!messageListData) {
@@ -221,6 +334,17 @@
}
this.props.clearTooltip();
this.possiblyLoadMoreMessages();
+
+ if (this.state.scrollTimeoutID) {
+ clearTimeout(this.state.scrollTimeoutID);
+ }
+ const scrollTimeoutID = setTimeout(() => {
+ if (this.state.scrollingEndCallback) {
+ this.state.scrollingEndCallback();
+ }
+ this.setState({ scrollingEndCallback: null });
+ }, 100);
+ this.setState({ scrollTimeoutID });
};
async possiblyLoadMoreMessages() {
@@ -313,7 +437,11 @@
const oldestMessageServerID = useOldestMessageServerID(threadInfo.id);
- const { editState } = useEditModalContext();
+ const {
+ editState,
+ addScrollToMessageListener,
+ removeScrollToMessageListener,
+ } = useEditModalContext();
const isEditState = editState !== null;
return (
@@ -330,6 +458,8 @@
clearTooltip={clearTooltip}
oldestMessageServerID={oldestMessageServerID}
isEditState={isEditState}
+ addScrollToMessageListener={addScrollToMessageListener}
+ removeScrollToMessageListener={removeScrollToMessageListener}
/>
</MessageListContext.Provider>
);
diff --git a/web/chat/composed-message.react.js b/web/chat/composed-message.react.js
--- a/web/chat/composed-message.react.js
+++ b/web/chat/composed-message.react.js
@@ -11,6 +11,7 @@
import { useStringForUser } from 'lib/hooks/ens-cache.js';
import { type ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
import { getMessageLabel } from 'lib/shared/edit-messages-utils.js';
+import { messageKey } from 'lib/shared/message-utils.js';
import { assertComposableMessageType } from 'lib/types/message-types.js';
import { type ThreadInfo } from 'lib/types/thread-types.js';
@@ -188,7 +189,11 @@
onMouseLeave={this.props.onMouseLeave}
>
{pinIcon}
- <div className={messageBoxClassName} style={messageBoxStyle}>
+ <div
+ className={messageBoxClassName}
+ style={messageBoxStyle}
+ id={messageKey(item.messageInfo)}
+ >
{this.props.children}
</div>
</div>
diff --git a/web/chat/edit-message-provider.js b/web/chat/edit-message-provider.js
--- a/web/chat/edit-message-provider.js
+++ b/web/chat/edit-message-provider.js
@@ -22,8 +22,14 @@
+editedMessageDraft: ?string,
+isError: boolean,
+position?: ModalPosition,
+ +maxHeight: number,
};
+export type ScrollToMessageCallback = (
+ messageKey: string,
+ callback: (maxHeight: number) => void,
+) => void;
+
type EditModalContextType = {
+renderEditModal: (params: EditState) => void,
+clearEditModal: () => void,
@@ -31,6 +37,9 @@
+setDraft: string => void,
+setError: boolean => void,
+updatePosition: ModalPosition => void,
+ +scrollToMessage: ScrollToMessageCallback,
+ +addScrollToMessageListener: ScrollToMessageCallback => void,
+ +removeScrollToMessageListener: ScrollToMessageCallback => void,
};
const EditModalContext: React.Context<EditModalContextType> =
@@ -41,6 +50,9 @@
setDraft: () => {},
setError: () => {},
updatePosition: () => {},
+ scrollToMessage: () => {},
+ addScrollToMessageListener: () => {},
+ removeScrollToMessageListener: () => {},
});
type Props = {
@@ -51,6 +63,9 @@
const [editState, setEditState] = React.useState<?EditState>(null);
+ const [scrollToMessageCallbacks, setScrollToMessageCallbacks] =
+ React.useState<Array<ScrollToMessageCallback>>([]);
+
const clearEditModal = React.useCallback(() => {
setEditState(null);
}, []);
@@ -118,6 +133,31 @@
[editState, setEditState],
);
+ const scrollToMessage: ScrollToMessageCallback = React.useCallback(
+ (messageKey: string, callback: (maxHeight: number) => void) => {
+ scrollToMessageCallbacks.forEach((callback2: ScrollToMessageCallback) =>
+ callback2(messageKey, callback),
+ );
+ },
+ [scrollToMessageCallbacks],
+ );
+
+ const addScrollToMessageListener = React.useCallback(
+ (callback: ScrollToMessageCallback): void => {
+ setScrollToMessageCallbacks([...scrollToMessageCallbacks, callback]);
+ },
+ [scrollToMessageCallbacks],
+ );
+
+ const removeScrollToMessageListener = React.useCallback(
+ (callback: ScrollToMessageCallback) => {
+ setScrollToMessageCallbacks(
+ scrollToMessageCallbacks.filter(candidate => candidate !== callback),
+ );
+ },
+ [scrollToMessageCallbacks],
+ );
+
const value = React.useMemo(
() => ({
renderEditModal,
@@ -126,6 +166,9 @@
setDraft,
setError,
updatePosition,
+ scrollToMessage,
+ addScrollToMessageListener,
+ removeScrollToMessageListener,
}),
[
renderEditModal,
@@ -134,6 +177,9 @@
setDraft,
setError,
updatePosition,
+ scrollToMessage,
+ addScrollToMessageListener,
+ removeScrollToMessageListener,
],
);
diff --git a/web/chat/edit-text-message.react.js b/web/chat/edit-text-message.react.js
--- a/web/chat/edit-text-message.react.js
+++ b/web/chat/edit-text-message.react.js
@@ -28,6 +28,9 @@
backgroundColor: 'transparent',
};
+export const editBoxTopMargin = 10;
+export const editBoxHeight = 84;
+
function EditTextMessage(props: Props): React.Node {
const { background, threadInfo, item } = props;
const { editState, clearEditModal, setDraft, setError, updatePosition } =
@@ -138,6 +141,8 @@
[css.backgroundEditMessage]: background,
});
+ const maxTextAreaHeight = editState?.maxHeight;
+
return (
<div className={containerStyle} ref={myRef}>
<div className={cssInputBar.inputBarTextInput}>
@@ -147,6 +152,7 @@
setCurrentText={setDraft}
onChangePosition={updateDimensions}
send={checkAndEdit}
+ maxHeight={maxTextAreaHeight}
/>
</div>
<div className={css.bottomRow}>
diff --git a/web/utils/tooltip-action-utils.js b/web/utils/tooltip-action-utils.js
--- a/web/utils/tooltip-action-utils.js
+++ b/web/utils/tooltip-action-utils.js
@@ -7,7 +7,7 @@
import { useModalContext } from 'lib/components/modal-provider.react.js';
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js';
import { useCanEditMessage } from 'lib/shared/edit-messages-utils.js';
-import { createMessageReply } from 'lib/shared/message-utils.js';
+import { createMessageReply, messageKey } from 'lib/shared/message-utils.js';
import { useCanCreateReactionFromMessage } from 'lib/shared/reaction-utils.js';
import {
threadHasPermission,
@@ -233,7 +233,7 @@
const { messageInfo } = item;
const canEditMessage = useCanEditMessage(threadInfo, messageInfo);
- const { renderEditModal } = useEditModalContext();
+ const { renderEditModal, scrollToMessage } = useEditModalContext();
const { clearTooltip } = useTooltipContext();
return React.useMemo(() => {
@@ -242,13 +242,16 @@
}
const buttonContent = <CommIcon icon="edit-filled" size={18} />;
const onClickEdit = () => {
+ const callback = (maxHeight: number) =>
+ renderEditModal({
+ messageInfo: item,
+ threadInfo,
+ isError: false,
+ editedMessageDraft: messageInfo.text,
+ maxHeight: maxHeight,
+ });
clearTooltip();
- renderEditModal({
- messageInfo: item,
- threadInfo,
- isError: false,
- editedMessageDraft: messageInfo.text,
- });
+ scrollToMessage(messageKey(messageInfo), callback);
};
return {
actionButtonContent: buttonContent,
@@ -259,8 +262,9 @@
canEditMessage,
clearTooltip,
item,
- messageInfo.text,
+ messageInfo,
renderEditModal,
+ scrollToMessage,
threadInfo,
]);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 7, 1:34 PM (20 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5844325
Default Alt Text
D8027.1765114494.diff (13 KB)
Attached To
Mode
D8027: [web] Scrolling to the edited message when it overflows
Attached
Detach File
Event Timeline
Log In to Comment