diff --git a/ts/Bytes.ts b/ts/Bytes.ts index d843e1e4cb2..ab89b54be34 100644 --- a/ts/Bytes.ts +++ b/ts/Bytes.ts @@ -37,6 +37,10 @@ export function toString(data: Uint8Array): string { return bytes.toString(data); } +export function byteLength(value: string): number { + return bytes.byteLength(value); +} + export function concatenate(list: ReadonlyArray): Uint8Array { return bytes.concatenate(list); } diff --git a/ts/components/GroupDescriptionInput.tsx b/ts/components/GroupDescriptionInput.tsx index ec467e3d321..bd3ea60ef03 100644 --- a/ts/components/GroupDescriptionInput.tsx +++ b/ts/components/GroupDescriptionInput.tsx @@ -22,10 +22,11 @@ export const GroupDescriptionInput = forwardRef( i18n={i18n} onChange={onChangeValue} placeholder={i18n('setGroupMetadata__group-description-placeholder')} - maxLengthCount={256} + maxLengthCount={480} + maxByteCount={8192} ref={ref} value={value} - whenToShowRemainingCount={150} + whenToShowRemainingCount={380} /> ); } diff --git a/ts/components/Input.tsx b/ts/components/Input.tsx index e9bdf5e9838..462fed8edb5 100644 --- a/ts/components/Input.tsx +++ b/ts/components/Input.tsx @@ -16,15 +16,18 @@ import * as grapheme from '../util/grapheme'; import { LocalizerType } from '../types/Util'; import { getClassNamesFor } from '../util/getClassNamesFor'; import { refMerger } from '../util/refMerger'; +import { byteLength } from '../Bytes'; export type PropsType = { countLength?: (value: string) => number; + countBytes?: (value: string) => number; disabled?: boolean; expandable?: boolean; hasClearButton?: boolean; i18n: LocalizerType; icon?: ReactNode; maxLengthCount?: number; + maxByteCount?: number; moduleClassName?: string; onChange: (value: string) => unknown; placeholder: string; @@ -56,12 +59,14 @@ export const Input = forwardRef< ( { countLength = grapheme.count, + countBytes = byteLength, disabled, expandable, hasClearButton, i18n, icon, maxLengthCount = 0, + maxByteCount = 0, moduleClassName, onChange, placeholder, @@ -114,8 +119,9 @@ export const Input = forwardRef< const newValue = inputEl.value; const newLengthCount = maxLengthCount ? countLength(newValue) : 0; + const newByteCount = maxByteCount ? countBytes(newValue) : 0; - if (newLengthCount <= maxLengthCount) { + if (newLengthCount <= maxLengthCount && newByteCount <= maxByteCount) { onChange(newValue); } else { inputEl.value = valueOnKeydownRef.current; @@ -124,12 +130,19 @@ export const Input = forwardRef< } maybeSetLarge(); - }, [countLength, maxLengthCount, maybeSetLarge, onChange]); + }, [ + countLength, + countBytes, + maxLengthCount, + maxByteCount, + maybeSetLarge, + onChange, + ]); const handlePaste = useCallback( (event: ClipboardEvent) => { const inputEl = innerRef.current; - if (!inputEl || !maxLengthCount) { + if (!inputEl || !maxLengthCount || !maxByteCount) { return; } @@ -145,14 +158,25 @@ export const Input = forwardRef< countLength(textBeforeSelection) + countLength(pastedText) + countLength(textAfterSelection); + const newByteCount = + countBytes(textBeforeSelection) + + countBytes(pastedText) + + countBytes(textAfterSelection); - if (newLengthCount > maxLengthCount) { + if (newLengthCount > maxLengthCount || newByteCount > maxByteCount) { event.preventDefault(); } maybeSetLarge(); }, - [countLength, maxLengthCount, maybeSetLarge, value] + [ + countLength, + countBytes, + maxLengthCount, + maxByteCount, + maybeSetLarge, + value, + ] ); useEffect(() => { diff --git a/ts/components/ProfileEditor.tsx b/ts/components/ProfileEditor.tsx index 729ec118e7a..cca98217a70 100644 --- a/ts/components/ProfileEditor.tsx +++ b/ts/components/ProfileEditor.tsx @@ -161,20 +161,6 @@ export const ProfileEditor = ({ [onProfileChanged, stagedProfile] ); - const getTextEncoder = useCallback(() => new TextEncoder(), []); - - const countByteLength = useCallback( - (str: string) => getTextEncoder().encode(str).byteLength, - [getTextEncoder] - ); - - const calculateLengthCount = useCallback( - (name = '') => { - return 256 - countByteLength(name); - }, - [countByteLength] - ); - const getFullNameText = () => { return [fullName.firstName, fullName.familyName].filter(Boolean).join(' '); }; @@ -225,9 +211,9 @@ export const ProfileEditor = ({ content = ( <> { setStagedProfile(profileData => ({ @@ -240,9 +226,9 @@ export const ProfileEditor = ({ value={stagedProfile.firstName} /> { setStagedProfile(profileData => ({ @@ -323,6 +309,7 @@ export const ProfileEditor = ({ } maxLengthCount={140} + maxByteCount={512} moduleClassName="ProfileEditor__about-input" onChange={value => { if (value) { diff --git a/ts/context/Bytes.ts b/ts/context/Bytes.ts index 1c8b6a4b752..636d0183ebd 100644 --- a/ts/context/Bytes.ts +++ b/ts/context/Bytes.ts @@ -40,6 +40,10 @@ export class Bytes { return Buffer.from(data).toString(); } + public byteLength(value: string): number { + return Buffer.byteLength(value); + } + public concatenate(list: ReadonlyArray): Uint8Array { return Buffer.concat(list); }