import React, { useCallback, useMemo } from 'react';
import isHotkey from 'is-hotkey';
import { Editable, withReact, useSlate, Slate, ReactEditor } from 'slate-react';
import { Editor, createEditor, BaseEditor, Descendant } from 'slate';
import { withHistory } from 'slate-history';
import { Button, Icon, Toolbar } from './components';
import { injectGlobal } from '@emotion/css';
const HOTKEYS = {
'mod+b': 'bold',
'mod+i': 'italic',
'mod+u': 'underline',
'mod+`': 'code',
};
//注入全局样式
injectGlobal`
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/materialicons/v140/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2)
format('woff2');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
`;
// 实现一个递归函数,有children就继续往下递归查找并把text拼接起来
function extractText(node: Descendant[] | any) {
let text = '';
if (node.text) {
// 处理加粗
text = node.bold ? `${node.text}` : node.text;
}
// 如果自己是数组
if (Array.isArray(node)) {
node.forEach(item => (text += extractText(item)));
} else {
if (node.children && node.children.length > 0) {
for (const curNode of node.children) {
text += extractText(curNode);
}
}
}
return text;
}
// const LIST_TYPES = ['numbered-list', 'bulleted-list'];
// const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify'];
const initialValue: Descendant[] = [
{
// @ts-ignore
type: 'paragraph',
children: [{ text: '' }],
},
];
const RichText = (props: {
editor?: ReactEditor;
value: Descendant[];
maxLength?: number;
children?: React.ReactNode;
onChange?: ((value: Descendant[], content: string) => void) | undefined;
}) => {
const { onChange, value, children, ...rest } = props;
const renderElement = useCallback((props: any) => , []);
const renderLeaf = useCallback((props: any) => , []);
const editor = useMemo(() => withHistory(withReact(createEditor())), []);
return (
{
if (onChange) {
return onChange(value, extractText(value));
}
// onChange && onChange(value, extractText(value));
}}
>
{/*
*/}
{
if (event.key === 'Enter') {
return event.preventDefault();
}
for (const hotkey in HOTKEYS) {
if (isHotkey(hotkey, event as any)) {
event.preventDefault();
// @ts-ignore
const mark = HOTKEYS[hotkey];
toggleMark(editor, mark);
}
}
}}
{...rest}
/>
);
};
// const toggleBlock = (editor: BaseEditor, format: string) => {
// const isActive = isBlockActive(
// editor,
// format,
// TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type'
// );
// const isList = LIST_TYPES.includes(format);
// Transforms.unwrapNodes(editor, {
// match: n =>
// !Editor.isEditor(n) &&
// SlateElement.isElement(n) &&
// LIST_TYPES.includes(n.type) &&
// !TEXT_ALIGN_TYPES.includes(format),
// split: true,
// });
// let newProperties: Partial;
// if (TEXT_ALIGN_TYPES.includes(format)) {
// newProperties = {
// align: isActive ? undefined : format,
// };
// } else {
// newProperties = {
// type: isActive ? 'paragraph' : isList ? 'list-item' : format,
// };
// }
// Transforms.setNodes(editor, newProperties);
// if (!isActive && isList) {
// const block = { type: format, children: [] };
// Transforms.wrapNodes(editor, block);
// }
// };
const toggleMark = (editor: BaseEditor, format: string) => {
const isActive = isMarkActive(editor, format);
if (isActive) {
Editor.removeMark(editor, format);
} else {
Editor.addMark(editor, format, true);
}
};
// const isBlockActive = (editor: BaseEditor, format: any, blockType = 'type') => {
// const { selection } = editor;
// if (!selection) return false;
// const [match] = Array.from(
// Editor.nodes(editor, {
// at: Editor.unhangRange(editor, selection),
// match: n =>
// !Editor.isEditor(n) &&
// SlateElement.isElement(n) &&
// n[blockType] === format,
// })
// );
// return !!match;
// };
const isMarkActive = (editor: BaseEditor, format: string | number) => {
const marks: Record | null = Editor.marks(editor);
return marks ? marks[format] === true : false;
};
const Element = ({ attributes, children, element }: any) => {
const style = { textAlign: element.align };
switch (element.type) {
case 'block-quote':
return (
{children}
);
case 'bulleted-list':
return (
);
case 'heading-one':
return (
{children}
);
case 'heading-two':
return (
{children}
);
case 'list-item':
return (
{children}
);
case 'numbered-list':
return (
{children}
);
default:
return (
{children}
);
}
};
const Leaf = ({ attributes, children, leaf }: any) => {
if (leaf.bold) {
children = {children};
}
if (leaf.code) {
children = {children};
}
if (leaf.italic) {
children = {children};
}
if (leaf.underline) {
children = {children};
}
return {children};
};
// const BlockButton = ({ format, icon }) => {
// const editor = useSlate();
// return (
//
// );
// };
const MarkButton = ({ format, icon }: any) => {
const editor = useSlate();
return (
);
};
export default RichText;