Work on mentions suggestions

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2023-03-23 22:35:57 +01:00
parent dadaadcdde
commit 2833bf4458
3 changed files with 104 additions and 32 deletions

View File

@ -35,8 +35,6 @@ const StatePlugin = ({ composeId }: { composeId: string }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [editor] = useLexicalComposerContext(); const [editor] = useLexicalComposerContext();
(window as any).xd = editor;
useEffect(() => { useEffect(() => {
editor.registerUpdateListener(({ editorState }) => { editor.registerUpdateListener(({ editorState }) => {
dispatch(setEditorState(composeId, editorState.isEmpty() ? null : JSON.stringify(editorState.toJSON()))); dispatch(setEditorState(composeId, editorState.isEmpty() ? null : JSON.stringify(editorState.toJSON())));

View File

@ -103,19 +103,6 @@ const scrollIntoViewIfNeeded = (target: HTMLElement) => {
target.scrollIntoView({ block: 'nearest' }); target.scrollIntoView({ block: 'nearest' });
}; };
function getTextUpToAnchor(selection: RangeSelection): string | null {
const anchor = selection.anchor;
if (!['mention', 'text'].includes(anchor.type)) {
return null;
}
const anchorNode = anchor.getNode();
if (anchor.type === 'text' && !anchorNode.isSimpleText()) {
return null;
}
const anchorOffset = anchor.offset;
return anchorNode.getTextContent().slice(0, anchorOffset);
}
function tryToPositionRange(leadOffset: number, range: Range): boolean { function tryToPositionRange(leadOffset: number, range: Range): boolean {
const domSelection = window.getSelection(); const domSelection = window.getSelection();
if (domSelection === null || !domSelection.isCollapsed) { if (domSelection === null || !domSelection.isCollapsed) {
@ -140,15 +127,12 @@ function tryToPositionRange(leadOffset: number, range: Range): boolean {
} }
function getQueryTextForSearch(editor: LexicalEditor): string | null { function getQueryTextForSearch(editor: LexicalEditor): string | null {
let text = null; const state = editor.getEditorState();
editor.getEditorState().read(() => { const node = (state._selection as RangeSelection)?.anchor?.getNode();
const selection = $getSelection();
if (!$isRangeSelection(selection)) { if (node && node.getType() === 'mention') return node.getTextContent();
return;
} return null;
text = getTextUpToAnchor(selection);
});
return text;
} }
/** /**
@ -173,10 +157,7 @@ function getFullMatchOffset(
* Split Lexical TextNode and return a new TextNode only containing matched text. * Split Lexical TextNode and return a new TextNode only containing matched text.
* Common use cases include: removing the node, replacing with a new node. * Common use cases include: removing the node, replacing with a new node.
*/ */
function splitNodeContainingQuery( function splitNodeContainingQuery(match: QueryMatch): TextNode | null {
editor: LexicalEditor,
match: QueryMatch,
): TextNode | null {
const selection = $getSelection(); const selection = $getSelection();
if (!$isRangeSelection(selection) || !selection.isCollapsed()) { if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
return null; return null;
@ -369,10 +350,7 @@ function LexicalPopoverMenu<TOption extends TypeaheadOption>({
const selectOptionAndCleanUp = useCallback( const selectOptionAndCleanUp = useCallback(
(selectedEntry: TOption) => { (selectedEntry: TOption) => {
editor.update(() => { editor.update(() => {
const textNodeContainingQuery = splitNodeContainingQuery( const textNodeContainingQuery = splitNodeContainingQuery(resolution.match);
editor,
resolution.match,
);
onSelectOption( onSelectOption(
selectedEntry, selectedEntry,

View File

@ -228,3 +228,99 @@
border-radius: 4px; border-radius: 4px;
} }
} }
.typeahead-popover {
background: #fff;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
border-radius: 8px;
margin-top: 25px;
}
.typeahead-popover ul {
padding: 0;
list-style: none;
margin: 0;
border-radius: 8px;
max-height: 200px;
overflow-y: scroll;
}
.typeahead-popover ul::-webkit-scrollbar {
display: none;
}
.typeahead-popover ul {
-ms-overflow-style: none;
scrollbar-width: none;
}
.typeahead-popover ul li {
margin: 0;
min-width: 180px;
font-size: 14px;
outline: none;
cursor: pointer;
border-radius: 8px;
}
.typeahead-popover ul li.selected {
background: #eee;
}
.typeahead-popover li {
margin: 0 8px;
padding: 8px;
color: #050505;
cursor: pointer;
line-height: 16px;
font-size: 15px;
display: flex;
align-content: center;
flex-direction: row;
flex-shrink: 0;
background-color: #fff;
border-radius: 8px;
border: 0;
}
.typeahead-popover li.active {
display: flex;
width: 20px;
height: 20px;
background-size: contain;
}
.typeahead-popover li:first-child {
border-radius: 8px 8px 0 0;
}
.typeahead-popover li:last-child {
border-radius: 0 0 8px 8px;
}
.typeahead-popover li:hover {
background-color: #eee;
}
.typeahead-popover li .text {
display: flex;
line-height: 20px;
flex-grow: 1;
min-width: 150px;
}
.typeahead-popover li .icon {
display: flex;
width: 20px;
height: 20px;
user-select: none;
margin-right: 8px;
line-height: 16px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.mentions-menu {
width: 250px;
}