Skip to content

Commit 676cc0e

Browse files
authored
feat: unify send btn display condition (#487)
### Description Of Changes Resolving [UIKIT-3438](https://sendbird.atlassian.net/browse/UIKIT-3438) Here's what we're having ATM. We can send the empty message which is consisted of only white spaces. Also, a sent message which contains white spaces at the beginning of it is shown like it's trimmed. ![before](https://user-images.githubusercontent.com/10060731/230881273-f3c93b4c-cae7-4630-8177-8edd7caa7423.gif) So two small things have been changed on displayed message & message input each. - New line, spaces only text should not show sending button (뉴 라인, 스페이스로만 이루어진 텍스트는 전송 버튼이 나타나면 안됨.) - No trim before sending (별도의 trim 없이 문자열 그대로 전송) ![after](https://user-images.githubusercontent.com/10060731/230880829-1cfa80a6-358d-4962-b84f-40654d462408.gif) Also, added a new library [ts-pattern](https://github.com/gvergnaud/ts-pattern) which's bundle size can be found here https://bundlephobia.com/package/[email protected]
1 parent 4237c04 commit 676cc0e

File tree

15 files changed

+117
-53
lines changed

15 files changed

+117
-53
lines changed

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
"css-loader": "^3.4.2",
111111
"dts-bundle-generator": "^6.5.0",
112112
"eslint": "^6.8.0",
113+
"ts-pattern": "^4.2.2",
113114
"eslint-config-airbnb": "^18.0.1",
114115
"eslint-plugin-babel": "^5.3.1",
115116
"eslint-plugin-import": "^2.20.0",

rollup.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ module.exports = ({
4747
'css-vars-ponyfill',
4848
'date-fns',
4949
'dompurify',
50+
// we do not add ts-pattern as dep to avoid conflict with client base
51+
'ts-pattern',
5052
],
5153
plugins: [
5254
postcss({

src/smart-components/Channel/context/hooks/useSendMessageCallback.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ export default function useSendMessageCallback({
2727
} = props;
2828
const createParamsDefault = () => {
2929
const params = {};
30-
params.message = message?.trim() || message;
30+
params.message = message;
3131
// if (isMentionEnabled && mentionedUserIds?.length > 0) {
3232
if (isMentionEnabled && mentionedUsers?.length > 0) {
3333
// params.mentionedUserIds = mentionedUserIds;
3434
params.mentionedUsers = mentionedUsers;
3535
}
3636
// if (isMentionEnabled && mentionTemplate && mentionedUserIds?.length > 0) {
3737
if (isMentionEnabled && mentionTemplate && mentionedUsers?.length > 0) {
38-
params.mentionedMessageTemplate = mentionTemplate?.trim() || mentionTemplate;
38+
params.mentionedMessageTemplate = mentionTemplate;
3939
}
4040
if (quoteMessage) {
4141
params.isReplyToChannel = true;
Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import React from 'react';
22
import { UserMessage } from '@sendbird/chat/message';
3+
import { match } from 'ts-pattern';
34

4-
import { TOKEN_TYPES, Token } from '../../utils/tokens/types'
5+
import { TOKEN_TYPES, Token } from '../../utils/tokens/types';
56
import { useMessageContext } from '../../context/MessageProvider';
67
import { keyGenerator } from '../../utils/tokens/keyGenerator';
78
import MentionLabel from '../../../../ui/MentionLabel';
89
import { USER_MENTION_PREFIX } from '../../consts';
910
import LinkLabel from '../../../../ui/LinkLabel';
10-
import { LabelTypography } from '../../../../ui//Label';
11+
import { LabelTypography } from '../../../../ui/Label';
12+
import { getWhiteSpacePreservedText } from '../../utils/tokens/tokenize';
1113

1214
export type TextFragmentProps = {
1315
tokens: Token[];
14-
}
16+
};
1517

1618
export default function TextFragment({
1719
tokens,
@@ -21,43 +23,35 @@ export default function TextFragment({
2123
const message = messageStore?.message as UserMessage;
2224
const isByMe = messageStore?.isByMe;
2325
const { updatedAt, createdAt } = message;
26+
2427
return (
2528
<>
26-
{
27-
tokens?.map((token, idx) => {
28-
const key = keyGenerator(createdAt, updatedAt, idx);
29-
switch (token.type) {
30-
case TOKEN_TYPES.mention:
31-
return (
32-
<span className="sendbird-word" key={key}>
33-
<MentionLabel
34-
mentionTemplate={USER_MENTION_PREFIX}
35-
mentionedUserId={token.userId}
36-
mentionedUserNickname={token.value}
37-
isByMe={isByMe}
38-
/>
39-
</span>
40-
);
41-
case TOKEN_TYPES.url:
42-
return (
43-
<span className='sendbird-word' key={key}>
44-
<LinkLabel
45-
className="sendbird-word__url"
46-
src={token.value}
47-
type={LabelTypography.BODY_1}
48-
>
49-
{token.value}
50-
</LinkLabel>
51-
</span>
52-
);
53-
case TOKEN_TYPES.string:
54-
default:
55-
return (
56-
<React.Fragment key={key}>{token.value}</React.Fragment>
57-
);
58-
}
59-
})
60-
}
29+
{tokens?.map((token, idx) => {
30+
const key = keyGenerator(createdAt, updatedAt, idx);
31+
return match(token.type)
32+
.with(TOKEN_TYPES.mention, () => (
33+
<span className="sendbird-word" key={key}>
34+
<MentionLabel
35+
mentionTemplate={USER_MENTION_PREFIX}
36+
mentionedUserId={token.userId}
37+
mentionedUserNickname={token.value}
38+
isByMe={isByMe}
39+
/>
40+
</span>
41+
))
42+
.with(TOKEN_TYPES.url, () => (
43+
<span className="sendbird-word" key={key}>
44+
<LinkLabel
45+
className="sendbird-word__url"
46+
src={token.value}
47+
type={LabelTypography.BODY_1}
48+
>
49+
{token.value}
50+
</LinkLabel>
51+
</span>
52+
))
53+
.otherwise(() => <React.Fragment key={key}>{getWhiteSpacePreservedText(token.value)}</React.Fragment>);
54+
})}
6155
</>
6256
);
6357
}

src/smart-components/Message/utils/tokens/__tests__/tokenizeUtils.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
identifyMentions,
55
identifyUrlsAndStrings,
66
combineNearbyStrings,
7+
getWhiteSpacePreservedText,
78
} from '../tokenize';
89
import { Token, UndeterminedToken } from '../types';
910

@@ -101,3 +102,16 @@ describe('combineNearbyStrings', () => {
101102
expect(result).toEqual(expected);
102103
});
103104
});
105+
106+
describe('getWhiteSpacePreservedText', () => {
107+
it('should keep the leading and trailing white spaces', () => {
108+
const text = ' aaa ';
109+
const result = getWhiteSpacePreservedText(text);
110+
expect(result).toEqual(' aaa\u00A0');
111+
});
112+
it('should keep the new lines', () => {
113+
const text = ' aaa\naa';
114+
const result = getWhiteSpacePreservedText(text);
115+
expect(result).toEqual(' aaa\naa');
116+
});
117+
});

src/smart-components/Message/utils/tokens/tokenize.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,16 @@ export function tokenizeMessage({
9999
return result;
100100
}
101101

102+
/**
103+
* To preserve the original text which has
104+
* leading & trailing white spaces & new-lines in the middle
105+
* @link https://sendbird.slack.com/archives/GPGHESTL3/p1681180484341369
106+
*/
107+
export function getWhiteSpacePreservedText(text: string): string {
108+
return text
109+
// convert any space or tab into the non-breaking space
110+
// to preserve the leading & trailing white spaces
111+
.replace(/(?<!^)[ \t]+/g, '\u00A0')
112+
// and keep the new line as well
113+
.replace(/\n/g, '\n');
114+
}

src/smart-components/Message/utils/tokens/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export type StringToken = {
1616
};
1717

1818
export type MentionToken = {
19-
type: typeof TOKEN_TYPES.mention;
19+
type: TokenType;
2020
value: string;
2121
userId: string;
2222
};

src/smart-components/OpenChannel/context/hooks/useSendMessageCallback.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function useSendMessageCallback(
2727
if (sdk) {
2828
const text = messageInputRef.current.innerText;
2929
const createParamsDefault = (txt: string | number): UserMessageCreateParams => {
30-
const message = (txt as string)?.trim() || txt as string;
30+
const message = txt as string;
3131
const params: UserMessageCreateParams = {
3232
message: message,
3333
};

src/smart-components/Thread/context/hooks/useSendUserMessageCallback.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ export default function useSendUserMessageCallback({
3333
} = props;
3434
const createDefaultParams = () => {
3535
const params = {} as UserMessageCreateParams;
36-
params.message = message?.trim() || message;
36+
params.message = message;
3737
if (isMentionEnabled && mentionedUsers?.length > 0) {
3838
params.mentionedUsers = mentionedUsers;
3939
}
4040
if (isMentionEnabled && mentionTemplate && mentionedUsers?.length > 0) {
41-
params.mentionedMessageTemplate = mentionTemplate?.trim() || mentionTemplate;
41+
params.mentionedMessageTemplate = mentionTemplate;
4242
}
4343
if (quoteMessage) {
4444
params.isReplyToChannel = true;

0 commit comments

Comments
 (0)