Skip to content

Commit

Permalink
Emojify and linkify group descriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanHahn-Signal committed Jun 17, 2021
1 parent 68f1023 commit 65a1e82
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 18 deletions.
24 changes: 24 additions & 0 deletions ts/components/GroupDescriptionText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import React, { FunctionComponent } from 'react';
import { RenderTextCallbackType } from '../types/Util';
import { AddNewLines } from './conversation/AddNewLines';
import { Emojify } from './conversation/Emojify';
import { Linkify } from './conversation/Linkify';

type PropsType = {
text: string;
};

const renderNonLink: RenderTextCallbackType = ({ key, text }) => (
<Emojify key={key} text={text} />
);

const renderNonNewLine: RenderTextCallbackType = ({ key, text }) => (
<Linkify key={key} text={text} renderNonLink={renderNonLink} />
);

export const GroupDescriptionText: FunctionComponent<PropsType> = ({
text,
}) => <AddNewLines text={text} renderNonNewLine={renderNonNewLine} />;
34 changes: 34 additions & 0 deletions ts/components/conversation/GroupDescription.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,37 @@ story.add('Long', () => (
})}
/>
));

story.add('With newlines', () => (
<GroupDescription
{...createProps({
text: 'This is long\n\nSo many lines\n\nToo many lines?',
})}
/>
));

story.add('With emoji', () => (
<GroupDescription
{...createProps({
text: '🍒🍩🌭',
})}
/>
));

story.add('With link', () => (
<GroupDescription
{...createProps({
text:
'I love https://example.com and http://example.com and example.com, but not https://user:bar@example.com',
})}
/>
));

story.add('Kitchen sink', () => (
<GroupDescription
{...createProps({
text:
'🍒 https://example.com this is a long thing\nhttps://example.com on another line\nhttps://example.com',
})}
/>
));
21 changes: 14 additions & 7 deletions ts/components/conversation/GroupDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import React, { useEffect, useRef, useState } from 'react';
import React, { useLayoutEffect, useRef, useState } from 'react';
import { Modal } from '../Modal';
import { LocalizerType } from '../../types/Util';
import { AddNewLines } from './AddNewLines';
import { GroupDescriptionText } from '../GroupDescriptionText';

// Emojification can cause the scroll height to be *slightly* larger than the client
// height, so we add a little wiggle room.
const SHOW_READ_MORE_THRESHOLD = 5;

export type PropsType = {
i18n: LocalizerType;
Expand All @@ -21,13 +25,16 @@ export const GroupDescription = ({
const [hasReadMore, setHasReadMore] = useState(false);
const [showFullDescription, setShowFullDescription] = useState(false);

useEffect(() => {
useLayoutEffect(() => {
if (!textRef || !textRef.current) {
return;
}

setHasReadMore(textRef.current.scrollHeight > textRef.current.clientHeight);
}, [setHasReadMore, textRef]);
setHasReadMore(
textRef.current.scrollHeight - SHOW_READ_MORE_THRESHOLD >
textRef.current.clientHeight
);
}, [setHasReadMore, text, textRef]);

return (
<>
Expand All @@ -38,11 +45,11 @@ export const GroupDescription = ({
onClose={() => setShowFullDescription(false)}
title={title}
>
<AddNewLines text={text} />
<GroupDescriptionText text={text} />
</Modal>
)}
<div className="GroupDescription__text" ref={textRef}>
{text}
<GroupDescriptionText text={text} />
</div>
{hasReadMore && (
<button
Expand Down
8 changes: 4 additions & 4 deletions ts/components/conversation/GroupV2Change.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Signal Messenger, LLC
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

/* eslint-disable-next-line max-classes-per-file */
Expand Down Expand Up @@ -1368,7 +1368,7 @@ storiesOf('Components/Conversation/GroupV2Change', module)
{
type: 'description',
description:
'This is a long description.\n\nWe need a dialog to view it all!',
'This is a long description.\n\nWe need a dialog to view it all!\n\nIt has a link to https://example.com',
},
],
},
Expand All @@ -1381,7 +1381,7 @@ storiesOf('Components/Conversation/GroupV2Change', module)
{
type: 'description',
description:
'This is a long description.\n\nWe need a dialog to view it all!',
'This is a long description.\n\nWe need a dialog to view it all!\n\nIt has a link to https://example.com',
},
],
},
Expand All @@ -1393,7 +1393,7 @@ storiesOf('Components/Conversation/GroupV2Change', module)
{
type: 'description',
description:
'This is a long description.\n\nWe need a dialog to view it all!',
'This is a long description.\n\nWe need a dialog to view it all!\n\nIt has a link to https://example.com',
},
],
},
Expand Down
14 changes: 7 additions & 7 deletions ts/components/conversation/GroupV2Change.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright 2020 Signal Messenger, LLC
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import React, { ReactElement, useState } from 'react';

import { ReplacementValuesType } from '../../types/I18N';
import { FullJSXType, Intl } from '../Intl';
import { LocalizerType } from '../../types/Util';
import { AddNewLines } from './AddNewLines';
import { GroupDescriptionText } from '../GroupDescriptionText';
import { Button, ButtonSize, ButtonVariant } from '../Button';

import { GroupV2ChangeType, GroupV2DescriptionChangeType } from '../../groups';
Expand Down Expand Up @@ -55,10 +55,10 @@ export function GroupV2Change(props: PropsType): ReactElement {
setIsGroupDescriptionDialogOpen,
] = useState<boolean>(false);

const groupDescriptionChange = change.details.find(
const newGroupDescription = change.details.find(
(item): item is GroupV2DescriptionChangeType =>
Boolean(item.type === 'description' && item.description)
);
)?.description;

return (
<div className="module-group-v2-change">
Expand All @@ -75,7 +75,7 @@ export function GroupV2Change(props: PropsType): ReactElement {
// eslint-disable-next-line react/no-array-index-key
<div key={index}>{item}</div>
))}
{groupDescriptionChange ? (
{newGroupDescription ? (
<div className="module-group-v2-change--button-container">
<Button
size={ButtonSize.Small}
Expand All @@ -86,14 +86,14 @@ export function GroupV2Change(props: PropsType): ReactElement {
</Button>
</div>
) : null}
{groupDescriptionChange && isGroupDescriptionDialogOpen ? (
{newGroupDescription && isGroupDescriptionDialogOpen ? (
<Modal
hasXButton
i18n={i18n}
title={groupName}
onClose={() => setIsGroupDescriptionDialogOpen(false)}
>
<AddNewLines text={groupDescriptionChange.description} />
<GroupDescriptionText text={newGroupDescription} />
</Modal>
) : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export const ConversationDetailsHeader: React.ComponentType<Props> = ({
<button
type="button"
onClick={ev => {
if (ev.target instanceof HTMLAnchorElement) {
return;
}

ev.preventDefault();
ev.stopPropagation();
startEditing(false);
Expand Down

0 comments on commit 65a1e82

Please sign in to comment.