Add Channel Mention selection ability #7151

Merged
saltrafael merged 9 commits from channel-mention into master 2021-09-30 23:30:32 +02:00
2 changed files with 32 additions and 20 deletions
Showing only changes of commit e9613ed26d - Show all commits

View file

@ -119,7 +119,7 @@ export default function ChannelMentionSuggestions(props: Props) {
comboboxInputRef.current.focus(); comboboxInputRef.current.focus();
} }
} else { } else {
if (keyCode === KEYCODES.TAB) { if ((isRefFocused(comboboxInputRef) || isRefFocused(inputRef)) && keyCode === KEYCODES.TAB) {
event.preventDefault(); event.preventDefault();
const activeValue = activeElement && activeElement.getAttribute('value'); const activeValue = activeElement && activeElement.getAttribute('value');
@ -131,7 +131,7 @@ export default function ChannelMentionSuggestions(props: Props) {
handleSelect(mentionTerm); handleSelect(mentionTerm);
} }
} }
inputRef.current.focus(); if (isRefFocused(comboboxInputRef)) inputRef.current.focus();
} }
} }
@ -186,7 +186,7 @@ export default function ChannelMentionSuggestions(props: Props) {
); );
}; };
return ( return isRefFocused(inputRef) || isRefFocused(comboboxInputRef) ? (
<Form onSubmit={() => handleSelect(mentionTerm)}> <Form onSubmit={() => handleSelect(mentionTerm)}>
<Combobox className="channel-mention" onSelect={handleSelect}> <Combobox className="channel-mention" onSelect={handleSelect}>
<ComboboxInput ref={comboboxInputRef} className="channel-mention__input--none" value={mentionTerm} /> <ComboboxInput ref={comboboxInputRef} className="channel-mention__input--none" value={mentionTerm} />
@ -216,5 +216,5 @@ export default function ChannelMentionSuggestions(props: Props) {
)} )}
</Combobox> </Combobox>
</Form> </Form>
); ) : null;
} }

View file

@ -84,6 +84,8 @@ export function CommentCreate(props: Props) {
fetchComment, fetchComment,
} = props; } = props;
const formFieldRef: ElementRef<any> = React.useRef(); const formFieldRef: ElementRef<any> = React.useRef();
const formFieldInputRef = formFieldRef && formFieldRef.current && formFieldRef.current.input;
const selectionIndex = formFieldInputRef && formFieldInputRef.current.selectionStart;
const buttonRef: ElementRef<any> = React.useRef(); const buttonRef: ElementRef<any> = React.useRef();
const { const {
push, push,
@ -97,15 +99,25 @@ export function CommentCreate(props: Props) {
const [isReviewingSupportComment, setIsReviewingSupportComment] = React.useState(); const [isReviewingSupportComment, setIsReviewingSupportComment] = React.useState();
const [tipAmount, setTipAmount] = React.useState(1); const [tipAmount, setTipAmount] = React.useState(1);
const [commentValue, setCommentValue] = React.useState(''); const [commentValue, setCommentValue] = React.useState('');
const [channelMention, setChannelMention] = React.useState('');
const [advancedEditor, setAdvancedEditor] = usePersistedState('comment-editor-mode', false); const [advancedEditor, setAdvancedEditor] = usePersistedState('comment-editor-mode', false);
const [activeTab, setActiveTab] = React.useState(''); const [activeTab, setActiveTab] = React.useState('');
const [tipError, setTipError] = React.useState(); const [tipError, setTipError] = React.useState();
const [deletedComment, setDeletedComment] = React.useState(false); const [deletedComment, setDeletedComment] = React.useState(false);
const [shouldDisableReviewButton, setShouldDisableReviewButton] = React.useState(); const [shouldDisableReviewButton, setShouldDisableReviewButton] = React.useState();
const commentWords = commentValue ? commentValue && commentValue.split(' ') : []; const selectedMentionIndex =
const lastCommentWord = commentWords && commentWords[commentWords.length - 1]; commentValue.indexOf('@', selectionIndex) === selectionIndex
? commentValue.indexOf('@', selectionIndex)
: commentValue.lastIndexOf('@', selectionIndex);
const mentionLengthIndex =
commentValue.indexOf(' ', selectedMentionIndex) >= 0
? commentValue.indexOf(' ', selectedMentionIndex)
: commentValue.length;
const channelMention =
selectedMentionIndex >= 0 && selectionIndex <= mentionLengthIndex
? commentValue.substring(selectedMentionIndex, mentionLengthIndex)
: '';
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
const signingChannel = (claim && claim.signing_channel) || claim; const signingChannel = (claim && claim.signing_channel) || claim;
const channelUri = signingChannel && signingChannel.permanent_url; const channelUri = signingChannel && signingChannel.permanent_url;
@ -159,16 +171,21 @@ export function CommentCreate(props: Props) {
} }
function handleSelectMention(mentionValue) { function handleSelectMention(mentionValue) {
const newCommentValue = commentWords.slice(0, -1).join(' '); let newMentionValue = mentionValue.replace('lbry://', '');
let newMentionValue = mentionValue; if (newMentionValue.includes('#')) {
if (mentionValue.includes('#')) { const fullId = newMentionValue.substring(newMentionValue.indexOf('#') + 1, newMentionValue.length);
newMentionValue = mentionValue newMentionValue = newMentionValue
.substring(0, mentionValue.indexOf('#') + 3) .substring(0, newMentionValue.indexOf('#') + (fullId.length > 2 ? 2 : newMentionValue.length))
.replace('lbry://', '')
.replace('#', ':'); .replace('#', ':');
} }
setCommentValue(newCommentValue + (commentWords.length > 1 ? ' ' : '') + `${newMentionValue} `); setCommentValue(
commentValue.substring(0, selectedMentionIndex) +
`${newMentionValue}` +
(commentValue.length > mentionLengthIndex + 1
? commentValue.substring(mentionLengthIndex, commentValue.length)
: ' ')
);
} }
function altEnterListener(e: SyntheticKeyboardEvent<*>) { function altEnterListener(e: SyntheticKeyboardEvent<*>) {
@ -399,11 +416,6 @@ export function CommentCreate(props: Props) {
} }
}, [fetchComment, shouldFetchComment, parentId]); }, [fetchComment, shouldFetchComment, parentId]);
React.useEffect(() => {
const isMentioning = lastCommentWord && lastCommentWord.indexOf('@') === 0;
setChannelMention(isMentioning ? lastCommentWord : '');
}, [lastCommentWord]);
// ************************************************************************** // **************************************************************************
// Render // Render
// ************************************************************************** // **************************************************************************
@ -494,7 +506,7 @@ export function CommentCreate(props: Props) {
<ChannelMentionSuggestions <ChannelMentionSuggestions
uri={uri} uri={uri}
isLivestream={livestream} isLivestream={livestream}
inputRef={formFieldRef && formFieldRef.current && formFieldRef.current.input} inputRef={formFieldInputRef}
mentionTerm={channelMention} mentionTerm={channelMention}
creatorUri={channelUri} creatorUri={channelUri}
customSelectAction={handleSelectMention} customSelectAction={handleSelectMention}