WYSIWYG markdown Editor 🍼 Milkdown for Angular out of box, only supports Angular 17+. Allow you to use native Angular components to create nodeView/pluginView/widgetView, and provide corresponding examples.
ng-milkdown
is only supported by Angular
version >=17.0.0
.
ng-milkdown-crepe
only supports Angular
version >=18.0.0
.
Angular | ng-milkdown |
---|---|
17.0.0+ | 0.0.3 |
18.0.0+ | 0.1.0-beta0 |
You can run this example by:
git clone https://github.com/ousc/ng-milkdown.git
cd ng-milkdown
npm install
npm run start
https://ousc.github.io/ng-milkdown
Angular adapter for ProseMirror, only supports Angular 17+.
https://github.com/ousc/ng-prosemirror-adapter
-
theme-nord
(preset) -
preset-commonmark
(preset) -
plugin-listener
(preset) -
preset-gfm
(supported) -
plugin-history
(supported) -
plugin-shiki
(supported) -
plugin-clipboard
(supported) -
plugin-cursor
(supported) -
plugin-latex
(supported) -
plugin-block
(supported) -
plugin-indent
(supported) -
plugin-tooltip
(supported) -
plugin-slash
(working) -
plugin-diagram
(working) -
plugin-emoji
(working) -
plugin-cursor
(supported) -
plugin-trailing
(supported) -
plugin-upload
(supported) -
plugin-collab
(working) -
plugin-copilot
(working)
usage of plugins can be found in example;
npm install ng-milkdown -S
<ng-milkdown-provider>
<ng-milkdown-crepe
[(ngModel)]="value"
[plugins]="plugins"
[features]="features"
[featureConfigs]="featureConfigs"
[(loading)]="loading"
[spinner]="spinner"
(beforeReady)="beforeReady($event)"
(ngModelChange)="onChange($event)"
/>
</ng-milkdown-provider>
import "@milkdown/crepe/theme/common/style.css";
import "@milkdown/crepe/theme/nord.css";
import {NgMilkdownCrepeEditor} from "./ng-milkdown.type";
@Component({...})
export class CrepeEditorComponent {
features = {
[Crepe.Feature.Placeholder]: false
}
beforeReady({crepe}: NgMilkdownCrepeEditor) {
editor.config(ctx => {
ctx.set(blockquoteAttr.key, () => ({
class: "border-l-4 border-nord10 pl-4 dark:border-nord8",
}));
ctx.set(inlineCodeAttr.key, () => ({
class: "font-mono text-nord10 tracking-tight dark:text-nord8",
}));
});
}
plugins = [imageInlineComponent];
value = 'Hello, World!';
onChange(markdownText: string) {
console.log({markdownText});
}
}
<ng-milkdown-provider>
<ng-milkdown
[(ngModel)]="value"
[plugins]="plugins"
[(loading)]="loading"
[spinner]="spinner"
(beforeReady)="beforeReady($event)"
(ngModelChange)="onChange($event)"
/>
</ng-milkdown-provider>
const tooltip = tooltipFactory('text-tooltip')
@Component({...})
export class WorkGroundComponent {
@ViewChild(NgMilkdownProvider, {static: true}) provider: NgMilkdownProvider;
beforeReady({editor}: NgMilkdownEditor) {
editor.config(ctx => {
ctx.set(editorViewOptionsCtx, {
attributes: {
class: "prose dark:prose-invert outline-none mx-auto px-2 py-4 max-w-full box-border milkdown-theme-nord editor",
spellcheck: "false",
},
});
ctx.set(blockquoteAttr.key, () => ({
class: "border-l-4 border-nord10 pl-4 dark:border-nord8",
}));
ctx.set(inlineCodeAttr.key, () => ({
class: "font-mono text-nord10 tracking-tight dark:text-nord8",
}));
});
}
plugins = [
commonmark,
link,
history,
imageInlineComponent,
iframeComponent,
trailing,
block,
indent,
milkShiki,
$nodeView(codeBlockSchema.node, {component: CodeBlock}),
$pluginView(block.key, {component: Block}),
$nodeView(listItemSchema.node, {component: ListItem}),
tooltip,
$pluginView(tooltip.key, {component: Tooltip}),
$prosePlugin({component: Size}),
latex,
];
value = 'Hello, World!';
onChange(markdownText: string) {
console.log({markdownText});
}
}
Property | Description | Type | Default |
---|---|---|---|
[classList] |
editor element class names | string[] |
[] |
[plugins] |
milkdown plugin to use | NgMilkdownPlugin[] |
[] |
[editor] |
pass in a fully controlled editor object | (HTMLElement) => Editor |
- |
[loading] |
set the loading status of editor | boolean |
true |
[spinner] |
custom spinner | TemplateRef<any> |
- |
[ngModel] |
current value , double binding | DefaultValue |
- |
(ngModelChange) |
callback when markdown change | EventEmitter<string> |
- |
(onReady) |
A callback function, can be executed when editor has bean created | Editor |
- |
@Component({
template: `
<button (click)="setBold($event)">
Bold
</button>
`,
...
})
export class ImageTooltipComponent extends NgMilkdownTooltip {
setBold(e: MouseEvent) {
e.preventDefault();
this.action(callCommand(toggleStrongCommand.key));
}
}
@Component({
selector: 'block',
template: `
<div class="w-6 bg-slate-200 rounded hover:bg-slate-300 cursor-grab">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width={1.5} stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z" />
</svg>
</div>
`,
styles:[],
standalone: true
})
export class BlockComponent extends NgMilkdownBlock {}
More detailed examples and more plugins can be found in example;