feat:添加分割线
This commit is contained in:
parent
4a995d69a5
commit
36f2cb43e0
|
@ -1,13 +1,13 @@
|
||||||
import {useCallback, useMemo, useState} from 'react';
|
import {useCallback, useMemo, useState} from 'react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Modal} from "antd";
|
|
||||||
|
import Modal from '../plugins/Input/Modal';
|
||||||
|
|
||||||
export default function useModal(){
|
export default function useModal(){
|
||||||
const [modalContent, setModalContent] = useState(null);
|
const [modalContent, setModalContent] = useState(null);
|
||||||
const [isOpen,setIsOpen]=useState(true)
|
|
||||||
const onClose = useCallback(() => {
|
const onClose = useCallback(() => {
|
||||||
setModalContent(null);
|
setModalContent(null);
|
||||||
setIsOpen(false)
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const modal = useMemo(() => {
|
const modal = useMemo(() => {
|
||||||
|
@ -15,21 +15,19 @@ export default function useModal(){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const {title, content, closeOnClickOutside} = modalContent;
|
const {title, content, closeOnClickOutside} = modalContent;
|
||||||
return (<div>
|
console.log("modalContent !== null",modalContent)
|
||||||
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={isOpen}
|
onClose={onClose}
|
||||||
//onOk={handleOk}
|
|
||||||
onCancel={onClose}
|
|
||||||
title={title}
|
title={title}
|
||||||
// closeOnClickOutside={closeOnClickOutside}
|
closeOnClickOutside={closeOnClickOutside}>
|
||||||
>
|
|
||||||
|
|
||||||
{content}
|
{content}
|
||||||
</Modal></div>
|
</Modal>
|
||||||
);
|
);
|
||||||
}, [modalContent, onClose,isOpen]);
|
}, [modalContent, onClose]);
|
||||||
|
|
||||||
const showModal = useCallback((
|
const showModal = useCallback(
|
||||||
|
(
|
||||||
title,
|
title,
|
||||||
getContent,
|
getContent,
|
||||||
closeOnClickOutside = false,
|
closeOnClickOutside = false,
|
||||||
|
|
|
@ -20,11 +20,13 @@ import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
|
||||||
import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin";
|
import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin";
|
||||||
import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin";
|
import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin";
|
||||||
import ImportFilePlugin from "./plugins/ImportFilePlugin";
|
import ImportFilePlugin from "./plugins/ImportFilePlugin";
|
||||||
import {TablePlugin} from "@lexical/react/LexicalTablePlugin";
|
|
||||||
import SaveFilePlugin from "./plugins/SaveFilePlugin";
|
import SaveFilePlugin from "./plugins/SaveFilePlugin";
|
||||||
import {TabIndentationPlugin} from "@lexical/react/LexicalTabIndentationPlugin";
|
import {TabIndentationPlugin} from "@lexical/react/LexicalTabIndentationPlugin";
|
||||||
import UsefulNodes from "./nodes/UsefulNodes";
|
import UsefulNodes from "./nodes/UsefulNodes";
|
||||||
import ImagesPlugin from "./plugins/ImagesPlugin";
|
import ImagesPlugin from "./plugins/ImagesPlugin";
|
||||||
|
import {TablePlugin} from "./plugins/TablePlugin";
|
||||||
|
import {HorizontalRulePlugin} from "@lexical/react/LexicalHorizontalRulePlugin"
|
||||||
function Placeholder() {
|
function Placeholder() {
|
||||||
return <div className="editor-placeholder">Enter some rich text...</div>;
|
return <div className="editor-placeholder">Enter some rich text...</div>;
|
||||||
}
|
}
|
||||||
|
@ -74,9 +76,12 @@ export default function Hlexical(props) {
|
||||||
<MarkdownShortcutPlugin transformers={TRANSFORMERS}/>
|
<MarkdownShortcutPlugin transformers={TRANSFORMERS}/>
|
||||||
{/*图片加载*/}
|
{/*图片加载*/}
|
||||||
<ImagesPlugin/>
|
<ImagesPlugin/>
|
||||||
|
{/*分割线 */}
|
||||||
|
<HorizontalRulePlugin />
|
||||||
|
{/*页分割线*/}
|
||||||
|
|
||||||
{/*目录加载*/}
|
{/*目录加载*/}
|
||||||
{/* 表格加载 */}
|
{/* 表格加载 */}
|
||||||
|
|
||||||
{/*<TableOfContentsPlugin />*/}
|
{/*<TableOfContentsPlugin />*/}
|
||||||
{/*<LexicalTableOfContents>*/}
|
{/*<LexicalTableOfContents>*/}
|
||||||
{/* {(tableOfContentsArray) => {*/}
|
{/* {(tableOfContentsArray) => {*/}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {ListItemNode, ListNode} from "@lexical/list";
|
||||||
import {CodeHighlightNode, CodeNode, $createCodeNode, $isCodeNode} from "@lexical/code";
|
import {CodeHighlightNode, CodeNode, $createCodeNode, $isCodeNode} from "@lexical/code";
|
||||||
import {AutoLinkNode, LinkNode} from "@lexical/link";
|
import {AutoLinkNode, LinkNode} from "@lexical/link";
|
||||||
import {ImageNode} from "./ImageNode";
|
import {ImageNode} from "./ImageNode";
|
||||||
|
import {HorizontalRuleNode} from "@lexical/react/LexicalHorizontalRuleNode";
|
||||||
|
|
||||||
const UsefulNodes=[
|
const UsefulNodes=[
|
||||||
HeadingNode,
|
HeadingNode,
|
||||||
|
@ -17,6 +18,7 @@ const UsefulNodes=[
|
||||||
TableRowNode,
|
TableRowNode,
|
||||||
AutoLinkNode,
|
AutoLinkNode,
|
||||||
ImageNode,
|
ImageNode,
|
||||||
LinkNode
|
LinkNode,
|
||||||
|
HorizontalRuleNode,
|
||||||
]
|
]
|
||||||
export default UsefulNodes;
|
export default UsefulNodes;
|
|
@ -0,0 +1,89 @@
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {useEffect, useRef} from 'react';
|
||||||
|
import {createPortal} from 'react-dom';
|
||||||
|
|
||||||
|
function PortalImpl({ onClose,
|
||||||
|
children,
|
||||||
|
title,
|
||||||
|
closeOnClickOutside,
|
||||||
|
}) {
|
||||||
|
const modalRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("PortalImpl")
|
||||||
|
if (modalRef.current !== null) {
|
||||||
|
modalRef.current.focus();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let modalOverlayElement= null;
|
||||||
|
const handler = (event) => {
|
||||||
|
if (event.keyCode === 27) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const clickOutsideHandler = (event) => {
|
||||||
|
const target = event.target;
|
||||||
|
if (
|
||||||
|
modalRef.current !== null &&
|
||||||
|
!modalRef.current.contains(target) &&
|
||||||
|
closeOnClickOutside
|
||||||
|
) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const modelElement = modalRef.current;
|
||||||
|
if (modelElement !== null) {
|
||||||
|
modalOverlayElement = modelElement.parentElement;
|
||||||
|
if (modalOverlayElement !== null) {
|
||||||
|
modalOverlayElement.addEventListener('click', clickOutsideHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handler);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('keydown', handler);
|
||||||
|
if (modalOverlayElement !== null) {
|
||||||
|
modalOverlayElement?.removeEventListener('click', clickOutsideHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [closeOnClickOutside, onClose]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="Modal__overlay" role="dialog">
|
||||||
|
<div className="Modal__modal" tabIndex={-1} ref={modalRef}>
|
||||||
|
<h2 className="Modal__title">{title}</h2>
|
||||||
|
<button
|
||||||
|
className="Modal__closeButton"
|
||||||
|
aria-label="Close modal"
|
||||||
|
type="button"
|
||||||
|
onClick={onClose}>
|
||||||
|
X
|
||||||
|
</button>
|
||||||
|
<div className="Modal__content">{children}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Modal({
|
||||||
|
onClose,
|
||||||
|
children,
|
||||||
|
title,
|
||||||
|
closeOnClickOutside = false,
|
||||||
|
}){
|
||||||
|
console.log("createPortal")
|
||||||
|
return createPortal(
|
||||||
|
<PortalImpl
|
||||||
|
onClose={onClose}
|
||||||
|
title={title}
|
||||||
|
closeOnClickOutside={closeOnClickOutside}>
|
||||||
|
{children}
|
||||||
|
</PortalImpl>,
|
||||||
|
document.body,
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
.Modal__overlay {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
flex-direction: column;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
background-color: rgba(40, 40, 40, 0.6);
|
||||||
|
flex-grow: 0px;
|
||||||
|
flex-shrink: 1px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
.Modal__modal {
|
||||||
|
padding: 20px;
|
||||||
|
min-height: 100px;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 0px;
|
||||||
|
background-color: #fff;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 0 20px 0 #444;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.Modal__title {
|
||||||
|
color: #444;
|
||||||
|
margin: 0px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.Modal__closeButton {
|
||||||
|
border: 0px;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
border-radius: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
.Modal__closeButton:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
.Modal__content {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
|
@ -102,53 +102,53 @@ export function InsertTableDialog({activeEditor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InsertNewTableDialog({activeEditor, onClose,
|
// export function InsertNewTableDialog({activeEditor, onClose,
|
||||||
}){
|
// }){
|
||||||
const [rows, setRows] = useState('');
|
// const [rows, setRows] = useState('');
|
||||||
const [columns, setColumns] = useState('');
|
// const [columns, setColumns] = useState('');
|
||||||
const [isDisabled, setIsDisabled] = useState(true);
|
// const [isDisabled, setIsDisabled] = useState(true);
|
||||||
|
//
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const row = Number(rows);
|
// const row = Number(rows);
|
||||||
const column = Number(columns);
|
// const column = Number(columns);
|
||||||
if (row && row > 0 && row <= 500 && column && column > 0 && column <= 50) {
|
// if (row && row > 0 && row <= 500 && column && column > 0 && column <= 50) {
|
||||||
setIsDisabled(false);
|
// setIsDisabled(false);
|
||||||
} else {
|
// } else {
|
||||||
setIsDisabled(true);
|
// setIsDisabled(true);
|
||||||
}
|
// }
|
||||||
}, [rows, columns]);
|
// }, [rows, columns]);
|
||||||
|
//
|
||||||
const onClick = () => {
|
// const onClick = () => {
|
||||||
activeEditor.dispatchCommand(INSERT_NEW_TABLE_COMMAND, {columns, rows});
|
// activeEditor.dispatchCommand(INSERT_NEW_TABLE_COMMAND, {columns, rows});
|
||||||
onClose();
|
// onClose();
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
return (
|
// return (
|
||||||
<>
|
// <>
|
||||||
<TextInput
|
// <TextInput
|
||||||
placeholder={'# of rows (1-500)'}
|
// placeholder={'# of rows (1-500)'}
|
||||||
label="Rows"
|
// label="Rows"
|
||||||
onChange={setRows}
|
// onChange={setRows}
|
||||||
value={rows}
|
// value={rows}
|
||||||
data-test-id="table-modal-rows"
|
// data-test-id="table-modal-rows"
|
||||||
type="number"
|
// type="number"
|
||||||
/>
|
// />
|
||||||
<TextInput
|
// <TextInput
|
||||||
placeholder={'# of columns (1-50)'}
|
// placeholder={'# of columns (1-50)'}
|
||||||
label="Columns"
|
// label="Columns"
|
||||||
onChange={setColumns}
|
// onChange={setColumns}
|
||||||
value={columns}
|
// value={columns}
|
||||||
data-test-id="table-modal-columns"
|
// data-test-id="table-modal-columns"
|
||||||
type="number"
|
// type="number"
|
||||||
/>
|
// />
|
||||||
<DialogActions data-test-id="table-model-confirm-insert">
|
// <DialogActions data-test-id="table-model-confirm-insert">
|
||||||
<Button disabled={isDisabled} onClick={onClick}>
|
// <Button disabled={isDisabled} onClick={onClick}>
|
||||||
Confirm
|
// Confirm
|
||||||
</Button>
|
// </Button>
|
||||||
</DialogActions>
|
// </DialogActions>
|
||||||
</>
|
// </>
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function TablePlugin({
|
export function TablePlugin({
|
||||||
cellEditorConfig,
|
cellEditorConfig,
|
||||||
|
@ -165,7 +165,7 @@ export function TablePlugin({
|
||||||
cellContext.set(cellEditorConfig, children);
|
cellContext.set(cellEditorConfig, children);
|
||||||
|
|
||||||
return editor.registerCommand(
|
return editor.registerCommand(
|
||||||
INSERT_NEW_TABLE_COMMAND,
|
INSERT_TABLE_COMMAND,
|
||||||
({columns, rows, includeHeaders}) => {
|
({columns, rows, includeHeaders}) => {
|
||||||
const tableNode = $createTableNodeWithDimensions(
|
const tableNode = $createTableNodeWithDimensions(
|
||||||
Number(rows),
|
Number(rows),
|
||||||
|
|
|
@ -44,7 +44,7 @@ import DropDown, {DropDownItem} from "./Input/DropDown";
|
||||||
import {InsertImageDialog} from "./ImagesPlugin";
|
import {InsertImageDialog} from "./ImagesPlugin";
|
||||||
import useModal from "../hook/userModal";
|
import useModal from "../hook/userModal";
|
||||||
import {InsertTableDialog} from "./TablePlugin";
|
import {InsertTableDialog} from "./TablePlugin";
|
||||||
import {INSERT_HORIZONTAL_RULE_COMMAND} from "@lexical/react/LexicalHorizontalRuleNode.prod";
|
import {INSERT_HORIZONTAL_RULE_COMMAND} from "@lexical/react/LexicalHorizontalRuleNode";
|
||||||
|
|
||||||
const LowPriority = 1;
|
const LowPriority = 1;
|
||||||
|
|
||||||
|
@ -701,11 +701,10 @@ export default function ToolbarPlugin() {
|
||||||
>
|
>
|
||||||
<i className="format justify-align"/>
|
<i className="format justify-align"/>
|
||||||
</button>
|
</button>
|
||||||
{" "}
|
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<DropDown
|
<DropDown
|
||||||
buttonClassName="toolbar-item spaced"
|
buttonClassName="toolbar-item spaced"
|
||||||
buttonLabel="Insert"
|
buttonLabel="插入"
|
||||||
buttonAriaLabel="Insert specialized editor node"
|
buttonAriaLabel="Insert specialized editor node"
|
||||||
buttonIconClassName="icon plus">
|
buttonIconClassName="icon plus">
|
||||||
<DropDownItem
|
<DropDownItem
|
||||||
|
@ -717,16 +716,16 @@ export default function ToolbarPlugin() {
|
||||||
}}
|
}}
|
||||||
className="item">
|
className="item">
|
||||||
<i className="icon horizontal-rule"/>
|
<i className="icon horizontal-rule"/>
|
||||||
<span className="text">Horizontal Rule</span>
|
<span className="text">分割线</span>
|
||||||
</DropDownItem>
|
|
||||||
<DropDownItem
|
|
||||||
onClick={() => {
|
|
||||||
activeEditor.dispatchCommand(INSERT_PAGE_BREAK, undefined);
|
|
||||||
}}
|
|
||||||
className="item">
|
|
||||||
<i className="icon page-break"/>
|
|
||||||
<span className="text">Page Break</span>
|
|
||||||
</DropDownItem>
|
</DropDownItem>
|
||||||
|
{/*<DropDownItem*/}
|
||||||
|
{/* onClick={() => {*/}
|
||||||
|
{/* activeEditor.dispatchCommand(INSERT_PAGE_BREAK, undefined);*/}
|
||||||
|
{/* }}*/}
|
||||||
|
{/* className="item">*/}
|
||||||
|
{/* <i className="icon page-break"/>*/}
|
||||||
|
{/* <span className="text">页分割线</span>*/}
|
||||||
|
{/*</DropDownItem>*/}
|
||||||
<DropDownItem
|
<DropDownItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
showModal('Insert Image', (onClose) => (
|
showModal('Insert Image', (onClose) => (
|
||||||
|
@ -738,7 +737,7 @@ export default function ToolbarPlugin() {
|
||||||
}}
|
}}
|
||||||
className="item">
|
className="item">
|
||||||
<i className="icon image"/>
|
<i className="icon image"/>
|
||||||
<span className="text">Image</span>
|
<span className="text">图片</span>
|
||||||
</DropDownItem>
|
</DropDownItem>
|
||||||
<DropDownItem
|
<DropDownItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -751,7 +750,7 @@ export default function ToolbarPlugin() {
|
||||||
}}
|
}}
|
||||||
className="item">
|
className="item">
|
||||||
<i className="icon image"/>
|
<i className="icon image"/>
|
||||||
<span className="text">Inline Image</span>
|
<span className="text">行内图片</span>
|
||||||
</DropDownItem>
|
</DropDownItem>
|
||||||
<DropDownItem
|
<DropDownItem
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
@ -762,7 +761,7 @@ export default function ToolbarPlugin() {
|
||||||
}
|
}
|
||||||
className="item">
|
className="item">
|
||||||
<i className="icon gif"/>
|
<i className="icon gif"/>
|
||||||
<span className="text">GIF</span>
|
<span className="text">动态图片</span>
|
||||||
</DropDownItem>
|
</DropDownItem>
|
||||||
<DropDownItem
|
<DropDownItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -773,7 +772,7 @@ export default function ToolbarPlugin() {
|
||||||
}}
|
}}
|
||||||
className="item">
|
className="item">
|
||||||
<i className="icon diagram-2"/>
|
<i className="icon diagram-2"/>
|
||||||
<span className="text">Excalidraw</span>
|
<span className="text">画图</span>
|
||||||
</DropDownItem>
|
</DropDownItem>
|
||||||
<DropDownItem
|
<DropDownItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -789,7 +788,7 @@ export default function ToolbarPlugin() {
|
||||||
<span className="text">表格</span>
|
<span className="text">表格</span>
|
||||||
</DropDownItem>
|
</DropDownItem>
|
||||||
</DropDown>
|
</DropDown>
|
||||||
|
{modal}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue