Skip to content

Commit

Permalink
feat: [Chat] Scroll to the bottom while focusing
Browse files Browse the repository at this point in the history
  • Loading branch information
akai committed Sep 18, 2021
1 parent 0944578 commit e8c4107
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 21 deletions.
14 changes: 8 additions & 6 deletions demo/src/demo/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,32 @@ const initialMessages: MessageWithoutId[] = [
const defaultQuickReplies = [
{
icon: 'message',
name: '联系人工服务',
name: '1联系人工服务',
code: 'q1',
isNew: true,
isHighlight: true,
},
{
name: '短语1',
name: '2短语',
code: 'q2',
isNew: true,
},
{
name: '强快捷短语',
name: '3强快捷短语',
code: 'q3',
isHighlight: true,
},
{
name: '弱快捷短语',
name: '4弱快捷短语',
code: 'q4',
},
{
name: '强快捷短语',
name: '5强快捷短语',
code: 'q5',
isHighlight: true,
},
{
name: '弱快捷短语',
name: '6弱快捷短语',
code: 'q6',
},
];
Expand All @@ -92,6 +92,7 @@ export default () => {
// 消息列表
const { messages, appendMsg, setTyping, prependMsgs } = useMessages(initialMessages);
const { quickReplies, replace } = useQuickReplies(defaultQuickReplies);
const msgRef = React.useRef(null);

// 发送回调
function handleSend(type: string, val: string) {
Expand Down Expand Up @@ -278,6 +279,7 @@ export default () => {
img: 'https://gw.alicdn.com/tfs/TB1eDjNj.T1gK0jSZFrXXcNCXXa-80-80.png',
},
]}
messagesRef={msgRef}
onToolbarClick={handleToolbarClick}
recorder={{ canRecord: true }}
wideBreakpoint="600px"
Expand Down
31 changes: 22 additions & 9 deletions src/components/Chat/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import React from 'react';
import { LocaleProvider } from '../LocaleProvider';
import { Navbar, NavbarProps } from '../Navbar';
import { MessageContainer, MessageContainerProps } from '../MessageContainer';
import {
MessageContainer,
MessageContainerProps,
MessageContainerHandle,
} from '../MessageContainer';
import { QuickReplies, QuickReplyItemProps } from '../QuickReplies';
import { Composer as DComposer, ComposerProps } from '../Composer';
import { Composer as DComposer, ComposerProps, ComposerHandle } from '../Composer';

export type ChatProps = ComposerProps &
export type ChatProps = Omit<ComposerProps, 'onFocus' | 'onChange' | 'onBlur'> &
MessageContainerProps & {
/**
* 宽版模式断点
Expand Down Expand Up @@ -38,7 +42,7 @@ export type ChatProps = ComposerProps &
/**
* 消息列表 ref
*/
messagesRef?: any; // FIXME
messagesRef?: React.RefObject<MessageContainerHandle>;
/**
* 下拉加载回调
*/
Expand Down Expand Up @@ -78,7 +82,7 @@ export type ChatProps = ComposerProps &
/**
* 输入区 ref
*/
composerRef?: any;
composerRef?: React.RefObject<ComposerHandle>;
/**
* 输入框初始内容
*/
Expand All @@ -90,15 +94,15 @@ export type ChatProps = ComposerProps &
/**
* 输入框聚焦回调
*/
onInputFocus?: () => void;
onInputFocus?: ComposerProps['onFocus'];
/**
* 输入框更新回调
*/
onInputChange?: () => void;
onInputChange?: ComposerProps['onChange'];
/**
* 输入框失去焦点回调
*/
onInputBlur?: () => void;
onInputBlur?: ComposerProps['onBlur'];
/**
* 发送消息回调
*/
Expand Down Expand Up @@ -175,6 +179,15 @@ export const Chat = React.forwardRef<HTMLDivElement, ChatProps>((props, ref) =>
Composer = DComposer,
} = props;

function handleInputFocus(e: React.FocusEvent<HTMLTextAreaElement>) {
if (messagesRef && messagesRef.current) {
messagesRef.current.scrollToEnd({ animated: false });
}
if (onInputFocus) {
onInputFocus(e);
}
}

return (
<LocaleProvider locale={locale} locales={locales}>
<div className="ChatApp" ref={ref}>
Expand Down Expand Up @@ -211,7 +224,7 @@ export const Chat = React.forwardRef<HTMLDivElement, ChatProps>((props, ref) =>
toolbar={toolbar}
onToolbarClick={onToolbarClick}
onInputTypeChange={onInputTypeChange}
onFocus={onInputFocus}
onFocus={handleInputFocus}
onChange={onInputChange}
onBlur={onInputBlur}
onSend={onSend}
Expand Down
10 changes: 9 additions & 1 deletion src/components/Chat/style.less
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,18 @@
-webkit-tap-highlight-color: transparent;
}

.S--noHomeBar {
.S--focusing {
--safe-bottom: 0px;
}

@media (hover: none) {
.S--focusing {
.MessageList {
margin-top: 75vh;
}
}
}

.ChatFooter {
position: relative;
z-index: @zindex-footer;
Expand Down
6 changes: 3 additions & 3 deletions src/components/Composer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Action } from './Action';
import riseInput from './riseInput';
import toggleClass from '../../utils/toggleClass';

const NO_HOME_BAR = 'S--noHomeBar';
const FOCUSING_CLASS = 'S--focusing';

export type InputType = 'voice' | 'text';

Expand Down Expand Up @@ -136,7 +136,7 @@ export const Composer = React.forwardRef<ComposerHandle, ComposerProps>((props,
const handleInputFocus = useCallback(
(e: React.FocusEvent<HTMLTextAreaElement>) => {
clearTimeout(blurTimer.current);
toggleClass(NO_HOME_BAR, true);
toggleClass(FOCUSING_CLASS, true);
focused.current = true;

if (onFocus) {
Expand All @@ -149,7 +149,7 @@ export const Composer = React.forwardRef<ComposerHandle, ComposerProps>((props,
const handleInputBlur = useCallback(
(e: React.FocusEvent<HTMLTextAreaElement>) => {
blurTimer.current = setTimeout(() => {
toggleClass(NO_HOME_BAR, false);
toggleClass(FOCUSING_CLASS, false);
focused.current = false;
}, 0);

Expand Down
4 changes: 2 additions & 2 deletions src/components/MessageContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export interface MessageContainerProps {
renderBeforeMessageList?: () => React.ReactNode;
}

interface MessageContainerHandle {
export interface MessageContainerHandle {
ref: React.RefObject<HTMLDivElement>;
scrollToEnd: () => void;
scrollToEnd: (options?: { animated?: boolean }) => void;
}

export const MessageContainer = React.forwardRef<MessageContainerHandle, MessageContainerProps>(
Expand Down

0 comments on commit e8c4107

Please sign in to comment.