const handleKeydown: KeyboardEventHandler = useCallback(
(evt) => {
onKeyDown?.(evt);
- toggleKeyboardShortcut(editor, evt);
+ const shortcutToggled = toggleKeyboardShortcut(editor, evt);
+ if (shortcutToggled) evt.preventDefault();
},
[editor, onKeyDown]
);
as="img"
src={mx.mxcUrlToHttp(key) || key}
alt={emoticon.shortcode}
- style={{ width: toRem(24), height: toRem(24) }}
+ style={{ width: toRem(24), height: toRem(24), objectFit: 'contain' }}
/>
) : (
<Box
validPrefixes: readonly TPrefix[]
): TPrefix | undefined => {
const world = Editor.string(editor, queryRange);
- const prefix = world[0] as TPrefix | undefined;
- if (!prefix) return undefined;
- return validPrefixes.includes(prefix) ? prefix : undefined;
+ return validPrefixes.find((p) => world.startsWith(p));
};
-export const getAutocompleteQueryText = (editor: Editor, queryRange: BaseRange): string =>
- Editor.string(editor, queryRange).slice(1);
+export const getAutocompleteQueryText = (
+ editor: Editor,
+ queryRange: BaseRange,
+ prefix: string
+): string => Editor.string(editor, queryRange).slice(prefix.length);
export const getAutocompleteQuery = <TPrefix extends string>(
editor: Editor,
return {
range: queryRange,
prefix,
- text: getAutocompleteQueryText(editor, queryRange),
+ text: getAutocompleteQueryText(editor, queryRange, prefix),
};
};
import { BlockType, MarkType } from './Elements';
import { EmoticonElement, FormattedText, HeadingLevel, LinkElement, MentionElement } from './slate';
+const ALL_MARK_TYPE: MarkType[] = [
+ MarkType.Bold,
+ MarkType.Code,
+ MarkType.Italic,
+ MarkType.Spoiler,
+ MarkType.StrikeThrough,
+ MarkType.Underline,
+];
+
export const isMarkActive = (editor: Editor, format: MarkType) => {
const marks = Editor.marks(editor);
return marks ? marks[format] === true : false;
};
+export const isAnyMarkActive = (editor: Editor) => {
+ const marks = Editor.marks(editor);
+ return marks && !!ALL_MARK_TYPE.find((type) => marks[type] === true);
+};
+
export const toggleMark = (editor: Editor, format: MarkType) => {
const isActive = isMarkActive(editor, format);
}
};
+export const removeAllMark = (editor: Editor) => {
+ ALL_MARK_TYPE.forEach((mark) => Editor.removeMark(editor, mark));
+};
+
export const isBlockActive = (editor: Editor, format: BlockType) => {
const [match] = Editor.nodes(editor, {
match: (node) => Element.isElement(node) && node.type === format,
};
export const moveCursor = (editor: Editor, withSpace?: boolean) => {
- // without timeout it works properly when we select autocomplete with Tab or Space
+ // without timeout move cursor doesn't works properly.
setTimeout(() => {
Transforms.move(editor);
if (withSpace) editor.insertText(' ');
- }, 1);
+ }, 100);
};
interface PointUntilCharOptions {
import { isHotkey } from 'is-hotkey';
import { KeyboardEvent } from 'react';
import { Editor } from 'slate';
-import { isBlockActive, toggleBlock, toggleMark } from './common';
+import { isAnyMarkActive, isBlockActive, removeAllMark, toggleBlock, toggleMark } from './common';
import { BlockType, MarkType } from './Elements';
export const INLINE_HOTKEYS: Record<string, MarkType> = {
};
const BLOCK_KEYS = Object.keys(BLOCK_HOTKEYS);
-export const toggleKeyboardShortcut = (editor: Editor, event: KeyboardEvent<Element>) => {
- BLOCK_KEYS.forEach((hotkey) => {
+/**
+ * @return boolean true if shortcut is toggled.
+ */
+export const toggleKeyboardShortcut = (editor: Editor, event: KeyboardEvent<Element>): boolean => {
+ if (isHotkey('escape', event)) {
+ if (isAnyMarkActive(editor)) {
+ removeAllMark(editor);
+ return true;
+ }
+ console.log(isBlockActive(editor, BlockType.Paragraph));
+ if (!isBlockActive(editor, BlockType.Paragraph)) {
+ toggleBlock(editor, BlockType.Paragraph);
+ return true;
+ }
+ return false;
+ }
+
+ const blockToggled = BLOCK_KEYS.find((hotkey) => {
if (isHotkey(hotkey, event)) {
event.preventDefault();
toggleBlock(editor, BLOCK_HOTKEYS[hotkey]);
+ return true;
}
+ return false;
});
+ if (blockToggled) return true;
- if (!isBlockActive(editor, BlockType.CodeBlock))
- INLINE_KEYS.forEach((hotkey) => {
- if (isHotkey(hotkey, event)) {
- event.preventDefault();
- toggleMark(editor, INLINE_HOTKEYS[hotkey]);
- }
- });
+ const inlineToggled = isBlockActive(editor, BlockType.CodeBlock)
+ ? false
+ : INLINE_KEYS.find((hotkey) => {
+ if (isHotkey(hotkey, event)) {
+ event.preventDefault();
+ toggleMark(editor, INLINE_HOTKEYS[hotkey]);
+ return true;
+ }
+ return false;
+ });
+ return !!inlineToggled;
};
export const toPlainText = (node: Descendant | Descendant[]): string => {
if (Array.isArray(node)) return node.map((n) => toPlainText(n)).join('');
- if (Text.isText(node)) return sanitizeText(node.text);
+ if (Text.isText(node)) return node.text;
const children = node.children.map((n) => toPlainText(n)).join('');
return elementToPlainText(node, children);
{
width: toRem(32),
height: toRem(32),
+ objectFit: 'contain',
},
]);
{
width: toRem(96),
height: toRem(96),
+ objectFit: 'contain',
},
]);
style={{
width: toRem(24),
height: toRem(24),
+ objectFit: 'contain',
}}
src={mx.mxcUrlToHttp(pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl}
alt={label || 'Unknown Pack'}
body,
formattedBody,
});
+ ReactEditor.focus(editor);
};
navigation.on(cons.events.navigation.REPLY_TO_CLICKED, handleReplyTo);
return () => {
navigation.removeListener(cons.events.navigation.REPLY_TO_CLICKED, handleReplyTo);
};
- }, [setReplyDraft]);
+ }, [setReplyDraft, editor]);
const handleRemoveUpload = useCallback(
(upload: TUploadContent | TUploadContent[]) => {