Skip to content

Commit da293f0

Browse files
authored
fix: align textarea placeholder and text with the surroundings (#3052)
1 parent b7c33c8 commit da293f0

File tree

6 files changed

+79
-15
lines changed

6 files changed

+79
-15
lines changed

src/components/MessageComposer/CommandChip.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { useMessageComposerController } from './hooks';
2-
import { useStateStore } from '../../store';
32
import type { TextComposerState } from 'stream-chat';
43
import { IconCrossMedium, IconThunder } from '../Icons';
54
import { useMessageComposerContext } from '../../context';
65

7-
const textComposerStateSelector = ({ command }: TextComposerState) => ({ command });
6+
export type CommandChipProps = {
7+
command?: TextComposerState['command'];
8+
};
89

9-
export const CommandChip = () => {
10+
export const CommandChip = ({ command }: CommandChipProps) => {
1011
const { textComposer } = useMessageComposerController();
1112
const { textareaRef } = useMessageComposerContext();
12-
const { command } = useStateStore(textComposer.state, textComposerStateSelector);
1313
if (!command) return null;
1414

1515
return (

src/components/MessageComposer/MessageComposerUI.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,11 @@ export const MessageComposerUI = () => {
174174
<div className='str-chat__message-composer-controls'>
175175
<div className='str-chat__message-composer-controls__text-composition-controls'>
176176
<div className='str-chat__message-composer-controls__text-composition-controls__text'>
177-
<div className='str-chat__message-composer-controls__text-composition-controls__command-chip-container'>
178-
<CommandChip />
179-
</div>
177+
{command && (
178+
<div className='str-chat__message-composer-controls__text-composition-controls__command-chip-container'>
179+
<CommandChip command={command} />
180+
</div>
181+
)}
180182
<TextareaComposer />
181183
</div>
182184
<SendToChannelCheckbox />
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from 'react';
2+
import { fireEvent, render, screen } from '@testing-library/react';
3+
import { CommandChip } from '../CommandChip';
4+
5+
const setCommandMock = vi.fn();
6+
const focusMock = vi.fn();
7+
8+
vi.mock('../hooks', () => ({
9+
useMessageComposerController: () => ({
10+
textComposer: {
11+
setCommand: setCommandMock,
12+
},
13+
}),
14+
}));
15+
16+
vi.mock('../../../context', () => ({
17+
useMessageComposerContext: () => ({
18+
textareaRef: {
19+
current: {
20+
focus: focusMock,
21+
},
22+
},
23+
}),
24+
}));
25+
26+
describe('CommandChip', () => {
27+
beforeEach(() => {
28+
vi.clearAllMocks();
29+
});
30+
31+
it('does not render when command is undefined', () => {
32+
const { container } = render(<CommandChip command={undefined} />);
33+
expect(container.firstChild).toBeNull();
34+
});
35+
36+
it('renders command name when command is defined', () => {
37+
render(<CommandChip command={{ name: 'giphy' }} />);
38+
expect(screen.getByText('giphy')).toBeInTheDocument();
39+
});
40+
41+
it('clears command and focuses textarea on close click', () => {
42+
const { container } = render(<CommandChip command={{ name: 'giphy' }} />);
43+
const closeButton = container.querySelector('.str-chat__command-chip__close-button');
44+
45+
expect(closeButton).toBeInTheDocument();
46+
fireEvent.click(closeButton);
47+
48+
expect(setCommandMock).toHaveBeenCalledWith(null);
49+
expect(focusMock).toHaveBeenCalledTimes(1);
50+
});
51+
});

src/components/MessageComposer/styling/CommandChip.scss

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@
22

33
.str-chat__command-chip {
44
display: flex;
5-
padding: var(--spacing-xxs) var(--spacing-sm);
5+
padding: var(--spacing-xxs) var(--spacing-xs);
66
justify-content: center;
77
align-items: center;
88
gap: var(--spacing-xxs);
99
border-radius: var(--radius-max);
10-
height: fit-content;
1110

1211
color: var(--text-inverse);
1312
background-color: var(--background-core-inverse, var(--slate-900));
1413
text-transform: uppercase;
15-
font-size: var(--typography-font-size-xs);
16-
font-weight: var(--typography-font-weight-semi-bold);
17-
line-height: var(--typography-line-height-tight);
14+
font: var(--str-chat__metadata-emphasis-text);
1815

1916
.str-chat__command-chip__close-button {
2017
@include utils.button-reset;

src/components/MessageComposer/styling/MessageComposer.scss

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,24 @@
180180
flex: 1;
181181
display: flex;
182182
flex-direction: column;
183+
min-height: $controls-containers-min-height;
184+
justify-content: center;
183185
gap: var(--spacing-sm);
186+
187+
.str-chat__message-composer-controls__text-composition-controls__command-chip-container {
188+
height: 100%;
189+
display: flex;
190+
align-items: flex-end;
191+
flex: 0 0 auto;
192+
align-self: flex-end;
193+
}
184194
}
185195

186196
.str-chat__message-composer-controls__text-composition-controls__text {
187197
display: flex;
188-
align-items: end;
198+
align-items: center;
199+
width: 100%;
200+
min-width: 0;
189201
gap: var(--spacing-xxs);
190202
}
191203

@@ -210,10 +222,11 @@
210222

211223
.str-chat__textarea {
212224
flex: 1;
225+
min-width: 0;
213226
position: relative;
214227
display: flex;
215228
align-items: center;
216-
margin-inline: var(--spacing-xxs) var(--spacing-xs);
229+
width: 100%;
217230

218231
textarea {
219232
@include utils.component-layer-overrides('message-textarea');

src/context/ComponentContext.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import type { StopAIGenerationButtonProps } from '../components/MessageComposer/
7171
import type { VideoPlayerProps } from '../components/VideoPlayer';
7272
import type { EditedMessagePreviewProps } from '../components/MessageComposer/EditedMessagePreview';
7373
import type { FileIconProps } from '../components/FileIcon/FileIcon';
74+
import type { CommandChipProps } from '../components/MessageComposer/CommandChip';
7475

7576
export type ComponentContextValue = {
7677
/** Custom UI component to display additional message composer action buttons left to the textarea, defaults to and accepts same props as: [AdditionalMessageComposerActions](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageComposer/MessageComposerActions.tsx) */
@@ -110,7 +111,7 @@ export type ComponentContextValue = {
110111
/** Custom UI component to display the channel preview in the list, defaults to and accepts same props as: [ChannelListItemUI](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelPreview/ChannelListItemUI.tsx) */
111112
ChannelListItemUI?: React.ComponentType<ChannelListItemUIProps>;
112113
/** Custom UI component to display command chip, defaults to and accepts same props as: [CommandChip](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageComposer/CommandChip.tsx) */
113-
CommandChip?: React.ComponentType;
114+
CommandChip?: React.ComponentType<CommandChipProps>;
114115
/** Custom UI component to display the slow mode cooldown timer, defaults to and accepts same props as: [CooldownTimer](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageComposer/CooldownTimer.tsx) */
115116
CooldownTimer?: React.ComponentType;
116117
/** Custom UI component for date separators, defaults to and accepts same props as: [DateSeparator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/DateSeparator.tsx) */

0 commit comments

Comments
 (0)