Markdown editor for React
SSR in Next.js is also supported.
- No control
import { MarkdownEditor } from "@react-libraries/markdown-editor";
const Page = () => {
return <MarkdownEditor defaultValule={"ABC"} onUpdate={(v) => console.log(v)} />;
};
export default Page;
- With control
import { MarkdownEditor } from "@react-libraries/markdown-editor";
const Page = () => {
const [value, setValue] = useState("ABC");
useEffect(() => {
console.log(value);
}, [value]);
return <MarkdownEditor value={value} onUpdate={setValue} />;
};
export default Page;
- External control
import { MarkdownEditor, useMarkdownEditor } from "@react-libraries/markdown-editor";
import { dispatchLocalEvent } from "@react-libraries/use-local-event";
const Page = () => {
const event = useMarkdownEditor();
return (
<>
<MarkdownEditor event={event} />
<button
onClick={() => {
dispatchLocalEvent(event, {
type: "update",
payload: { value: "{new value}\n", start: 0 },
});
}}
>
Insert text
</button>
</>
);
};
export default Page;
HTMLAttributes<HTMLDivElement>
now has the following properties.
interface Props {
event?: LocalEvent<MarkdownEvent>;
defaultValue?: string;
value?: string;
onUpdate?: (value: string) => void;
}
Parameters to be used from dispatchLocalEvent
export declare type MarkdownEvent =
| {
type: "getPosition";
payload: {
onResult: (start: number, end: number) => void;
};
}
| {
type: "getLine";
payload: {
onResult: (line: number, offset: number) => void;
};
}
| {
type: "getScrollLine";
payload: {
onResult: (line: number, offset: number) => void;
};
}
| {
type: "setPosition";
payload: {
start: number;
end?: number;
};
}
| {
type: "setFocus";
}
| {
type: "setValue";
payload: {
value: string;
};
}
| {
type: "update";
payload: {
start?: number;
end?: number;
value?: string;
};
}
| {
type: "redo";
}
| {
type: "undo";
};
If the number of characters in {children} changes, it will not work properly.
const components: MarkdownComponents = {
strong: ({ children, node, ...props }) => <strong {...props}>{children}</strong>,
heading: ({ children, node, ...props }) => {
const Tag = ("h" + node.depth) as ElementType;
return (
<Tag
{...props}
onMouseOver={(e: React.MouseEvent<HTMLHeadingElement>) =>
setMessage(e.currentTarget.innerText)
}
>
{children}
</Tag>
);
},
};
…
<MarkdownEditor components={components} />;
If you use display:block
, it will not work properly.
.markdown {
[datatype="heading"] {
color: blue;
}
}
import styled from "./styled.module.scss";
…
<MarkdownEditor className={styled.markdown} />;