@ng-doc/app 22.1.0 → 22.2.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.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/fesm2022/ng-doc-app-classes-content-controller.mjs +22 -4
  3. package/fesm2022/ng-doc-app-classes-content-controller.mjs.map +1 -1
  4. package/fesm2022/ng-doc-app-classes-default-search-engine.mjs +36 -12
  5. package/fesm2022/ng-doc-app-classes-default-search-engine.mjs.map +1 -1
  6. package/fesm2022/ng-doc-app-classes-root-page.mjs.map +1 -1
  7. package/fesm2022/ng-doc-app-components-api-list.mjs +7 -5
  8. package/fesm2022/ng-doc-app-components-api-list.mjs.map +1 -1
  9. package/fesm2022/ng-doc-app-components-breadcrumb.mjs +5 -3
  10. package/fesm2022/ng-doc-app-components-breadcrumb.mjs.map +1 -1
  11. package/fesm2022/ng-doc-app-components-code.mjs +6 -4
  12. package/fesm2022/ng-doc-app-components-code.mjs.map +1 -1
  13. package/fesm2022/ng-doc-app-components-command-palette.mjs +35 -27
  14. package/fesm2022/ng-doc-app-components-command-palette.mjs.map +1 -1
  15. package/fesm2022/ng-doc-app-components-copy-button.mjs +6 -4
  16. package/fesm2022/ng-doc-app-components-copy-button.mjs.map +1 -1
  17. package/fesm2022/ng-doc-app-components-demo-displayer.mjs +19 -4
  18. package/fesm2022/ng-doc-app-components-demo-displayer.mjs.map +1 -1
  19. package/fesm2022/ng-doc-app-components-demo-frame.mjs +195 -12
  20. package/fesm2022/ng-doc-app-components-demo-frame.mjs.map +1 -1
  21. package/fesm2022/ng-doc-app-components-demo-pane.mjs +2 -2
  22. package/fesm2022/ng-doc-app-components-demo-pane.mjs.map +1 -1
  23. package/fesm2022/ng-doc-app-components-demo.mjs +49 -12
  24. package/fesm2022/ng-doc-app-components-demo.mjs.map +1 -1
  25. package/fesm2022/ng-doc-app-components-fullscreen-button.mjs +5 -3
  26. package/fesm2022/ng-doc-app-components-fullscreen-button.mjs.map +1 -1
  27. package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs +4 -2
  28. package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs.map +1 -1
  29. package/fesm2022/ng-doc-app-components-heading-anchor.mjs +5 -3
  30. package/fesm2022/ng-doc-app-components-heading-anchor.mjs.map +1 -1
  31. package/fesm2022/ng-doc-app-components-image-viewer.mjs +5 -3
  32. package/fesm2022/ng-doc-app-components-image-viewer.mjs.map +1 -1
  33. package/fesm2022/ng-doc-app-components-navbar.mjs +4 -2
  34. package/fesm2022/ng-doc-app-components-navbar.mjs.map +1 -1
  35. package/fesm2022/ng-doc-app-components-page-navigation.mjs +5 -3
  36. package/fesm2022/ng-doc-app-components-page-navigation.mjs.map +1 -1
  37. package/fesm2022/ng-doc-app-components-page-wrapper.mjs +2 -2
  38. package/fesm2022/ng-doc-app-components-page-wrapper.mjs.map +1 -1
  39. package/fesm2022/ng-doc-app-components-page.mjs +83 -16
  40. package/fesm2022/ng-doc-app-components-page.mjs.map +1 -1
  41. package/fesm2022/ng-doc-app-components-playground.mjs +743 -108
  42. package/fesm2022/ng-doc-app-components-playground.mjs.map +1 -1
  43. package/fesm2022/ng-doc-app-components-root.mjs +51 -4
  44. package/fesm2022/ng-doc-app-components-root.mjs.map +1 -1
  45. package/fesm2022/ng-doc-app-components-search-result.mjs +8 -6
  46. package/fesm2022/ng-doc-app-components-search-result.mjs.map +1 -1
  47. package/fesm2022/ng-doc-app-components-search.mjs +7 -5
  48. package/fesm2022/ng-doc-app-components-search.mjs.map +1 -1
  49. package/fesm2022/ng-doc-app-components-sidebar.mjs +4 -3
  50. package/fesm2022/ng-doc-app-components-sidebar.mjs.map +1 -1
  51. package/fesm2022/ng-doc-app-components-theme-toggle.mjs +7 -5
  52. package/fesm2022/ng-doc-app-components-theme-toggle.mjs.map +1 -1
  53. package/fesm2022/ng-doc-app-components-toc.mjs +4 -2
  54. package/fesm2022/ng-doc-app-components-toc.mjs.map +1 -1
  55. package/fesm2022/ng-doc-app-constants.mjs +11 -1
  56. package/fesm2022/ng-doc-app-constants.mjs.map +1 -1
  57. package/fesm2022/ng-doc-app-demo-app.mjs +618 -15
  58. package/fesm2022/ng-doc-app-demo-app.mjs.map +1 -1
  59. package/fesm2022/ng-doc-app-helpers.mjs +125 -6
  60. package/fesm2022/ng-doc-app-helpers.mjs.map +1 -1
  61. package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs +29 -18
  62. package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs.map +1 -1
  63. package/fesm2022/ng-doc-app-providers-texts.mjs +53 -0
  64. package/fesm2022/ng-doc-app-providers-texts.mjs.map +1 -0
  65. package/fesm2022/ng-doc-app-providers.mjs +1 -0
  66. package/fesm2022/ng-doc-app-providers.mjs.map +1 -1
  67. package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs +27 -2
  68. package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs.map +1 -1
  69. package/fesm2022/ng-doc-app-services-highlighter.mjs +8 -5
  70. package/fesm2022/ng-doc-app-services-highlighter.mjs.map +1 -1
  71. package/fesm2022/ng-doc-app-services-shortcuts.mjs +38 -4
  72. package/fesm2022/ng-doc-app-services-shortcuts.mjs.map +1 -1
  73. package/fesm2022/ng-doc-app-texts-ar.mjs +238 -0
  74. package/fesm2022/ng-doc-app-texts-ar.mjs.map +1 -0
  75. package/fesm2022/ng-doc-app-texts-de.mjs +205 -0
  76. package/fesm2022/ng-doc-app-texts-de.mjs.map +1 -0
  77. package/fesm2022/ng-doc-app-texts-es.mjs +205 -0
  78. package/fesm2022/ng-doc-app-texts-es.mjs.map +1 -0
  79. package/fesm2022/ng-doc-app-texts-fr.mjs +205 -0
  80. package/fesm2022/ng-doc-app-texts-fr.mjs.map +1 -0
  81. package/fesm2022/ng-doc-app-texts-hi.mjs +219 -0
  82. package/fesm2022/ng-doc-app-texts-hi.mjs.map +1 -0
  83. package/fesm2022/ng-doc-app-texts-ja.mjs +205 -0
  84. package/fesm2022/ng-doc-app-texts-ja.mjs.map +1 -0
  85. package/fesm2022/ng-doc-app-texts-ko.mjs +205 -0
  86. package/fesm2022/ng-doc-app-texts-ko.mjs.map +1 -0
  87. package/fesm2022/ng-doc-app-texts-pt-br.mjs +205 -0
  88. package/fesm2022/ng-doc-app-texts-pt-br.mjs.map +1 -0
  89. package/fesm2022/ng-doc-app-texts-ru.mjs +231 -0
  90. package/fesm2022/ng-doc-app-texts-ru.mjs.map +1 -0
  91. package/fesm2022/ng-doc-app-texts-uk.mjs +231 -0
  92. package/fesm2022/ng-doc-app-texts-uk.mjs.map +1 -0
  93. package/fesm2022/ng-doc-app-texts-zh.mjs +205 -0
  94. package/fesm2022/ng-doc-app-texts-zh.mjs.map +1 -0
  95. package/fesm2022/ng-doc-app-tokens.mjs +214 -1
  96. package/fesm2022/ng-doc-app-tokens.mjs.map +1 -1
  97. package/fesm2022/ng-doc-app-type-controls-json-control.mjs +90 -0
  98. package/fesm2022/ng-doc-app-type-controls-json-control.mjs.map +1 -0
  99. package/fesm2022/ng-doc-app-type-controls-list-control.mjs +792 -0
  100. package/fesm2022/ng-doc-app-type-controls-list-control.mjs.map +1 -0
  101. package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs +5 -3
  102. package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs.map +1 -1
  103. package/fesm2022/ng-doc-app-type-controls.mjs +2 -0
  104. package/fesm2022/ng-doc-app-type-controls.mjs.map +1 -1
  105. package/package.json +59 -3
  106. package/styles/global.css +1 -0
  107. package/styles/main.css +1 -0
  108. package/types/ng-doc-app-classes-default-search-engine.d.ts +11 -0
  109. package/types/ng-doc-app-classes-root-page.d.ts +5 -0
  110. package/types/ng-doc-app-components-api-list.d.ts +3 -1
  111. package/types/ng-doc-app-components-breadcrumb.d.ts +2 -1
  112. package/types/ng-doc-app-components-code.d.ts +2 -0
  113. package/types/ng-doc-app-components-command-palette.d.ts +3 -1
  114. package/types/ng-doc-app-components-copy-button.d.ts +3 -1
  115. package/types/ng-doc-app-components-demo-displayer.d.ts +13 -1
  116. package/types/ng-doc-app-components-demo-frame.d.ts +62 -3
  117. package/types/ng-doc-app-components-demo.d.ts +27 -8
  118. package/types/ng-doc-app-components-fullscreen-button.d.ts +2 -0
  119. package/types/ng-doc-app-components-fullscreen-toggle.d.ts +2 -0
  120. package/types/ng-doc-app-components-heading-anchor.d.ts +2 -0
  121. package/types/ng-doc-app-components-image-viewer.d.ts +2 -0
  122. package/types/ng-doc-app-components-navbar.d.ts +2 -0
  123. package/types/ng-doc-app-components-page-navigation.d.ts +2 -1
  124. package/types/ng-doc-app-components-page.d.ts +10 -1
  125. package/types/ng-doc-app-components-playground.d.ts +241 -44
  126. package/types/ng-doc-app-components-root.d.ts +18 -0
  127. package/types/ng-doc-app-components-search-result.d.ts +2 -0
  128. package/types/ng-doc-app-components-search.d.ts +2 -0
  129. package/types/ng-doc-app-components-sidebar.d.ts +2 -1
  130. package/types/ng-doc-app-components-theme-toggle.d.ts +4 -1
  131. package/types/ng-doc-app-components-toc.d.ts +2 -1
  132. package/types/ng-doc-app-constants.d.ts +11 -1
  133. package/types/ng-doc-app-demo-app.d.ts +211 -3
  134. package/types/ng-doc-app-helpers.d.ts +56 -3
  135. package/types/ng-doc-app-interfaces.d.ts +621 -3
  136. package/types/ng-doc-app-providers-ng-doc-app.d.ts +6 -0
  137. package/types/ng-doc-app-providers-texts.d.ts +28 -0
  138. package/types/ng-doc-app-providers.d.ts +1 -0
  139. package/types/ng-doc-app-services-content-scroll-intent.d.ts +11 -1
  140. package/types/ng-doc-app-services-highlighter.d.ts +3 -1
  141. package/types/ng-doc-app-services-shortcuts.d.ts +16 -0
  142. package/types/ng-doc-app-texts-ar.d.ts +13 -0
  143. package/types/ng-doc-app-texts-de.d.ts +12 -0
  144. package/types/ng-doc-app-texts-es.d.ts +12 -0
  145. package/types/ng-doc-app-texts-fr.d.ts +12 -0
  146. package/types/ng-doc-app-texts-hi.d.ts +12 -0
  147. package/types/ng-doc-app-texts-ja.d.ts +12 -0
  148. package/types/ng-doc-app-texts-ko.d.ts +12 -0
  149. package/types/ng-doc-app-texts-pt-br.d.ts +12 -0
  150. package/types/ng-doc-app-texts-ru.d.ts +12 -0
  151. package/types/ng-doc-app-texts-uk.d.ts +12 -0
  152. package/types/ng-doc-app-texts-zh.d.ts +12 -0
  153. package/types/ng-doc-app-tokens.d.ts +21 -2
  154. package/types/ng-doc-app-type-controls-json-control.d.ts +38 -0
  155. package/types/ng-doc-app-type-controls-list-control.d.ts +313 -0
  156. package/types/ng-doc-app-type-controls-type-alias-control.d.ts +2 -1
  157. package/types/ng-doc-app-type-controls.d.ts +2 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Aleksandr Skoropad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,7 @@
1
+ import { isPlatformBrowser, DOCUMENT } from '@angular/common';
1
2
  import * as i0 from '@angular/core';
2
- import { signal, inject, PendingTasks, DestroyRef, Injectable } from '@angular/core';
3
- import { ɵforgetNgDocContent as _forgetNgDocContent, ɵpeekNgDocContent as _peekNgDocContent, ɵpendingNgDocContent as _pendingNgDocContent } from '@ng-doc/app/helpers';
3
+ import { signal, inject, PendingTasks, DestroyRef, PLATFORM_ID, Injectable } from '@angular/core';
4
+ import { ɵlistenNgDocContentUpdates as _listenNgDocContentUpdates, ɵwatchNgDocContentUpdates as _watchNgDocContentUpdates, ɵforgetNgDocContent as _forgetNgDocContent, ɵpeekNgDocContent as _peekNgDocContent, ɵpendingNgDocContent as _pendingNgDocContent, ɵloadNgDocContent as _loadNgDocContent } from '@ng-doc/app/helpers';
4
5
  import { NgDocContentState } from '@ng-doc/app/services/content-state';
5
6
 
6
7
  /**
@@ -43,6 +44,11 @@ class NgDocContentController {
43
44
  };
44
45
  this.destroyed = false;
45
46
  inject(DestroyRef).onDestroy(() => this.destroy());
47
+ // The Vite development host updates the content of an edited guide in place (see
48
+ // `ɵlistenNgDocContentUpdates`); a connected source then renders its new payload.
49
+ if (isPlatformBrowser(inject(PLATFORM_ID))) {
50
+ _listenNgDocContentUpdates(inject(DOCUMENT).defaultView);
51
+ }
46
52
  }
47
53
  /**
48
54
  * Loads the source and reloads it whenever the source reports a change. Connecting the
@@ -65,14 +71,26 @@ class NgDocContentController {
65
71
  }
66
72
  this.contentState.clear(this.owner);
67
73
  this.error.set(undefined);
74
+ const stopUpdates = _watchNgDocContentUpdates(({ ids }) => {
75
+ if (!ids.has(source.id) || this.source !== source || this.sourceEpoch !== sourceEpoch) {
76
+ return;
77
+ }
78
+ // The update's payload is the newest one, and it is at hand: render it at once.
79
+ this.reload(true);
80
+ });
81
+ this.unsubscribe = stopUpdates;
68
82
  try {
69
- this.unsubscribe = source.subscribe?.(() => {
83
+ const unsubscribe = source.subscribe?.(() => {
70
84
  if (this.source !== source || this.sourceEpoch !== sourceEpoch)
71
85
  return;
72
86
  // The source has a new revision, so a preloaded payload is stale.
73
87
  _forgetNgDocContent(source);
74
88
  this.reload(false);
75
89
  });
90
+ this.unsubscribe = () => {
91
+ stopUpdates();
92
+ unsubscribe?.();
93
+ };
76
94
  }
77
95
  catch (error) {
78
96
  this.fail(source.id, error);
@@ -170,7 +188,7 @@ class NgDocContentController {
170
188
  }
171
189
  async load(source, request, signal, pending) {
172
190
  try {
173
- const payload = validatePayload(await (pending ?? source.load(signal)), source.id);
191
+ const payload = validatePayload(await (pending ?? _loadNgDocContent(source, signal)), source.id);
174
192
  if (!this.isCurrent(source, request, signal))
175
193
  return;
176
194
  this.apply(payload, request);
@@ -1 +1 @@
1
- {"version":3,"file":"ng-doc-app-classes-content-controller.mjs","sources":["../../../../libs/app/classes/content-controller/content-controller.ts","../../../../libs/app/classes/content-controller/ng-doc-app-classes-content-controller.ts"],"sourcesContent":["import {\n DestroyRef,\n inject,\n Injectable,\n PendingTasks,\n signal,\n WritableSignal,\n} from '@angular/core';\nimport { ɵforgetNgDocContent, ɵpeekNgDocContent, ɵpendingNgDocContent } from '@ng-doc/app/helpers';\nimport { NgDocContentState } from '@ng-doc/app/services/content-state';\nimport type { NgDocContentModule, NgDocContentSource } from '@ng-doc/core/interfaces';\n\n/** A failed processing pass of one content version. */\nexport interface NgDocContentRenderFailure {\n /** The content version the pass rendered. */\n readonly version: number;\n /** The error the pass failed with. */\n readonly error: unknown;\n}\n\n/**\n * Owns one body or header content source for one component instance. Provide it in the\n * component's `providers`; it holds a pending task from each load until the processors accept\n * the loaded HTML.\n */\n@Injectable()\nexport class NgDocContentController {\n /** The loaded HTML. */\n readonly html: WritableSignal<string> = signal('');\n /** Increments whenever the HTML must be processed again. */\n readonly version: WritableSignal<number> = signal(0);\n /** The load or processing error of the current source. */\n readonly error: WritableSignal<Error | undefined> = signal(undefined);\n /**\n * Whether the latest load of the current source has been rendered: its version was processed,\n * or the load or its processing failed. False while a load or its processing is pending.\n */\n readonly settled: WritableSignal<boolean> = signal(false);\n /**\n * The version of the latest loaded content of the current source, or undefined before the\n * first load. A processing pass of this version renders loaded content.\n * @internal\n */\n readonly loadedVersion: WritableSignal<number | undefined> = signal(undefined);\n\n private readonly pendingTasks = inject(PendingTasks);\n private readonly contentState = inject(NgDocContentState);\n\n private readonly owner = {};\n private source?: NgDocContentSource;\n private unsubscribe?: () => void;\n private abort?: AbortController;\n private pending?: {\n readonly request: number;\n readonly release: () => void;\n awaitingVersion?: number;\n };\n private request = 0;\n private sourceEpoch = 0;\n private renderState: { version: number; status: 'pending' | 'complete' | 'failed' } = {\n version: 0,\n status: 'pending',\n };\n private destroyed = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.destroy());\n }\n\n /**\n * Loads the source and reloads it whenever the source reports a change. Connecting the\n * connected source again does nothing.\n * @param source - The content source.\n */\n connect(source: NgDocContentSource): void {\n if (this.destroyed || this.source === source) return;\n\n const previousId = this.source?.id;\n this.cancelCurrent();\n this.unsubscribeCurrent();\n const sourceEpoch = ++this.sourceEpoch;\n this.source = source;\n this.loadedVersion.set(undefined);\n if (previousId !== undefined && previousId !== source.id) {\n this.html.set('');\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n }\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n\n try {\n this.unsubscribe = source.subscribe?.(() => {\n if (this.source !== source || this.sourceEpoch !== sourceEpoch) return;\n // The source has a new revision, so a preloaded payload is stale.\n ɵforgetNgDocContent(source);\n this.reload(false);\n });\n } catch (error) {\n this.fail(source.id, error);\n return;\n }\n this.reload(true);\n }\n\n /** Drops the current source and clears the HTML. */\n disconnect(): void {\n if (this.destroyed || !this.source) return;\n this.cancelCurrent();\n this.sourceEpoch++;\n this.unsubscribeCurrent();\n this.source = undefined;\n this.loadedVersion.set(undefined);\n this.settled.set(false);\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n if (this.html()) {\n this.html.set('');\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n }\n }\n\n /**\n * Accepts a processing pass. Only the pass of the current version counts.\n * @param version - The content version the pass rendered.\n */\n processed(version: number): void {\n if (version !== this.version()) return;\n this.renderState = { version, status: 'complete' };\n if (this.pending?.awaitingVersion === version) this.settle(this.pending.request);\n }\n\n /**\n * Reports a failed processing pass. Only a failure of the current version counts.\n * @param failure - The version and the error.\n */\n processingFailed(failure: NgDocContentRenderFailure): void {\n if (failure.version !== this.version() || !this.source) return;\n this.renderState = { version: failure.version, status: 'failed' };\n if (this.pending?.awaitingVersion !== failure.version) return;\n this.fail(this.source.id, failure.error);\n }\n\n /** Cancels the current load and releases its pending task. Called on destroy. */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.request++;\n this.sourceEpoch++;\n this.abort?.abort();\n this.abort = undefined;\n try {\n this.unsubscribeCurrent();\n } finally {\n this.finishPending();\n this.contentState.clear(this.owner);\n }\n }\n\n /**\n * Loads the current source.\n * @param preloaded - Whether a payload that was preloaded for the source (by the route resolver\n * or by link preloading) may be used. It is applied at once, so the first render of the\n * component already shows the content instead of an empty page.\n */\n private reload(preloaded: boolean): void {\n const source = this.source;\n if (!source || this.destroyed) return;\n\n this.cancelCurrent();\n this.settled.set(false);\n const request = ++this.request;\n const abort = new AbortController();\n this.abort = abort;\n this.pending = { request, release: once(this.pendingTasks.add()) };\n\n const payload = preloaded ? ɵpeekNgDocContent(source) : undefined;\n\n if (payload) {\n try {\n this.apply(validatePayload(payload, source.id), request);\n } catch (error) {\n this.fail(source.id, error);\n }\n return;\n }\n // A page that opened before its preload finished (the router stopped waiting) waits for the\n // same load instead of starting a second one.\n void this.load(\n source,\n request,\n abort.signal,\n preloaded ? ɵpendingNgDocContent(source) : undefined,\n );\n }\n\n private async load(\n source: NgDocContentSource,\n request: number,\n signal: AbortSignal,\n pending?: Promise<NgDocContentModule>,\n ): Promise<void> {\n try {\n const payload = validatePayload(await (pending ?? source.load(signal)), source.id);\n if (!this.isCurrent(source, request, signal)) return;\n\n this.apply(payload, request);\n } catch (error) {\n if (!this.isCurrent(source, request, signal)) return;\n this.fail(source.id, error);\n }\n }\n\n private apply(payload: NgDocContentModule, request: number): void {\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n if (payload.html === this.html()) {\n if (this.renderState.version !== this.version() || this.renderState.status === 'failed') {\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n this.loadedVersion.set(this.version());\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n } else if (this.renderState.status === 'complete') {\n // The loaded content is already on the page (for example an empty body).\n this.loadedVersion.set(this.version());\n this.settle(request);\n } else {\n this.loadedVersion.set(this.version());\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n }\n return;\n }\n\n this.html.set(payload.html);\n this.version.update((version) => version + 1);\n this.loadedVersion.set(this.version());\n this.renderState = { version: this.version(), status: 'pending' };\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n }\n\n private isCurrent(source: NgDocContentSource, request: number, signal: AbortSignal): boolean {\n return !this.destroyed && !signal.aborted && this.source === source && this.request === request;\n }\n\n private fail(contentId: string, error: unknown): void {\n const normalized = error instanceof Error ? error : new Error(String(error));\n this.contentState.report(this.owner, { contentId, error });\n this.error.set(normalized);\n this.finishPending();\n this.settled.set(true);\n }\n\n private settle(request: number): void {\n if (this.pending?.request !== request) return;\n this.finishPending(request);\n this.settled.set(true);\n }\n\n private cancelCurrent(): void {\n this.request++;\n this.abort?.abort();\n this.abort = undefined;\n this.finishPending();\n }\n\n private finishPending(request?: number): void {\n if (!this.pending || (request !== undefined && this.pending.request !== request)) return;\n this.pending.release();\n this.pending = undefined;\n }\n\n private unsubscribeCurrent(): void {\n const unsubscribe = this.unsubscribe;\n this.unsubscribe = undefined;\n try {\n unsubscribe?.();\n } catch {\n // Cleanup cannot keep an application unstable or revive an obsolete source.\n }\n }\n}\n\n/**\n * Checks that a loaded content module has the expected shape and id.\n * @param payload - The loaded value.\n * @param expectedId - The id of the source that loaded it.\n * @returns The payload, typed.\n */\nexport function validatePayload(payload: unknown, expectedId: string): NgDocContentModule {\n if (\n typeof payload !== 'object' ||\n payload === null ||\n !('schemaVersion' in payload) ||\n payload.schemaVersion !== 1 ||\n !('id' in payload) ||\n payload.id !== expectedId ||\n !('revision' in payload) ||\n typeof payload.revision !== 'string' ||\n !('html' in payload) ||\n typeof payload.html !== 'string'\n ) {\n throw new Error(`Invalid NgDoc content payload for \"${expectedId}\".`);\n }\n return payload as NgDocContentModule;\n}\n\n/**\n * Wraps a callback so that only its first call runs.\n * @param callback - The callback.\n * @returns The wrapped callback.\n */\nfunction once(callback: () => void): () => void {\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n callback();\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["ɵforgetNgDocContent","ɵpeekNgDocContent","ɵpendingNgDocContent"],"mappings":"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"}
1
+ {"version":3,"file":"ng-doc-app-classes-content-controller.mjs","sources":["../../../../libs/app/classes/content-controller/content-controller.ts","../../../../libs/app/classes/content-controller/ng-doc-app-classes-content-controller.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n DestroyRef,\n inject,\n Injectable,\n PendingTasks,\n PLATFORM_ID,\n signal,\n WritableSignal,\n} from '@angular/core';\nimport {\n ɵforgetNgDocContent,\n ɵlistenNgDocContentUpdates,\n ɵloadNgDocContent,\n ɵpeekNgDocContent,\n ɵpendingNgDocContent,\n ɵwatchNgDocContentUpdates,\n} from '@ng-doc/app/helpers';\nimport { NgDocContentState } from '@ng-doc/app/services/content-state';\nimport type { NgDocContentModule, NgDocContentSource } from '@ng-doc/core/interfaces';\n\n/** A failed processing pass of one content version. */\nexport interface NgDocContentRenderFailure {\n /** The content version the pass rendered. */\n readonly version: number;\n /** The error the pass failed with. */\n readonly error: unknown;\n}\n\n/**\n * Owns one body or header content source for one component instance. Provide it in the\n * component's `providers`; it holds a pending task from each load until the processors accept\n * the loaded HTML.\n */\n@Injectable()\nexport class NgDocContentController {\n /** The loaded HTML. */\n readonly html: WritableSignal<string> = signal('');\n /** Increments whenever the HTML must be processed again. */\n readonly version: WritableSignal<number> = signal(0);\n /** The load or processing error of the current source. */\n readonly error: WritableSignal<Error | undefined> = signal(undefined);\n /**\n * Whether the latest load of the current source has been rendered: its version was processed,\n * or the load or its processing failed. False while a load or its processing is pending.\n */\n readonly settled: WritableSignal<boolean> = signal(false);\n /**\n * The version of the latest loaded content of the current source, or undefined before the\n * first load. A processing pass of this version renders loaded content.\n * @internal\n */\n readonly loadedVersion: WritableSignal<number | undefined> = signal(undefined);\n\n private readonly pendingTasks = inject(PendingTasks);\n private readonly contentState = inject(NgDocContentState);\n\n private readonly owner = {};\n private source?: NgDocContentSource;\n private unsubscribe?: () => void;\n private abort?: AbortController;\n private pending?: {\n readonly request: number;\n readonly release: () => void;\n awaitingVersion?: number;\n };\n private request = 0;\n private sourceEpoch = 0;\n private renderState: { version: number; status: 'pending' | 'complete' | 'failed' } = {\n version: 0,\n status: 'pending',\n };\n private destroyed = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.destroy());\n // The Vite development host updates the content of an edited guide in place (see\n // `ɵlistenNgDocContentUpdates`); a connected source then renders its new payload.\n if (isPlatformBrowser(inject(PLATFORM_ID))) {\n ɵlistenNgDocContentUpdates(inject(DOCUMENT).defaultView);\n }\n }\n\n /**\n * Loads the source and reloads it whenever the source reports a change. Connecting the\n * connected source again does nothing.\n * @param source - The content source.\n */\n connect(source: NgDocContentSource): void {\n if (this.destroyed || this.source === source) return;\n\n const previousId = this.source?.id;\n this.cancelCurrent();\n this.unsubscribeCurrent();\n const sourceEpoch = ++this.sourceEpoch;\n this.source = source;\n this.loadedVersion.set(undefined);\n if (previousId !== undefined && previousId !== source.id) {\n this.html.set('');\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n }\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n\n const stopUpdates = ɵwatchNgDocContentUpdates(({ ids }) => {\n if (!ids.has(source.id) || this.source !== source || this.sourceEpoch !== sourceEpoch) {\n return;\n }\n // The update's payload is the newest one, and it is at hand: render it at once.\n this.reload(true);\n });\n this.unsubscribe = stopUpdates;\n try {\n const unsubscribe = source.subscribe?.(() => {\n if (this.source !== source || this.sourceEpoch !== sourceEpoch) return;\n // The source has a new revision, so a preloaded payload is stale.\n ɵforgetNgDocContent(source);\n this.reload(false);\n });\n this.unsubscribe = () => {\n stopUpdates();\n unsubscribe?.();\n };\n } catch (error) {\n this.fail(source.id, error);\n return;\n }\n this.reload(true);\n }\n\n /** Drops the current source and clears the HTML. */\n disconnect(): void {\n if (this.destroyed || !this.source) return;\n this.cancelCurrent();\n this.sourceEpoch++;\n this.unsubscribeCurrent();\n this.source = undefined;\n this.loadedVersion.set(undefined);\n this.settled.set(false);\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n if (this.html()) {\n this.html.set('');\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n }\n }\n\n /**\n * Accepts a processing pass. Only the pass of the current version counts.\n * @param version - The content version the pass rendered.\n */\n processed(version: number): void {\n if (version !== this.version()) return;\n this.renderState = { version, status: 'complete' };\n if (this.pending?.awaitingVersion === version) this.settle(this.pending.request);\n }\n\n /**\n * Reports a failed processing pass. Only a failure of the current version counts.\n * @param failure - The version and the error.\n */\n processingFailed(failure: NgDocContentRenderFailure): void {\n if (failure.version !== this.version() || !this.source) return;\n this.renderState = { version: failure.version, status: 'failed' };\n if (this.pending?.awaitingVersion !== failure.version) return;\n this.fail(this.source.id, failure.error);\n }\n\n /** Cancels the current load and releases its pending task. Called on destroy. */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.request++;\n this.sourceEpoch++;\n this.abort?.abort();\n this.abort = undefined;\n try {\n this.unsubscribeCurrent();\n } finally {\n this.finishPending();\n this.contentState.clear(this.owner);\n }\n }\n\n /**\n * Loads the current source.\n * @param preloaded - Whether a payload that was preloaded for the source (by the route resolver\n * or by link preloading) may be used. It is applied at once, so the first render of the\n * component already shows the content instead of an empty page.\n */\n private reload(preloaded: boolean): void {\n const source = this.source;\n if (!source || this.destroyed) return;\n\n this.cancelCurrent();\n this.settled.set(false);\n const request = ++this.request;\n const abort = new AbortController();\n this.abort = abort;\n this.pending = { request, release: once(this.pendingTasks.add()) };\n\n const payload = preloaded ? ɵpeekNgDocContent(source) : undefined;\n\n if (payload) {\n try {\n this.apply(validatePayload(payload, source.id), request);\n } catch (error) {\n this.fail(source.id, error);\n }\n return;\n }\n // A page that opened before its preload finished (the router stopped waiting) waits for the\n // same load instead of starting a second one.\n void this.load(\n source,\n request,\n abort.signal,\n preloaded ? ɵpendingNgDocContent(source) : undefined,\n );\n }\n\n private async load(\n source: NgDocContentSource,\n request: number,\n signal: AbortSignal,\n pending?: Promise<NgDocContentModule>,\n ): Promise<void> {\n try {\n const payload = validatePayload(\n await (pending ?? ɵloadNgDocContent(source, signal)),\n source.id,\n );\n if (!this.isCurrent(source, request, signal)) return;\n\n this.apply(payload, request);\n } catch (error) {\n if (!this.isCurrent(source, request, signal)) return;\n this.fail(source.id, error);\n }\n }\n\n private apply(payload: NgDocContentModule, request: number): void {\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n if (payload.html === this.html()) {\n if (this.renderState.version !== this.version() || this.renderState.status === 'failed') {\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n this.loadedVersion.set(this.version());\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n } else if (this.renderState.status === 'complete') {\n // The loaded content is already on the page (for example an empty body).\n this.loadedVersion.set(this.version());\n this.settle(request);\n } else {\n this.loadedVersion.set(this.version());\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n }\n return;\n }\n\n this.html.set(payload.html);\n this.version.update((version) => version + 1);\n this.loadedVersion.set(this.version());\n this.renderState = { version: this.version(), status: 'pending' };\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n }\n\n private isCurrent(source: NgDocContentSource, request: number, signal: AbortSignal): boolean {\n return !this.destroyed && !signal.aborted && this.source === source && this.request === request;\n }\n\n private fail(contentId: string, error: unknown): void {\n const normalized = error instanceof Error ? error : new Error(String(error));\n this.contentState.report(this.owner, { contentId, error });\n this.error.set(normalized);\n this.finishPending();\n this.settled.set(true);\n }\n\n private settle(request: number): void {\n if (this.pending?.request !== request) return;\n this.finishPending(request);\n this.settled.set(true);\n }\n\n private cancelCurrent(): void {\n this.request++;\n this.abort?.abort();\n this.abort = undefined;\n this.finishPending();\n }\n\n private finishPending(request?: number): void {\n if (!this.pending || (request !== undefined && this.pending.request !== request)) return;\n this.pending.release();\n this.pending = undefined;\n }\n\n private unsubscribeCurrent(): void {\n const unsubscribe = this.unsubscribe;\n this.unsubscribe = undefined;\n try {\n unsubscribe?.();\n } catch {\n // Cleanup cannot keep an application unstable or revive an obsolete source.\n }\n }\n}\n\n/**\n * Checks that a loaded content module has the expected shape and id.\n * @param payload - The loaded value.\n * @param expectedId - The id of the source that loaded it.\n * @returns The payload, typed.\n */\nexport function validatePayload(payload: unknown, expectedId: string): NgDocContentModule {\n if (\n typeof payload !== 'object' ||\n payload === null ||\n !('schemaVersion' in payload) ||\n payload.schemaVersion !== 1 ||\n !('id' in payload) ||\n payload.id !== expectedId ||\n !('revision' in payload) ||\n typeof payload.revision !== 'string' ||\n !('html' in payload) ||\n typeof payload.html !== 'string'\n ) {\n throw new Error(`Invalid NgDoc content payload for \"${expectedId}\".`);\n }\n return payload as NgDocContentModule;\n}\n\n/**\n * Wraps a callback so that only its first call runs.\n * @param callback - The callback.\n * @returns The wrapped callback.\n */\nfunction once(callback: () => void): () => void {\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n callback();\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["ɵlistenNgDocContentUpdates","ɵwatchNgDocContentUpdates","ɵforgetNgDocContent","ɵpeekNgDocContent","ɵpendingNgDocContent","ɵloadNgDocContent"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  import { NgDocSearchEngine } from '@ng-doc/app/classes/search-engine';
2
+ import { ɵNG_DOC_CONTENT_UPDATE_EVENT as _NG_DOC_CONTENT_UPDATE_EVENT } from '@ng-doc/app/constants';
2
3
  import { asArray } from '@ng-doc/core/helpers/as-array';
3
- import { create, insertMultiple } from '@orama/orama';
4
- import { searchWithHighlight, afterInsert } from '@orama/plugin-match-highlight';
5
- import { from, defer } from 'rxjs';
6
- import { switchMap, shareReplay, map } from 'rxjs/operators';
4
+ import { defer, from } from 'rxjs';
5
+ import { switchMap, map, shareReplay } from 'rxjs/operators';
7
6
 
8
7
  /** The properties the engine searches in; the page type only filters the results. */
9
8
  const SEARCHED_PROPERTIES = ['title', 'section', 'content'];
@@ -19,19 +18,20 @@ class NgDocDefaultSearchEngine extends NgDocSearchEngine {
19
18
  constructor(options) {
20
19
  super();
21
20
  this.options = options;
22
- this.db$ = this.request(`assets/ng-doc/indexes.json`).pipe(switchMap((pages) => this.createDatabase(pages)), shareReplay(1));
21
+ this.db$ = defer(() => (this.index ??= this.loadIndex()));
22
+ this.refreshOnContentUpdates();
23
23
  }
24
24
  /**
25
25
  * Search the documentation for the given query.
26
26
  * @param query The query to search for.
27
27
  */
28
28
  search(query) {
29
- return this.db$.pipe(switchMap((db) =>
29
+ return this.db$.pipe(switchMap((index) =>
30
30
  // Each type of page is searched on its own, so that API references, which usually have
31
31
  // many more records, cannot push the guides out of the limit.
32
32
  from(Promise.all([
33
- this.searchPages(db, query, { eq: 'guide' }),
34
- this.searchPages(db, query, { nin: ['guide'] }),
33
+ this.searchPages(index, query, { eq: 'guide' }),
34
+ this.searchPages(index, query, { nin: ['guide'] }),
35
35
  ]))), map(([guides, others]) => share(guides.hits, others.hits, this.options?.limit ?? 10).map((hit) => {
36
36
  const keys = SEARCHED_PROPERTIES.filter((key) => hit.positions[key]);
37
37
  return {
@@ -43,8 +43,8 @@ class NgDocDefaultSearchEngine extends NgDocSearchEngine {
43
43
  };
44
44
  })));
45
45
  }
46
- searchPages(db, query, pageType) {
47
- return searchWithHighlight(db, {
46
+ searchPages({ db, api }, query, pageType) {
47
+ return api.searchWithHighlight(db, {
48
48
  term: query,
49
49
  boost: { title: 4, section: 2 },
50
50
  threshold: 0.3,
@@ -56,15 +56,39 @@ class NgDocDefaultSearchEngine extends NgDocSearchEngine {
56
56
  limit: this.options?.limit ?? 10,
57
57
  });
58
58
  }
59
+ /**
60
+ * The Vite development host updates an edited guide in place (`ɵNG_DOC_CONTENT_UPDATE_EVENT`);
61
+ * when its search records changed too, the next search loads the index again, as a reloaded
62
+ * page would. The listener holds the engine weakly, so an engine nobody uses any more stops
63
+ * listening. Nothing dispatches the event outside the development host, and Angular's
64
+ * production mode skips the listener altogether.
65
+ */
66
+ refreshOnContentUpdates() {
67
+ if ((typeof ngDevMode !== 'undefined' && !ngDevMode) || typeof window === 'undefined')
68
+ return;
69
+ const engine = new WeakRef(this);
70
+ const listener = (event) => {
71
+ const current = engine.deref();
72
+ if (!current)
73
+ window.removeEventListener(_NG_DOC_CONTENT_UPDATE_EVENT, listener);
74
+ else if (event.detail?.search === true) {
75
+ current.index = undefined;
76
+ }
77
+ };
78
+ window.addEventListener(_NG_DOC_CONTENT_UPDATE_EVENT, listener);
79
+ }
80
+ loadIndex() {
81
+ return this.request(`assets/ng-doc/indexes.json`).pipe(switchMap((pages) => this.createDatabase(pages)), shareReplay(1));
82
+ }
59
83
  request(url) {
60
84
  return defer(() => fetch(url)).pipe(switchMap((response) => response.json()));
61
85
  }
62
86
  createDatabase(pages) {
63
- return from(create({
87
+ return from(Promise.all([import('@orama/orama'), import('@orama/plugin-match-highlight')])).pipe(switchMap(([{ create, insertMultiple }, { afterInsert, searchWithHighlight: search }]) => from(create({
64
88
  schema: { title: 'string', section: 'string', content: 'string', pageType: 'enum' },
65
89
  plugins: [{ name: 'highlight', afterInsert }],
66
90
  components: { tokenizer: { stemmer: this.options?.stemmer } },
67
- })).pipe(switchMap((db) => from(insertMultiple(db, pages)).pipe(map(() => db))));
91
+ })).pipe(switchMap((db) => from(insertMultiple(db, pages)).pipe(map(() => ({ db: db, api: { searchWithHighlight: search } })))))));
68
92
  }
69
93
  }
70
94
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ng-doc-app-classes-default-search-engine.mjs","sources":["../../../../libs/app/classes/default-search-engine/default-search-engine.ts","../../../../libs/app/classes/default-search-engine/ng-doc-app-classes-default-search-engine.ts"],"sourcesContent":["import { NgDocSearchEngine } from '@ng-doc/app/classes/search-engine';\nimport { NgDocSearchResult } from '@ng-doc/app/interfaces';\nimport { asArray } from '@ng-doc/core/helpers/as-array';\nimport { NgDocPageIndex } from '@ng-doc/core/interfaces';\nimport { NgDocHighlightPosition } from '@ng-doc/ui-kit';\nimport { create, insertMultiple, Orama } from '@orama/orama';\nimport {\n afterInsert,\n OramaWithHighlight,\n searchWithHighlight,\n} from '@orama/plugin-match-highlight';\nimport { stemmer } from '@orama/stemmers/english';\nimport { defer, from, Observable } from 'rxjs';\nimport { map, shareReplay, switchMap } from 'rxjs/operators';\n\ntype OramaDb = OramaWithHighlight<\n Orama<{\n title: 'string';\n section: 'string';\n content: 'string';\n pageType: 'enum';\n }>\n>;\n\n/** The properties the engine searches in; the page type only filters the results. */\nconst SEARCHED_PROPERTIES = ['title', 'section', 'content'] as const;\n\n/**\n * Options for the `NgDocDefaultSearchEngine`.\n */\nexport interface NgDocDefaultSearchEngineOptions {\n /**\n * The language to use for the search engine. See https://www.npmjs.com/package/@orama/stemmers for available languages\n */\n stemmer?: typeof stemmer;\n /**\n * Specifies the maximum distance (following the Levenshtein algorithm) between the term and the searchable property.\n * (doesn't work with `exact` option)\n */\n tolerance?: number;\n /**\n * If `true`, finds all the document with an exact match of the term property.\n */\n exact?: boolean;\n /**\n * Number of results to return (default: 10). Guides get up to half of them, and more when\n * fewer API references match; API references fill the rest.\n */\n limit?: number;\n}\n\n/**\n * Search engine for the documentation, it loads the index and provides a search method.\n *\n * Guides rank above API references: the results list the matching guides first, then the\n * matching API references, each in order of relevance. Guides take up to half of the `limit`\n * (rounded up), or more when fewer API references match; API references fill the rest, and take\n * more than half when fewer guides match.\n */\nexport class NgDocDefaultSearchEngine extends NgDocSearchEngine {\n private db$: Observable<OramaDb>;\n\n constructor(private options?: NgDocDefaultSearchEngineOptions) {\n super();\n\n this.db$ = this.request<NgDocPageIndex[]>(`assets/ng-doc/indexes.json`).pipe(\n switchMap((pages) => this.createDatabase(pages)),\n shareReplay(1),\n ) as Observable<OramaDb>;\n }\n\n /**\n * Search the documentation for the given query.\n * @param query The query to search for.\n */\n search(query: string): Observable<NgDocSearchResult[]> {\n return this.db$.pipe(\n switchMap((db) =>\n // Each type of page is searched on its own, so that API references, which usually have\n // many more records, cannot push the guides out of the limit.\n from(\n Promise.all([\n this.searchPages(db, query, { eq: 'guide' }),\n this.searchPages(db, query, { nin: ['guide'] }),\n ]),\n ),\n ),\n map(([guides, others]) =>\n share(guides.hits, others.hits, this.options?.limit ?? 10).map((hit) => {\n const keys = SEARCHED_PROPERTIES.filter((key) => hit.positions[key]);\n\n return {\n index: hit.document as unknown as NgDocPageIndex,\n positions: keys.reduce(\n (acc: Partial<Record<keyof NgDocPageIndex, NgDocHighlightPosition[]>>, key) => {\n acc[key] = [...asArray(acc[key]), ...Object.values(hit.positions[key]).flat()];\n\n return acc;\n },\n {},\n ),\n };\n }),\n ),\n );\n }\n\n private searchPages(\n db: OramaDb,\n query: string,\n pageType: { eq: string } | { nin: string[] },\n ): ReturnType<typeof searchWithHighlight> {\n return searchWithHighlight(db, {\n term: query,\n boost: { title: 4, section: 2 },\n threshold: 0.3,\n properties: [...SEARCHED_PROPERTIES],\n where: { pageType },\n tolerance: this.options?.tolerance,\n exact: this.options?.exact,\n // Each type may need the whole limit when the other one has few matches.\n limit: this.options?.limit ?? 10,\n });\n }\n\n private request<T>(url: string): Observable<T> {\n return defer(() => fetch(url)).pipe(\n switchMap((response: Response) => response.json() as Promise<T>),\n );\n }\n\n private createDatabase(pages: NgDocPageIndex[]): Observable<OramaDb> {\n return from(\n create({\n schema: { title: 'string', section: 'string', content: 'string', pageType: 'enum' },\n plugins: [{ name: 'highlight', afterInsert }],\n components: { tokenizer: { stemmer: this.options?.stemmer } },\n }),\n ).pipe(\n switchMap((db) =>\n from(insertMultiple(db, pages as any)).pipe(map(() => db as unknown as OramaDb)),\n ),\n );\n }\n}\n\n/**\n * Shares the limit between the guide and the API hits: guides first, with up to half of the\n * limit (rounded up) or whatever the API hits leave, then the API hits.\n * @param guides - The guide hits, in order of relevance.\n * @param others - The API hits, in order of relevance.\n * @param limit - The total number of results.\n */\nfunction share<T>(guides: T[], others: T[], limit: number): T[] {\n const guideCount = Math.min(guides.length, Math.max(Math.ceil(limit / 2), limit - others.length));\n\n return [...guides.slice(0, guideCount), ...others.slice(0, limit - guideCount)];\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ng-doc-app-classes-default-search-engine.mjs","sources":["../../../../libs/app/classes/default-search-engine/default-search-engine.ts","../../../../libs/app/classes/default-search-engine/ng-doc-app-classes-default-search-engine.ts"],"sourcesContent":["import { NgDocSearchEngine } from '@ng-doc/app/classes/search-engine';\nimport { ɵNG_DOC_CONTENT_UPDATE_EVENT } from '@ng-doc/app/constants';\nimport { NgDocSearchResult } from '@ng-doc/app/interfaces';\nimport { asArray } from '@ng-doc/core/helpers/as-array';\nimport { NgDocPageIndex } from '@ng-doc/core/interfaces';\nimport { NgDocHighlightPosition } from '@ng-doc/ui-kit';\n// Types only: Orama loads with the first search, so an application that imports NgDoc only in a\n// lazy route keeps it out of its initial bundle, and readers who never search never load it.\nimport type { Orama } from '@orama/orama';\nimport type { OramaWithHighlight, searchWithHighlight } from '@orama/plugin-match-highlight';\nimport type { stemmer } from '@orama/stemmers/english';\nimport { defer, from, Observable } from 'rxjs';\nimport { map, shareReplay, switchMap } from 'rxjs/operators';\n\ntype OramaDb = OramaWithHighlight<\n Orama<{\n title: 'string';\n section: 'string';\n content: 'string';\n pageType: 'enum';\n }>\n>;\n\n/** The Orama functions the engine calls, loaded with the index. */\ninterface OramaApi {\n readonly searchWithHighlight: typeof searchWithHighlight;\n}\n\n/** The database of the index and the Orama functions that search it. */\ninterface OramaIndex {\n readonly db: OramaDb;\n readonly api: OramaApi;\n}\n\n/** The properties the engine searches in; the page type only filters the results. */\nconst SEARCHED_PROPERTIES = ['title', 'section', 'content'] as const;\n\n/**\n * Options for the `NgDocDefaultSearchEngine`.\n */\nexport interface NgDocDefaultSearchEngineOptions {\n /**\n * The language to use for the search engine. See https://www.npmjs.com/package/@orama/stemmers for available languages\n */\n stemmer?: typeof stemmer;\n /**\n * Specifies the maximum distance (following the Levenshtein algorithm) between the term and the searchable property.\n * (doesn't work with `exact` option)\n */\n tolerance?: number;\n /**\n * If `true`, finds all the document with an exact match of the term property.\n */\n exact?: boolean;\n /**\n * Number of results to return (default: 10). Guides get up to half of them, and more when\n * fewer API references match; API references fill the rest.\n */\n limit?: number;\n}\n\n/**\n * Search engine for the documentation, it loads the index and provides a search method.\n *\n * Guides rank above API references: the results list the matching guides first, then the\n * matching API references, each in order of relevance. Guides take up to half of the `limit`\n * (rounded up), or more when fewer API references match; API references fill the rest, and take\n * more than half when fewer guides match.\n */\nexport class NgDocDefaultSearchEngine extends NgDocSearchEngine {\n private db$: Observable<OramaIndex>;\n /** The loaded index, shared by every search until a development update replaces it. */\n private index?: Observable<OramaIndex>;\n\n constructor(private options?: NgDocDefaultSearchEngineOptions) {\n super();\n\n this.db$ = defer(() => (this.index ??= this.loadIndex()));\n this.refreshOnContentUpdates();\n }\n\n /**\n * Search the documentation for the given query.\n * @param query The query to search for.\n */\n search(query: string): Observable<NgDocSearchResult[]> {\n return this.db$.pipe(\n switchMap((index) =>\n // Each type of page is searched on its own, so that API references, which usually have\n // many more records, cannot push the guides out of the limit.\n from(\n Promise.all([\n this.searchPages(index, query, { eq: 'guide' }),\n this.searchPages(index, query, { nin: ['guide'] }),\n ]),\n ),\n ),\n map(([guides, others]) =>\n share(guides.hits, others.hits, this.options?.limit ?? 10).map((hit) => {\n const keys = SEARCHED_PROPERTIES.filter((key) => hit.positions[key]);\n\n return {\n index: hit.document as unknown as NgDocPageIndex,\n positions: keys.reduce(\n (acc: Partial<Record<keyof NgDocPageIndex, NgDocHighlightPosition[]>>, key) => {\n acc[key] = [...asArray(acc[key]), ...Object.values(hit.positions[key]).flat()];\n\n return acc;\n },\n {},\n ),\n };\n }),\n ),\n );\n }\n\n private searchPages(\n { db, api }: OramaIndex,\n query: string,\n pageType: { eq: string } | { nin: string[] },\n ): ReturnType<OramaApi['searchWithHighlight']> {\n return api.searchWithHighlight(db, {\n term: query,\n boost: { title: 4, section: 2 },\n threshold: 0.3,\n properties: [...SEARCHED_PROPERTIES],\n where: { pageType },\n tolerance: this.options?.tolerance,\n exact: this.options?.exact,\n // Each type may need the whole limit when the other one has few matches.\n limit: this.options?.limit ?? 10,\n });\n }\n\n /**\n * The Vite development host updates an edited guide in place (`ɵNG_DOC_CONTENT_UPDATE_EVENT`);\n * when its search records changed too, the next search loads the index again, as a reloaded\n * page would. The listener holds the engine weakly, so an engine nobody uses any more stops\n * listening. Nothing dispatches the event outside the development host, and Angular's\n * production mode skips the listener altogether.\n */\n private refreshOnContentUpdates(): void {\n if ((typeof ngDevMode !== 'undefined' && !ngDevMode) || typeof window === 'undefined') return;\n const engine = new WeakRef(this);\n const listener = (event: Event): void => {\n const current = engine.deref();\n\n if (!current) window.removeEventListener(ɵNG_DOC_CONTENT_UPDATE_EVENT, listener);\n else if ((event as CustomEvent<{ search?: unknown } | null>).detail?.search === true) {\n current.index = undefined;\n }\n };\n\n window.addEventListener(ɵNG_DOC_CONTENT_UPDATE_EVENT, listener);\n }\n\n private loadIndex(): Observable<OramaIndex> {\n return this.request<NgDocPageIndex[]>(`assets/ng-doc/indexes.json`).pipe(\n switchMap((pages) => this.createDatabase(pages)),\n shareReplay(1),\n );\n }\n\n private request<T>(url: string): Observable<T> {\n return defer(() => fetch(url)).pipe(\n switchMap((response: Response) => response.json() as Promise<T>),\n );\n }\n\n private createDatabase(pages: NgDocPageIndex[]): Observable<OramaIndex> {\n return from(\n Promise.all([import('@orama/orama'), import('@orama/plugin-match-highlight')]),\n ).pipe(\n switchMap(([{ create, insertMultiple }, { afterInsert, searchWithHighlight: search }]) =>\n from(\n create({\n schema: { title: 'string', section: 'string', content: 'string', pageType: 'enum' },\n plugins: [{ name: 'highlight', afterInsert }],\n components: { tokenizer: { stemmer: this.options?.stemmer } },\n }),\n ).pipe(\n switchMap((db) =>\n from(insertMultiple(db, pages as any)).pipe(\n map(() => ({ db: db as unknown as OramaDb, api: { searchWithHighlight: search } })),\n ),\n ),\n ),\n ),\n );\n }\n}\n\n/**\n * Shares the limit between the guide and the API hits: guides first, with up to half of the\n * limit (rounded up) or whatever the API hits leave, then the API hits.\n * @param guides - The guide hits, in order of relevance.\n * @param others - The API hits, in order of relevance.\n * @param limit - The total number of results.\n */\nfunction share<T>(guides: T[], others: T[], limit: number): T[] {\n const guideCount = Math.min(guides.length, Math.max(Math.ceil(limit / 2), limit - others.length));\n\n return [...guides.slice(0, guideCount), ...others.slice(0, limit - guideCount)];\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["ɵNG_DOC_CONTENT_UPDATE_EVENT"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ng-doc-app-classes-root-page.mjs","sources":["../../../../libs/app/classes/root-page/root-page.ts","../../../../libs/app/classes/root-page/ng-doc-app-classes-root-page.ts"],"sourcesContent":["import { NgDocDemoAssets } from '@ng-doc/app/interfaces';\nimport type { NgDocContentSource, NgDocPage } from '@ng-doc/core/interfaces';\nimport { NgDocPageType } from '@ng-doc/core/types';\n\n/**\n * Base class for NgDoc page\n */\nexport abstract class NgDocRootPage {\n /**\n * The type of the page\n */\n abstract readonly pageType: NgDocPageType;\n /**\n * Html content of the page\n */\n abstract readonly pageContent: string;\n\n /**\n * Deferred content for generated pages. Legacy pages can continue to provide\n * {@link pageContent} only.\n */\n readonly pageContentSource?: NgDocContentSource;\n\n /**\n * Edit URL that can be used to edit the page source file in the repository\n */\n abstract readonly editSourceFileUrl?: string;\n\n /**\n * View URL that can be used to view the page source file in the repository\n */\n abstract readonly viewSourceFileUrl?: string;\n\n /**\n * The page dependencies file\n */\n readonly page?: NgDocPage;\n\n /**\n * The page demo assets that have code examples of the demo components\n */\n readonly demoAssets?: NgDocDemoAssets;\n\n /**\n * The path of the page's demo pages, relative to the base href, when the Vite engine built them:\n * the demo `X` has its page at `<base href><demoRoute>/X`. Isolated demos show it in an iframe,\n * and the demo toolbar opens it in a new tab.\n */\n readonly demoRoute?: string;\n\n /** Whether the page's demos are isolated unless their `demo` action says otherwise (`isolatedDemos`). */\n readonly isolatedDemos?: boolean;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"AAIA;;AAEG;MACmB,aAAa,CAAA;AA6ClC;;ACpDD;;AAEG;;;;"}
1
+ {"version":3,"file":"ng-doc-app-classes-root-page.mjs","sources":["../../../../libs/app/classes/root-page/root-page.ts","../../../../libs/app/classes/root-page/ng-doc-app-classes-root-page.ts"],"sourcesContent":["import { NgDocDemoAssets } from '@ng-doc/app/interfaces';\nimport type { NgDocContentSource, NgDocPage } from '@ng-doc/core/interfaces';\nimport { NgDocPageType } from '@ng-doc/core/types';\n\n/**\n * Base class for NgDoc page\n */\nexport abstract class NgDocRootPage {\n /**\n * The type of the page\n */\n abstract readonly pageType: NgDocPageType;\n /**\n * Html content of the page\n */\n abstract readonly pageContent: string;\n\n /**\n * Deferred content for generated pages. Legacy pages can continue to provide\n * {@link pageContent} only.\n */\n readonly pageContentSource?: NgDocContentSource;\n\n /**\n * Edit URL that can be used to edit the page source file in the repository\n */\n abstract readonly editSourceFileUrl?: string;\n\n /**\n * View URL that can be used to view the page source file in the repository\n */\n abstract readonly viewSourceFileUrl?: string;\n\n /**\n * The page dependencies file\n */\n readonly page?: NgDocPage;\n\n /**\n * The page demo assets that have code examples of the demo components\n */\n readonly demoAssets?: NgDocDemoAssets;\n\n /**\n * The path of the page's demo pages, relative to the base href, when the Vite engine built them:\n * the demo `X` has its page at `<base href><demoRoute>/X`. Isolated demos show it in an iframe,\n * and the demo toolbar opens it in a new tab.\n */\n readonly demoRoute?: string;\n\n /** Whether the page's demos are isolated unless their `demo` action says otherwise (`isolatedDemos`). */\n readonly isolatedDemos?: boolean;\n\n /**\n * Whether the page's playgrounds are isolated unless their `playground` action or configuration\n * says otherwise (`isolatedPlaygrounds`).\n */\n readonly isolatedPlaygrounds?: boolean;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"AAIA;;AAEG;MACmB,aAAa,CAAA;AAmDlC;;AC1DD;;AAEG;;;;"}
@@ -1,12 +1,13 @@
1
1
  import { httpResource } from '@angular/common/http';
2
2
  import * as i0 from '@angular/core';
3
- import { input, inject, signal, viewChild, computed, untracked, effect, DestroyRef, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { inject, input, signal, viewChild, computed, untracked, effect, DestroyRef, ChangeDetectionStrategy, Component } from '@angular/core';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import { form, FormField } from '@angular/forms/signals';
6
6
  import { ActivatedRoute, Router, RouterLink } from '@angular/router';
7
7
  import { ngDocKindLabel, NgDocKindIconComponent } from '@ng-doc/app/components/kind-icon';
8
8
  import { NgDocApiListIndexService } from '@ng-doc/app/services';
9
9
  import { NgDocShortcutsService } from '@ng-doc/app/services/shortcuts';
10
+ import { NG_DOC_TEXTS } from '@ng-doc/app/tokens';
10
11
  import { asArray } from '@ng-doc/core/helpers/as-array';
11
12
  import { NgDocSelectionComponent, NgDocSelectionHostDirective, NgDocSelectionOriginDirective } from '@ng-doc/ui-kit/components/selection';
12
13
  import { NG_REQUEST_BASE_PATH } from '@ng-doc/ui-kit/tokens';
@@ -24,8 +25,9 @@ const NAME_ORDER = new Intl.Collator('en');
24
25
  */
25
26
  class NgDocApiListComponent {
26
27
  constructor() {
27
- /** The title of the page. */
28
- this.title = input('API References', /* @ts-ignore */
28
+ this.texts = inject(NG_DOC_TEXTS).apiList;
29
+ /** The title of the page. Defaults to the `apiList.title` text. */
30
+ this.title = input(this.texts.title, /* @ts-ignore */
29
31
  ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
30
32
  /** The segment of the API list data, when the site has more than one API list. */
31
33
  this.segment = input(/* @ts-ignore */
@@ -171,7 +173,7 @@ class NgDocApiListComponent {
171
173
  this.scope.set('');
172
174
  }
173
175
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocApiListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
174
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.1", type: NgDocApiListComponent, isStandalone: true, selector: "ng-doc-api-list", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, segment: { classPropertyName: "segment", publicName: "segment", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<h1 class=\"ng-doc-api-list-title\">{{ title() }}</h1>\n@if (loaded()) {\n <p class=\"ng-doc-api-list-lead\">\n {{ declarations().length }} declarations in {{ scopes().length }}\n {{ scopes().length === 1 ? 'scope' : 'scopes' }}.\n </p>\n}\n\n<div class=\"ng-doc-api-list-tools\">\n <label class=\"ng-doc-api-list-filter\">\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\">\n <path d=\"M3 5h18l-7 8.5V19l-4 2v-7.5z\" />\n </svg>\n <input\n #filterInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"hasDescriptions() ? 'Filter by name or description' : 'Filter by name'\"\n [attr.aria-label]=\"\n hasDescriptions()\n ? 'Filter declarations by name or description'\n : 'Filter declarations by name'\n \"\n [attr.aria-keyshortcuts]=\"shortcuts.enabled() ? 'F' : null\"\n [formField]=\"filterForm.filter\" />\n @if (shortcuts.enabled()) {\n <kbd class=\"ng-doc-api-list-kbd\">F</kbd>\n }\n </label>\n <div class=\"ng-doc-api-list-group-by\">\n <span id=\"ng-doc-api-list-group-by\">Group by</span>\n <div\n class=\"ng-doc-api-list-segments\"\n role=\"group\"\n aria-labelledby=\"ng-doc-api-list-group-by\"\n ngDocSelectionHost>\n <ng-doc-selection [align]=\"null\" />\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'kind'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'kind'\"\n (click)=\"selectGroupBy('kind')\">\n Kind\n </button>\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'scope'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'scope'\"\n (click)=\"selectGroupBy('scope')\">\n Scope\n </button>\n </div>\n </div>\n</div>\n\n@if (kinds().length) {\n <div class=\"ng-doc-api-list-kinds\" role=\"group\" aria-label=\"Filter by kind\">\n <button type=\"button\" [attr.aria-pressed]=\"!kind()\" (click)=\"selectKind('')\">\n All <span class=\"ng-doc-api-list-count\">{{ inScope().length }}</span>\n </button>\n @for (item of kinds(); track item.kind) {\n <button\n type=\"button\"\n [attr.data-ng-doc-kind]=\"item.kind\"\n [attr.aria-pressed]=\"kind() === item.kind\"\n (click)=\"selectKind(item.kind)\">\n <span class=\"ng-doc-api-list-dot\" [attr.data-ng-doc-kind]=\"item.kind\"></span>\n {{ item.label }}\n <span class=\"ng-doc-api-list-count\">{{ item.count }}</span>\n </button>\n }\n </div>\n}\n\n@if (scope()) {\n <p class=\"ng-doc-api-list-scope-note\">\n Showing {{ scope() }} only.\n <button type=\"button\" (click)=\"clearScope()\">Show every scope</button>\n </p>\n}\n\n@for (group of groups(); track group.id) {\n <section class=\"ng-doc-api-list-group\" [id]=\"group.id\">\n <h2 class=\"ng-doc-api-list-group-title\">\n @if (group.kind) {\n <ng-doc-kind-icon [kind]=\"group.kind\" size=\"medium\"></ng-doc-kind-icon>\n } @else {\n {{ group.label }}\n }\n <span class=\"ng-doc-api-list-count\">{{ group.items.length }}</span>\n </h2>\n <ul class=\"ng-doc-api-list-index\" [class.ng-doc-api-list-described]=\"hasDescriptions()\">\n @for (item of group.items; track item.route) {\n <li>\n <a [routerLink]=\"item.route\">\n <span class=\"ng-doc-api-list-name\">{{ item.name }}</span>\n @if (hasDescriptions()) {\n @if (item.description) {\n <span class=\"ng-doc-api-list-description\" [title]=\"item.description\">{{\n item.description\n }}</span>\n } @else {\n <span class=\"ng-doc-api-list-description ng-doc-api-list-none\">No description</span>\n }\n }\n @if (group.kind) {\n <span class=\"ng-doc-api-list-scope\">{{ item.scope }}</span>\n } @else {\n <ng-doc-kind-icon class=\"ng-doc-api-list-scope\" [kind]=\"item.type\"></ng-doc-kind-icon>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n} @empty {\n @if (loaded()) {\n <p class=\"ng-doc-api-list-empty\">No declarations match.</p>\n } @else if (failed()) {\n <p class=\"ng-doc-api-list-empty\">The API list could not be loaded.</p>\n }\n}\n", styles: [":host{display:block;max-width:var(--ng-doc-api-content-max-width);font-family:var(--ng-doc-font-family);color:var(--ng-doc-text)}.ng-doc-api-list-title{margin-top:0}.ng-doc-api-list-lead{margin:var(--ng-doc-space-2) 0 0;font-size:var(--ng-doc-font-size);color:var(--ng-doc-text-muted)}.ng-doc-api-list-tools{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-3);margin:var(--ng-doc-space-6) 0 var(--ng-doc-space-3)}.ng-doc-api-list-filter{display:flex;flex:1 1 280px;align-items:center;gap:var(--ng-doc-space-2);max-width:420px;height:36px;padding:0 var(--ng-doc-space-2) 0 var(--ng-doc-space-3);border:var(--ng-doc-input-border);border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-input-background-color, var(--ng-doc-background));color:var(--ng-doc-text-muted);cursor:text}.ng-doc-api-list-filter:hover{border:var(--ng-doc-input-border-hover)}.ng-doc-api-list-filter:focus-within{box-shadow:var(--ng-doc-focus-ring)}.ng-doc-api-list-filter svg{flex:none}.ng-doc-api-list-filter input{flex:1;min-width:0;height:100%;padding:0;border:0;outline:0;background:none;font:400 14px/20px var(--ng-doc-font-family);color:var(--ng-doc-heading-color)}.ng-doc-api-list-filter input::placeholder{color:var(--ng-doc-text-muted);opacity:1}.ng-doc-api-list-kbd{display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 5px;border:1px solid var(--ng-doc-kbd-border-color);border-radius:var(--ng-doc-radius-xs);background:var(--ng-doc-kbd-background);font:500 12px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted)}.ng-doc-api-list-group-by{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin-left:auto;font-size:13px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-segments{position:relative;display:inline-flex;gap:2px;padding:3px;border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-base-2)}.ng-doc-api-list-segments ng-doc-selection,.ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{border-radius:var(--ng-doc-radius-sm);background:var(--ng-doc-background);box-shadow:var(--ng-doc-shadow-xs)}.ng-doc-api-list-segments button{position:relative;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-sm);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted);cursor:pointer}.ng-doc-api-list-segments button:hover,.ng-doc-api-list-segments button[aria-pressed=true]{color:var(--ng-doc-heading-color)}:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}@media(prefers-color-scheme:dark){:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}}.ng-doc-api-list-kinds{display:flex;flex-wrap:wrap;gap:2px var(--ng-doc-space-1);margin:0 0 var(--ng-doc-space-2);padding-bottom:var(--ng-doc-space-3);border-bottom:1px solid var(--ng-doc-border-color)}.ng-doc-api-list-kinds button{display:inline-flex;flex:none;align-items:center;gap:7px;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-md);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text);white-space:nowrap;cursor:pointer}.ng-doc-api-list-kinds button:hover{background:var(--ng-doc-hover-background);color:var(--ng-doc-heading-color)}.ng-doc-api-list-kinds button[aria-pressed=true]{background:var(--ng-doc-primary-soft);color:var(--ng-doc-primary-strong);font-weight:600}.ng-doc-api-list-kinds button[aria-pressed=true] .ng-doc-api-list-count{color:var(--ng-doc-primary-strong)}.ng-doc-api-list-count{font-size:12px;font-weight:400;color:var(--ng-doc-text-muted);font-variant-numeric:tabular-nums}.ng-doc-api-list-dot{--_hue: var(--ng-doc-hue-neutral);display:inline-block;flex:none;width:8px;height:8px;border-radius:50%;background:var(--_hue)}.ng-doc-api-list-dot[data-ng-doc-kind=Class]{--_hue: var(--ng-doc-class-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Interface]{--_hue: var(--ng-doc-interface-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Enum]{--_hue: var(--ng-doc-enum-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Variable]{--_hue: var(--ng-doc-variable-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Function]{--_hue: var(--ng-doc-function-background)}.ng-doc-api-list-dot[data-ng-doc-kind=TypeAlias]{--_hue: var(--ng-doc-type-alias-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Component]{--_hue: var(--ng-doc-component-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Directive]{--_hue: var(--ng-doc-directive-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Injectable]{--_hue: var(--ng-doc-injectable-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Pipe]{--_hue: var(--ng-doc-pipe-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=NgModule]{--_hue: var(--ng-doc-ng-module-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=ng-doc-tag-selector]{--_hue: var(--ng-doc-selector-background)}.ng-doc-api-list-scope-note{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-2);margin:var(--ng-doc-space-3) 0 0;font-size:14px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope-note button{padding:0;border:0;background:none;font:inherit;color:var(--ng-doc-link-color);cursor:pointer}.ng-doc-api-list-group{margin-top:var(--ng-doc-space-8);scroll-margin-top:calc(var(--ng-doc-navbar-height) + 16px)}.ng-doc-api-list-group-title{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin:0 0 var(--ng-doc-space-2);padding:0;border:0;font-family:var(--ng-doc-heading-font-family);font-size:17px;line-height:26px;font-weight:600;color:var(--ng-doc-heading-color)}.ng-doc-api-list-group-title .ng-doc-api-list-count{font-family:var(--ng-doc-font-family);font-size:13px}.ng-doc-api-list-index{margin:0;padding:0;list-style:none;border:1px solid var(--ng-doc-border-color);border-radius:var(--ng-doc-radius-lg);overflow:hidden}.ng-doc-api-list-index li{margin:0;padding:0}.ng-doc-api-list-index li+li{border-top:1px solid var(--ng-doc-base-2)}.ng-doc-api-list-index a{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--ng-doc-space-4);min-height:44px;padding:8px var(--ng-doc-space-4);font-size:14px;line-height:20px;color:var(--ng-doc-text);text-decoration:none}.ng-doc-api-list-index a:hover{background:var(--ng-doc-scope-item-link-background, var(--ng-doc-row-hover-background))}.ng-doc-api-list-index a:hover .ng-doc-api-list-name{color:var(--ng-doc-link-color)}.ng-doc-api-list-index a:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--ng-doc-primary)}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,17rem) minmax(0,1fr) auto}.ng-doc-api-list-name{min-width:0;overflow-wrap:anywhere;font:500 13px/20px var(--ng-doc-code-font);color:var(--ng-doc-heading-color)}.ng-doc-api-list-description{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ng-doc-api-list-none{color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope{justify-self:end;font-size:12px;color:var(--ng-doc-text-muted);white-space:nowrap}.ng-doc-api-list-empty{padding:var(--ng-doc-space-5) var(--ng-doc-space-4);text-align:center;font-size:14px;color:var(--ng-doc-text-muted)}@media(max-width:900px){.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,16rem) minmax(0,1fr)}.ng-doc-api-list-index.ng-doc-api-list-described a .ng-doc-api-list-scope{display:none}}@media(max-width:640px){.ng-doc-api-list-filter{flex-basis:100%;max-width:none}.ng-doc-api-list-group-by{margin-left:0}.ng-doc-api-list-kinds{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,1fr);gap:2px;padding:10px var(--ng-doc-space-3)}}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "component", type: NgDocKindIconComponent, selector: "ng-doc-kind-icon", inputs: ["kind", "type", "size"] }, { kind: "component", type: NgDocSelectionComponent, selector: "ng-doc-selection", inputs: ["align"] }, { kind: "directive", type: NgDocSelectionHostDirective, selector: "[ngDocSelectionHost]" }, { kind: "directive", type: NgDocSelectionOriginDirective, selector: "[ngDocSelectionOrigin]", inputs: ["ngDocSelectionOrigin"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
176
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.1", type: NgDocApiListComponent, isStandalone: true, selector: "ng-doc-api-list", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, segment: { classPropertyName: "segment", publicName: "segment", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<h1 class=\"ng-doc-api-list-title\">{{ title() }}</h1>\n@if (loaded()) {\n <p class=\"ng-doc-api-list-lead\">\n {{ texts.summary({ declarations: declarations().length, scopes: scopes().length }) }}\n </p>\n}\n\n<div class=\"ng-doc-api-list-tools\">\n <label class=\"ng-doc-api-list-filter\">\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\">\n <path d=\"M3 5h18l-7 8.5V19l-4 2v-7.5z\" />\n </svg>\n <input\n #filterInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"\n hasDescriptions() ? texts.filterPlaceholderWithDescriptions : texts.filterPlaceholder\n \"\n [attr.aria-label]=\"hasDescriptions() ? texts.filterLabelWithDescriptions : texts.filterLabel\"\n [attr.aria-keyshortcuts]=\"shortcuts.enabled() ? 'F' : null\"\n [formField]=\"filterForm.filter\" />\n @if (shortcuts.enabled()) {\n <kbd class=\"ng-doc-api-list-kbd\">F</kbd>\n }\n </label>\n <div class=\"ng-doc-api-list-group-by\">\n <span id=\"ng-doc-api-list-group-by\">{{ texts.groupBy }}</span>\n <div\n class=\"ng-doc-api-list-segments\"\n role=\"group\"\n aria-labelledby=\"ng-doc-api-list-group-by\"\n ngDocSelectionHost>\n <ng-doc-selection [align]=\"null\" />\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'kind'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'kind'\"\n (click)=\"selectGroupBy('kind')\">\n {{ texts.groupByKind }}\n </button>\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'scope'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'scope'\"\n (click)=\"selectGroupBy('scope')\">\n {{ texts.groupByScope }}\n </button>\n </div>\n </div>\n</div>\n\n@if (kinds().length) {\n <div class=\"ng-doc-api-list-kinds\" role=\"group\" [attr.aria-label]=\"texts.kindsLabel\">\n <button type=\"button\" [attr.aria-pressed]=\"!kind()\" (click)=\"selectKind('')\">\n {{ texts.allKinds }} <span class=\"ng-doc-api-list-count\">{{ inScope().length }}</span>\n </button>\n @for (item of kinds(); track item.kind) {\n <button\n type=\"button\"\n [attr.data-ng-doc-kind]=\"item.kind\"\n [attr.aria-pressed]=\"kind() === item.kind\"\n (click)=\"selectKind(item.kind)\">\n <span class=\"ng-doc-api-list-dot\" [attr.data-ng-doc-kind]=\"item.kind\"></span>\n {{ item.label }}\n <span class=\"ng-doc-api-list-count\">{{ item.count }}</span>\n </button>\n }\n </div>\n}\n\n@if (scope()) {\n <p class=\"ng-doc-api-list-scope-note\">\n {{ texts.scopeNote({ scope: scope() }) }}\n <button type=\"button\" (click)=\"clearScope()\">{{ texts.showEveryScope }}</button>\n </p>\n}\n\n@for (group of groups(); track group.id) {\n <section class=\"ng-doc-api-list-group\" [id]=\"group.id\">\n <h2 class=\"ng-doc-api-list-group-title\">\n @if (group.kind) {\n <ng-doc-kind-icon [kind]=\"group.kind\" size=\"medium\"></ng-doc-kind-icon>\n } @else {\n {{ group.label }}\n }\n <span class=\"ng-doc-api-list-count\">{{ group.items.length }}</span>\n </h2>\n <ul class=\"ng-doc-api-list-index\" [class.ng-doc-api-list-described]=\"hasDescriptions()\">\n @for (item of group.items; track item.route) {\n <li>\n <a [routerLink]=\"item.route\">\n <span class=\"ng-doc-api-list-name\">{{ item.name }}</span>\n @if (hasDescriptions()) {\n @if (item.description) {\n <span class=\"ng-doc-api-list-description\" [title]=\"item.description\">{{\n item.description\n }}</span>\n } @else {\n <span class=\"ng-doc-api-list-description ng-doc-api-list-none\">{{\n texts.noDescription\n }}</span>\n }\n }\n @if (group.kind) {\n <span class=\"ng-doc-api-list-scope\">{{ item.scope }}</span>\n } @else {\n <ng-doc-kind-icon class=\"ng-doc-api-list-scope\" [kind]=\"item.type\"></ng-doc-kind-icon>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n} @empty {\n @if (loaded()) {\n <p class=\"ng-doc-api-list-empty\">{{ texts.empty }}</p>\n } @else if (failed()) {\n <p class=\"ng-doc-api-list-empty\">{{ texts.failed }}</p>\n }\n}\n", styles: [":host{display:block;max-width:var(--ng-doc-api-content-max-width);font-family:var(--ng-doc-font-family);color:var(--ng-doc-text)}.ng-doc-api-list-title{margin-top:0}.ng-doc-api-list-lead{margin:var(--ng-doc-space-2) 0 0;font-size:var(--ng-doc-font-size);color:var(--ng-doc-text-muted)}.ng-doc-api-list-tools{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-3);margin:var(--ng-doc-space-6) 0 var(--ng-doc-space-3)}.ng-doc-api-list-filter{display:flex;flex:1 1 280px;align-items:center;gap:var(--ng-doc-space-2);max-width:420px;height:36px;padding:0 var(--ng-doc-space-2) 0 var(--ng-doc-space-3);border:var(--ng-doc-input-border);border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-input-background-color, var(--ng-doc-background));color:var(--ng-doc-text-muted);cursor:text}.ng-doc-api-list-filter:hover{border:var(--ng-doc-input-border-hover)}.ng-doc-api-list-filter:focus-within{box-shadow:var(--ng-doc-focus-ring)}.ng-doc-api-list-filter svg{flex:none}.ng-doc-api-list-filter input{flex:1;min-width:0;height:100%;padding:0;border:0;outline:0;background:none;font:400 14px/20px var(--ng-doc-font-family);color:var(--ng-doc-heading-color)}.ng-doc-api-list-filter input::placeholder{color:var(--ng-doc-text-muted);opacity:1}.ng-doc-api-list-kbd{display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 5px;border:1px solid var(--ng-doc-kbd-border-color);border-radius:var(--ng-doc-radius-xs);background:var(--ng-doc-kbd-background);font:500 12px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted)}.ng-doc-api-list-group-by{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin-left:auto;font-size:13px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-segments{position:relative;display:inline-flex;gap:2px;padding:3px;border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-base-2)}.ng-doc-api-list-segments ng-doc-selection,.ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{border-radius:var(--ng-doc-radius-sm);background:var(--ng-doc-background);box-shadow:var(--ng-doc-shadow-xs)}.ng-doc-api-list-segments button{position:relative;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-sm);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted);cursor:pointer}.ng-doc-api-list-segments button:hover,.ng-doc-api-list-segments button[aria-pressed=true]{color:var(--ng-doc-heading-color)}:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}@media(prefers-color-scheme:dark){:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}}.ng-doc-api-list-kinds{display:flex;flex-wrap:wrap;gap:2px var(--ng-doc-space-1);margin:0 0 var(--ng-doc-space-2);padding-bottom:var(--ng-doc-space-3);border-bottom:1px solid var(--ng-doc-border-color)}.ng-doc-api-list-kinds button{display:inline-flex;flex:none;align-items:center;gap:7px;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-md);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text);white-space:nowrap;cursor:pointer}.ng-doc-api-list-kinds button:hover{background:var(--ng-doc-hover-background);color:var(--ng-doc-heading-color)}.ng-doc-api-list-kinds button[aria-pressed=true]{background:var(--ng-doc-primary-soft);color:var(--ng-doc-primary-strong);font-weight:600}.ng-doc-api-list-kinds button[aria-pressed=true] .ng-doc-api-list-count{color:var(--ng-doc-primary-strong)}.ng-doc-api-list-count{font-size:12px;font-weight:400;color:var(--ng-doc-text-muted);font-variant-numeric:tabular-nums}.ng-doc-api-list-dot{--_hue: var(--ng-doc-hue-neutral);display:inline-block;flex:none;width:8px;height:8px;border-radius:50%;background:var(--_hue)}.ng-doc-api-list-dot[data-ng-doc-kind=Class]{--_hue: var(--ng-doc-class-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Interface]{--_hue: var(--ng-doc-interface-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Enum]{--_hue: var(--ng-doc-enum-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Variable]{--_hue: var(--ng-doc-variable-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Function]{--_hue: var(--ng-doc-function-background)}.ng-doc-api-list-dot[data-ng-doc-kind=TypeAlias]{--_hue: var(--ng-doc-type-alias-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Component]{--_hue: var(--ng-doc-component-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Directive]{--_hue: var(--ng-doc-directive-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Injectable]{--_hue: var(--ng-doc-injectable-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Pipe]{--_hue: var(--ng-doc-pipe-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=NgModule]{--_hue: var(--ng-doc-ng-module-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=ng-doc-tag-selector]{--_hue: var(--ng-doc-selector-background)}.ng-doc-api-list-scope-note{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-2);margin:var(--ng-doc-space-3) 0 0;font-size:14px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope-note button{padding:0;border:0;background:none;font:inherit;color:var(--ng-doc-link-color);cursor:pointer}.ng-doc-api-list-group{margin-top:var(--ng-doc-space-8);scroll-margin-top:calc(var(--ng-doc-navbar-height) + var(--ng-doc-layout-top) + 16px)}.ng-doc-api-list-group-title{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin:0 0 var(--ng-doc-space-2);padding:0;border:0;font-family:var(--ng-doc-heading-font-family);font-size:17px;line-height:26px;font-weight:600;color:var(--ng-doc-heading-color)}.ng-doc-api-list-group-title .ng-doc-api-list-count{font-family:var(--ng-doc-font-family);font-size:13px}.ng-doc-api-list-index{margin:0;padding:0;list-style:none;border:1px solid var(--ng-doc-border-color);border-radius:var(--ng-doc-radius-lg);overflow:hidden}.ng-doc-api-list-index li{margin:0;padding:0}.ng-doc-api-list-index li+li{border-top:1px solid var(--ng-doc-base-2)}.ng-doc-api-list-index a{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--ng-doc-space-4);min-height:44px;padding:8px var(--ng-doc-space-4);font-size:14px;line-height:20px;color:var(--ng-doc-text);text-decoration:none}.ng-doc-api-list-index a:hover{background:var(--ng-doc-scope-item-link-background, var(--ng-doc-row-hover-background))}.ng-doc-api-list-index a:hover .ng-doc-api-list-name{color:var(--ng-doc-link-color)}.ng-doc-api-list-index a:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--ng-doc-primary)}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,17rem) minmax(0,1fr) auto}.ng-doc-api-list-name{min-width:0;overflow-wrap:anywhere;font:500 13px/20px var(--ng-doc-code-font);color:var(--ng-doc-heading-color)}.ng-doc-api-list-description{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ng-doc-api-list-none{color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope{justify-self:end;font-size:12px;color:var(--ng-doc-text-muted);white-space:nowrap}.ng-doc-api-list-empty{padding:var(--ng-doc-space-5) var(--ng-doc-space-4);text-align:center;font-size:14px;color:var(--ng-doc-text-muted)}@media(max-width:900px){.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,16rem) minmax(0,1fr)}.ng-doc-api-list-index.ng-doc-api-list-described a .ng-doc-api-list-scope{display:none}}@media(max-width:640px){.ng-doc-api-list-filter{flex-basis:100%;max-width:none}.ng-doc-api-list-group-by{margin-left:0}.ng-doc-api-list-kinds{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,1fr);gap:2px;padding:10px var(--ng-doc-space-3)}}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "component", type: NgDocKindIconComponent, selector: "ng-doc-kind-icon", inputs: ["kind", "type", "size"] }, { kind: "component", type: NgDocSelectionComponent, selector: "ng-doc-selection", inputs: ["align"] }, { kind: "directive", type: NgDocSelectionHostDirective, selector: "[ngDocSelectionHost]" }, { kind: "directive", type: NgDocSelectionOriginDirective, selector: "[ngDocSelectionOrigin]", inputs: ["ngDocSelectionOrigin"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
175
177
  }
176
178
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocApiListComponent, decorators: [{
177
179
  type: Component,
@@ -182,7 +184,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImpor
182
184
  NgDocSelectionHostDirective,
183
185
  NgDocSelectionOriginDirective,
184
186
  RouterLink,
185
- ], template: "<h1 class=\"ng-doc-api-list-title\">{{ title() }}</h1>\n@if (loaded()) {\n <p class=\"ng-doc-api-list-lead\">\n {{ declarations().length }} declarations in {{ scopes().length }}\n {{ scopes().length === 1 ? 'scope' : 'scopes' }}.\n </p>\n}\n\n<div class=\"ng-doc-api-list-tools\">\n <label class=\"ng-doc-api-list-filter\">\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\">\n <path d=\"M3 5h18l-7 8.5V19l-4 2v-7.5z\" />\n </svg>\n <input\n #filterInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"hasDescriptions() ? 'Filter by name or description' : 'Filter by name'\"\n [attr.aria-label]=\"\n hasDescriptions()\n ? 'Filter declarations by name or description'\n : 'Filter declarations by name'\n \"\n [attr.aria-keyshortcuts]=\"shortcuts.enabled() ? 'F' : null\"\n [formField]=\"filterForm.filter\" />\n @if (shortcuts.enabled()) {\n <kbd class=\"ng-doc-api-list-kbd\">F</kbd>\n }\n </label>\n <div class=\"ng-doc-api-list-group-by\">\n <span id=\"ng-doc-api-list-group-by\">Group by</span>\n <div\n class=\"ng-doc-api-list-segments\"\n role=\"group\"\n aria-labelledby=\"ng-doc-api-list-group-by\"\n ngDocSelectionHost>\n <ng-doc-selection [align]=\"null\" />\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'kind'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'kind'\"\n (click)=\"selectGroupBy('kind')\">\n Kind\n </button>\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'scope'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'scope'\"\n (click)=\"selectGroupBy('scope')\">\n Scope\n </button>\n </div>\n </div>\n</div>\n\n@if (kinds().length) {\n <div class=\"ng-doc-api-list-kinds\" role=\"group\" aria-label=\"Filter by kind\">\n <button type=\"button\" [attr.aria-pressed]=\"!kind()\" (click)=\"selectKind('')\">\n All <span class=\"ng-doc-api-list-count\">{{ inScope().length }}</span>\n </button>\n @for (item of kinds(); track item.kind) {\n <button\n type=\"button\"\n [attr.data-ng-doc-kind]=\"item.kind\"\n [attr.aria-pressed]=\"kind() === item.kind\"\n (click)=\"selectKind(item.kind)\">\n <span class=\"ng-doc-api-list-dot\" [attr.data-ng-doc-kind]=\"item.kind\"></span>\n {{ item.label }}\n <span class=\"ng-doc-api-list-count\">{{ item.count }}</span>\n </button>\n }\n </div>\n}\n\n@if (scope()) {\n <p class=\"ng-doc-api-list-scope-note\">\n Showing {{ scope() }} only.\n <button type=\"button\" (click)=\"clearScope()\">Show every scope</button>\n </p>\n}\n\n@for (group of groups(); track group.id) {\n <section class=\"ng-doc-api-list-group\" [id]=\"group.id\">\n <h2 class=\"ng-doc-api-list-group-title\">\n @if (group.kind) {\n <ng-doc-kind-icon [kind]=\"group.kind\" size=\"medium\"></ng-doc-kind-icon>\n } @else {\n {{ group.label }}\n }\n <span class=\"ng-doc-api-list-count\">{{ group.items.length }}</span>\n </h2>\n <ul class=\"ng-doc-api-list-index\" [class.ng-doc-api-list-described]=\"hasDescriptions()\">\n @for (item of group.items; track item.route) {\n <li>\n <a [routerLink]=\"item.route\">\n <span class=\"ng-doc-api-list-name\">{{ item.name }}</span>\n @if (hasDescriptions()) {\n @if (item.description) {\n <span class=\"ng-doc-api-list-description\" [title]=\"item.description\">{{\n item.description\n }}</span>\n } @else {\n <span class=\"ng-doc-api-list-description ng-doc-api-list-none\">No description</span>\n }\n }\n @if (group.kind) {\n <span class=\"ng-doc-api-list-scope\">{{ item.scope }}</span>\n } @else {\n <ng-doc-kind-icon class=\"ng-doc-api-list-scope\" [kind]=\"item.type\"></ng-doc-kind-icon>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n} @empty {\n @if (loaded()) {\n <p class=\"ng-doc-api-list-empty\">No declarations match.</p>\n } @else if (failed()) {\n <p class=\"ng-doc-api-list-empty\">The API list could not be loaded.</p>\n }\n}\n", styles: [":host{display:block;max-width:var(--ng-doc-api-content-max-width);font-family:var(--ng-doc-font-family);color:var(--ng-doc-text)}.ng-doc-api-list-title{margin-top:0}.ng-doc-api-list-lead{margin:var(--ng-doc-space-2) 0 0;font-size:var(--ng-doc-font-size);color:var(--ng-doc-text-muted)}.ng-doc-api-list-tools{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-3);margin:var(--ng-doc-space-6) 0 var(--ng-doc-space-3)}.ng-doc-api-list-filter{display:flex;flex:1 1 280px;align-items:center;gap:var(--ng-doc-space-2);max-width:420px;height:36px;padding:0 var(--ng-doc-space-2) 0 var(--ng-doc-space-3);border:var(--ng-doc-input-border);border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-input-background-color, var(--ng-doc-background));color:var(--ng-doc-text-muted);cursor:text}.ng-doc-api-list-filter:hover{border:var(--ng-doc-input-border-hover)}.ng-doc-api-list-filter:focus-within{box-shadow:var(--ng-doc-focus-ring)}.ng-doc-api-list-filter svg{flex:none}.ng-doc-api-list-filter input{flex:1;min-width:0;height:100%;padding:0;border:0;outline:0;background:none;font:400 14px/20px var(--ng-doc-font-family);color:var(--ng-doc-heading-color)}.ng-doc-api-list-filter input::placeholder{color:var(--ng-doc-text-muted);opacity:1}.ng-doc-api-list-kbd{display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 5px;border:1px solid var(--ng-doc-kbd-border-color);border-radius:var(--ng-doc-radius-xs);background:var(--ng-doc-kbd-background);font:500 12px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted)}.ng-doc-api-list-group-by{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin-left:auto;font-size:13px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-segments{position:relative;display:inline-flex;gap:2px;padding:3px;border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-base-2)}.ng-doc-api-list-segments ng-doc-selection,.ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{border-radius:var(--ng-doc-radius-sm);background:var(--ng-doc-background);box-shadow:var(--ng-doc-shadow-xs)}.ng-doc-api-list-segments button{position:relative;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-sm);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted);cursor:pointer}.ng-doc-api-list-segments button:hover,.ng-doc-api-list-segments button[aria-pressed=true]{color:var(--ng-doc-heading-color)}:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}@media(prefers-color-scheme:dark){:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}}.ng-doc-api-list-kinds{display:flex;flex-wrap:wrap;gap:2px var(--ng-doc-space-1);margin:0 0 var(--ng-doc-space-2);padding-bottom:var(--ng-doc-space-3);border-bottom:1px solid var(--ng-doc-border-color)}.ng-doc-api-list-kinds button{display:inline-flex;flex:none;align-items:center;gap:7px;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-md);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text);white-space:nowrap;cursor:pointer}.ng-doc-api-list-kinds button:hover{background:var(--ng-doc-hover-background);color:var(--ng-doc-heading-color)}.ng-doc-api-list-kinds button[aria-pressed=true]{background:var(--ng-doc-primary-soft);color:var(--ng-doc-primary-strong);font-weight:600}.ng-doc-api-list-kinds button[aria-pressed=true] .ng-doc-api-list-count{color:var(--ng-doc-primary-strong)}.ng-doc-api-list-count{font-size:12px;font-weight:400;color:var(--ng-doc-text-muted);font-variant-numeric:tabular-nums}.ng-doc-api-list-dot{--_hue: var(--ng-doc-hue-neutral);display:inline-block;flex:none;width:8px;height:8px;border-radius:50%;background:var(--_hue)}.ng-doc-api-list-dot[data-ng-doc-kind=Class]{--_hue: var(--ng-doc-class-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Interface]{--_hue: var(--ng-doc-interface-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Enum]{--_hue: var(--ng-doc-enum-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Variable]{--_hue: var(--ng-doc-variable-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Function]{--_hue: var(--ng-doc-function-background)}.ng-doc-api-list-dot[data-ng-doc-kind=TypeAlias]{--_hue: var(--ng-doc-type-alias-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Component]{--_hue: var(--ng-doc-component-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Directive]{--_hue: var(--ng-doc-directive-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Injectable]{--_hue: var(--ng-doc-injectable-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Pipe]{--_hue: var(--ng-doc-pipe-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=NgModule]{--_hue: var(--ng-doc-ng-module-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=ng-doc-tag-selector]{--_hue: var(--ng-doc-selector-background)}.ng-doc-api-list-scope-note{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-2);margin:var(--ng-doc-space-3) 0 0;font-size:14px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope-note button{padding:0;border:0;background:none;font:inherit;color:var(--ng-doc-link-color);cursor:pointer}.ng-doc-api-list-group{margin-top:var(--ng-doc-space-8);scroll-margin-top:calc(var(--ng-doc-navbar-height) + 16px)}.ng-doc-api-list-group-title{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin:0 0 var(--ng-doc-space-2);padding:0;border:0;font-family:var(--ng-doc-heading-font-family);font-size:17px;line-height:26px;font-weight:600;color:var(--ng-doc-heading-color)}.ng-doc-api-list-group-title .ng-doc-api-list-count{font-family:var(--ng-doc-font-family);font-size:13px}.ng-doc-api-list-index{margin:0;padding:0;list-style:none;border:1px solid var(--ng-doc-border-color);border-radius:var(--ng-doc-radius-lg);overflow:hidden}.ng-doc-api-list-index li{margin:0;padding:0}.ng-doc-api-list-index li+li{border-top:1px solid var(--ng-doc-base-2)}.ng-doc-api-list-index a{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--ng-doc-space-4);min-height:44px;padding:8px var(--ng-doc-space-4);font-size:14px;line-height:20px;color:var(--ng-doc-text);text-decoration:none}.ng-doc-api-list-index a:hover{background:var(--ng-doc-scope-item-link-background, var(--ng-doc-row-hover-background))}.ng-doc-api-list-index a:hover .ng-doc-api-list-name{color:var(--ng-doc-link-color)}.ng-doc-api-list-index a:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--ng-doc-primary)}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,17rem) minmax(0,1fr) auto}.ng-doc-api-list-name{min-width:0;overflow-wrap:anywhere;font:500 13px/20px var(--ng-doc-code-font);color:var(--ng-doc-heading-color)}.ng-doc-api-list-description{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ng-doc-api-list-none{color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope{justify-self:end;font-size:12px;color:var(--ng-doc-text-muted);white-space:nowrap}.ng-doc-api-list-empty{padding:var(--ng-doc-space-5) var(--ng-doc-space-4);text-align:center;font-size:14px;color:var(--ng-doc-text-muted)}@media(max-width:900px){.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,16rem) minmax(0,1fr)}.ng-doc-api-list-index.ng-doc-api-list-described a .ng-doc-api-list-scope{display:none}}@media(max-width:640px){.ng-doc-api-list-filter{flex-basis:100%;max-width:none}.ng-doc-api-list-group-by{margin-left:0}.ng-doc-api-list-kinds{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,1fr);gap:2px;padding:10px var(--ng-doc-space-3)}}\n"] }]
187
+ ], template: "<h1 class=\"ng-doc-api-list-title\">{{ title() }}</h1>\n@if (loaded()) {\n <p class=\"ng-doc-api-list-lead\">\n {{ texts.summary({ declarations: declarations().length, scopes: scopes().length }) }}\n </p>\n}\n\n<div class=\"ng-doc-api-list-tools\">\n <label class=\"ng-doc-api-list-filter\">\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\">\n <path d=\"M3 5h18l-7 8.5V19l-4 2v-7.5z\" />\n </svg>\n <input\n #filterInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"\n hasDescriptions() ? texts.filterPlaceholderWithDescriptions : texts.filterPlaceholder\n \"\n [attr.aria-label]=\"hasDescriptions() ? texts.filterLabelWithDescriptions : texts.filterLabel\"\n [attr.aria-keyshortcuts]=\"shortcuts.enabled() ? 'F' : null\"\n [formField]=\"filterForm.filter\" />\n @if (shortcuts.enabled()) {\n <kbd class=\"ng-doc-api-list-kbd\">F</kbd>\n }\n </label>\n <div class=\"ng-doc-api-list-group-by\">\n <span id=\"ng-doc-api-list-group-by\">{{ texts.groupBy }}</span>\n <div\n class=\"ng-doc-api-list-segments\"\n role=\"group\"\n aria-labelledby=\"ng-doc-api-list-group-by\"\n ngDocSelectionHost>\n <ng-doc-selection [align]=\"null\" />\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'kind'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'kind'\"\n (click)=\"selectGroupBy('kind')\">\n {{ texts.groupByKind }}\n </button>\n <button\n type=\"button\"\n [attr.aria-pressed]=\"groupBy() === 'scope'\"\n [ngDocSelectionOrigin]=\"groupBy() === 'scope'\"\n (click)=\"selectGroupBy('scope')\">\n {{ texts.groupByScope }}\n </button>\n </div>\n </div>\n</div>\n\n@if (kinds().length) {\n <div class=\"ng-doc-api-list-kinds\" role=\"group\" [attr.aria-label]=\"texts.kindsLabel\">\n <button type=\"button\" [attr.aria-pressed]=\"!kind()\" (click)=\"selectKind('')\">\n {{ texts.allKinds }} <span class=\"ng-doc-api-list-count\">{{ inScope().length }}</span>\n </button>\n @for (item of kinds(); track item.kind) {\n <button\n type=\"button\"\n [attr.data-ng-doc-kind]=\"item.kind\"\n [attr.aria-pressed]=\"kind() === item.kind\"\n (click)=\"selectKind(item.kind)\">\n <span class=\"ng-doc-api-list-dot\" [attr.data-ng-doc-kind]=\"item.kind\"></span>\n {{ item.label }}\n <span class=\"ng-doc-api-list-count\">{{ item.count }}</span>\n </button>\n }\n </div>\n}\n\n@if (scope()) {\n <p class=\"ng-doc-api-list-scope-note\">\n {{ texts.scopeNote({ scope: scope() }) }}\n <button type=\"button\" (click)=\"clearScope()\">{{ texts.showEveryScope }}</button>\n </p>\n}\n\n@for (group of groups(); track group.id) {\n <section class=\"ng-doc-api-list-group\" [id]=\"group.id\">\n <h2 class=\"ng-doc-api-list-group-title\">\n @if (group.kind) {\n <ng-doc-kind-icon [kind]=\"group.kind\" size=\"medium\"></ng-doc-kind-icon>\n } @else {\n {{ group.label }}\n }\n <span class=\"ng-doc-api-list-count\">{{ group.items.length }}</span>\n </h2>\n <ul class=\"ng-doc-api-list-index\" [class.ng-doc-api-list-described]=\"hasDescriptions()\">\n @for (item of group.items; track item.route) {\n <li>\n <a [routerLink]=\"item.route\">\n <span class=\"ng-doc-api-list-name\">{{ item.name }}</span>\n @if (hasDescriptions()) {\n @if (item.description) {\n <span class=\"ng-doc-api-list-description\" [title]=\"item.description\">{{\n item.description\n }}</span>\n } @else {\n <span class=\"ng-doc-api-list-description ng-doc-api-list-none\">{{\n texts.noDescription\n }}</span>\n }\n }\n @if (group.kind) {\n <span class=\"ng-doc-api-list-scope\">{{ item.scope }}</span>\n } @else {\n <ng-doc-kind-icon class=\"ng-doc-api-list-scope\" [kind]=\"item.type\"></ng-doc-kind-icon>\n }\n </a>\n </li>\n }\n </ul>\n </section>\n} @empty {\n @if (loaded()) {\n <p class=\"ng-doc-api-list-empty\">{{ texts.empty }}</p>\n } @else if (failed()) {\n <p class=\"ng-doc-api-list-empty\">{{ texts.failed }}</p>\n }\n}\n", styles: [":host{display:block;max-width:var(--ng-doc-api-content-max-width);font-family:var(--ng-doc-font-family);color:var(--ng-doc-text)}.ng-doc-api-list-title{margin-top:0}.ng-doc-api-list-lead{margin:var(--ng-doc-space-2) 0 0;font-size:var(--ng-doc-font-size);color:var(--ng-doc-text-muted)}.ng-doc-api-list-tools{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-3);margin:var(--ng-doc-space-6) 0 var(--ng-doc-space-3)}.ng-doc-api-list-filter{display:flex;flex:1 1 280px;align-items:center;gap:var(--ng-doc-space-2);max-width:420px;height:36px;padding:0 var(--ng-doc-space-2) 0 var(--ng-doc-space-3);border:var(--ng-doc-input-border);border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-input-background-color, var(--ng-doc-background));color:var(--ng-doc-text-muted);cursor:text}.ng-doc-api-list-filter:hover{border:var(--ng-doc-input-border-hover)}.ng-doc-api-list-filter:focus-within{box-shadow:var(--ng-doc-focus-ring)}.ng-doc-api-list-filter svg{flex:none}.ng-doc-api-list-filter input{flex:1;min-width:0;height:100%;padding:0;border:0;outline:0;background:none;font:400 14px/20px var(--ng-doc-font-family);color:var(--ng-doc-heading-color)}.ng-doc-api-list-filter input::placeholder{color:var(--ng-doc-text-muted);opacity:1}.ng-doc-api-list-kbd{display:inline-grid;place-items:center;min-width:20px;height:20px;padding:0 5px;border:1px solid var(--ng-doc-kbd-border-color);border-radius:var(--ng-doc-radius-xs);background:var(--ng-doc-kbd-background);font:500 12px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted)}.ng-doc-api-list-group-by{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin-left:auto;font-size:13px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-segments{position:relative;display:inline-flex;gap:2px;padding:3px;border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-base-2)}.ng-doc-api-list-segments ng-doc-selection,.ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{border-radius:var(--ng-doc-radius-sm);background:var(--ng-doc-background);box-shadow:var(--ng-doc-shadow-xs)}.ng-doc-api-list-segments button{position:relative;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-sm);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text-muted);cursor:pointer}.ng-doc-api-list-segments button:hover,.ng-doc-api-list-segments button[aria-pressed=true]{color:var(--ng-doc-heading-color)}:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=dark]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}@media(prefers-color-scheme:dark){:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection,:host-context([data-theme=auto]) .ng-doc-api-list-segments ng-doc-selection:not([data-ng-doc-placed])~button[aria-pressed=true]{box-shadow:var(--ng-doc-shadow-xs),inset 0 0 0 1px var(--ng-doc-base-4)}}.ng-doc-api-list-kinds{display:flex;flex-wrap:wrap;gap:2px var(--ng-doc-space-1);margin:0 0 var(--ng-doc-space-2);padding-bottom:var(--ng-doc-space-3);border-bottom:1px solid var(--ng-doc-border-color)}.ng-doc-api-list-kinds button{display:inline-flex;flex:none;align-items:center;gap:7px;height:28px;padding:0 10px;border:0;border-radius:var(--ng-doc-radius-md);background:none;font:500 13px/1 var(--ng-doc-font-family);color:var(--ng-doc-text);white-space:nowrap;cursor:pointer}.ng-doc-api-list-kinds button:hover{background:var(--ng-doc-hover-background);color:var(--ng-doc-heading-color)}.ng-doc-api-list-kinds button[aria-pressed=true]{background:var(--ng-doc-primary-soft);color:var(--ng-doc-primary-strong);font-weight:600}.ng-doc-api-list-kinds button[aria-pressed=true] .ng-doc-api-list-count{color:var(--ng-doc-primary-strong)}.ng-doc-api-list-count{font-size:12px;font-weight:400;color:var(--ng-doc-text-muted);font-variant-numeric:tabular-nums}.ng-doc-api-list-dot{--_hue: var(--ng-doc-hue-neutral);display:inline-block;flex:none;width:8px;height:8px;border-radius:50%;background:var(--_hue)}.ng-doc-api-list-dot[data-ng-doc-kind=Class]{--_hue: var(--ng-doc-class-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Interface]{--_hue: var(--ng-doc-interface-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Enum]{--_hue: var(--ng-doc-enum-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Variable]{--_hue: var(--ng-doc-variable-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Function]{--_hue: var(--ng-doc-function-background)}.ng-doc-api-list-dot[data-ng-doc-kind=TypeAlias]{--_hue: var(--ng-doc-type-alias-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Component]{--_hue: var(--ng-doc-component-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Directive]{--_hue: var(--ng-doc-directive-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Injectable]{--_hue: var(--ng-doc-injectable-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=Pipe]{--_hue: var(--ng-doc-pipe-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=NgModule]{--_hue: var(--ng-doc-ng-module-decorator-background)}.ng-doc-api-list-dot[data-ng-doc-kind=ng-doc-tag-selector]{--_hue: var(--ng-doc-selector-background)}.ng-doc-api-list-scope-note{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ng-doc-space-2);margin:var(--ng-doc-space-3) 0 0;font-size:14px;color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope-note button{padding:0;border:0;background:none;font:inherit;color:var(--ng-doc-link-color);cursor:pointer}.ng-doc-api-list-group{margin-top:var(--ng-doc-space-8);scroll-margin-top:calc(var(--ng-doc-navbar-height) + var(--ng-doc-layout-top) + 16px)}.ng-doc-api-list-group-title{display:flex;align-items:center;gap:var(--ng-doc-space-2);margin:0 0 var(--ng-doc-space-2);padding:0;border:0;font-family:var(--ng-doc-heading-font-family);font-size:17px;line-height:26px;font-weight:600;color:var(--ng-doc-heading-color)}.ng-doc-api-list-group-title .ng-doc-api-list-count{font-family:var(--ng-doc-font-family);font-size:13px}.ng-doc-api-list-index{margin:0;padding:0;list-style:none;border:1px solid var(--ng-doc-border-color);border-radius:var(--ng-doc-radius-lg);overflow:hidden}.ng-doc-api-list-index li{margin:0;padding:0}.ng-doc-api-list-index li+li{border-top:1px solid var(--ng-doc-base-2)}.ng-doc-api-list-index a{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--ng-doc-space-4);min-height:44px;padding:8px var(--ng-doc-space-4);font-size:14px;line-height:20px;color:var(--ng-doc-text);text-decoration:none}.ng-doc-api-list-index a:hover{background:var(--ng-doc-scope-item-link-background, var(--ng-doc-row-hover-background))}.ng-doc-api-list-index a:hover .ng-doc-api-list-name{color:var(--ng-doc-link-color)}.ng-doc-api-list-index a:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--ng-doc-primary)}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,17rem) minmax(0,1fr) auto}.ng-doc-api-list-name{min-width:0;overflow-wrap:anywhere;font:500 13px/20px var(--ng-doc-code-font);color:var(--ng-doc-heading-color)}.ng-doc-api-list-description{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ng-doc-api-list-none{color:var(--ng-doc-text-muted)}.ng-doc-api-list-scope{justify-self:end;font-size:12px;color:var(--ng-doc-text-muted);white-space:nowrap}.ng-doc-api-list-empty{padding:var(--ng-doc-space-5) var(--ng-doc-space-4);text-align:center;font-size:14px;color:var(--ng-doc-text-muted)}@media(max-width:900px){.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,16rem) minmax(0,1fr)}.ng-doc-api-list-index.ng-doc-api-list-described a .ng-doc-api-list-scope{display:none}}@media(max-width:640px){.ng-doc-api-list-filter{flex-basis:100%;max-width:none}.ng-doc-api-list-group-by{margin-left:0}.ng-doc-api-list-kinds{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}.ng-doc-api-list-index.ng-doc-api-list-described a{grid-template-columns:minmax(0,1fr);gap:2px;padding:10px var(--ng-doc-space-3)}}\n"] }]
186
188
  }], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], segment: [{ type: i0.Input, args: [{ isSignal: true, alias: "segment", required: false }] }], filterInput: [{ type: i0.ViewChild, args: ['filterInput', { isSignal: true }] }] } });
187
189
  /**
188
190
  * An id fragment for a kind or a scope.