Skip to content

Commit 3d68dc6

Browse files
authored
feat!: add global configuration for mermaid and update options (#560)
1 parent 620b366 commit 3d68dc6

14 files changed

+1589
-290
lines changed

README.md

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,50 @@ Using `markdown` component and/or directive, you will be able to use the `mermai
347347
</markdown>
348348
```
349349

350-
Optionally, you can specify mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) using `mermaidOptions` property.
350+
#### Global configuration
351+
352+
You can provide a global configuration for mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) to use across your application with the `mermaidOptions` in the `MarkdownModuleConfig` either with `provideMarkdown` provide-function for standalone components or `MarkdownModule.forRoot()` for module configuration.
353+
354+
##### Using the `provideMarkdown` function
355+
356+
```typescript
357+
provideMarkdown({
358+
mermaidOptions: {
359+
provide: MERMAID_OPTIONS,
360+
useValue: {
361+
darkMode: true,
362+
look: 'handDrawn',
363+
...
364+
},
365+
},
366+
}),
367+
```
368+
369+
##### Using the `MarkdownModule` import
370+
371+
```typescript
372+
MarkdownModule.forRoot({
373+
mermaidOptions: {
374+
provide: MERMAID_OPTIONS,
375+
useValue: {
376+
darkMode: true,
377+
look: 'handDrawn',
378+
...
379+
},
380+
},
381+
}),
382+
```
383+
384+
#### Component configuration
385+
386+
Additionally, you can specify mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) on component directly using `mermaidOptions` property.
351387

352388
```typescript
353389
import { MermaidAPI } from 'ngx-markdown';
354390

355-
public options: MermaidAPI.Config = {
356-
fontFamily: '"trebuchet ms", verdana, arial, sans-serif',
357-
logLevel: MermaidAPI.LogLevel.Info,
358-
theme: MermaidAPI.Theme.Dark,
391+
public options: MermaidAPI.MermaidConfig = {
392+
darkMode: true,
393+
look: 'handDrawn',
359394
...
360395
};
361396
```
@@ -842,7 +877,7 @@ export interface MarkdownPipeOptions {
842877
katex?: boolean;
843878
katexOptions?: KatexOptions;
844879
mermaid?: boolean;
845-
mermaidOptions?: MermaidAPI.Config;
880+
mermaidOptions?: MermaidAPI.MermaidConfig;
846881
markedOptions?: MarkedOptions;
847882
disableSanitizer?: boolean;
848883
}

demo/src/app/app.config.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ApplicationConfig, SecurityContext } from '@angular/core';
33
import { provideAnimations } from '@angular/platform-browser/animations';
44
import { provideRouter, withInMemoryScrolling } from '@angular/router';
55
import { gfmHeadingId } from 'marked-gfm-heading-id';
6-
import { CLIPBOARD_OPTIONS, MARKED_OPTIONS, provideMarkdown } from 'ngx-markdown';
6+
import { CLIPBOARD_OPTIONS, MARKED_OPTIONS, MERMAID_OPTIONS, provideMarkdown } from 'ngx-markdown';
77
import { appRoutes } from '@app/app-routes';
88
import { markedOptionsFactory } from '@app/marked-options-factory';
99
import { AnchorService } from '@shared/anchor/anchor.service';
@@ -22,15 +22,22 @@ export const appConfig: ApplicationConfig = {
2222
),
2323
provideMarkdown({
2424
loader: HttpClient,
25+
clipboardOptions: {
26+
provide: CLIPBOARD_OPTIONS,
27+
useValue: { buttonComponent: ClipboardButtonComponent },
28+
},
2529
markedOptions: {
2630
provide: MARKED_OPTIONS,
2731
useFactory: markedOptionsFactory,
2832
deps: [AnchorService],
2933
},
3034
markedExtensions: [gfmHeadingId()],
31-
clipboardOptions: {
32-
provide: CLIPBOARD_OPTIONS,
33-
useValue: { buttonComponent: ClipboardButtonComponent },
35+
mermaidOptions: {
36+
provide: MERMAID_OPTIONS,
37+
useValue: {
38+
darkMode: true,
39+
look: 'handDrawn',
40+
},
3441
},
3542
sanitize: SecurityContext.NONE,
3643
}),

demo/src/app/bindings/bindings.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ <h2 id="variable-binding">Variable Binding</h2>
3838

3939
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px">
4040
<mat-form-field appearance="fill" color="accent" fxFlex.gt-sm="calc(50% - 8px)">
41-
<textarea matInput [(ngModel)]="markdown"></textarea>
41+
<textarea matInput cdkTextareaAutosize="true" [(ngModel)]="markdown"></textarea>
4242
</mat-form-field>
4343

4444
<markdown [data]="markdown" fxFlex.gt-sm="calc(50% - 8px)"></markdown>
@@ -66,7 +66,7 @@ <h2 id="pipe-usage">Pipe Usage</h2>
6666

6767
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px">
6868
<mat-form-field appearance="fill" color="accent" fxFlex.gt-sm="calc(50% - 8px)">
69-
<textarea matInput [(ngModel)]="typescriptMarkdown"></textarea>
69+
<textarea matInput cdkTextareaAutosize="true" [(ngModel)]="typescriptMarkdown"></textarea>
7070
</mat-form-field>
7171

7272
<div [innerHTML]="typescriptMarkdown | language : 'typescript' | markdown | async" fxFlex.gt-sm="calc(50% - 8px)"></div>

demo/src/app/plugins/plugins.component.html

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ <h2 id="emoji">Emoji plugin</h2>
3434

3535
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px">
3636
<mat-form-field appearance="fill" color="accent" fxFlex.gt-sm="calc(50% - 8px)">
37-
<textarea matInput [(ngModel)]="emojiMarkdown"></textarea>
37+
<textarea matInput cdkTextareaAutosize="true" [(ngModel)]="emojiMarkdown"></textarea>
3838
</mat-form-field>
3939

4040
<markdown [data]="emojiMarkdown" emoji fxFlex.gt-sm="calc(50% - 8px)"></markdown>
@@ -308,7 +308,7 @@ <h2 id="katex">KaTeX plugin</h2>
308308

309309
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px">
310310
<mat-form-field appearance="fill" color="accent" fxFlex.gt-sm="calc(50% - 8px)">
311-
<textarea matInput [(ngModel)]="katexMarkdown"></textarea>
311+
<textarea matInput cdkTextareaAutosize="true" [(ngModel)]="katexMarkdown"></textarea>
312312
</mat-form-field>
313313

314314
<markdown [data]="katexMarkdown" katex fxFlex.gt-sm="calc(50% - 8px)"></markdown>
@@ -367,23 +367,54 @@ <h2 id="mermaid">Mermaid plugin</h2>
367367

368368
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px">
369369
<mat-form-field appearance="fill" color="accent" fxFlex.gt-sm="calc(50% - 8px)">
370-
<textarea matInput [(ngModel)]="mermaidMarkdown"></textarea>
370+
<textarea matInput cdkTextareaAutosize="true" [(ngModel)]="mermaidMarkdown"></textarea>
371371
</mat-form-field>
372372

373-
<markdown [data]="mermaidMarkdown" mermaid [mermaidOptions]="mermaidOptions" fxFlex.gt-sm="calc(50% - 8px)"></markdown>
373+
<markdown [data]="mermaidMarkdown" mermaid [mermaidOptions]="mermaidOptions" fxLayoutAlign="center center" fxFlex.gt-sm="calc(50% - 8px)"></markdown>
374374
</div>
375375

376376
<markdown ngPreserveWhitespaces>
377-
Optionally, you can specify mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) using `mermaidOptions` property.
377+
#### Global configuration
378378

379-
**example.component.ts**
379+
You can provide a global configuration for mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) to use across your application with the `mermaidOptions` in the `MarkdownModuleConfig` either with `provideMarkdown` provide-function for standalone components or `MarkdownModule.forRoot()` for module configuration.
380+
381+
```typescript
382+
// using the `provideMarkdown` function
383+
provideMarkdown(&#123;
384+
mermaidOptions: &#123;
385+
provide: MERMAID_OPTIONS,
386+
useValue: &#123;
387+
darkMode: true,
388+
look: 'handDrawn',
389+
...
390+
&#125;,
391+
&#125;,
392+
&#125;),
393+
394+
// using the `MarkdownModule` import
395+
MarkdownModule.forRoot(&#123;
396+
mermaidOptions: &#123;
397+
provide: MERMAID_OPTIONS,
398+
useValue: &#123;
399+
darkMode: true,
400+
look: 'handDrawn',
401+
...
402+
&#125;,
403+
&#125;,
404+
&#125;),
405+
```
406+
407+
#### Component configuration
408+
409+
Additionally, you can specify mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) on component directly using `mermaidOptions` property.
410+
411+
**example.component.ts**
380412
```typescript
381413
import &#123; MermaidAPI &#125; from 'ngx-markdown';
382414

383-
public options: MermaidAPI.Config = &#123;
384-
fontFamily: '"trebuchet ms", verdana, arial, sans-serif',
385-
logLevel: MermaidAPI.LogLevel.Info,
386-
theme: MermaidAPI.Theme.Dark,
415+
public options: MermaidAPI.MermaidConfig = &#123;
416+
darkMode: true,
417+
look: 'handDrawn',
387418
...
388419
&#125;;
389420
```

demo/src/app/plugins/plugins.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ graph TD;
5555
C-->D;
5656
\`\`\``;
5757

58-
mermaidOptions: MermaidAPI.Config = {
58+
mermaidOptions: MermaidAPI.MermaidConfig = {
5959
fontFamily: 'inherit',
60-
theme: MermaidAPI.Theme.Dark,
60+
theme: 'dark',
6161
};
6262

6363
headings: Element[] | undefined;

demo/src/app/rerender/rerender.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ <h2 id="example">Example</h2>
3737
</mat-form-field>
3838

3939
<mat-form-field appearance="fill" color="accent" fxFlex>
40-
<textarea matInput [(ngModel)]="markdown"></textarea>
40+
<textarea matInput cdkTextareaAutosize="true" [(ngModel)]="markdown"></textarea>
4141
</mat-form-field>
4242
</div>
4343

lib/src/markdown.component.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ describe('MarkdownComponent', () => {
297297
} as TemplateRef<unknown>,
298298
};
299299
const katexOptions: KatexOptions = { displayMode: true };
300-
const mermaidOptions: MermaidAPI.Config = { darkMode: true };
300+
const mermaidOptions: MermaidAPI.MermaidConfig = { darkMode: true };
301301

302302
spyOn(markdownService, 'parse').and.returnValue(parsed);
303303
spyOn(markdownService, 'render');

lib/src/markdown.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {
7070
get mermaid(): boolean { return this._mermaid; }
7171
set mermaid(value: boolean) { this._mermaid = this.coerceBooleanProperty(value); }
7272

73-
@Input() mermaidOptions: MermaidAPI.Config | undefined;
73+
@Input() mermaidOptions: MermaidAPI.MermaidConfig | undefined;
7474

7575
// Plugin - lineHighlight
7676
@Input()

lib/src/markdown.module.spec.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import { MARKED_EXTENSIONS } from './marked-extensions';
1111
import { MARKED_OPTIONS, MarkedOptions } from './marked-options';
1212

1313
@Component({
14-
// eslint-disable-next-line @angular-eslint/component-selector
15-
selector: 'host-comp',
14+
selector: 'markdown-host',
1615
template: `
1716
<div *ngIf="src; else dataTemplate">
1817
<markdown [src]="src"></markdown>
@@ -57,7 +56,7 @@ describe('MarkdownModule', () => {
5756
MarkdownModule.forRoot({
5857
markedOptions: {
5958
provide: MARKED_OPTIONS,
60-
useValue: 'mockMarkedOptions',
59+
useValue: {},
6160
},
6261
}),
6362
],
@@ -182,7 +181,7 @@ describe('MarkdownModule', () => {
182181
MarkdownModule.forRoot({
183182
markedOptions: {
184183
provide: MARKED_OPTIONS,
185-
useValue: 'mockMarkedOptions',
184+
useValue: {},
186185
},
187186
}),
188187
],
@@ -226,7 +225,7 @@ describe('MarkdownModule', () => {
226225
MarkdownModule.forRoot({
227226
markedOptions: {
228227
provide: MARKED_OPTIONS,
229-
useValue: 'mockMarkedOptions',
228+
useValue: {},
230229
},
231230
}),
232231
],

lib/src/markdown.module.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
11
import { CommonModule } from '@angular/common';
2-
import { ModuleWithProviders, NgModule, Provider, SecurityContext } from '@angular/core';
2+
import { InjectionToken, ModuleWithProviders, NgModule, Provider, SecurityContext } from '@angular/core';
33
import { MarkedExtension } from 'marked';
44
import { ClipboardButtonComponent } from './clipboard-button.component';
5+
import { CLIPBOARD_OPTIONS } from './clipboard-options';
56
import { LanguagePipe } from './language.pipe';
67
import { MarkdownComponent } from './markdown.component';
78
import { MarkdownPipe } from './markdown.pipe';
9+
import { MARKED_OPTIONS } from './marked-options';
10+
import { MERMAID_OPTIONS } from './mermaid-options';
811
import { provideMarkdown } from './provide-markdown';
912

13+
type InjectionTokenType<T extends InjectionToken<any>> = T extends InjectionToken<infer R> ? R : unknown;
14+
15+
interface TypedValueProvider<T extends InjectionToken<any>> {
16+
provide: T;
17+
useValue: InjectionTokenType<T>;
18+
};
19+
20+
interface TypedFactoryProvider<T extends InjectionToken<any>> {
21+
provide: T;
22+
useFactory: (...args: any[]) => InjectionTokenType<T>;
23+
deps?: any[];
24+
};
25+
26+
type TypedProvider<T extends InjectionToken<any>> = TypedValueProvider<T> | TypedFactoryProvider<T>;
27+
1028
// having a dependency on `HttpClientModule` within a library
1129
// breaks all the interceptors from the app consuming the library
1230
// here, we explicitely ask the user to pass a provider with
1331
// their own instance of `HttpClientModule`
1432
export interface MarkdownModuleConfig {
1533
loader?: Provider;
16-
clipboardOptions?: Provider;
17-
markedOptions?: Provider;
34+
clipboardOptions?: TypedProvider<typeof CLIPBOARD_OPTIONS>;
35+
markedOptions?: TypedProvider<typeof MARKED_OPTIONS>;
1836
markedExtensions?: MarkedExtension[];
37+
mermaidOptions?: TypedProvider<typeof MERMAID_OPTIONS>;
1938
sanitize?: SecurityContext;
2039
}
2140

0 commit comments

Comments
 (0)