feat: added monospace textarea support to sessioninput

this will replace the sessionideditable eventually still needs error handling etc
pull/3083/head
William Grant 1 year ago
parent e96519445d
commit 30118c3426

@ -3,7 +3,7 @@
"accept": "Accept", "accept": "Accept",
"accountIDCopy": "Copy Account ID", "accountIDCopy": "Copy Account ID",
"accountIdEnter": "Enter Account ID", "accountIdEnter": "Enter Account ID",
"accountIdEnterYourFriends": "Enter your friend's Account ID or ONS", "accountIdOrOnsEnter": "Enter Account ID or ONS",
"accountIdYours": "Your Account ID", "accountIdYours": "Your Account ID",
"accountIdErrorInvalid": "This Account ID is invalid. Please check and try again.", "accountIdErrorInvalid": "This Account ID is invalid. Please check and try again.",
"activeMembers": "$count$ active members", "activeMembers": "$count$ active members",

@ -30,13 +30,14 @@ const StyledInputContainer = styled(Flex)<{ error: boolean }>`
} }
} }
input::placeholder { input::placeholder,
textarea::placeholder {
transition: opacity var(--default-duration) color var(--default-duration); transition: opacity var(--default-duration) color var(--default-duration);
${props => props.error && `color: var(--danger-color); opacity: 1;`} ${props => props.error && `color: var(--danger-color); opacity: 1;`}
} }
`; `;
const StyledInput = styled(motion.input)` const StyledInput = styled(motion.input)<{ centerText?: boolean }>`
border: 1px solid var(--input-border-color); border: 1px solid var(--input-border-color);
border-radius: 13px; border-radius: 13px;
outline: 0; outline: 0;
@ -48,9 +49,57 @@ const StyledInput = styled(motion.input)`
font-size: 12px; font-size: 12px;
line-height: 14px; line-height: 14px;
padding: var(--margins-lg); padding: var(--margins-lg);
${props => props.centerText && 'text-align: center;'}
::placeholder { ::placeholder {
color: var(--input-text-placeholder-color); color: var(--input-text-placeholder-color);
${props => props.centerText && 'text-align: center;'}
}
`;
const StyledTextAreaContainer = styled(motion.div)<{ centerText?: boolean }>`
border: 1px solid var(--input-border-color);
border-radius: 13px;
outline: 0;
width: 100%;
background: transparent;
color: var(--input-text-color);
font-family: var(--font-mono);
font-size: var(--font-size-md);
min-height: 100px;
line-height: 18px;
${props => props.centerText && 'text-align: center;'}
textarea {
width: 100%;
outline: 0;
border: none;
background: transparent;
resize: none;
overflow: hidden;
overflow-wrap: break-word;
user-select: all;
display: inline-block;
padding: var(--margins-lg);
margin: var(--margins-xs) 0;
${props => props.centerText && 'text-align: center;'}
:placeholder-shown {
font-family: var(--font-default);
height: 28px;
margin: var(--margins-md) 0;
padding: var(--margins-xl);
}
::placeholder {
color: var(--input-text-placeholder-color);
${props => props.centerText && 'text-align: center;'}
}
} }
`; `;
@ -123,6 +172,9 @@ type Props = {
inputDataTestId?: string; inputDataTestId?: string;
id?: string; id?: string;
ctaButton?: ReactNode; ctaButton?: ReactNode;
/** Gives us a textarea with a monospace font. Mostly used for joining conversations, groups or communities */
isSpecial?: boolean;
centerText?: boolean;
}; };
export const SessionInput = (props: Props) => { export const SessionInput = (props: Props) => {
@ -140,6 +192,8 @@ export const SessionInput = (props: Props) => {
inputDataTestId, inputDataTestId,
id = 'session-input-floating-label', id = 'session-input-floating-label',
ctaButton, ctaButton,
isSpecial,
centerText,
} = props; } = props;
const [inputValue, setInputValue] = useState(''); const [inputValue, setInputValue] = useState('');
const [errorString, setErrorString] = useState(''); const [errorString, setErrorString] = useState('');
@ -156,6 +210,38 @@ export const SessionInput = (props: Props) => {
} }
}; };
// TODO[epic=893] Type inputProps properly
const inputProps: any = {
id,
type: correctType,
placeholder,
value,
maxLength,
autoFocus,
'data-testid': inputDataTestId,
onChange: updateInputValue,
style: { paddingInlineEnd: enableShowHide ? '48px' : undefined },
// just in case onChange isn't triggered
onBlur: (event: ChangeEvent<HTMLInputElement>) => {
if (!disabledOnBlur) {
updateInputValue(event);
}
},
onKeyDown: (event: KeyboardEvent) => {
if (event.key === 'Enter' && onEnterPressed) {
onEnterPressed(inputValue);
setErrorString('');
}
},
initial: {
borderColor: errorString ? 'var(--input-border-color)' : undefined,
},
animate: {
borderColor: errorString ? 'var(--danger-color)' : undefined,
},
transition: { duration: THEME_GLOBALS['--default-duration-seconds'] },
};
// if we have an error, we want to show it even if the input changes to a valid value // if we have an error, we want to show it even if the input changes to a valid value
useEffect(() => { useEffect(() => {
if (error && !isEmpty(error) && !isEqual(error, errorString)) { if (error && !isEmpty(error) && !isEqual(error, errorString)) {
@ -172,36 +258,13 @@ export const SessionInput = (props: Props) => {
error={Boolean(errorString)} error={Boolean(errorString)}
> >
<Flex container={true} width="100%" alignItems="center" style={{ position: 'relative' }}> <Flex container={true} width="100%" alignItems="center" style={{ position: 'relative' }}>
<StyledInput {isSpecial ? (
id={id} <StyledTextAreaContainer centerText={centerText}>
type={correctType} <textarea {...inputProps} />
placeholder={placeholder} </StyledTextAreaContainer>
value={value} ) : (
maxLength={maxLength} <StyledInput {...inputProps} centerText={centerText} />
autoFocus={autoFocus} )}
data-testid={inputDataTestId}
onChange={updateInputValue}
style={{ paddingInlineEnd: enableShowHide ? '48px' : undefined }}
// just in case onChange isn't triggered
onBlur={(event: ChangeEvent<HTMLInputElement>) => {
if (!disabledOnBlur) {
updateInputValue(event);
}
}}
onKeyDown={event => {
if (event.key === 'Enter' && onEnterPressed) {
onEnterPressed(inputValue);
setErrorString('');
}
}}
initial={{
borderColor: errorString ? 'var(--input-border-color)' : undefined,
}}
animate={{
borderColor: errorString ? 'var(--danger-color)' : undefined,
}}
transition={{ duration: THEME_GLOBALS['--default-duration-seconds'] }}
/>
{enableShowHide && ( {enableShowHide && (
<ShowHideButton <ShowHideButton
forceShow={forceShow} forceShow={forceShow}

@ -10,14 +10,14 @@ import { ToastUtils, UserUtils } from '../../../session/utils';
import { openConversationWithMessages } from '../../../state/ducks/conversations'; import { openConversationWithMessages } from '../../../state/ducks/conversations';
import { resetLeftOverlayMode } from '../../../state/ducks/section'; import { resetLeftOverlayMode } from '../../../state/ducks/section';
import { SessionButton } from '../../basic/SessionButton'; import { SessionButton } from '../../basic/SessionButton';
import { SessionIdEditable } from '../../basic/SessionIdEditable';
import { SessionSpinner } from '../../loading'; import { SessionSpinner } from '../../loading';
import { ONSResolve } from '../../../session/apis/snode_api/onsResolve'; import { ONSResolve } from '../../../session/apis/snode_api/onsResolve';
import { Flex } from '../../basic/Flex'; import { Flex } from '../../basic/Flex';
import { SpacerMD } from '../../basic/Text'; import { SpacerLG, SpacerMD } from '../../basic/Text';
import { YourSessionIDPill, YourSessionIDSelectable } from '../../basic/YourSessionIDPill'; import { YourSessionIDPill, YourSessionIDSelectable } from '../../basic/YourSessionIDPill';
import { SessionIconButton } from '../../icon'; import { SessionIconButton } from '../../icon';
import { SessionInput } from '../../inputs';
const SessionIDDescription = styled.div` const SessionIDDescription = styled.div`
color: var(--text-secondary-color); color: var(--text-secondary-color);
@ -49,7 +49,7 @@ export const OverlayMessage = () => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const buttonText = window.i18n('next'); const buttonText = window.i18n('next');
const placeholder = window.i18n('accountIdEnterYourFriends'); const placeholder = window.i18n('accountIdOrOnsEnter');
const disableNextButton = !pubkeyOrOns || loading; const disableNextButton = !pubkeyOrOns || loading;
@ -111,13 +111,29 @@ export const OverlayMessage = () => {
return ( return (
<div className="module-left-pane-overlay"> <div className="module-left-pane-overlay">
<SessionIdEditable {/* TODO[epic=893] Replace everywhere and test new error handling */}
{/* <SessionIdEditable
editable={!loading} editable={!loading}
placeholder={placeholder} placeholder={placeholder}
onChange={setPubkeyOrOns} onChange={setPubkeyOrOns}
dataTestId="new-session-conversation" dataTestId="new-session-conversation"
onPressEnter={handleMessageButtonClick} onPressEnter={handleMessageButtonClick}
/> */}
<div style={{ width: '90%', margin: '0 auto' }}>
<SessionInput
autoFocus={true}
type="text"
placeholder={placeholder}
value={pubkeyOrOns}
onValueChanged={setPubkeyOrOns}
onEnterPressed={handleMessageButtonClick}
inputDataTestId="new-session-conversation"
isSpecial={true}
centerText={true}
/> />
</div>
<SpacerLG />
<SessionSpinner loading={loading} /> <SessionSpinner loading={loading} />

@ -3,8 +3,8 @@ export type LocalizerKeys =
| 'accept' | 'accept'
| 'accountIDCopy' | 'accountIDCopy'
| 'accountIdEnter' | 'accountIdEnter'
| 'accountIdEnterYourFriends'
| 'accountIdErrorInvalid' | 'accountIdErrorInvalid'
| 'accountIdOrOnsEnter'
| 'accountIdYours' | 'accountIdYours'
| 'activeMembers' | 'activeMembers'
| 'add' | 'add'

Loading…
Cancel
Save