wip
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
8c68e93e55
commit
6dd2172a04
3 changed files with 42 additions and 31 deletions
|
@ -208,7 +208,7 @@ const useDraggableBlockMenu = (
|
||||||
useState<HTMLElement | null>(null);
|
useState<HTMLElement | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onMouseMove(event: MouseEvent) {
|
const onMouseMove = (event: MouseEvent) => {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
if (!isHTMLElement(target)) {
|
if (!isHTMLElement(target)) {
|
||||||
setDraggableBlockElem(null);
|
setDraggableBlockElem(null);
|
||||||
|
@ -222,11 +222,9 @@ const useDraggableBlockMenu = (
|
||||||
const _draggableBlockElem = getBlockElement(anchorElem, editor, event);
|
const _draggableBlockElem = getBlockElement(anchorElem, editor, event);
|
||||||
|
|
||||||
setDraggableBlockElem(_draggableBlockElem);
|
setDraggableBlockElem(_draggableBlockElem);
|
||||||
}
|
};
|
||||||
|
|
||||||
function onMouseLeave() {
|
const onMouseLeave = () => setDraggableBlockElem(null);
|
||||||
setDraggableBlockElem(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollerElem?.addEventListener('mousemove', onMouseMove);
|
scrollerElem?.addEventListener('mousemove', onMouseMove);
|
||||||
scrollerElem?.addEventListener('mouseleave', onMouseLeave);
|
scrollerElem?.addEventListener('mouseleave', onMouseLeave);
|
||||||
|
@ -244,7 +242,7 @@ const useDraggableBlockMenu = (
|
||||||
}, [anchorElem, draggableBlockElem]);
|
}, [anchorElem, draggableBlockElem]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function onDragover(event: DragEvent): boolean {
|
const onDragover = (event: DragEvent): boolean => {
|
||||||
const [isFileTransfer] = eventFiles(event);
|
const [isFileTransfer] = eventFiles(event);
|
||||||
if (isFileTransfer) {
|
if (isFileTransfer) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -262,9 +260,9 @@ const useDraggableBlockMenu = (
|
||||||
// Prevent default event to be able to trigger onDrop events
|
// Prevent default event to be able to trigger onDrop events
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
function onDrop(event: DragEvent): boolean {
|
const onDrop = (event: DragEvent): boolean => {
|
||||||
const [isFileTransfer] = eventFiles(event);
|
const [isFileTransfer] = eventFiles(event);
|
||||||
if (isFileTransfer) {
|
if (isFileTransfer) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -299,7 +297,7 @@ const useDraggableBlockMenu = (
|
||||||
setDraggableBlockElem(null);
|
setDraggableBlockElem(null);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
return mergeRegister(
|
return mergeRegister(
|
||||||
editor.registerCommand(
|
editor.registerCommand(
|
||||||
|
@ -319,7 +317,7 @@ const useDraggableBlockMenu = (
|
||||||
);
|
);
|
||||||
}, [anchorElem, editor]);
|
}, [anchorElem, editor]);
|
||||||
|
|
||||||
function onDragStart(event: ReactDragEvent<HTMLDivElement>): void {
|
const onDragStart = (event: ReactDragEvent<HTMLDivElement>): void => {
|
||||||
const dataTransfer = event.dataTransfer;
|
const dataTransfer = event.dataTransfer;
|
||||||
if (!dataTransfer || !draggableBlockElem) {
|
if (!dataTransfer || !draggableBlockElem) {
|
||||||
return;
|
return;
|
||||||
|
@ -333,11 +331,11 @@ const useDraggableBlockMenu = (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dataTransfer.setData(DRAG_DATA_FORMAT, nodeKey);
|
dataTransfer.setData(DRAG_DATA_FORMAT, nodeKey);
|
||||||
}
|
};
|
||||||
|
|
||||||
function onDragEnd(): void {
|
const onDragEnd = (): void => {
|
||||||
hideTargetLine(targetLineRef.current);
|
hideTargetLine(targetLineRef.current);
|
||||||
}
|
};
|
||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<>
|
<>
|
||||||
|
@ -359,11 +357,13 @@ const useDraggableBlockMenu = (
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DraggableBlockPlugin({
|
const DraggableBlockPlugin = ({
|
||||||
anchorElem = document.body,
|
anchorElem = document.body,
|
||||||
}: {
|
}: {
|
||||||
anchorElem?: HTMLElement
|
anchorElem?: HTMLElement
|
||||||
}): JSX.Element {
|
}): JSX.Element => {
|
||||||
const [editor] = useLexicalComposerContext();
|
const [editor] = useLexicalComposerContext();
|
||||||
return useDraggableBlockMenu(editor, anchorElem, editor._editable);
|
return useDraggableBlockMenu(editor, anchorElem, editor._editable);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default DraggableBlockPlugin;
|
||||||
|
|
|
@ -109,6 +109,7 @@ const TextFormatFloatingToolbar = ({
|
||||||
editor.getEditorState().read(() => {
|
editor.getEditorState().read(() => {
|
||||||
updateTextFormatFloatingToolbar();
|
updateTextFormatFloatingToolbar();
|
||||||
});
|
});
|
||||||
|
|
||||||
return mergeRegister(
|
return mergeRegister(
|
||||||
editor.registerUpdateListener(({ editorState }) => {
|
editor.registerUpdateListener(({ editorState }) => {
|
||||||
editorState.read(() => {
|
editorState.read(() => {
|
||||||
|
@ -131,6 +132,16 @@ const TextFormatFloatingToolbar = ({
|
||||||
<div ref={popupCharStylesEditorRef} className='floating-text-format-popup'>
|
<div ref={popupCharStylesEditorRef} className='floating-text-format-popup'>
|
||||||
{editor.isEditable() && (
|
{editor.isEditable() && (
|
||||||
<>
|
<>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
|
||||||
|
}}
|
||||||
|
className={'popup-item spaced ' + (isBold ? 'active' : '')}
|
||||||
|
aria-label='Format text as bold'
|
||||||
|
type='button'
|
||||||
|
>
|
||||||
|
<Icon src={require('@tabler/icons/align-left.svg')} />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
|
||||||
|
|
|
@ -106,7 +106,7 @@ const dummyLookupService = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function useMentionLookupService(mentionString: string | null) {
|
const useMentionLookupService = (mentionString: string | null) => {
|
||||||
const [results, setResults] = useState<Array<string>>([]);
|
const [results, setResults] = useState<Array<string>>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -132,12 +132,12 @@ function useMentionLookupService(mentionString: string | null) {
|
||||||
}, [mentionString]);
|
}, [mentionString]);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
};
|
||||||
|
|
||||||
function checkForCapitalizedNameMentions(
|
const checkForCapitalizedNameMentions = (
|
||||||
text: string,
|
text: string,
|
||||||
minMatchLength: number,
|
minMatchLength: number,
|
||||||
): QueryMatch | null {
|
): QueryMatch | null => {
|
||||||
const match = CapitalizedNameMentionsRegex.exec(text);
|
const match = CapitalizedNameMentionsRegex.exec(text);
|
||||||
if (match !== null) {
|
if (match !== null) {
|
||||||
// The strategy ignores leading whitespace but we need to know it's
|
// The strategy ignores leading whitespace but we need to know it's
|
||||||
|
@ -154,12 +154,12 @@ function checkForCapitalizedNameMentions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
function checkForAtSignMentions(
|
const checkForAtSignMentions = (
|
||||||
text: string,
|
text: string,
|
||||||
minMatchLength: number,
|
minMatchLength: number,
|
||||||
): QueryMatch | null {
|
): QueryMatch | null => {
|
||||||
let match = AtSignMentionsRegex.exec(text);
|
let match = AtSignMentionsRegex.exec(text);
|
||||||
if (match === null) {
|
if (match === null) {
|
||||||
match = AtSignMentionsRegexAliasRegex.exec(text);
|
match = AtSignMentionsRegexAliasRegex.exec(text);
|
||||||
|
@ -179,12 +179,12 @@ function checkForAtSignMentions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
function getPossibleQueryMatch(text: string): QueryMatch | null {
|
const getPossibleQueryMatch = (text: string): QueryMatch | null => {
|
||||||
const match = checkForAtSignMentions(text, 1);
|
const match = checkForAtSignMentions(text, 1);
|
||||||
return match === null ? checkForCapitalizedNameMentions(text, 3) : match;
|
return match === null ? checkForCapitalizedNameMentions(text, 3) : match;
|
||||||
}
|
};
|
||||||
|
|
||||||
class MentionTypeaheadOption extends TypeaheadOption {
|
class MentionTypeaheadOption extends TypeaheadOption {
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ class MentionTypeaheadOption extends TypeaheadOption {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function MentionsTypeaheadMenuItem({
|
const MentionsTypeaheadMenuItem = ({
|
||||||
index,
|
index,
|
||||||
isSelected,
|
isSelected,
|
||||||
onClick,
|
onClick,
|
||||||
|
@ -211,7 +211,7 @@ function MentionsTypeaheadMenuItem({
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
onMouseEnter: () => void
|
onMouseEnter: () => void
|
||||||
option: MentionTypeaheadOption
|
option: MentionTypeaheadOption
|
||||||
}) {
|
}) => {
|
||||||
let className = 'item';
|
let className = 'item';
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
className += ' selected';
|
className += ' selected';
|
||||||
|
@ -232,9 +232,9 @@ function MentionsTypeaheadMenuItem({
|
||||||
<span className='text'>{option.name}</span>
|
<span className='text'>{option.name}</span>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function MentionPlugin(): JSX.Element | null {
|
export const MentionPlugin = (): JSX.Element | null => {
|
||||||
const [editor] = useLexicalComposerContext();
|
const [editor] = useLexicalComposerContext();
|
||||||
|
|
||||||
const [queryString, setQueryString] = useState<string | null>(null);
|
const [queryString, setQueryString] = useState<string | null>(null);
|
||||||
|
@ -352,4 +352,4 @@ export function MentionPlugin(): JSX.Element | null {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
Loading…
Reference in a new issue