import React, { useCallback, useMemo, useRef, useState } from "react";
import { DraftHandleValue, EditorState } from "draft-js";
import Editor from "@draft-js-plugins/editor";
import ProfileImage, { Profile } from "pages/common/ProfileImage";
import createMentionPlugin, { MentionData } from "@draft-js-plugins/mention";
import styled from "styled-components";
import "@draft-js-plugins/mention/lib/plugin.css";
import "draft-js/dist/Draft.css";
import { getTypographyByKey } from "constants/DefaultTheme";
import { EntryComponentProps } from "@draft-js-plugins/mention/lib/MentionSuggestions/Entry/Entry";
import Icon from "components/ads/Icon";
import { INVITE_A_NEW_USER, createMessage } from "constants/messages";
import { USER_PHOTO_URL } from "constants/userConstants";
import scrollIntoView from "scroll-into-view-if-needed";
import { useEffect } from "react";
const StyledMention = styled.span`
color: ${(props) => props.theme.colors.comments.mention};
`;
export function MentionComponent(props: {
children: React.ReactNode;
entityKey: string;
}) {
const { children } = props;
return @{children};
}
export enum Trigger {
"@" = "@",
"+" = "+",
}
const StyledSuggestionsComponent = styled.div<{ isFocused?: boolean }>`
display: flex;
width: 250px;
padding: ${(props) =>
`${props.theme.spaces[4]}px ${props.theme.spaces[6]}px`};
& ${Profile} {
margin-right: ${(props) => props.theme.spaces[4]}px;
}
align-items: center;
&:hover {
background-color: ${(props) => props.theme.colors.mentionSuggestion.hover};
}
${(props) =>
props.isFocused
? `
background-color: ${props.theme.colors.mentionSuggestion.hover};
`
: ""}
`;
const Name = styled.div`
${(props) => getTypographyByKey(props, "h5")}
color: ${(props) => props.theme.colors.mentionSuggestion.nameText};
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
`;
const Username = styled.div`
${(props) => getTypographyByKey(props, "p3")}
color: ${(props) => props.theme.colors.mentionSuggestion.usernameText};
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
`;
const PlusCircle = styled.div`
width: 25px;
height: 25px;
display: flex;
border-radius: 50%;
align-items: center;
justify-content: center;
background-color: ${(props) =>
props.theme.colors.mentionsInput.mentionsInviteBtnPlusIcon};
& svg path {
stroke: #fff;
}
margin-right: ${(props) => props.theme.spaces[4]}px;
flex-shrink: 0;
`;
const SuggestionRightContainer = styled.div`
flex: 1;
min-width: 0;
`;
function SuggestionComponent(props: EntryComponentProps) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { theme, ...parentProps } = props;
const { user } = props.mention;
const mentionRef = useRef(null);
useEffect(() => {
if (parentProps.isFocused && mentionRef.current) {
scrollIntoView(mentionRef.current, {
scrollMode: "if-needed",
behavior: "smooth",
block: "nearest",
inline: "nearest",
});
}
}, [parentProps.isFocused]);
if (props.mention?.isInviteTrigger) {
return (
{createMessage(INVITE_A_NEW_USER)}
{props.mention.name}
);
}
return (
{props.mention.name}
{user?.username}
);
}
const StyledContainer = styled.div`
overflow: auto;
flex: 1;
.mentions-list {
position: absolute;
background: #fff;
border-radius: 2px;
box-shadow: 0px 4px 30px 0px rgb(220 220 220);
cursor: pointer;
display: flex;
flex-direction: column;
overflow: auto;
max-height: 300px;
z-index: 2;
}
`;
type Props = {
suggestions: Array;
onSubmit: (editorState: EditorState) => void;
editorState: EditorState;
setEditorState: (editorState: EditorState) => void;
readOnly?: boolean;
onSearchSuggestions: (props: { value: string; trigger: string }) => void;
autoFocus: boolean;
placeholder?: string;
onAddMention?: (mention: MentionData) => void;
};
function MentionsInput({
autoFocus,
editorState,
onAddMention,
onSearchSuggestions,
onSubmit,
placeholder,
setEditorState,
suggestions,
}: Props) {
const ref = useRef(null);
const [open, setOpen] = useState(false);
const { MentionSuggestions, plugins } = useMemo(() => {
const mentionPlugin = createMentionPlugin({
mentionRegExp: "[\\w@\\._]",
mentionTrigger: ["@", "+"],
mentionComponent: MentionComponent,
theme: {
mentionSuggestions: "mentions-list",
},
});
const { MentionSuggestions } = mentionPlugin;
return { plugins: [mentionPlugin], MentionSuggestions };
}, []);
const onOpenChange = useCallback((_open: boolean) => {
setOpen(_open);
}, []);
const handleReturn = useCallback(
(e: React.KeyboardEvent, editorState: EditorState): DraftHandleValue => {
if (!e.nativeEvent.shiftKey && !open) {
onSubmit(editorState);
return "handled";
}
return "not-handled";
},
[open],
);
const focusInput = useCallback(() => {
// Forcing focus breaks plugins
// Ref: https://github.com/draft-js-plugins/draft-js-plugins/issues/800
setTimeout(() => ref.current?.focus());
}, []);
const setRef = useCallback((editorRef) => {
ref.current = editorRef;
if (autoFocus) focusInput();
}, []);
return (
{
if (onAddMention) {
onAddMention(mention);
}
}}
onOpenChange={onOpenChange}
onSearchChange={onSearchSuggestions}
open={open}
suggestions={suggestions}
/>
);
}
export default MentionsInput;