feat: started adding rtl support to composition input

updated buttons, emoji panel, @mentions
pull/2796/head
William Grant 2 years ago
parent 80178a6e4c
commit 7542a42fa6

@ -6,7 +6,7 @@ export interface FlexProps {
container?: boolean; container?: boolean;
dataTestId?: string; dataTestId?: string;
/****** Container Props ********/ /****** Container Props ********/
flexDirection?: 'row' | 'column'; flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
justifyContent?: justifyContent?:
| 'flex-start' | 'flex-start'
| 'flex-end' | 'flex-end'

@ -16,8 +16,10 @@ import {
import { hexColorToRGB } from '../../util/hexColorToRGB'; import { hexColorToRGB } from '../../util/hexColorToRGB';
import { getPrimaryColor } from '../../state/selectors/primaryColor'; import { getPrimaryColor } from '../../state/selectors/primaryColor';
import { i18nEmojiData } from '../../util/emoji'; import { i18nEmojiData } from '../../util/emoji';
import { getWritingDirection } from '../../state/selectors/user';
export const StyledEmojiPanel = styled.div<{ export const StyledEmojiPanel = styled.div<{
dir: string;
isModal: boolean; isModal: boolean;
primaryColor: PrimaryColorStateType; primaryColor: PrimaryColorStateType;
theme: ThemeStateType; theme: ThemeStateType;
@ -68,7 +70,7 @@ export const StyledEmojiPanel = styled.div<{
content: ''; content: '';
position: absolute; position: absolute;
top: calc(100% - 40px); top: calc(100% - 40px);
left: calc(100% - 79px); left: ${props.dir === 'rtl' ? '75px' : 'calc(100% - 106px)'};
width: 22px; width: 22px;
height: 22px; height: 22px;
transform: rotate(45deg); transform: rotate(45deg);
@ -102,6 +104,7 @@ export const SessionEmojiPanel = forwardRef<HTMLDivElement, Props>((props: Props
const primaryColor = useSelector(getPrimaryColor); const primaryColor = useSelector(getPrimaryColor);
const theme = useSelector(getTheme); const theme = useSelector(getTheme);
const isDarkMode = useSelector(isDarkTheme); const isDarkMode = useSelector(isDarkTheme);
const writingDirection = useSelector(getWritingDirection);
let panelBackgroundRGB = hexColorToRGB(THEMES.CLASSIC_DARK.COLOR1); let panelBackgroundRGB = hexColorToRGB(THEMES.CLASSIC_DARK.COLOR1);
let panelTextRGB = hexColorToRGB(THEMES.CLASSIC_DARK.COLOR6); let panelTextRGB = hexColorToRGB(THEMES.CLASSIC_DARK.COLOR6);
@ -134,6 +137,7 @@ export const SessionEmojiPanel = forwardRef<HTMLDivElement, Props>((props: Props
theme={theme} theme={theme}
panelBackgroundRGB={panelBackgroundRGB} panelBackgroundRGB={panelBackgroundRGB}
panelTextRGB={panelTextRGB} panelTextRGB={panelTextRGB}
dir={writingDirection}
className={classNames(show && 'show')} className={classNames(show && 'show')}
ref={ref} ref={ref}
> >

@ -57,6 +57,7 @@ import {
getSelectedConversationKey, getSelectedConversationKey,
} from '../../../state/selectors/selectedConversation'; } from '../../../state/selectors/selectedConversation';
import { SettingsKey } from '../../../data/settings-key'; import { SettingsKey } from '../../../data/settings-key';
import { isRtlBody } from '../../menu/Menu';
export interface ReplyingToMessageProps { export interface ReplyingToMessageProps {
convoId: string; convoId: string;
@ -205,21 +206,22 @@ const getSelectionBasedOnMentions = (draft: string, index: number) => {
return Number.MAX_SAFE_INTEGER; return Number.MAX_SAFE_INTEGER;
}; };
const StyledEmojiPanelContainer = styled.div` const StyledEmojiPanelContainer = styled.div<{ dir: string }>`
${StyledEmojiPanel} { ${StyledEmojiPanel} {
position: absolute; position: absolute;
bottom: 68px; bottom: 68px;
right: 0px; ${props => (props.dir === 'rtl' ? 'left: 0px' : 'right: 0px;')}
} }
`; `;
const StyledSendMessageInput = styled.div` const StyledSendMessageInput = styled.div<{ dir: string }>`
cursor: text; cursor: text;
display: flex; display: flex;
align-items: center; align-items: center;
flex-grow: 1; flex-grow: 1;
min-height: var(--composition-container-height); min-height: var(--composition-container-height);
padding: var(--margins-xs) 0; padding: var(--margins-xs) 0;
${props => (props.dir = 'rtl' && 'margin-right: var(--margins-sm);')}
z-index: 1; z-index: 1;
background-color: inherit; background-color: inherit;
@ -409,8 +411,16 @@ class CompositionBoxInner extends React.Component<Props, State> {
const { showEmojiPanel } = this.state; const { showEmojiPanel } = this.state;
const { typingEnabled } = this.props; const { typingEnabled } = this.props;
const rtl = isRtlBody();
const writingDirection = rtl ? 'rtl' : 'ltr';
return ( return (
<> <Flex
container={true}
flexDirection={rtl ? 'row-reverse' : 'row'}
alignItems={'center'}
width={'100%'}
>
{typingEnabled && <AddStagedAttachmentButton onClick={this.onChooseAttachment} />} {typingEnabled && <AddStagedAttachmentButton onClick={this.onChooseAttachment} />}
<input <input
@ -426,13 +436,14 @@ class CompositionBoxInner extends React.Component<Props, State> {
<StyledSendMessageInput <StyledSendMessageInput
role="main" role="main"
dir={writingDirection}
onClick={this.focusCompositionBox} // used to focus on the textarea when clicking in its container onClick={this.focusCompositionBox} // used to focus on the textarea when clicking in its container
ref={el => { ref={el => {
this.container = el; this.container = el;
}} }}
data-testid="message-input" data-testid="message-input"
> >
{this.renderTextArea()} {this.renderTextArea(writingDirection)}
</StyledSendMessageInput> </StyledSendMessageInput>
{typingEnabled && ( {typingEnabled && (
@ -441,7 +452,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
<SendMessageButton onClick={this.onSendMessage} /> <SendMessageButton onClick={this.onSendMessage} />
{typingEnabled && showEmojiPanel && ( {typingEnabled && showEmojiPanel && (
<StyledEmojiPanelContainer role="button"> <StyledEmojiPanelContainer role="button" dir={writingDirection}>
<SessionEmojiPanel <SessionEmojiPanel
ref={this.emojiPanel} ref={this.emojiPanel}
show={showEmojiPanel} show={showEmojiPanel}
@ -450,11 +461,11 @@ class CompositionBoxInner extends React.Component<Props, State> {
/> />
</StyledEmojiPanelContainer> </StyledEmojiPanelContainer>
)} )}
</> </Flex>
); );
} }
private renderTextArea() { private renderTextArea(dir: string) {
const { i18n } = window; const { i18n } = window;
const { draft } = this.state; const { draft } = this.state;
@ -491,6 +502,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
onKeyUp={this.onKeyUp} onKeyUp={this.onKeyUp}
placeholder={messagePlaceHolder} placeholder={messagePlaceHolder}
spellCheck={true} spellCheck={true}
dir={dir}
inputRef={this.textarea} inputRef={this.textarea}
disabled={!typingEnabled} disabled={!typingEnabled}
rows={1} rows={1}
@ -505,7 +517,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
markup="@ᅭ__id__ᅲ__display__ᅭ" // ᅭ = \uFFD2 is one of the forbidden char for a display name (check displayNameRegex) markup="@ᅭ__id__ᅲ__display__ᅭ" // ᅭ = \uFFD2 is one of the forbidden char for a display name (check displayNameRegex)
trigger="@" trigger="@"
// this is only for the composition box visible content. The real stuff on the backend box is the @markup // this is only for the composition box visible content. The real stuff on the backend box is the @markup
displayTransform={(_id, display) => `@${display}`} displayTransform={(_id, display) => (dir === 'rtl' ? `${display}@` : `@${display}`)}
data={this.fetchUsersForGroup} data={this.fetchUsersForGroup}
renderSuggestion={renderUserMentionRow} renderSuggestion={renderUserMentionRow}
/> />

@ -4,6 +4,7 @@ import { LocalizerType } from '../../types/Util';
import { StateType } from '../reducer'; import { StateType } from '../reducer';
import { UserStateType } from '../ducks/user'; import { UserStateType } from '../ducks/user';
import { isRtlBody } from '../../components/menu/Menu';
export const getUser = (state: StateType): UserStateType => state.user; export const getUser = (state: StateType): UserStateType => state.user;
@ -13,3 +14,7 @@ export const getOurNumber = createSelector(
); );
export const getIntl = createSelector(getUser, (): LocalizerType => window.i18n); export const getIntl = createSelector(getUser, (): LocalizerType => window.i18n);
export const getWritingDirection = createSelector(getUser, (): string =>
isRtlBody() ? 'rtl' : 'ltr'
);

Loading…
Cancel
Save