Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: add global configuration for mermaid and update options #560

Merged
merged 7 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 41 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,50 @@ Using `markdown` component and/or directive, you will be able to use the `mermai
</markdown>
```

Optionally, you can specify mermaid [configuration options](https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-properties) using `mermaidOptions` property.
#### Global configuration

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.

##### Using the `provideMarkdown` function

```typescript
provideMarkdown({
mermaidOptions: {
provide: MERMAID_OPTIONS,
useValue: {
darkMode: true,
look: 'handDrawn',
...
},
},
}),
```

##### Using the `MarkdownModule` import

```typescript
MarkdownModule.forRoot({
mermaidOptions: {
provide: MERMAID_OPTIONS,
useValue: {
darkMode: true,
look: 'handDrawn',
...
},
},
}),
```

#### Component configuration

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.

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

public options: MermaidAPI.Config = {
fontFamily: '"trebuchet ms", verdana, arial, sans-serif',
logLevel: MermaidAPI.LogLevel.Info,
theme: MermaidAPI.Theme.Dark,
public options: MermaidAPI.MermaidConfig = {
darkMode: true,
look: 'handDrawn',
...
};
```
Expand Down Expand Up @@ -842,7 +877,7 @@ export interface MarkdownPipeOptions {
katex?: boolean;
katexOptions?: KatexOptions;
mermaid?: boolean;
mermaidOptions?: MermaidAPI.Config;
mermaidOptions?: MermaidAPI.MermaidConfig;
markedOptions?: MarkedOptions;
disableSanitizer?: boolean;
}
Expand Down
15 changes: 11 additions & 4 deletions demo/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ApplicationConfig, SecurityContext } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideRouter, withInMemoryScrolling } from '@angular/router';
import { gfmHeadingId } from 'marked-gfm-heading-id';
import { CLIPBOARD_OPTIONS, MARKED_OPTIONS, provideMarkdown } from 'ngx-markdown';
import { CLIPBOARD_OPTIONS, MARKED_OPTIONS, MERMAID_OPTIONS, provideMarkdown } from 'ngx-markdown';
import { appRoutes } from '@app/app-routes';
import { markedOptionsFactory } from '@app/marked-options-factory';
import { AnchorService } from '@shared/anchor/anchor.service';
Expand All @@ -22,15 +22,22 @@ export const appConfig: ApplicationConfig = {
),
provideMarkdown({
loader: HttpClient,
clipboardOptions: {
provide: CLIPBOARD_OPTIONS,
useValue: { buttonComponent: ClipboardButtonComponent },
},
markedOptions: {
provide: MARKED_OPTIONS,
useFactory: markedOptionsFactory,
deps: [AnchorService],
},
markedExtensions: [gfmHeadingId()],
clipboardOptions: {
provide: CLIPBOARD_OPTIONS,
useValue: { buttonComponent: ClipboardButtonComponent },
mermaidOptions: {
provide: MERMAID_OPTIONS,
useValue: {
darkMode: true,
look: 'handDrawn',
},
},
sanitize: SecurityContext.NONE,
}),
Expand Down
4 changes: 2 additions & 2 deletions demo/src/app/bindings/bindings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ <h2 id="variable-binding">Variable Binding</h2>

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

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

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

<div [innerHTML]="typescriptMarkdown | language : 'typescript' | markdown | async" fxFlex.gt-sm="calc(50% - 8px)"></div>
Expand Down
51 changes: 41 additions & 10 deletions demo/src/app/plugins/plugins.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2 id="emoji">Emoji plugin</h2>

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

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

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

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

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

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

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

**example.component.ts**
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.

```typescript
// using the `provideMarkdown` function
provideMarkdown(&#123;
mermaidOptions: &#123;
provide: MERMAID_OPTIONS,
useValue: &#123;
darkMode: true,
look: 'handDrawn',
...
&#125;,
&#125;,
&#125;),

// using the `MarkdownModule` import
MarkdownModule.forRoot(&#123;
mermaidOptions: &#123;
provide: MERMAID_OPTIONS,
useValue: &#123;
darkMode: true,
look: 'handDrawn',
...
&#125;,
&#125;,
&#125;),
```

#### Component configuration

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.

**example.component.ts**
```typescript
import &#123; MermaidAPI &#125; from 'ngx-markdown';

public options: MermaidAPI.Config = &#123;
fontFamily: '"trebuchet ms", verdana, arial, sans-serif',
logLevel: MermaidAPI.LogLevel.Info,
theme: MermaidAPI.Theme.Dark,
public options: MermaidAPI.MermaidConfig = &#123;
darkMode: true,
look: 'handDrawn',
...
&#125;;
```
Expand Down
4 changes: 2 additions & 2 deletions demo/src/app/plugins/plugins.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ graph TD;
C-->D;
\`\`\``;

mermaidOptions: MermaidAPI.Config = {
mermaidOptions: MermaidAPI.MermaidConfig = {
fontFamily: 'inherit',
theme: MermaidAPI.Theme.Dark,
theme: 'dark',
};

headings: Element[] | undefined;
Expand Down
2 changes: 1 addition & 1 deletion demo/src/app/rerender/rerender.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ <h2 id="example">Example</h2>
</mat-form-field>

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

Expand Down
2 changes: 1 addition & 1 deletion lib/src/markdown.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ describe('MarkdownComponent', () => {
} as TemplateRef<unknown>,
};
const katexOptions: KatexOptions = { displayMode: true };
const mermaidOptions: MermaidAPI.Config = { darkMode: true };
const mermaidOptions: MermaidAPI.MermaidConfig = { darkMode: true };

spyOn(markdownService, 'parse').and.returnValue(parsed);
spyOn(markdownService, 'render');
Expand Down
2 changes: 1 addition & 1 deletion lib/src/markdown.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {
get mermaid(): boolean { return this._mermaid; }
set mermaid(value: boolean) { this._mermaid = this.coerceBooleanProperty(value); }

@Input() mermaidOptions: MermaidAPI.Config | undefined;
@Input() mermaidOptions: MermaidAPI.MermaidConfig | undefined;

// Plugin - lineHighlight
@Input()
Expand Down
9 changes: 4 additions & 5 deletions lib/src/markdown.module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import { MARKED_EXTENSIONS } from './marked-extensions';
import { MARKED_OPTIONS, MarkedOptions } from './marked-options';

@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'host-comp',
selector: 'markdown-host',
template: `
<div *ngIf="src; else dataTemplate">
<markdown [src]="src"></markdown>
Expand Down Expand Up @@ -57,7 +56,7 @@ describe('MarkdownModule', () => {
MarkdownModule.forRoot({
markedOptions: {
provide: MARKED_OPTIONS,
useValue: 'mockMarkedOptions',
useValue: {},
},
}),
],
Expand Down Expand Up @@ -182,7 +181,7 @@ describe('MarkdownModule', () => {
MarkdownModule.forRoot({
markedOptions: {
provide: MARKED_OPTIONS,
useValue: 'mockMarkedOptions',
useValue: {},
},
}),
],
Expand Down Expand Up @@ -226,7 +225,7 @@ describe('MarkdownModule', () => {
MarkdownModule.forRoot({
markedOptions: {
provide: MARKED_OPTIONS,
useValue: 'mockMarkedOptions',
useValue: {},
},
}),
],
Expand Down
25 changes: 22 additions & 3 deletions lib/src/markdown.module.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
import { CommonModule } from '@angular/common';
import { ModuleWithProviders, NgModule, Provider, SecurityContext } from '@angular/core';
import { InjectionToken, ModuleWithProviders, NgModule, Provider, SecurityContext } from '@angular/core';
import { MarkedExtension } from 'marked';
import { ClipboardButtonComponent } from './clipboard-button.component';
import { CLIPBOARD_OPTIONS } from './clipboard-options';
import { LanguagePipe } from './language.pipe';
import { MarkdownComponent } from './markdown.component';
import { MarkdownPipe } from './markdown.pipe';
import { MARKED_OPTIONS } from './marked-options';
import { MERMAID_OPTIONS } from './mermaid-options';
import { provideMarkdown } from './provide-markdown';

type InjectionTokenType<T extends InjectionToken<any>> = T extends InjectionToken<infer R> ? R : unknown;

interface TypedValueProvider<T extends InjectionToken<any>> {
provide: T;
useValue: InjectionTokenType<T>;
};

interface TypedFactoryProvider<T extends InjectionToken<any>> {
provide: T;
useFactory: (...args: any[]) => InjectionTokenType<T>;
deps?: any[];
};

type TypedProvider<T extends InjectionToken<any>> = TypedValueProvider<T> | TypedFactoryProvider<T>;

// having a dependency on `HttpClientModule` within a library
// breaks all the interceptors from the app consuming the library
// here, we explicitely ask the user to pass a provider with
// their own instance of `HttpClientModule`
export interface MarkdownModuleConfig {
loader?: Provider;
clipboardOptions?: Provider;
markedOptions?: Provider;
clipboardOptions?: TypedProvider<typeof CLIPBOARD_OPTIONS>;
markedOptions?: TypedProvider<typeof MARKED_OPTIONS>;
markedExtensions?: MarkedExtension[];
mermaidOptions?: TypedProvider<typeof MERMAID_OPTIONS>;
sanitize?: SecurityContext;
}

Expand Down
16 changes: 8 additions & 8 deletions lib/src/markdown.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,11 +608,11 @@ describe('MarkdownService', () => {
container.append(elementOne);
container.append(elementTwo);

const defaultOptions: MermaidAPI.Config = { startOnLoad: false };
const defaultOptions: MermaidAPI.MermaidConfig = { startOnLoad: false };
const mermaidElements = container.querySelectorAll<HTMLElement>('.mermaid');

window['mermaid'] = {
initialize: (options: MermaidAPI.Config) => {},
initialize: (options: MermaidAPI.MermaidConfig) => {},
run: (runOptions: MermaidAPI.RunOptions) => {},
};

Expand All @@ -634,15 +634,15 @@ describe('MarkdownService', () => {
const container = document.createElement('div');
container.append(element);

const providedOptions: MermaidAPI.Config = {
const providedOptions: MermaidAPI.MermaidConfig = {
startOnLoad: false,
darkMode: true,
};

const mermaidElements = container.querySelectorAll<HTMLElement>('.mermaid');

window['mermaid'] = {
initialize: (options: MermaidAPI.Config) => {},
initialize: (options: MermaidAPI.MermaidConfig) => {},
run: (runOptions: MermaidAPI.RunOptions) => {},
};

Expand All @@ -660,7 +660,7 @@ describe('MarkdownService', () => {
const container = document.createElement('div');

window['mermaid'] = {
initialize: (options: MermaidAPI.Config) => {},
initialize: (options: MermaidAPI.MermaidConfig) => {},
run: (runOptions: MermaidAPI.RunOptions) => {},
};

Expand All @@ -686,7 +686,7 @@ describe('MarkdownService', () => {
const container = document.createElement('div');

window['mermaid'] = {
initialize: (options: MermaidAPI.Config) => {},
initialize: (options: MermaidAPI.MermaidConfig) => {},
run: (runOptions: MermaidAPI.RunOptions) => {},
};

Expand Down Expand Up @@ -723,7 +723,7 @@ describe('MarkdownService', () => {
container.append(element);

window['mermaid'] = {
initialize: (options: MermaidAPI.Config) => {},
initialize: (options: MermaidAPI.MermaidConfig) => {},
run: (runOptions: MermaidAPI.RunOptions) => {},
};

Expand Down Expand Up @@ -774,7 +774,7 @@ describe('MarkdownService', () => {
container.append(mermaidElement);

window['mermaid'] = {
initialize: (options: MermaidAPI.Config) => {},
initialize: (options: MermaidAPI.MermaidConfig) => {},
run: (runOptions: MermaidAPI.RunOptions) => {},
};

Expand Down
Loading