Skip to content

Commit

Permalink
[feat](ng-milkdown.component.ts): Added type annotation for the "edit…
Browse files Browse the repository at this point in the history
…or" getter and setter

[feat](ng-milkdown.component.ts): Refactored the "userEditor" input to "editor" input and changed the input type to accept a function
[feat](ng-milkdown.component.ts): Replaced the "editorConfig" input with a "config" input
[feat](ng-milkdown.component.ts): Updated references to "editorConfig" to use "config" instead
[feat](README.md): Updated the title and added a logo for the library
[feat](README.md): Added a section for the example and provided instructions on how to run it
[feat](README.md): Added a link to the online demo
[feat](README.md): Added a section for the ng-prosemirror-adapter library and provided a link to its GitHub repository
[feat](README.md): Added a section for the official plugins supported by NgMilkdown and marked them as "supported" or "preset"
[feat](README.md): Added a section for the installation and an example of how to use NgMilkdown
[feat](ng-milkdown): Added new examples and plugins
[fix](copilot.service.ts): Updated API URL and token retrieval
[fix](tool-bar.component.ts): Fixed toolbar item click event
[fix](collaborative-editing.component.ts): Updated input property name
[fix](workGround.component.html): Updated input property name
[fix](README.md): Updated input property names in table
[feat](README.md): Added license information
[fix](tool-bar.component.ts): Fixed copilot open/close buttons
[fix](tool-bar.component.ts): Fixed onMouseDown method to handle click event
[fix](collaborative-editing.component.ts): Updated input property name
[fix](workGround.component.html): Updated input property name
[feat](workGround.component.ts): Added new input properties
[fix](README.md): Updated table content for input properties
  • Loading branch information
ousc committed Jan 9, 2024
1 parent bc04563 commit e4611e3
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 58 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ npm install ng-milkdown ng-prosemirror-adapter @milkdown/core @milkdown/ctx @mil
```html
<ng-milkdown-provider>
<ng-milkdown
[editorConfig]="config"
[config]="config"
[plugins]="plugins"
[(ngModel)]="value"
[(loading)]="loading"
Expand Down Expand Up @@ -172,16 +172,17 @@ export class WorkGroundComponent {

### API

| Property | Description | Type | Default |
|-------------------|-------------------------------------------------------------------|--------------------------|------------------------|
| `[classList]` | editor element class names | `string[]` | `[]` |
| `[editorConfig]` | config before Editor.create() | `NgMilkdownEditorConfig` | `(ctx: Ctx) => void 0` |
| `[plugins]` | milkdown plugin to use | `NgMilkdownPlugin[]` | `[]` |
| `[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` | - |
| 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<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` | - |

## OutOfBox Plugins

Expand Down
258 changes: 245 additions & 13 deletions projects/ng-milkdown/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,256 @@
# NgMilkdown
<p align="center">
<a href="https://ousc.github.io/ng-milkdown">
<img src="milkdownLogo.png" width="230" style="vertical-align: middle;">
</a>
</p>

This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.0.
<h1 align="center">
NG-MILKDOWN
</h1>

## Code scaffolding

Run `ng generate component component-name --project ng-milkdown` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ng-milkdown`.
> Note: Don't forget to add `--project ng-milkdown` or else it will be added to the default project in your `angular.json` file.
WYSIWYG markdown Editor 🍼 [**Milkdown**](https://github.com/Milkdown/milkdown) for [**Angular**](https://angular.dev/) out of box, only supports Angular **17**+.

## Build
## Example

Run `ng build ng-milkdown` to build the project. The build artifacts will be stored in the `dist/` directory.
You can run this example by:

## Publishing
```bash
git clone https://github.com/ousc/ng-milkdown.git
cd ng-milkdown
npm install
npm run start
```

After building your library with `ng build ng-milkdown`, go to the dist folder `cd dist/ng-milkdown` and run `npm publish`.
## Online Demo

## Running unit tests
[https://ousc.github.io/ng-milkdown](https://ousc.github.io/ng-milkdown)

Run `ng test ng-milkdown` to execute the unit tests via [Karma](https://karma-runner.github.io).
## ng-prosemirror-adapter

## Further help
Angular adapter for ProseMirror, only supports Angular 17+.(now this library is not published to npm, we will publish it soon)

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
[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)**
- [ ] `plugin-copilot`**(planned)**

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
<ng-milkdown-provider>
<ng-milkdown
[config]="config"
[plugins]="plugins"
[(ngModel)]="value"
[(loading)]="loading"
[spinner]="spinner"
(ngModelChange)="onChange($event)"
(onReady)="editor = $event"
/>
</ng-milkdown-provider>
```
#### workGround.component.ts

```typescript
import {NgMilkdownProvider} from "./ng-milkdown-provider.component";

@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",
},
});
}

tooltip = tooltipFactory('my-tooltip')
slash = slashFactory('my-slash')
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,
})
)
].flat(),
$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}
})
});
}
},
{
plugin: indent,
config: ctx => {
ctx.set(indentConfig.key as any, { // set indent config
type: 'space',
size: 4,
});
}
},
{
plugin: this.tooltip,
config: ctx => {
ctx.set(this.tooltip.key, {
view: this.provider.createPluginView({component: ImageTooltipComponent}) // create plugin view for tooltip plugin
})
}
},
{
plugin: this.slash,
config: ctx => {
ctx.set(this.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<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` | - |

## OutOfBox Plugins

### ng-milkdown-tooltip

```typescript
@Component({
template: `
<button (click)="setBold($event)">
Bold
</button>
`,
...
})
export class ImageTooltipComponent extends NgMilkdownTooltip {
setBold(e: MouseEvent) {
e.preventDefault();
this.action(callCommand(toggleStrongCommand.key));
}
}
```

### ng-milkdown-slash

```typescript
@Component({
template: `
<button
[class]="selected === 0 ? ['selected'] : []"
(mousemove)="selected = $index"
(mousedown)="action(onPick)"
>
Code Block
</button>
`,
...
})
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: `
<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](https://github.com/ousc/ng-milkdown/tree/main/src/app/components);

## license

[MIT](./LICENSE)
33 changes: 13 additions & 20 deletions projects/ng-milkdown/src/lib/ng-milkdown.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,15 @@ export class NgMilkdown extends NgProsemirrorEditor implements ControlValueAcces

@Input() spinner: TemplateRef<any> = null;

get editor() {
return this.ngMilkdownService.editor
get editor(): Editor {
return this.ngMilkdownService.editor;
}

set editor(value) {
this.ngMilkdownService.editor = value
}

_userEditor: (element: HTMLElement) => Promise<Editor> = null;

@Input() set userEditor(value: (element: HTMLElement) => Promise<Editor>) {
this._userEditor = value;
}
_editorFn: (element: HTMLElement) => Promise<Editor> = null;

get userEditor() {
return this._userEditor;
@Input()
set editor(editorFn: ((element: HTMLElement) => Promise<Editor>)) {
this._editorFn = editorFn;
}

writeValue(value: any): void {
Expand Down Expand Up @@ -124,7 +117,7 @@ export class NgMilkdown extends NgProsemirrorEditor implements ControlValueAcces
@Output() onChanged = new EventEmitter<string>();

@Input() plugins: NgMilkdownPlugin[] = [];
@Input() editorConfig: NgMilkdownEditorConfig = (ctx, provider) => null;
@Input() config: NgMilkdownEditorConfig = (ctx, provider) => null;
@Output() onReady = new EventEmitter<Editor>();
onTouched: () => void = () => {
};
Expand All @@ -138,8 +131,8 @@ export class NgMilkdown extends NgProsemirrorEditor implements ControlValueAcces
disabled = false;

async render(): Promise<void> {
if (this.userEditor) {
this.editor = await this.userEditor(this.editorRef.nativeElement);
if (this._editorFn) {
this.ngMilkdownService.editor = await this._editorFn(this.editorRef.nativeElement);
this.onReady.emit(this.editor);
return;
}
Expand All @@ -154,10 +147,10 @@ export class NgMilkdown extends NgProsemirrorEditor implements ControlValueAcces
this.onChange(md);
});

if (isZoneAwarePromise(this.editorConfig)) {
await this.editorConfig(ctx, this.provider);
if (isZoneAwarePromise(this.config)) {
await this.config(ctx, this.provider);
} else {
this.editorConfig(ctx, this.provider);
this.config(ctx, this.provider);
}
})
.config(nord)
Expand Down Expand Up @@ -185,7 +178,7 @@ export class NgMilkdown extends NgProsemirrorEditor implements ControlValueAcces
this.loading = false;
this.loadingChange.emit(false);
this.onReady.emit(editor);
this.editor = editor;
this.ngMilkdownService.editor = editor;
})
}

Expand Down
Loading

0 comments on commit e4611e3

Please sign in to comment.