feat: updated SessionInput to support multiple font sizes

this replaces the bigger text option, new props required, tabIndex, inputRef
pull/3083/head
William Grant 12 months ago
parent 681f488874
commit e5625cac76

@ -1,27 +1,32 @@
import { useState } from 'react'; import { useState } from 'react';
import useCopyToClipboard from 'react-use/lib/useCopyToClipboard';
import useKey from 'react-use/lib/useKey'; import useKey from 'react-use/lib/useKey';
import styled from 'styled-components';
import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { getConversationController } from '../../session/conversations'; import { getConversationController } from '../../session/conversations';
import { ToastUtils } from '../../session/utils';
import { openConversationWithMessages } from '../../state/ducks/conversations'; import { openConversationWithMessages } from '../../state/ducks/conversations';
import { updateUserDetailsModal, UserDetailsModalState } from '../../state/ducks/modalDialog'; import { updateUserDetailsModal, UserDetailsModalState } from '../../state/ducks/modalDialog';
import { Avatar, AvatarSize } from '../avatar/Avatar'; import { Avatar, AvatarSize } from '../avatar/Avatar';
import { Flex } from '../basic/Flex';
import { SessionButton, SessionButtonType } from '../basic/SessionButton'; import { SessionButton, SessionButtonType } from '../basic/SessionButton';
import { SpacerLG } from '../basic/Text'; import { SpacerLG } from '../basic/Text';
import { CopyToClipboardButton } from '../buttons/CopyToClipboardButton';
import { SessionInput } from '../inputs'; import { SessionInput } from '../inputs';
import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionWrapperModal } from '../SessionWrapperModal';
const StyledInputContainer = styled(Flex)`
textarea {
position: unset;
top: unset;
overflow: hidden;
}
`;
export const UserDetailsDialog = (props: UserDetailsModalState) => { export const UserDetailsDialog = (props: UserDetailsModalState) => {
const [isEnlargedImageShown, setIsEnlargedImageShown] = useState(false); const [isEnlargedImageShown, setIsEnlargedImageShown] = useState(false);
const size = isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL; const size = isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, copyToClipboard] = useCopyToClipboard();
function closeDialog() { function closeDialog() {
window.inboxStore?.dispatch(updateUserDetailsModal(null)); window.inboxStore?.dispatch(updateUserDetailsModal(null));
} }
@ -68,16 +73,22 @@ export const UserDetailsDialog = (props: UserDetailsModalState) => {
/> />
</div> </div>
</div> </div>
<SpacerLG /> <SpacerLG />
<SessionInput <StyledInputContainer
value={props.conversationId} container={true}
biggerText={true} width={'100%'}
centerText={true} justifyContent="center"
editable={false} alignItems="center"
monospaced={true} >
isTextArea={true} <SessionInput
/> value={props.conversationId}
fontSize="md"
centerText={true}
editable={false}
monospaced={true}
isTextArea={true}
/>
</StyledInputContainer>
<SpacerLG /> <SpacerLG />
<div className="session-modal__button-group__center"> <div className="session-modal__button-group__center">
<SessionButton <SessionButton
@ -85,13 +96,9 @@ export const UserDetailsDialog = (props: UserDetailsModalState) => {
buttonType={SessionButtonType.Simple} buttonType={SessionButtonType.Simple}
onClick={onClickStartConversation} onClick={onClickStartConversation}
/> />
<SessionButton <CopyToClipboardButton
text={window.i18n('editMenuCopy')} copyContent={props.conversationId}
buttonType={SessionButtonType.Simple} buttonType={SessionButtonType.Simple}
onClick={() => {
copyToClipboard(props.conversationId);
ToastUtils.pushCopiedToClipBoard();
}}
/> />
</div> </div>
</SessionWrapperModal> </SessionWrapperModal>

@ -5,26 +5,81 @@ import { isEmpty, isEqual } from 'lodash';
import styled, { CSSProperties } from 'styled-components'; import styled, { CSSProperties } from 'styled-components';
import { THEME_GLOBALS } from '../../themes/globals'; import { THEME_GLOBALS } from '../../themes/globals';
import { useHTMLDirection } from '../../util/i18n'; import { useHTMLDirection } from '../../util/i18n';
import { Flex } from '../basic/Flex'; import { AnimatedFlex, Flex } from '../basic/Flex';
import { SpacerMD } from '../basic/Text'; import { SpacerMD } from '../basic/Text';
import { SessionIconButton } from '../icon'; import { SessionIconButton } from '../icon';
type TextSizes = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
const StyledSessionInput = styled(Flex)<{
error: boolean;
fontSize?: TextSizes;
}>`
position: relative;
width: 100%;
label {
color: var(--text-primary-color);
opacity: 0;
transition: opacity var(--default-duration);
text-align: center;
&.filled {
opacity: 1;
}
&.error {
color: var(--danger-color);
font-weight: 700;
}
}
input::placeholder,
textarea::placeholder {
transition: opacity var(--default-duration) color var(--default-duration);
${props => props.error && `color: var(--danger-color); opacity: 1;`}
}
${props =>
props.fontSize &&
`
${StyledInput} {
font-size: var(--font-size-${props.fontSize});
}
${StyledTextAreaContainer} {
font-size: var(--font-size-${props.fontSize});
textarea {
&:placeholder-shown {
font-size: var(--font-size-${props.fontSize});
}
}
}
`}
`;
const StyledBorder = styled(AnimatedFlex)`
position: relative;
border: 1px solid var(--input-border-color);
border-radius: 13px;
`;
const StyledInput = styled(motion.input)<{ const StyledInput = styled(motion.input)<{
error: boolean; error: boolean;
centerText?: boolean; centerText?: boolean;
monospaced?: boolean; monospaced?: boolean;
}>` }>`
border: 1px solid var(--input-border-color);
border-radius: 13px;
outline: 0; outline: 0;
border: none;
width: 100%; width: 100%;
padding: var(--margins-lg);
background: transparent; background: transparent;
color: ${props => (props.error ? 'var(--danger-color)' : 'var(--input-text-color)')}; color: ${props => (props.error ? 'var(--danger-color)' : 'var(--input-text-color)')};
font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')}; font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')};
font-size: 12px; font-size: 12px;
line-height: 14px; line-height: 1.4;
padding: var(--margins-lg);
${props => props.centerText && 'text-align: center;'} ${props => props.centerText && 'text-align: center;'}
&::placeholder { &::placeholder {
@ -36,43 +91,48 @@ const StyledInput = styled(motion.input)<{
const StyledTextAreaContainer = styled(motion.div)<{ const StyledTextAreaContainer = styled(motion.div)<{
error: boolean; error: boolean;
centerText?: boolean; centerText?: boolean;
fontSize?: TextSizes;
monospaced?: boolean; monospaced?: boolean;
}>` }>`
border: 1px solid var(--input-border-color); overflow: hidden;
border-radius: 13px; position: relative;
outline: 0; height: ${props => (props.fontSize ? `calc(var(--font-size-${props.fontSize}) * 4)` : '48px')};
width: 100%; width: 100%;
margin: var(--margins-sm) var(--margins-md);
background: transparent; background: transparent;
color: ${props => (props.error ? 'var(--danger-color)' : 'var(--input-text-color)')}; color: ${props => (props.error ? 'var(--danger-color)' : 'var(--input-text-color)')};
outline: 0;
font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')}; font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')};
font-size: 12px; font-size: 12px;
line-height: 14px; line-height: 1.4;
${props => props.centerText && 'text-align: center;'} ${props => props.centerText && 'text-align: center;'}
textarea { textarea {
display: flex;
height: 100%;
width: 100%; width: 100%;
padding: 0;
outline: 0; outline: 0;
border: none; border: none;
background: transparent; background: transparent;
position: absolute;
top: ${props =>
props.fontSize ? `calc(var(--font-size-${props.fontSize}) + 5px)` : 'calc(12px + 5px)'};
resize: none; resize: none;
overflow: hidden;
overflow-wrap: break-word; overflow-wrap: break-word;
user-select: all; user-select: all;
display: inline-block;
padding: var(--margins-lg);
margin: var(--margins-xs) 0;
${props => props.centerText && 'text-align: center;'} ${props => props.centerText && 'text-align: center;'}
&:placeholder-shown { &:placeholder-shown {
font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')}; font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')};
font-size: 12px; font-size: 12px;
height: 48px; line-height: 1.4;
margin: var(--margins-md) 0;
} }
&::placeholder { &::placeholder {
@ -82,54 +142,6 @@ const StyledTextAreaContainer = styled(motion.div)<{
} }
`; `;
const StyledInputContainer = styled(Flex)<{ error: boolean; biggerText?: boolean }>`
position: relative;
width: 100%;
label {
color: var(--text-primary-color);
opacity: 0;
transition: opacity var(--default-duration);
text-align: center;
&.filled {
opacity: 1;
}
&.error {
color: var(--danger-color);
font-weight: 700;
}
}
input::placeholder,
textarea::placeholder {
transition: opacity var(--default-duration) color var(--default-duration);
${props => props.error && `color: var(--danger-color); opacity: 1;`}
}
${props =>
props.biggerText &&
`
${StyledInput} {
font-size: var(--font-size-md);
line-height: 18px;
}
${StyledTextAreaContainer} {
font-size: var(--font-size-md);
line-height: 18px;
textarea {
&:placeholder-shown {
font-size: var(--font-size-md);
height: 56px;
}
}
}
`}
`;
const ErrorItem = (props: { id: string; error: string }) => { const ErrorItem = (props: { id: string; error: string }) => {
return ( return (
<motion.label <motion.label
@ -198,16 +210,19 @@ type Props = {
onValueChanged?: (value: string) => any; onValueChanged?: (value: string) => any;
onEnterPressed?: (value: string) => any; onEnterPressed?: (value: string) => any;
autoFocus?: boolean; autoFocus?: boolean;
// TODO rename disableOnBlurEvent
disabledOnBlur?: boolean; disabledOnBlur?: boolean;
ref?: any; inputRef?: any;
inputDataTestId?: string; inputDataTestId?: string;
id?: string; id?: string;
ctaButton?: ReactNode; ctaButton?: ReactNode;
monospaced?: boolean; monospaced?: boolean;
biggerText?: boolean; fontSize?: TextSizes;
centerText?: boolean; centerText?: boolean;
editable?: boolean; editable?: boolean;
isTextArea?: boolean; isTextArea?: boolean;
required?: boolean;
tabIndex?: number;
className?: string; className?: string;
}; };
@ -223,14 +238,17 @@ export const SessionInput = (props: Props) => {
onEnterPressed, onEnterPressed,
autoFocus, autoFocus,
disabledOnBlur, disabledOnBlur,
inputRef,
inputDataTestId, inputDataTestId,
id = 'session-input-floating-label', id = 'session-input-floating-label',
ctaButton, ctaButton,
monospaced, monospaced,
biggerText, fontSize,
centerText, centerText,
editable = true, editable = true,
isTextArea, isTextArea,
required,
tabIndex,
className, className,
} = props; } = props;
const [inputValue, setInputValue] = useState(''); const [inputValue, setInputValue] = useState('');
@ -261,6 +279,10 @@ export const SessionInput = (props: Props) => {
maxLength, maxLength,
autoFocus, autoFocus,
'data-testid': inputDataTestId, 'data-testid': inputDataTestId,
required,
'aria-required': required,
tabIndex,
ref: inputRef,
onChange: updateInputValue, onChange: updateInputValue,
style: { paddingInlineEnd: enableShowHide ? '48px' : undefined }, style: { paddingInlineEnd: enableShowHide ? '48px' : undefined },
// just in case onChange isn't triggered // just in case onChange isn't triggered
@ -282,18 +304,12 @@ export const SessionInput = (props: Props) => {
setErrorString(''); setErrorString('');
} }
}, },
initial: {
borderColor: errorString ? 'var(--input-border-color)' : undefined,
},
animate: {
borderColor: errorString ? 'var(--danger-color)' : undefined,
},
transition: { duration: THEME_GLOBALS['--default-duration-seconds'] },
}; };
const containerProps = { const containerProps = {
error: Boolean(error), error: Boolean(error),
centerText, centerText,
fontSize,
monospaced, monospaced,
}; };
@ -305,16 +321,27 @@ export const SessionInput = (props: Props) => {
}, [error, errorString]); }, [error, errorString]);
return ( return (
<StyledInputContainer <StyledSessionInput
className={className} className={className}
container={true} container={true}
flexDirection="column" flexDirection="column"
justifyContent="center" justifyContent="center"
alignItems="center" alignItems="center"
error={Boolean(errorString)} error={Boolean(errorString)}
biggerText={biggerText} fontSize={fontSize}
> >
<Flex container={true} width="100%" alignItems="center" style={{ position: 'relative' }}> <StyledBorder
container={true}
width="100%"
alignItems="center"
initial={{
borderColor: errorString ? 'var(--input-border-color)' : undefined,
}}
animate={{
borderColor: errorString ? 'var(--danger-color)' : undefined,
}}
transition={{ duration: THEME_GLOBALS['--default-duration-seconds'] }}
>
{isTextArea ? ( {isTextArea ? (
<StyledTextAreaContainer {...containerProps}> <StyledTextAreaContainer {...containerProps}>
<textarea {...inputProps} /> <textarea {...inputProps} />
@ -331,7 +358,7 @@ export const SessionInput = (props: Props) => {
error={Boolean(errorString)} error={Boolean(errorString)}
/> />
)} )}
</Flex> </StyledBorder>
{ctaButton || errorString ? <SpacerMD /> : null} {ctaButton || errorString ? <SpacerMD /> : null}
{errorString ? <ErrorItem id={id} error={errorString} /> : null} {errorString ? <ErrorItem id={id} error={errorString} /> : null}
@ -342,6 +369,6 @@ export const SessionInput = (props: Props) => {
> >
{ctaButton} {ctaButton}
</StyledCtaContainer> </StyledCtaContainer>
</StyledInputContainer> </StyledSessionInput>
); );
}; };

@ -149,7 +149,7 @@ export const OverlayClosedGroup = () => {
onEnterPressed={onEnterPressed} onEnterPressed={onEnterPressed}
error={groupNameError} error={groupNameError}
maxLength={VALIDATION.MAX_GROUP_NAME_LENGTH} maxLength={VALIDATION.MAX_GROUP_NAME_LENGTH}
biggerText={true} fontSize="md"
centerText={true} centerText={true}
monospaced={true} monospaced={true}
isTextArea={true} isTextArea={true}

@ -106,7 +106,7 @@ export const OverlayCommunity = () => {
onEnterPressed={onTryJoinRoom} onEnterPressed={onTryJoinRoom}
error={groupUrlError} error={groupUrlError}
maxLength={VALIDATION.MAX_COMMUNITY_NAME_LENGTH} maxLength={VALIDATION.MAX_COMMUNITY_NAME_LENGTH}
biggerText={true} fontSize="md"
centerText={true} centerText={true}
monospaced={true} monospaced={true}
isTextArea={true} isTextArea={true}

@ -52,6 +52,12 @@ const StyledButtonerContainer = styled.div`
} }
`; `;
const StyledInputContainer = styled(Flex)`
textarea {
top: 8px;
}
`;
export const OverlayInvite = () => { export const OverlayInvite = () => {
const ourSessionID = UserUtils.getOurPubKeyStrFromCache(); const ourSessionID = UserUtils.getOurPubKeyStrFromCache();
@ -75,15 +81,22 @@ export const OverlayInvite = () => {
> >
{!idCopied ? ( {!idCopied ? (
<> <>
<SessionInput <StyledInputContainer
autoFocus={true} container={true}
type="text" width={'100%'}
value={ourSessionID} justifyContent="center"
centerText={true} alignItems="center"
editable={false} >
isTextArea={true} <SessionInput
inputDataTestId="invite-account-id" autoFocus={true}
/> type="text"
value={ourSessionID}
editable={false}
centerText={true}
isTextArea={true}
inputDataTestId="invite-account-id"
/>
</StyledInputContainer>
<SpacerMD /> <SpacerMD />
<StyledDescription>{window.i18n('sessionInviteAFriendDescription')}</StyledDescription> <StyledDescription>{window.i18n('sessionInviteAFriendDescription')}</StyledDescription>
<SpacerLG /> <SpacerLG />

Loading…
Cancel
Save