@mzebley/mark-down-angular 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,26 +30,38 @@ Provide a shared `SnippetClient` from your root bootstrap call or feature module
30
30
 
31
31
  ```ts
32
32
  import { bootstrapApplication } from '@angular/platform-browser';
33
- import { provideMarkDown } from '@mzebley/mark-down-angular';
33
+ import { provideSnippetClient } from '@mzebley/mark-down/angular';
34
34
 
35
35
  bootstrapApplication(AppComponent, {
36
36
  providers: [
37
- ...provideMarkDown({
38
- manifest: '/snippets-index.json',
37
+ ...provideSnippetClient({
38
+ manifest: '/assets/content/snippets/manifest.json',
39
+ base: '/assets/content/snippets',
39
40
  }),
40
41
  ],
41
42
  });
42
43
  ```
43
44
 
44
- `provideMarkDown` wires up the client as an Angular provider using the options you pass through. The manifest can be a URL, a factory, or a pre-fetched array—identical to the [core runtime options](../core/README.md#client-options).
45
+ `provideSnippetClient` wires up the client as an Angular provider using the same options supported by the core runtime (`manifest`, `base`, `fetch`, `frontMatter`, `cache`, `verbose`). Prefer the scoped `@mzebley/mark-down/angular` entry point for tree-shaking and clearer typing. For backwards compatibility this package also re-exports `provideMarkDown`, `MARK_DOWN_CLIENT`, and the legacy `SnippetService` name.
46
+
47
+ ### Angular compatibility
48
+
49
+ | Angular version | Status |
50
+ | ---------------- | ------ |
51
+ | 17.x | ✅ Supported |
52
+ | 18.x | ✅ Supported |
53
+ | 19.x | ✅ Supported |
54
+ | 20.x | ✅ Supported |
55
+
56
+ The package declares peer dependency ranges `>=17 <21` so projects running any currently supported Angular major release can install without `--legacy-peer-deps`.
45
57
 
46
58
  ## Consuming snippets
47
59
 
48
- Inject `SnippetService` into components or services to access Observables for snippets:
60
+ Inject `MarkdownSnippetService` into components or services to access Observables for snippets:
49
61
 
50
62
  ```ts
51
63
  import { Component, inject } from '@angular/core';
52
- import { SnippetService } from '@mzebley/mark-down-angular';
64
+ import { MarkdownSnippetService } from '@mzebley/mark-down/angular';
53
65
 
54
66
  @Component({
55
67
  selector: 'docs-hero',
@@ -61,12 +73,12 @@ import { SnippetService } from '@mzebley/mark-down-angular';
61
73
  `,
62
74
  })
63
75
  export class DocsHeroComponent {
64
- private readonly snippets = inject(SnippetService);
76
+ private readonly snippets = inject(MarkdownSnippetService);
65
77
  readonly hero$ = this.snippets.get('getting-started-welcome');
66
78
  }
67
79
  ```
68
80
 
69
- The service mirrors the core client APIs (`get`, `list`, `listByType`, `listByGroup`) but returns cold Observables that share cached results across subscribers.
81
+ The service mirrors the core client APIs (`get`, `listAll`, `listByType`, `listByGroup`, `search`) but returns cold Observables that share cached results across subscribers.
70
82
 
71
83
  ## `<snippet-view>` component
72
84
 
@@ -80,7 +92,7 @@ Features:
80
92
 
81
93
  - Uses Angular's `DomSanitizer` to render HTML safely.
82
94
  - Emits a `loaded` event once the snippet resolves so parent components can react.
83
- - Provides built-in "Loading snippet…" and "Snippet not found" fallbacks (customize by wrapping the component or using the service directly).
95
+ - Provides a loading placeholder and gracefully emits `undefined` when the slug cannot be resolved.
84
96
  - Supports `class`/`ngClass` bindings for styling since it renders a standard `<div>`.
85
97
 
86
98
  ## Server-side rendering
@@ -90,18 +102,23 @@ When running in Angular Universal, supply a server-compatible fetch implementati
90
102
  ```ts
91
103
  import fetch from 'node-fetch';
92
104
 
93
- provideMarkDown({
105
+ provideSnippetClient({
94
106
  manifest: () => import('../snippets-index.json'),
95
- fetcher: (input, init) => fetch(input as string, init),
107
+ fetch: (url) => fetch(url).then((response) => {
108
+ if (!response.ok) {
109
+ throw new Error(`Request failed with status ${response.status}`);
110
+ }
111
+ return response;
112
+ }),
96
113
  });
97
114
  ```
98
115
 
99
- The provider forwards all options to the underlying `SnippetClient`, so SSR and preloaded manifests work exactly like the core package.
116
+ The provider forwards all options to the underlying `SnippetClient`, so SSR, custom cache policies, and preloaded manifests work exactly like the core package.
100
117
 
101
118
  ## Testing tips
102
119
 
103
- - Provide a mock manifest array during tests: `provideMarkDown({ manifest: mockManifest })`.
104
- - Use `SnippetService` with the Angular `TestBed` to assert filtering behaviour.
120
+ - Provide a mock manifest array during tests: `provideSnippetClient({ manifest: mockManifest })`.
121
+ - Use `MarkdownSnippetService` with the Angular `TestBed` to assert filtering behaviour.
105
122
  - Pair with the [example application](../../examples/basic/README.md) to see how snippets integrate with routing and feature modules.
106
123
 
107
124
  ## Roadmap
package/dist/index.cjs CHANGED
@@ -9,14 +9,15 @@ var __export = (target, all) => {
9
9
  for (var name in all)
10
10
  __defProp(target, name, { get: all[name], enumerable: true });
11
11
  };
12
- var __copyProps = (to, from2, except, desc) => {
13
- if (from2 && typeof from2 === "object" || typeof from2 === "function") {
14
- for (let key of __getOwnPropNames(from2))
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
15
  if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
17
  }
18
18
  return to;
19
19
  };
20
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
21
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
22
  // If the importer is in node compatibility mode or this is not an ESM
22
23
  // file that has been converted to a CommonJS file using a Babel-
@@ -34,80 +35,49 @@ var __decorateClass = (decorators, target, key, kind) => {
34
35
  if (kind && result) __defProp(target, key, result);
35
36
  return result;
36
37
  };
37
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
38
38
 
39
39
  // src/index.ts
40
40
  var index_exports = {};
41
41
  __export(index_exports, {
42
42
  MARK_DOWN_CLIENT: () => MARK_DOWN_CLIENT,
43
43
  MARK_DOWN_OPTIONS: () => MARK_DOWN_OPTIONS,
44
- SnippetService: () => SnippetService,
44
+ SnippetService: () => import_angular2.MarkdownSnippetService,
45
45
  SnippetViewComponent: () => SnippetViewComponent,
46
46
  provideMarkDown: () => provideMarkDown
47
47
  });
48
48
  module.exports = __toCommonJS(index_exports);
49
+ __reExport(index_exports, require("@mzebley/mark-down/angular"), module.exports);
49
50
 
50
51
  // src/token.ts
51
- var import_core = require("@angular/core");
52
- var import_mark_down = require("@mzebley/mark-down");
53
- var MARK_DOWN_CLIENT = new import_core.InjectionToken("mark-down-client");
54
- var MARK_DOWN_OPTIONS = new import_core.InjectionToken("mark-down-options");
55
- function provideMarkDown(options, client) {
56
- return [
57
- { provide: MARK_DOWN_OPTIONS, useValue: options },
58
- {
59
- provide: MARK_DOWN_CLIENT,
60
- useFactory: (opts) => client ?? new import_mark_down.SnippetClient(opts),
61
- deps: [MARK_DOWN_OPTIONS]
62
- }
63
- ];
52
+ var import_angular = require("@mzebley/mark-down/angular");
53
+ var MARK_DOWN_CLIENT = import_angular.SNIPPET_CLIENT;
54
+ var MARK_DOWN_OPTIONS = import_angular.SNIPPET_CLIENT_OPTIONS;
55
+ function provideMarkDown(options) {
56
+ return (0, import_angular.provideSnippetClient)(options);
64
57
  }
65
58
 
66
59
  // src/snippet.service.ts
67
- var import_core2 = require("@angular/core");
68
- var import_rxjs = require("rxjs");
69
- var SnippetService = class {
70
- constructor(client) {
71
- this.client = client;
72
- }
73
- get(slug) {
74
- return (0, import_rxjs.from)(this.client.get(slug)).pipe((0, import_rxjs.shareReplay)(1));
75
- }
76
- list(options) {
77
- return (0, import_rxjs.from)(this.client.list(options)).pipe((0, import_rxjs.shareReplay)(1));
78
- }
79
- listByGroup(group, options) {
80
- return (0, import_rxjs.from)(this.client.listByGroup(group, options)).pipe((0, import_rxjs.shareReplay)(1));
81
- }
82
- listByType(type, options) {
83
- return (0, import_rxjs.from)(this.client.listByType(type, options)).pipe((0, import_rxjs.shareReplay)(1));
84
- }
85
- html(slug) {
86
- return this.get(slug).pipe((0, import_rxjs.map)((snippet) => snippet?.html ?? null));
87
- }
88
- };
89
- SnippetService = __decorateClass([
90
- (0, import_core2.Injectable)({ providedIn: "root" }),
91
- __decorateParam(0, (0, import_core2.Inject)(MARK_DOWN_CLIENT))
92
- ], SnippetService);
60
+ var import_angular2 = require("@mzebley/mark-down/angular");
93
61
 
94
62
  // src/snippet-view.component.ts
95
63
  var import_common = require("@angular/common");
96
- var import_core3 = require("@angular/core");
64
+ var import_core = require("@angular/core");
97
65
  var import_platform_browser = require("@angular/platform-browser");
98
- var import_rxjs2 = require("rxjs");
66
+ var import_rxjs = require("rxjs");
99
67
  var import_operators = require("rxjs/operators");
100
68
  var import_dompurify = __toESM(require("dompurify"), 1);
101
69
  var SnippetViewComponent = class {
102
70
  constructor() {
103
- this.slug$ = new import_rxjs2.BehaviorSubject(null);
104
- this.sanitizer = (0, import_core3.inject)(import_platform_browser.DomSanitizer);
105
- this.snippets = (0, import_core3.inject)(SnippetService);
106
- this.loaded = new import_core3.EventEmitter();
71
+ this.slug$ = new import_rxjs.BehaviorSubject(null);
72
+ this.sanitizer = (0, import_core.inject)(import_platform_browser.DomSanitizer);
73
+ this.snippets = (0, import_core.inject)(import_angular2.MarkdownSnippetService);
74
+ this.loaded = new import_core.EventEmitter();
107
75
  this.snippet$ = this.slug$.pipe(
108
- (0, import_operators.switchMap)((slug) => slug ? this.snippets.get(slug) : (0, import_rxjs2.of)(void 0)),
109
- (0, import_operators.tap)((snippet) => this.loaded.emit(snippet)),
110
- (0, import_operators.shareReplay)(1)
76
+ (0, import_operators.switchMap)(
77
+ (slug) => slug ? this.snippets.get(slug).pipe((0, import_operators.catchError)(() => (0, import_rxjs.of)(null))) : (0, import_rxjs.of)(null)
78
+ ),
79
+ (0, import_operators.tap)((snippet) => this.loaded.emit(snippet ?? void 0)),
80
+ (0, import_operators.shareReplay)({ bufferSize: 1, refCount: true })
111
81
  );
112
82
  this.content$ = this.snippet$.pipe(
113
83
  (0, import_operators.map)((snippet) => {
@@ -124,13 +94,13 @@ var SnippetViewComponent = class {
124
94
  }
125
95
  };
126
96
  __decorateClass([
127
- (0, import_core3.Input)()
97
+ (0, import_core.Input)()
128
98
  ], SnippetViewComponent.prototype, "slug", 2);
129
99
  __decorateClass([
130
- (0, import_core3.Output)()
100
+ (0, import_core.Output)()
131
101
  ], SnippetViewComponent.prototype, "loaded", 2);
132
102
  SnippetViewComponent = __decorateClass([
133
- (0, import_core3.Component)({
103
+ (0, import_core.Component)({
134
104
  selector: "snippet-view",
135
105
  standalone: true,
136
106
  imports: [import_common.CommonModule],
@@ -142,7 +112,7 @@ SnippetViewComponent = __decorateClass([
142
112
  <div class="mark-down-snippet--loading">Loading snippet\u2026</div>
143
113
  </ng-template>
144
114
  `,
145
- changeDetection: import_core3.ChangeDetectionStrategy.OnPush
115
+ changeDetection: import_core.ChangeDetectionStrategy.OnPush
146
116
  })
147
117
  ], SnippetViewComponent);
148
118
  // Annotate the CommonJS export names for ESM import in node:
@@ -151,5 +121,6 @@ SnippetViewComponent = __decorateClass([
151
121
  MARK_DOWN_OPTIONS,
152
122
  SnippetService,
153
123
  SnippetViewComponent,
154
- provideMarkDown
124
+ provideMarkDown,
125
+ ...require("@mzebley/mark-down/angular")
155
126
  });
package/dist/index.d.cts CHANGED
@@ -1,21 +1,16 @@
1
- import { InjectionToken, Provider, OnChanges, EventEmitter } from '@angular/core';
2
- import { SnippetClient, SnippetClientOptions, Snippet, ListOptions, SnippetMeta } from '@mzebley/mark-down';
3
- import { Observable } from 'rxjs';
1
+ import { SnippetClientOptions } from '@mzebley/mark-down/angular';
2
+ export * from '@mzebley/mark-down/angular';
3
+ export { MarkdownSnippetService as SnippetService } from '@mzebley/mark-down/angular';
4
+ import * as _angular_core from '@angular/core';
5
+ import { Provider, OnChanges, EventEmitter } from '@angular/core';
6
+ import * as _mzebley_mark_down from '@mzebley/mark-down';
7
+ import { Snippet } from '@mzebley/mark-down';
4
8
  import { SafeHtml } from '@angular/platform-browser';
9
+ import { Observable } from 'rxjs';
5
10
 
6
- declare const MARK_DOWN_CLIENT: InjectionToken<SnippetClient>;
7
- declare const MARK_DOWN_OPTIONS: InjectionToken<SnippetClientOptions>;
8
- declare function provideMarkDown(options: SnippetClientOptions, client?: SnippetClient): Provider[];
9
-
10
- declare class SnippetService {
11
- private readonly client;
12
- constructor(client: SnippetClient);
13
- get(slug: string): Observable<Snippet | undefined>;
14
- list(options?: ListOptions): Observable<SnippetMeta[]>;
15
- listByGroup(group: string, options?: ListOptions): Observable<SnippetMeta[]>;
16
- listByType(type: string, options?: ListOptions): Observable<SnippetMeta[]>;
17
- html(slug: string): Observable<string | null>;
18
- }
11
+ declare const MARK_DOWN_CLIENT: _angular_core.InjectionToken<_mzebley_mark_down.SnippetClient>;
12
+ declare const MARK_DOWN_OPTIONS: _angular_core.InjectionToken<SnippetClientOptions>;
13
+ declare function provideMarkDown(options: SnippetClientOptions): Provider[];
19
14
 
20
15
  declare class SnippetViewComponent implements OnChanges {
21
16
  private readonly slug$;
@@ -28,4 +23,4 @@ declare class SnippetViewComponent implements OnChanges {
28
23
  ngOnChanges(): void;
29
24
  }
30
25
 
31
- export { MARK_DOWN_CLIENT, MARK_DOWN_OPTIONS, SnippetService, SnippetViewComponent, provideMarkDown };
26
+ export { MARK_DOWN_CLIENT, MARK_DOWN_OPTIONS, SnippetViewComponent, provideMarkDown };
package/dist/index.d.ts CHANGED
@@ -1,21 +1,16 @@
1
- import { InjectionToken, Provider, OnChanges, EventEmitter } from '@angular/core';
2
- import { SnippetClient, SnippetClientOptions, Snippet, ListOptions, SnippetMeta } from '@mzebley/mark-down';
3
- import { Observable } from 'rxjs';
1
+ import { SnippetClientOptions } from '@mzebley/mark-down/angular';
2
+ export * from '@mzebley/mark-down/angular';
3
+ export { MarkdownSnippetService as SnippetService } from '@mzebley/mark-down/angular';
4
+ import * as _angular_core from '@angular/core';
5
+ import { Provider, OnChanges, EventEmitter } from '@angular/core';
6
+ import * as _mzebley_mark_down from '@mzebley/mark-down';
7
+ import { Snippet } from '@mzebley/mark-down';
4
8
  import { SafeHtml } from '@angular/platform-browser';
9
+ import { Observable } from 'rxjs';
5
10
 
6
- declare const MARK_DOWN_CLIENT: InjectionToken<SnippetClient>;
7
- declare const MARK_DOWN_OPTIONS: InjectionToken<SnippetClientOptions>;
8
- declare function provideMarkDown(options: SnippetClientOptions, client?: SnippetClient): Provider[];
9
-
10
- declare class SnippetService {
11
- private readonly client;
12
- constructor(client: SnippetClient);
13
- get(slug: string): Observable<Snippet | undefined>;
14
- list(options?: ListOptions): Observable<SnippetMeta[]>;
15
- listByGroup(group: string, options?: ListOptions): Observable<SnippetMeta[]>;
16
- listByType(type: string, options?: ListOptions): Observable<SnippetMeta[]>;
17
- html(slug: string): Observable<string | null>;
18
- }
11
+ declare const MARK_DOWN_CLIENT: _angular_core.InjectionToken<_mzebley_mark_down.SnippetClient>;
12
+ declare const MARK_DOWN_OPTIONS: _angular_core.InjectionToken<SnippetClientOptions>;
13
+ declare function provideMarkDown(options: SnippetClientOptions): Provider[];
19
14
 
20
15
  declare class SnippetViewComponent implements OnChanges {
21
16
  private readonly slug$;
@@ -28,4 +23,4 @@ declare class SnippetViewComponent implements OnChanges {
28
23
  ngOnChanges(): void;
29
24
  }
30
25
 
31
- export { MARK_DOWN_CLIENT, MARK_DOWN_OPTIONS, SnippetService, SnippetViewComponent, provideMarkDown };
26
+ export { MARK_DOWN_CLIENT, MARK_DOWN_OPTIONS, SnippetViewComponent, provideMarkDown };
package/dist/index.js CHANGED
@@ -8,51 +8,24 @@ var __decorateClass = (decorators, target, key, kind) => {
8
8
  if (kind && result) __defProp(target, key, result);
9
9
  return result;
10
10
  };
11
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
11
+
12
+ // src/index.ts
13
+ export * from "@mzebley/mark-down/angular";
12
14
 
13
15
  // src/token.ts
14
- import { InjectionToken } from "@angular/core";
15
- import { SnippetClient } from "@mzebley/mark-down";
16
- var MARK_DOWN_CLIENT = new InjectionToken("mark-down-client");
17
- var MARK_DOWN_OPTIONS = new InjectionToken("mark-down-options");
18
- function provideMarkDown(options, client) {
19
- return [
20
- { provide: MARK_DOWN_OPTIONS, useValue: options },
21
- {
22
- provide: MARK_DOWN_CLIENT,
23
- useFactory: (opts) => client ?? new SnippetClient(opts),
24
- deps: [MARK_DOWN_OPTIONS]
25
- }
26
- ];
16
+ import {
17
+ SNIPPET_CLIENT,
18
+ SNIPPET_CLIENT_OPTIONS,
19
+ provideSnippetClient
20
+ } from "@mzebley/mark-down/angular";
21
+ var MARK_DOWN_CLIENT = SNIPPET_CLIENT;
22
+ var MARK_DOWN_OPTIONS = SNIPPET_CLIENT_OPTIONS;
23
+ function provideMarkDown(options) {
24
+ return provideSnippetClient(options);
27
25
  }
28
26
 
29
27
  // src/snippet.service.ts
30
- import { Inject, Injectable } from "@angular/core";
31
- import { from, map, shareReplay } from "rxjs";
32
- var SnippetService = class {
33
- constructor(client) {
34
- this.client = client;
35
- }
36
- get(slug) {
37
- return from(this.client.get(slug)).pipe(shareReplay(1));
38
- }
39
- list(options) {
40
- return from(this.client.list(options)).pipe(shareReplay(1));
41
- }
42
- listByGroup(group, options) {
43
- return from(this.client.listByGroup(group, options)).pipe(shareReplay(1));
44
- }
45
- listByType(type, options) {
46
- return from(this.client.listByType(type, options)).pipe(shareReplay(1));
47
- }
48
- html(slug) {
49
- return this.get(slug).pipe(map((snippet) => snippet?.html ?? null));
50
- }
51
- };
52
- SnippetService = __decorateClass([
53
- Injectable({ providedIn: "root" }),
54
- __decorateParam(0, Inject(MARK_DOWN_CLIENT))
55
- ], SnippetService);
28
+ import { MarkdownSnippetService } from "@mzebley/mark-down/angular";
56
29
 
57
30
  // src/snippet-view.component.ts
58
31
  import { CommonModule } from "@angular/common";
@@ -66,21 +39,23 @@ import {
66
39
  } from "@angular/core";
67
40
  import { DomSanitizer } from "@angular/platform-browser";
68
41
  import { BehaviorSubject, of } from "rxjs";
69
- import { map as map2, shareReplay as shareReplay2, switchMap, tap } from "rxjs/operators";
42
+ import { catchError, map, shareReplay, switchMap, tap } from "rxjs/operators";
70
43
  import DOMPurify from "dompurify";
71
44
  var SnippetViewComponent = class {
72
45
  constructor() {
73
46
  this.slug$ = new BehaviorSubject(null);
74
47
  this.sanitizer = inject(DomSanitizer);
75
- this.snippets = inject(SnippetService);
48
+ this.snippets = inject(MarkdownSnippetService);
76
49
  this.loaded = new EventEmitter();
77
50
  this.snippet$ = this.slug$.pipe(
78
- switchMap((slug) => slug ? this.snippets.get(slug) : of(void 0)),
79
- tap((snippet) => this.loaded.emit(snippet)),
80
- shareReplay2(1)
51
+ switchMap(
52
+ (slug) => slug ? this.snippets.get(slug).pipe(catchError(() => of(null))) : of(null)
53
+ ),
54
+ tap((snippet) => this.loaded.emit(snippet ?? void 0)),
55
+ shareReplay({ bufferSize: 1, refCount: true })
81
56
  );
82
57
  this.content$ = this.snippet$.pipe(
83
- map2((snippet) => {
58
+ map((snippet) => {
84
59
  if (!snippet) {
85
60
  return null;
86
61
  }
@@ -118,7 +93,7 @@ SnippetViewComponent = __decorateClass([
118
93
  export {
119
94
  MARK_DOWN_CLIENT,
120
95
  MARK_DOWN_OPTIONS,
121
- SnippetService,
96
+ MarkdownSnippetService as SnippetService,
122
97
  SnippetViewComponent,
123
98
  provideMarkDown
124
99
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mzebley/mark-down-angular",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "mark↓ Angular Adapter",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -17,9 +17,14 @@
17
17
  "dompurify": "^3.0.9"
18
18
  },
19
19
  "peerDependencies": {
20
- "@angular/common": "^17.0.0",
21
- "@angular/core": "^17.0.0",
22
- "@angular/platform-browser": "^17.0.0",
23
- "rxjs": "^7.8.0"
20
+ "@angular/common": ">=17 <21",
21
+ "@angular/core": ">=17 <21",
22
+ "@angular/platform-browser": ">=17 <21",
23
+ "rxjs": ">=7.8.0 <8.0.0 || >=8.0.0 <9.0.0"
24
+ },
25
+ "peerDependenciesMeta": {
26
+ "@angular/platform-browser": {
27
+ "optional": true
28
+ }
24
29
  }
25
30
  }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "@mzebley/mark-down/angular";
1
2
  export * from "./token";
2
3
  export * from "./snippet.service";
3
4
  export * from "./snippet-view.component";
@@ -10,7 +10,7 @@ import {
10
10
  } from "@angular/core";
11
11
  import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
12
12
  import { BehaviorSubject, Observable, of } from "rxjs";
13
- import { map, shareReplay, switchMap, tap } from "rxjs/operators";
13
+ import { catchError, map, shareReplay, switchMap, tap } from "rxjs/operators";
14
14
  import type { Snippet } from "@mzebley/mark-down";
15
15
  import { SnippetService } from "./snippet.service";
16
16
  import DOMPurify from "dompurify";
@@ -37,10 +37,12 @@ export class SnippetViewComponent implements OnChanges {
37
37
  @Input() slug?: string;
38
38
  @Output() readonly loaded = new EventEmitter<Snippet | undefined>();
39
39
 
40
- private readonly snippet$: Observable<Snippet | undefined> = this.slug$.pipe(
41
- switchMap((slug) => (slug ? this.snippets.get(slug) : of(undefined))),
42
- tap((snippet) => this.loaded.emit(snippet)),
43
- shareReplay(1)
40
+ private readonly snippet$: Observable<Snippet | null> = this.slug$.pipe(
41
+ switchMap((slug) =>
42
+ slug ? this.snippets.get(slug).pipe(catchError(() => of(null))) : of(null)
43
+ ),
44
+ tap((snippet) => this.loaded.emit(snippet ?? undefined)),
45
+ shareReplay({ bufferSize: 1, refCount: true })
44
46
  );
45
47
 
46
48
  readonly content$: Observable<SafeHtml | null> = this.snippet$.pipe(
@@ -1,30 +1 @@
1
- import { Inject, Injectable } from "@angular/core";
2
- import { from, map, Observable, shareReplay } from "rxjs";
3
- import type { ListOptions, Snippet, SnippetMeta } from "@mzebley/mark-down";
4
- import { SnippetClient } from "@mzebley/mark-down";
5
- import { MARK_DOWN_CLIENT } from "./token";
6
-
7
- @Injectable({ providedIn: "root" })
8
- export class SnippetService {
9
- constructor(@Inject(MARK_DOWN_CLIENT) private readonly client: SnippetClient) {}
10
-
11
- get(slug: string): Observable<Snippet | undefined> {
12
- return from(this.client.get(slug)).pipe(shareReplay(1));
13
- }
14
-
15
- list(options?: ListOptions): Observable<SnippetMeta[]> {
16
- return from(this.client.list(options)).pipe(shareReplay(1));
17
- }
18
-
19
- listByGroup(group: string, options?: ListOptions): Observable<SnippetMeta[]> {
20
- return from(this.client.listByGroup(group, options)).pipe(shareReplay(1));
21
- }
22
-
23
- listByType(type: string, options?: ListOptions): Observable<SnippetMeta[]> {
24
- return from(this.client.listByType(type, options)).pipe(shareReplay(1));
25
- }
26
-
27
- html(slug: string): Observable<string | null> {
28
- return this.get(slug).pipe(map((snippet) => snippet?.html ?? null));
29
- }
30
- }
1
+ export { MarkdownSnippetService as SnippetService } from "@mzebley/mark-down/angular";
package/src/token.ts CHANGED
@@ -1,16 +1,14 @@
1
- import { InjectionToken, Provider } from "@angular/core";
2
- import { SnippetClient, type SnippetClientOptions } from "@mzebley/mark-down";
1
+ import type { Provider } from "@angular/core";
2
+ import {
3
+ SNIPPET_CLIENT,
4
+ SNIPPET_CLIENT_OPTIONS,
5
+ provideSnippetClient,
6
+ type SnippetClientOptions
7
+ } from "@mzebley/mark-down/angular";
3
8
 
4
- export const MARK_DOWN_CLIENT = new InjectionToken<SnippetClient>("mark-down-client");
5
- export const MARK_DOWN_OPTIONS = new InjectionToken<SnippetClientOptions>("mark-down-options");
9
+ export const MARK_DOWN_CLIENT = SNIPPET_CLIENT;
10
+ export const MARK_DOWN_OPTIONS = SNIPPET_CLIENT_OPTIONS;
6
11
 
7
- export function provideMarkDown(options: SnippetClientOptions, client?: SnippetClient): Provider[] {
8
- return [
9
- { provide: MARK_DOWN_OPTIONS, useValue: options },
10
- {
11
- provide: MARK_DOWN_CLIENT,
12
- useFactory: (opts: SnippetClientOptions) => client ?? new SnippetClient(opts),
13
- deps: [MARK_DOWN_OPTIONS]
14
- }
15
- ];
12
+ export function provideMarkDown(options: SnippetClientOptions): Provider[] {
13
+ return provideSnippetClient(options);
16
14
  }
package/tsconfig.json CHANGED
@@ -3,7 +3,14 @@
3
3
  "compilerOptions": {
4
4
  "outDir": "dist",
5
5
  "experimentalDecorators": true,
6
- "emitDecoratorMetadata": true
6
+ "emitDecoratorMetadata": true,
7
+ "baseUrl": ".",
8
+ "paths": {
9
+ "@mzebley/mark-down": ["../core/src/index.ts"],
10
+ "@mzebley/mark-down/angular": ["../core/src/angular/index.ts"],
11
+ "@mzebley/mark-down/browser": ["../core/src/browser.ts"],
12
+ "@mzebley/mark-down/slug": ["../core/src/slug.ts"]
13
+ }
7
14
  },
8
15
  "include": ["src/**/*"]
9
16
  }