Open cevio opened 1 year ago
@cevio
@thesunny
My project is PJBlog which since 2004-present. We decided to restart the project. So, Markdown editor is a very important function for us. The core of the blog is the editor, we hope that the basic functions and extended functions can be realized through your editor. But we're running into some difficulties now.
Can you consider the following implementation?
import { Editable, useEditor, Plugin } from '@wysimark/react';
import type { IPlugin } from '@wysimark/react';
import type { PropsWithoutRef } from 'react';
class CustomPlugin extends Plugin implements IPlugin {
static create(key: string) {
return new CustomPlugin(key);
}
}
const plugins = [
Plugin.Headings('headings', 2, 3),
Plugin.Source('source', ...),
Plugin.Image('image', {
api: '...'
}),
CustomPlugin.create('custom'),
// ... and more plugins
]
export default function Editor(props: PropsWithoutRef<{ value: string }>) {
const editor = useEditor({
initialMarkdown: props.value,
// ... more options
})
return <Editable.Context plugins={plugins} language="en">
<Editable.Toolbar format="source | headings| aligns font fontSize | custom history ..." />
<Editable.Editor editor={editor} />
</Editable.Context>
}
The plug-in provides the content on the toolbar and the function realization of the main part of the editor for the editor, and can achieve the desired effect through its own configuration. format
can control the sorting order on the toolbar.
The separation of toolbar
and editor
can make the editor more customizable.
well, here we go. my project is helpbuttons.org and it would be awesome to be able to customize the toolbar so that some of the buttons could be hidden. also in the near future i will like to add a possibility to mention someone (but this is another issue)
a possible implementation could be:
export default function TextEditor() {
const editor = useEditor({
initialMarkdown: 'Type your post text here...',
});
return (
<Editable editor={editor}>
<EditableDefaultToolbar/>
</Editable>);
}
custom toolbar:
export default function TextEditor() {
const editor = useEditor({
initialMarkdown: 'Type your post text here...',
});
return (
<Editable editor={editor}>
<CustomEditableToolbar/>
</Editable>);
}
function CustomEditableToolar() {
return (<>
<EditableButtonParagraph/>
<EditableButtonBold/>
</>
)
}
+1 for this! I need to remove some toolbar options for my implementation and right now just have some janky CSS which targets the buttons and hides them. Would love to have this configurable.
Adding and removing buttons (e.g. customizing the toolbar) would definitely be a nice feature enhancement.
Customizing the buttons is tricky, since the class names are dynamic, without changing the source code we can perform a hack.
The first is to hide the buttons by position in css:
.mdeditor > div > div > div > div:nth-child(5),
.mdeditor > div > div > div > div:nth-child(7),
.mdeditor > div > div > div > div:nth-child(9),
.mdeditor > div > div > div > div:nth-child(10),
.mdeditor > div > div > div > div:nth-child(11),
.mdeditor > div > div > div > div:nth-child(12) {
display: none;
}
//if you want to customize the editor you can do it here or use className
.mdeditor > div > div[role="textbox"] {
padding: 1.2rem 1.2rem 0.2rem;
color: red;
}
Next to remove the dropdown options of menus, we can add an observer to listen to changes in UI. In the following example, the code will hide "Checklist", "Heading 3", "Heading 4", "Heading 5", "Heading 6" options.
"use client";
import { Editable, useEditor } from "@wysimark/react";
import { useEffect, useRef, useState } from "react";
import "./hideToolbar.css";
const Test = () => {
const [markdown, setMarkdown] = useState(
"Favorite recipes:\n\n- Lasagna\n\n- Parmegianna Bistec\n\n- Mashed Potatoes\n\nYummy!"
);
const editor = useEditor({});
useEffect(() => {
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (
mutation.type === "childList" ||
mutation.type === "characterData"
) {
const titles = document.querySelectorAll("div.--title");
titles.forEach((title: any) => {
const textContent = title.textContent.trim();
const optionsToRemove = [
"Checklist",
"Heading 3",
"Heading 4",
"Heading 5",
"Heading 6",
];
if (optionsToRemove.includes(textContent)) {
console.log('Found element with text "Numbered List"');
const parentElement = title.parentElement;
if (parentElement) {
parentElement.style.display = "none";
}
}
});
}
}
});
// Start observing the entire document for changes
observer.observe(document.documentElement, {
subtree: true,
childList: true,
characterData: true,
});
// Clean up the observer when the component is unmounted
return () => {
observer.disconnect();
};
}, []);
return (
<div className="mdeditor">
<Editable editor={editor} value={markdown} onChange={setMarkdown} />
<br></br>
<div>What you will get:</div>
<code style={{ backgroundColor: "#dadada" }}>
{JSON.stringify(markdown)}
</code>
</div>
);
};
export default Test;
It's a very nice markdown editor!
I have some questions:
React
https://api.portive.com/api/v1/upload
? How to change api by myself?i18n
?Thanks!