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

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

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

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

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

Loading…
Cancel
Save