https://github.com/ousc/ng-milkdown
Milkdown(WYSIWYG markdown Editor ) for Angular out-of-box.
https://github.com/ousc/ng-milkdown
milkdown
Last synced: about 2 months ago
JSON representation
Milkdown(WYSIWYG markdown Editor ) for Angular out-of-box.
- Host: GitHub
- URL: https://github.com/ousc/ng-milkdown
- Owner: ousc
- License: mit
- Created: 2023-12-02T02:49:04.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-13T17:35:06.000Z (4 months ago)
- Last Synced: 2025-03-22T13:38:00.874Z (3 months ago)
- Topics: milkdown
- Language: TypeScript
- Homepage:
- Size: 17 MB
- Stars: 12
- Watchers: 1
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
NG-MILKDOWN[](https://www.npmjs.com/package/ng-milkdown)
WYSIWYG markdown Editor 🍼 [**Milkdown**](https://github.com/Milkdown/milkdown) for [**Angular**](https://angular.dev/) out of box, only supports Angular **17**+.
Allow you to use native Angular components to create nodeView/pluginView/widgetView, and provide corresponding examples.## Example
You can run this example by:
```bash
git clone https://github.com/ousc/ng-milkdown.git
cd ng-milkdown
npm install
npm run start
```## Online Demo
[https://ousc.github.io/ng-milkdown](https://ousc.github.io/ng-milkdown)
## ng-prosemirror-adapter
Angular adapter for ProseMirror, only supports Angular 17+.
[https://github.com/ousc/ng-prosemirror-adapter](https://github.com/ousc/ng-prosemirror-adapter)
## Official plugins support on NgMilkdown:
- [X] `theme-nord`**(preset)**
- [X] `preset-commonmark`**(preset)**
- [X] `plugin-listener`**(preset)**
- [X] `preset-gfm`**(supported)**
- [X] `plugin-history`**(supported)**
- [X] `plugin-prism`**(supported)**
- [X] `plugin-clipboard`**(supported)**
- [X] `plugin-cursor`**(supported)**
- [X] `plugin-math`**(supported)**
- [X] `plugin-block`**(supported)**
- [X] `plugin-indent`**(supported)**
- [X] `plugin-tooltip`**(supported)**
- [X] `plugin-slash`**(supported)**
- [X] `plugin-diagram`**(supported)**
- [X] `plugin-emoji`**(supported)**
- [X] `plugin-cursor`**(supported)**
- [X] `plugin-trailing`**(supported)**
- [X] `plugin-upload`**(supported)**
- [X] `plugin-collab`**(supported)**
- [X] `plugin-copilot`**(supported)**usage of plugins can be found in [example](https://github.com/ousc/ng-milkdown/tree/main/src/app/components);
## Quick Start
### Install
```bash
npm install ng-milkdown ng-prosemirror-adapter @milkdown/core @milkdown/ctx @milkdown/plugin-listener @milkdown/preset-commonmark @milkdown/theme-nord
```### Example
#### workGround.component.html
```html
```
#### workGround.component.ts```typescript
import {NgMilkdownProvider} from "./ng-milkdown-provider.component";const tooltip = tooltipFactory('my-tooltip')
const slash = slashFactory('my-slash')
@Component({...})
export class WorkGroundComponent {
@ViewChild(NgMilkdownProvider, {static: true}) provider: NgMilkdownProvider;config = (ctx: any) => {
ctx.set(editorViewOptionsCtx, {
attributes: {
class: "prose dark:prose-invert outline-none mx-auto px-2 py-4 box-border milkdown-theme-nord editor",
spellcheck: "false",
},
});
}plugins: NgMilkdownPlugin[] = [
gfm,
history,
prism,
clipboard,
cursor,
math,
emoji,
[
diagram, // diagram plugin
$view(diagramSchema.node, () =>
this.provider.createNodeView({ // create node view for diagram node
component: Diagram,
stopEvent: () => true,
})
)
],
$view(listItemSchema.node, () =>
this.provider.createNodeView({component: ListItem}) // create node view for list item node
),
{
plugin: block,
config: ctx => {
ctx.set(block.key, {
view: this.provider.createPluginView({ // create plugin view for block plugin
component: BlockComponent,
inputs: {ctx}
})
});
}
},
$provide(linkPlugin), // $provide is an alias of `provider => MilkdownPlugin`, allow you create your own plugin without waiting for `provider` initialization
{
plugin: indent,
config: ctx => {
ctx.set(indentConfig.key as any, { // set indent config
type: 'space',
size: 4,
});
}
},
{
plugin: tooltip,
config: ctx => {
ctx.set(tooltip.key, {
view: this.provider.createPluginView({component: ImageTooltipComponent}) // create plugin view for tooltip plugin
})
}
},
{
plugin: slash,
config: ctx => {
ctx.set(slash.key, {
view: this.provider.createPluginView({component: SlashComponent}) // create plugin view for slash plugin
})
}
}
];value = 'Hello, World!';
editor: Editor;
onChange(markdownText: string) {
console.log({markdownText});
}
}```
### API
| Property | Description | Type | Default |
|-------------------|-------------------------------------------------------------------|---------------------------|------------------------|
| `[classList]` | editor element class names | `string[]` | `[]` |
| `[config]` | config before Editor.create() | `NgMilkdownEditorConfig` | `(ctx: Ctx) => void 0` |
| `[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` | - |
| `[ngModel]` | current value , double binding | `DefaultValue` | - |
| `(ngModelChange)` | callback when markdown change | `EventEmitter` | - |
| `(onReady)` | A callback function, can be executed when editor has bean created | `Editor` | - |## OutOfBox Plugins
### ng-milkdown-tooltip
```typescript
@Component({
template: `
Bold
`,
...
})
export class ImageTooltipComponent extends NgMilkdownTooltip {
setBold(e: MouseEvent) {
e.preventDefault();
this.action(callCommand(toggleStrongCommand.key));
}
}
```### ng-milkdown-slash
```typescript
@Component({
template: `
@for (item of list;track item) {
{{item.label}}
}
`,
...
})
export class SlashComponent extends NgMilkdownSlash {
override get onPick(): (ctx: Ctx) => void {
return (ctx: Ctx) => {
this.removeSlash(ctx);
ctx.get(commandsCtx).call(createCodeBlockCommand.key);
ctx.get(editorViewCtx).focus();
}
}
}
```### ng-milkdown-block
```typescript
@Component({
selector: 'block',
template: `
`,
styles:[],
standalone: true
})
export class BlockComponent extends NgMilkdownBlock {}
```## How to create a nodeView in ng-milkdown
It's very easy to create a nodeView in ng-milkdown, you can use the following example
```html
@Component({
selector: 'list-item',
template: `
@if (isBullet && checked != null) {
} @else if (isBullet) {
} @else {
{{ label }}
}
`,
styles: [`
:host {
display: contents;
}
`],
standalone: true
})
export class ListItem extends NgMilkdownNodeComp {
get checked() {
return this.node.attrs?.checked;
}
set checked(checked){
this.setAttrs({checked})
}
get isBullet() {
return this.node.attrs?.listType === "bullet";
}
get label() {
return this.node.attrs?.label;
}
}
```
Firstly, you should make your nodeView class inherit from `NgMilkdownNodeComp`.
To additionally, you should add `#contentRef` ElementRef in your nodeView, which will be used to render the content of the node.
More detailed examples and more plugins can be found in [example](https://github.com/ousc/ng-milkdown/tree/main/src/app/components);
## license
[MIT](./LICENSE)