@mathstack/app-kit 0.0.1-beta.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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/baseline-styles/_css-reset.scss +118 -0
  4. package/baseline-styles/_grid.scss +4 -0
  5. package/baseline-styles/_index.scss +6 -0
  6. package/baseline-styles/_sass-utils.scss +23 -0
  7. package/baseline-styles/_themes.scss +19 -0
  8. package/baseline-styles/_typography.scss +232 -0
  9. package/baseline-styles/_webkit-scrollbar.scss +22 -0
  10. package/baseline-styles/theming/_colors.scss +46 -0
  11. package/baseline-styles/theming/_index.scss +2 -0
  12. package/baseline-styles/theming/_typography.scss +32 -0
  13. package/fesm2022/mathstack-app-kit.mjs +846 -0
  14. package/fesm2022/mathstack-app-kit.mjs.map +1 -0
  15. package/index.d.ts +5 -0
  16. package/lib/assets/assets-resource.d.ts +11 -0
  17. package/lib/assets/assets-service.d.ts +35 -0
  18. package/lib/assets/index.d.ts +1 -0
  19. package/lib/content-parsing/index.d.ts +2 -0
  20. package/lib/content-parsing/markdown-parser.d.ts +54 -0
  21. package/lib/content-parsing/shiki-highlighter.d.ts +77 -0
  22. package/lib/core/utilities/deep-merge.d.ts +1 -0
  23. package/lib/core/utilities/index.d.ts +2 -0
  24. package/lib/core/utilities/safe-assign.d.ts +18 -0
  25. package/lib/documentation-display/active-heading-tracker.d.ts +14 -0
  26. package/lib/documentation-display/document-index/document-index.component.d.ts +17 -0
  27. package/lib/documentation-display/documentation-config-parser.d.ts +41 -0
  28. package/lib/documentation-display/documentation-content-service.d.ts +50 -0
  29. package/lib/documentation-display/documentation-display.component.d.ts +39 -0
  30. package/lib/documentation-display/index.d.ts +6 -0
  31. package/lib/documentation-display/navigation-siblings/navigation-siblings.component.d.ts +18 -0
  32. package/lib/ng-utilities/index.d.ts +2 -0
  33. package/lib/ng-utilities/ng-on-changes.d.ts +22 -0
  34. package/lib/ng-utilities/run-ng-change-detection-then.d.ts +22 -0
  35. package/package.json +46 -0
  36. package/public-api.d.ts +6 -0
@@ -0,0 +1,846 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, Component, ContentChild, ViewChild, Inject, ViewEncapsulation } from '@angular/core';
3
+ import { csvParse } from 'd3';
4
+ import { forkJoin, of, mergeMap, from, map, switchMap, BehaviorSubject, fromEvent, debounceTime, distinctUntilChanged, withLatestFrom } from 'rxjs';
5
+ import { parse } from 'yaml';
6
+ import * as i1 from '@angular/common/http';
7
+ import rehypeAutolinkHeadings from 'rehype-autolink-headings';
8
+ import rehypeRaw from 'rehype-raw';
9
+ import rehypeSlug from 'rehype-slug';
10
+ import rehypeStringify from 'rehype-stringify';
11
+ import remarkGfm from 'remark-gfm';
12
+ import remarkParse from 'remark-parse';
13
+ import remarkRehype from 'remark-rehype';
14
+ import { unified } from 'unified';
15
+ import { fromParse5 } from 'hast-util-from-parse5';
16
+ import { parse as parse$1 } from 'parse5';
17
+ import { createHighlighter } from 'shiki/index.mjs';
18
+ import { visit } from 'unist-util-visit';
19
+ import * as i1$1 from '@angular/platform-browser';
20
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
21
+ import * as i3 from '@angular/common';
22
+ import { CommonModule, TitleCasePipe, DOCUMENT } from '@angular/common';
23
+ import { isEqual, get } from 'lodash-es';
24
+
25
+ class AdkAssetsResource {
26
+ constructor(http) {
27
+ this.http = http;
28
+ }
29
+ getAsset(path, responseType) {
30
+ return this.http.get(path, {
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ responseType: responseType,
33
+ });
34
+ }
35
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkAssetsResource, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
36
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkAssetsResource, providedIn: 'root' }); }
37
+ }
38
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkAssetsResource, decorators: [{
39
+ type: Injectable,
40
+ args: [{
41
+ providedIn: 'root',
42
+ }]
43
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
44
+
45
+ var AdkAssetResponse;
46
+ (function (AdkAssetResponse) {
47
+ AdkAssetResponse["ArrayBuffer"] = "arraybuffer";
48
+ AdkAssetResponse["Blob"] = "blob";
49
+ AdkAssetResponse["Json"] = "json";
50
+ AdkAssetResponse["Text"] = "text";
51
+ })(AdkAssetResponse || (AdkAssetResponse = {}));
52
+ class AdkAssetsService {
53
+ constructor(resource) {
54
+ this.resource = resource;
55
+ this.assets = {};
56
+ this.assetsPath = 'assets/';
57
+ }
58
+ setAssetsPath(path) {
59
+ this.assetsPath = path;
60
+ }
61
+ /**
62
+ * Loads an asset from the assets folder.
63
+ *
64
+ * @param assetName The path to the asset from assets/. Should not include leading slash.
65
+ * @returns An observable that emits the asset data.
66
+ */
67
+ getAsset(assetName, responseType) {
68
+ if (!this.assets[assetName]) {
69
+ this.assets[assetName] = this.fetchAsset(assetName, responseType);
70
+ }
71
+ return this.assets[assetName];
72
+ }
73
+ fetchAsset(assetName, responseType) {
74
+ return this.resource.getAsset(`${this.assetsPath}${assetName}`, responseType);
75
+ }
76
+ /**
77
+ * Loads multiple assets concurrently.
78
+ *
79
+ * @param assetNames An array of asset names to load.
80
+ * @returns An observable that emits an array of asset data.
81
+ */
82
+ getAssets(assetNames, responseType) {
83
+ return forkJoin(assetNames.map((assetName) => this.getAsset(assetName, responseType)));
84
+ }
85
+ parseCsv(str) {
86
+ return csvParse(str);
87
+ }
88
+ parseYaml(str) {
89
+ return parse(str);
90
+ }
91
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkAssetsService, deps: [{ token: AdkAssetsResource }], target: i0.ɵɵFactoryTarget.Injectable }); }
92
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkAssetsService, providedIn: 'root' }); }
93
+ }
94
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkAssetsService, decorators: [{
95
+ type: Injectable,
96
+ args: [{ providedIn: 'root' }]
97
+ }], ctorParameters: () => [{ type: AdkAssetsResource }] });
98
+
99
+ function deepMerge(target, source) {
100
+ const output = Object.assign({}, target);
101
+ if (isObject(target) && isObject(source)) {
102
+ Object.keys(source).forEach((key) => {
103
+ if (isObject(source[key])) {
104
+ if (!(key in target)) {
105
+ Object.assign(output, { [key]: source[key] });
106
+ }
107
+ else {
108
+ output[key] = deepMerge(target[key], source[key]);
109
+ }
110
+ }
111
+ else {
112
+ Object.assign(output, { [key]: source[key] });
113
+ }
114
+ });
115
+ }
116
+ return output;
117
+ }
118
+ function isObject(item) {
119
+ return item && typeof item === 'object' && !Array.isArray(item);
120
+ }
121
+
122
+ const defaultHighlighterLangs = [
123
+ 'json',
124
+ 'ts',
125
+ 'js',
126
+ 'html',
127
+ 'css',
128
+ 'scss',
129
+ 'yaml',
130
+ 'angular-html',
131
+ 'angular-ts',
132
+ 'mermaid',
133
+ 'bash',
134
+ ];
135
+ var ShikiTheme;
136
+ (function (ShikiTheme) {
137
+ ShikiTheme["Andromeeda"] = "andromeeda";
138
+ ShikiTheme["AuroraX"] = "aurora-x";
139
+ ShikiTheme["AyuDark"] = "ayu-dark";
140
+ ShikiTheme["CatppuccinFrappe"] = "catppuccin-frappe";
141
+ ShikiTheme["CatppuccinLatte"] = "catppuccin-latte";
142
+ ShikiTheme["CatppuccinMacchiato"] = "catppuccin-macchiato";
143
+ ShikiTheme["CatppuccinMocha"] = "catppuccin-mocha";
144
+ ShikiTheme["DarkPlus"] = "dark-plus";
145
+ ShikiTheme["DraculaTheme"] = "dracula";
146
+ ShikiTheme["DraculaThemeSoft"] = "dracula-soft";
147
+ ShikiTheme["EverforestDark"] = "everforest-dark";
148
+ ShikiTheme["EverforestLight"] = "everforest-light";
149
+ ShikiTheme["GitHubDark"] = "github-dark";
150
+ ShikiTheme["GitHubDarkDefault"] = "github-dark-default";
151
+ ShikiTheme["GitHubDarkDimmed"] = "github-dark-dimmed";
152
+ ShikiTheme["GitHubDarkHighContrast"] = "github-dark-high-contrast";
153
+ ShikiTheme["GitHubLight"] = "github-light";
154
+ ShikiTheme["GitHubLightDefault"] = "github-light-default";
155
+ ShikiTheme["GitHubLightHighContrast"] = "github-light-high-contrast";
156
+ ShikiTheme["Houston"] = "houston";
157
+ ShikiTheme["LaserWave"] = "laserwave";
158
+ ShikiTheme["LightPlus"] = "light-plus";
159
+ ShikiTheme["MaterialTheme"] = "material-theme";
160
+ ShikiTheme["MaterialThemeDarker"] = "material-theme-darker";
161
+ ShikiTheme["MaterialThemeLighter"] = "material-theme-lighter";
162
+ ShikiTheme["MaterialThemeOcean"] = "material-theme-ocean";
163
+ ShikiTheme["MaterialThemePalenight"] = "material-theme-palenight";
164
+ ShikiTheme["MinDark"] = "min-dark";
165
+ ShikiTheme["MinLight"] = "min-light";
166
+ ShikiTheme["Monokai"] = "monokai";
167
+ ShikiTheme["NightOwl"] = "night-owl";
168
+ ShikiTheme["Nord"] = "nord";
169
+ ShikiTheme["OneDarkPro"] = "one-dark-pro";
170
+ ShikiTheme["OneLight"] = "one-light";
171
+ ShikiTheme["Plastic"] = "plastic";
172
+ ShikiTheme["Poimandres"] = "poimandres";
173
+ ShikiTheme["Red"] = "red";
174
+ ShikiTheme["RosePine"] = "rose-pine";
175
+ ShikiTheme["RosePineDawn"] = "rose-pine-dawn";
176
+ ShikiTheme["RosePineMoon"] = "rose-pine-moon";
177
+ ShikiTheme["SlackDark"] = "slack-dark";
178
+ ShikiTheme["SlackOchin"] = "slack-ochin";
179
+ ShikiTheme["SnazzyLight"] = "snazzy-light";
180
+ ShikiTheme["SolarizedDark"] = "solarized-dark";
181
+ ShikiTheme["SolarizedLight"] = "solarized-light";
182
+ ShikiTheme["Synthwave84"] = "synthwave-84";
183
+ ShikiTheme["TokyoNight"] = "tokyo-night";
184
+ ShikiTheme["Vesper"] = "vesper";
185
+ ShikiTheme["VitesseBlack"] = "vitesse-black";
186
+ ShikiTheme["VitesseDark"] = "vitesse-dark";
187
+ ShikiTheme["VitesseLight"] = "vitesse-light";
188
+ })(ShikiTheme || (ShikiTheme = {}));
189
+ const MISSING_HIGHLIGHTER = `Please provide a \`shiki\` highlighter instance via \`options\`.`;
190
+ class AdkShikiHighlighter {
191
+ constructor() {
192
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
193
+ this.highlighterPromise = null;
194
+ }
195
+ /**
196
+ * Initialize the highlighter. This should only be called one in an application.
197
+ *
198
+ * @param themes an array of any Shiki themes you may want to use anywhere in the app. You can control which theme for your particular parsing by passing the theme name to the actual parsing function.
199
+ *
200
+ * @returns void
201
+ */
202
+ async initialize(themes, langs = defaultHighlighterLangs) {
203
+ if (!this.highlighterPromise) {
204
+ this.highlighterPromise = createHighlighter({
205
+ langs,
206
+ themes: themes.length ? themes : [ShikiTheme.GitHubLight],
207
+ });
208
+ }
209
+ await this.highlighterPromise;
210
+ }
211
+ async getHighlighter() {
212
+ if (!this.highlighterPromise) {
213
+ throw new Error('Highlighter is not initialized. Please call initialize() once in your application first.');
214
+ }
215
+ return this.highlighterPromise;
216
+ }
217
+ remarkHighlight(options) {
218
+ const highlighter = options.highlighter;
219
+ if (!options.highlighter) {
220
+ throw new Error(MISSING_HIGHLIGHTER);
221
+ }
222
+ const loadedLanguages = highlighter.getLoadedLanguages();
223
+ const ignoreUnknownLanguage = options.ignoreUnknownLanguage === undefined
224
+ ? true
225
+ : options.ignoreUnknownLanguage;
226
+ const visitor = (node) => {
227
+ if (!loadedLanguages.includes(node.lang)) {
228
+ if (ignoreUnknownLanguage) {
229
+ node.lang = null;
230
+ }
231
+ else {
232
+ return;
233
+ }
234
+ }
235
+ const highlighted = highlighter.codeToHtml(node.value, {
236
+ lang: node.lang,
237
+ theme: options.theme,
238
+ });
239
+ node.type = 'html';
240
+ node.value = highlighted;
241
+ };
242
+ const transformer = (tree) => {
243
+ visit(tree, 'code', visitor);
244
+ };
245
+ return transformer;
246
+ }
247
+ rehypeHighlight(options) {
248
+ const highlighter = options.highlighter;
249
+ if (!options.highlighter) {
250
+ throw new Error(MISSING_HIGHLIGHTER);
251
+ }
252
+ const visitor = (node, _index, parent) => {
253
+ if (!parent || parent.tagName !== 'pre' || node.tagName !== 'code') {
254
+ return;
255
+ }
256
+ const [langClass] = node.properties.className;
257
+ const lang = langClass.replace('language-', '');
258
+ if (highlighter.getLoadedLanguages().includes(lang)) {
259
+ const code = node.children[0]?.value;
260
+ if (!code) {
261
+ return;
262
+ }
263
+ const highlighted = highlighter.codeToHtml(code, {
264
+ lang,
265
+ theme: options.theme,
266
+ });
267
+ const parsed = parse$1(highlighted);
268
+ const hastTree = fromParse5(parsed);
269
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
270
+ const content = hastTree.children[0].children[1].children[0]
271
+ .children[0];
272
+ content.properties.class = ['shiki', 'shiki-' + lang, langClass];
273
+ node.properties = content.properties;
274
+ node.children = content.children;
275
+ }
276
+ };
277
+ const transformer = (tree) => {
278
+ visit(tree, 'element', visitor);
279
+ };
280
+ return transformer;
281
+ }
282
+ getLanguage(node) {
283
+ const dataLanguage = node.properties.dataLanguage;
284
+ if (dataLanguage != null) {
285
+ return dataLanguage;
286
+ }
287
+ const className = node.properties.className || [];
288
+ for (const classListItem of className) {
289
+ if (classListItem.slice(0, 9) === 'language-') {
290
+ return classListItem.slice(9).toLowerCase();
291
+ }
292
+ }
293
+ return null;
294
+ }
295
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkShikiHighlighter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
296
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkShikiHighlighter, providedIn: 'root' }); }
297
+ }
298
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkShikiHighlighter, decorators: [{
299
+ type: Injectable,
300
+ args: [{
301
+ providedIn: 'root',
302
+ }]
303
+ }] });
304
+
305
+ const DEFAULT_HIGHLIGHTER_OPTIONS = {
306
+ highlighter: undefined,
307
+ theme: ShikiTheme.GitHubLight,
308
+ type: 'markdown',
309
+ ignoreUnknownLanguage: true,
310
+ };
311
+ const DEFAULT_PARSING_OPTIONS = {
312
+ gfm: true,
313
+ headingIds: true,
314
+ headingFragmentLinks: { createLinks: false },
315
+ highlighter: DEFAULT_HIGHLIGHTER_OPTIONS,
316
+ };
317
+ class AdkMarkdownParser {
318
+ constructor(sanitizer, shikiHighlighter) {
319
+ this.sanitizer = sanitizer;
320
+ this.shikiHighlighter = shikiHighlighter;
321
+ this.parser = unified;
322
+ }
323
+ parse(markdown, options) {
324
+ const mergedOptions = deepMerge(DEFAULT_PARSING_OPTIONS, options || {});
325
+ return of(mergedOptions).pipe(mergeMap((_options) => {
326
+ if (_options.highlighter && !_options.highlighter.highlighter) {
327
+ return from(this.shikiHighlighter.getHighlighter()).pipe(map((highlighter) => ({
328
+ ..._options,
329
+ highlighter: {
330
+ ..._options.highlighter,
331
+ highlighter,
332
+ },
333
+ })));
334
+ }
335
+ else {
336
+ return of(_options);
337
+ }
338
+ }), switchMap((_options) => {
339
+ const sections = this.getSections(markdown);
340
+ const parsedSections$ = sections.map((section) => {
341
+ return this.parseSection(section, _options);
342
+ });
343
+ return forkJoin(parsedSections$);
344
+ }));
345
+ }
346
+ getSections(markdown) {
347
+ const sections = [];
348
+ let currentMarkdown = '';
349
+ const lines = markdown.split('\n');
350
+ for (const line of lines) {
351
+ currentMarkdown += line + '\n';
352
+ }
353
+ // Add any remaining markdown
354
+ if (currentMarkdown.trim()) {
355
+ sections.push({
356
+ type: 'markdown',
357
+ content: currentMarkdown,
358
+ html: undefined,
359
+ headers: this.getHeaders(currentMarkdown),
360
+ });
361
+ }
362
+ return sections;
363
+ }
364
+ parseSection(section, options) {
365
+ const parsedContent$ = from(unified()
366
+ .use(remarkParse)
367
+ .use(options.gfm ? remarkGfm : undefined)
368
+ .use(options.highlighter && options.highlighter.type === 'markdown'
369
+ ? this.shikiHighlighter.remarkHighlight
370
+ : undefined, options.highlighter)
371
+ .use(remarkRehype, { allowDangerousHtml: true })
372
+ .use(rehypeRaw)
373
+ .use(options.headingIds ? rehypeSlug : undefined)
374
+ .use(options.headingFragmentLinks ? rehypeAutolinkHeadings : undefined, { behavior: options.headingFragmentLinks?.behavior })
375
+ .use(rehypeStringify)
376
+ .process(section.content)
377
+ .then((file) => String(file)));
378
+ return parsedContent$.pipe(map((parsedContent) => {
379
+ const toReturn = {
380
+ ...section,
381
+ html: this.sanitizer.bypassSecurityTrustHtml(parsedContent),
382
+ };
383
+ return toReturn;
384
+ }));
385
+ }
386
+ getHeaders(markdown) {
387
+ const headerRegex = /^(#{1,6})\s*(.+)$|<h([1-6])(?:\s+[^>]*)?>(.*?)<\/h[1-6]>/gm;
388
+ const headers = [];
389
+ let match;
390
+ while ((match = headerRegex.exec(markdown)) !== null) {
391
+ let level;
392
+ let text;
393
+ if (match[1]) {
394
+ // Markdown header, e.g., ## Heading
395
+ level = match[1].length;
396
+ text = match[2].trim();
397
+ }
398
+ else {
399
+ // HTML header, e.g., <h2>Heading</h2>
400
+ level = parseInt(match[3], 10);
401
+ text = match[4].trim();
402
+ }
403
+ const id = text
404
+ .toLowerCase()
405
+ .replace(/\s+/g, '-')
406
+ .replace(/[^\w-]+/g, '');
407
+ headers.push({ id, text, level });
408
+ }
409
+ return headers;
410
+ }
411
+ parseComponent(content) {
412
+ const cleanedLine = content.trim().slice(2, -2).trim();
413
+ const [nameKV, pathToKV] = cleanedLine.split(',');
414
+ const name = nameKV.split(':')[1]?.trim();
415
+ const pathTo = pathToKV.split(':')[1]?.trim();
416
+ return { name, pathTo };
417
+ }
418
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkMarkdownParser, deps: [{ token: i1$1.DomSanitizer }, { token: AdkShikiHighlighter }], target: i0.ɵɵFactoryTarget.Injectable }); }
419
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkMarkdownParser }); }
420
+ }
421
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkMarkdownParser, decorators: [{
422
+ type: Injectable
423
+ }], ctorParameters: () => [{ type: i1$1.DomSanitizer }, { type: AdkShikiHighlighter }] });
424
+
425
+ /* eslint-disable @typescript-eslint/no-explicit-any */
426
+ /**
427
+ * Safely assigns properties from a source object to a target object.
428
+ *
429
+ * Copies all own, enumerable properties from `source` to `target`,
430
+ * except when the target already has a property of the same name that is a function.
431
+ *
432
+ * Logs a warning for each skipped property if `logConflicts` is true.
433
+ *
434
+ * @template TTarget The type of the target object.
435
+ * @template TSource The type of the source object.
436
+ * @param target The object to assign properties to.
437
+ * @param source The object providing properties to assign.
438
+ * @param logConflicts If true, logs when a method/property on the target prevents assignment. Default is false.
439
+ *
440
+ * @example
441
+ * safeAssign(this, { log: 'hello' }, true);
442
+ */
443
+ function safeAssign(target, source, logConflicts = false) {
444
+ if (!source)
445
+ return;
446
+ for (const key of Object.keys(source)) {
447
+ const existing = target[key];
448
+ const incoming = source[key];
449
+ if (typeof existing === 'function') {
450
+ if (logConflicts) {
451
+ console.warn(`safeAssign: Skipped assignment for key "${key}" because it would overwrite an existing method.`);
452
+ }
453
+ continue;
454
+ }
455
+ target[key] = incoming;
456
+ }
457
+ }
458
+
459
+ class AdkActiveHeadingTracker {
460
+ constructor(ngZone) {
461
+ this.ngZone = ngZone;
462
+ this.activeHeadingId = new BehaviorSubject(null);
463
+ this.activeHeadingId$ = this.activeHeadingId.asObservable();
464
+ }
465
+ initScrollListener(contentEl, destroyRef) {
466
+ this.ngZone.runOutsideAngular(() => {
467
+ fromEvent(window, 'scroll')
468
+ .pipe(takeUntilDestroyed(destroyRef), debounceTime(50), distinctUntilChanged())
469
+ .subscribe(() => {
470
+ const headings = Array.from(contentEl.querySelectorAll('h1, h2, h3, h4, h5, h6'));
471
+ const activeHeading = this.findActiveHeading(headings);
472
+ this.ngZone.run(() => {
473
+ if (activeHeading) {
474
+ this.activeHeadingId.next(activeHeading.id);
475
+ }
476
+ });
477
+ });
478
+ });
479
+ }
480
+ findActiveHeading(headings) {
481
+ const scrollPosition = window.scrollY;
482
+ for (let i = headings.length - 1; i >= 0; i--) {
483
+ const heading = headings[i];
484
+ if (heading.offsetTop <= scrollPosition + 50) {
485
+ return heading;
486
+ }
487
+ }
488
+ return headings[0] || null;
489
+ }
490
+ setActiveHeading(heading) {
491
+ this.activeHeadingId.next(heading.id);
492
+ }
493
+ scrollToTop() {
494
+ window.scrollTo({ top: 0, behavior: 'smooth' });
495
+ }
496
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkActiveHeadingTracker, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
497
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkActiveHeadingTracker, providedIn: 'root' }); }
498
+ }
499
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkActiveHeadingTracker, decorators: [{
500
+ type: Injectable,
501
+ args: [{
502
+ providedIn: 'root',
503
+ }]
504
+ }], ctorParameters: () => [{ type: i0.NgZone }] });
505
+
506
+ class AdkDocumentIndexComponent {
507
+ constructor(activeHeadingTracker) {
508
+ this.activeHeadingTracker = activeHeadingTracker;
509
+ this.headings = [];
510
+ this.activeHeading = new EventEmitter();
511
+ }
512
+ setActiveHeading(event, heading) {
513
+ this.activeHeading.emit({ heading, event });
514
+ }
515
+ scrollToTop() {
516
+ this.activeHeadingTracker.scrollToTop();
517
+ }
518
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentIndexComponent, deps: [{ token: AdkActiveHeadingTracker }], target: i0.ɵɵFactoryTarget.Component }); }
519
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: AdkDocumentIndexComponent, isStandalone: true, selector: "hsi-adk-document-index", inputs: { headings: "headings" }, outputs: { activeHeading: "activeHeading" }, ngImport: i0, template: "<nav class=\"toc\">\n @if (headings.length > 0) {\n <p class=\"index-title\">On this page</p>\n <ul class=\"links-container\">\n @for (heading of headings; track $index) {\n <li class=\"toc-item\">\n <button\n type=\"button\"\n class=\"toc-link\"\n [style.--level]=\"heading.level\"\n (click)=\"setActiveHeading($event, heading)\"\n (keydown.enter)=\"setActiveHeading($event, heading)\"\n [class.active]=\"\n heading.id === (activeHeadingTracker.activeHeadingId$ | async)\n \"\n >{{ heading.text }}</button\n >\n </li>\n }\n </ul>\n <button\n type=\"button\"\n class=\"back-to-top\"\n (click)=\"scrollToTop()\"\n (keydown.enter)=\"scrollToTop()\"\n >\n Back to top<span\n aria-hidden=\"true\"\n class=\"material-symbols-outlined arrow\"\n >arrow_upward</span\n >\n </button>\n }\n</nav>\n", styles: [".links-container{list-style:none;flex-basis:28%;padding:0;margin:0;width:250px}.index-title{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-medium);font-size:9pt;letter-spacing:.25pt;line-height:12pt;letter-spacing:.8pt;text-transform:uppercase;padding-bottom:.25rem}.toc-link{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:11pt;letter-spacing:0;line-height:16pt;cursor:pointer;padding-top:.25rem;padding-bottom:.25rem;padding-left:calc((var(--level) - 1) * 1rem);display:block;border-left:2px solid var(--hsi-adk-color-muted-primary-90);color:var(--hsi-adk-color-muted-primary-50);text-align:left}.toc-link:hover{color:var(--hsi-adk-color-muted-primary-25);border-left:2px solid var(--hsi-adk-color-muted-primary-70)}.toc-link.active{color:var(--hsi-adk-color-primary-40);border-left:2px solid var(--hsi-adk-color-primary-40)}.back-to-top{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:11pt;letter-spacing:0;line-height:16pt;cursor:pointer;padding:.5rem 0;display:flex;align-items:center;text-align:left;color:var(--hsi-adk-color-muted-primary-40)}.back-to-top:hover{color:var(--hsi-adk-color-muted-primary-10)}.arrow{transform:scale(.7)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
520
+ }
521
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentIndexComponent, decorators: [{
522
+ type: Component,
523
+ args: [{ selector: 'hsi-adk-document-index', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav class=\"toc\">\n @if (headings.length > 0) {\n <p class=\"index-title\">On this page</p>\n <ul class=\"links-container\">\n @for (heading of headings; track $index) {\n <li class=\"toc-item\">\n <button\n type=\"button\"\n class=\"toc-link\"\n [style.--level]=\"heading.level\"\n (click)=\"setActiveHeading($event, heading)\"\n (keydown.enter)=\"setActiveHeading($event, heading)\"\n [class.active]=\"\n heading.id === (activeHeadingTracker.activeHeadingId$ | async)\n \"\n >{{ heading.text }}</button\n >\n </li>\n }\n </ul>\n <button\n type=\"button\"\n class=\"back-to-top\"\n (click)=\"scrollToTop()\"\n (keydown.enter)=\"scrollToTop()\"\n >\n Back to top<span\n aria-hidden=\"true\"\n class=\"material-symbols-outlined arrow\"\n >arrow_upward</span\n >\n </button>\n }\n</nav>\n", styles: [".links-container{list-style:none;flex-basis:28%;padding:0;margin:0;width:250px}.index-title{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-medium);font-size:9pt;letter-spacing:.25pt;line-height:12pt;letter-spacing:.8pt;text-transform:uppercase;padding-bottom:.25rem}.toc-link{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:11pt;letter-spacing:0;line-height:16pt;cursor:pointer;padding-top:.25rem;padding-bottom:.25rem;padding-left:calc((var(--level) - 1) * 1rem);display:block;border-left:2px solid var(--hsi-adk-color-muted-primary-90);color:var(--hsi-adk-color-muted-primary-50);text-align:left}.toc-link:hover{color:var(--hsi-adk-color-muted-primary-25);border-left:2px solid var(--hsi-adk-color-muted-primary-70)}.toc-link.active{color:var(--hsi-adk-color-primary-40);border-left:2px solid var(--hsi-adk-color-primary-40)}.back-to-top{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:11pt;letter-spacing:0;line-height:16pt;cursor:pointer;padding:.5rem 0;display:flex;align-items:center;text-align:left;color:var(--hsi-adk-color-muted-primary-40)}.back-to-top:hover{color:var(--hsi-adk-color-muted-primary-10)}.arrow{transform:scale(.7)}\n"] }]
524
+ }], ctorParameters: () => [{ type: AdkActiveHeadingTracker }], propDecorators: { headings: [{
525
+ type: Input
526
+ }], activeHeading: [{
527
+ type: Output
528
+ }] } });
529
+
530
+ class AdkDocumentationConfigParser {
531
+ /**
532
+ * This method takes a path from the application and a configuration object, and returns a path to a file that will be fetched.
533
+ *
534
+ * This assumes that the pathFromApp matches a path through the keys of the Nested Object.
535
+ *
536
+ * If the path is 'viz/content/items/bars', the config object might look like this:
537
+ * viz: {
538
+ * content: {
539
+ * items: {
540
+ * bars: 'bars.md'
541
+ * }
542
+ * }
543
+ * }
544
+ *
545
+ * @param pathFromApp a string representing the path from the application, for example 'viz/content/items/bars'
546
+ * @param config a nested object representing the configuration
547
+ * @returns a string representing the file path
548
+ */
549
+ getPathToFile(pathFromApp, config, basePath) {
550
+ const pathParts = pathFromApp.split('/');
551
+ const fileName = this.getFileNameFromPath(pathParts, config);
552
+ const pathToFile = basePath ? `${basePath}/${fileName}` : fileName;
553
+ return pathToFile;
554
+ }
555
+ /**
556
+ *
557
+ * @param pathParts a string array of path parts, for example ['viz', 'content', 'items', 'bars]
558
+ * @param config a nested object representing the configuration
559
+ * @returns a string representing the file name
560
+ */
561
+ getFileNameFromPath(pathParts, config) {
562
+ const fileName = pathParts.reduce((acc, part) => {
563
+ const level = acc[part];
564
+ acc = level;
565
+ return acc;
566
+ }, config);
567
+ return fileName;
568
+ }
569
+ findPreviousAndNextByPath(obj, targetPath) {
570
+ const flatPaths = this.flattenObjectWithPath(obj);
571
+ const index = flatPaths.indexOf(targetPath);
572
+ if (index === -1) {
573
+ return { previous: undefined, next: undefined };
574
+ }
575
+ return {
576
+ previous: index > 0 ? flatPaths[index - 1] : undefined,
577
+ next: index < flatPaths.length - 1 ? flatPaths[index + 1] : undefined,
578
+ };
579
+ }
580
+ flattenObjectWithPath(obj, prefix = '') {
581
+ let result = [];
582
+ for (const [key, value] of Object.entries(obj)) {
583
+ const newPath = prefix ? `${prefix}/${key}` : key;
584
+ if (typeof value === 'object' && value !== null) {
585
+ result = result.concat(this.flattenObjectWithPath(value, newPath));
586
+ }
587
+ else {
588
+ result.push(newPath);
589
+ }
590
+ }
591
+ return result;
592
+ }
593
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationConfigParser, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
594
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationConfigParser }); }
595
+ }
596
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationConfigParser, decorators: [{
597
+ type: Injectable
598
+ }] });
599
+
600
+ class AdkDocumentationContentService {
601
+ constructor(assetsService, docsConfigParser, markdownParser) {
602
+ this.assetsService = assetsService;
603
+ this.docsConfigParser = docsConfigParser;
604
+ this.markdownParser = markdownParser;
605
+ this.files = {};
606
+ }
607
+ /**
608
+ * This service requires the consuming app to provide the AdkDocumentationDisplayService, the AdkAssetsService, and the AdkDocumentationConfigParser at the level at which this service is configured.
609
+ *
610
+ * OPTIONAL: If the consuming app wants to use a different assets directory, they can pass it in here.
611
+ */
612
+ initialize(assetsDirectory) {
613
+ this.assetsService.setAssetsPath(assetsDirectory || 'assets/');
614
+ }
615
+ /**
616
+ * Assumes that the content path matches
617
+ */
618
+ getContentForCurrentContentPath(contentPath$, options) {
619
+ return contentPath$.pipe(switchMap((contentPath) => {
620
+ const pathToFile = this.docsConfigParser.getPathToFile(contentPath, options.fileConfig, options.basePath);
621
+ return this.getParsedMarkdownFile(pathToFile, options.parsingOptions);
622
+ }), withLatestFrom(contentPath$), map(([markdownSections, configPath]) => {
623
+ return {
624
+ sections: markdownSections,
625
+ headings: markdownSections.reduce((acc, section) => {
626
+ if (section.headers.length > 0) {
627
+ acc.push(...section.headers);
628
+ }
629
+ return acc;
630
+ }, []),
631
+ siblings: this.docsConfigParser.findPreviousAndNextByPath(options.fileConfig, configPath),
632
+ };
633
+ }));
634
+ }
635
+ getParsedMarkdownFile(filePathFromAssets, parsingOptions) {
636
+ if (!this.files[filePathFromAssets]) {
637
+ this.files[filePathFromAssets] = this.assetsService
638
+ .getAsset(filePathFromAssets, AdkAssetResponse.Text)
639
+ .pipe(switchMap((text) => this.markdownParser.parse(text, parsingOptions)));
640
+ }
641
+ return this.files[filePathFromAssets];
642
+ }
643
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationContentService, deps: [{ token: AdkAssetsService }, { token: AdkDocumentationConfigParser }, { token: AdkMarkdownParser }], target: i0.ɵɵFactoryTarget.Injectable }); }
644
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationContentService }); }
645
+ }
646
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationContentService, decorators: [{
647
+ type: Injectable
648
+ }], ctorParameters: () => [{ type: AdkAssetsService }, { type: AdkDocumentationConfigParser }, { type: AdkMarkdownParser }] });
649
+
650
+ class NavigationSiblingsComponent {
651
+ constructor(titleCase) {
652
+ this.titleCase = titleCase;
653
+ this.nextDoc = new EventEmitter();
654
+ }
655
+ ngOnChanges() {
656
+ this.setDisplayNames();
657
+ }
658
+ setDisplayNames() {
659
+ this.previous = this.siblings.previous
660
+ ? this.getDisplayName(this.siblings.previous)
661
+ : undefined;
662
+ this.next = this.siblings.next
663
+ ? this.getDisplayName(this.siblings.next)
664
+ : undefined;
665
+ }
666
+ getDisplayName(path) {
667
+ const paths = path.split('/');
668
+ const end = paths[paths.length - 1];
669
+ const dehyphenated = end.replace(/-/g, ' ');
670
+ return this.titleCase.transform(dehyphenated);
671
+ }
672
+ navigateToDoc(sibling) {
673
+ this.nextDoc.emit(sibling);
674
+ }
675
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NavigationSiblingsComponent, deps: [{ token: i3.TitleCasePipe }], target: i0.ɵɵFactoryTarget.Component }); }
676
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: NavigationSiblingsComponent, isStandalone: true, selector: "hsi-adk-navigation-siblings", inputs: { siblings: "siblings" }, outputs: { nextDoc: "nextDoc" }, providers: [TitleCasePipe], usesOnChanges: true, ngImport: i0, template: "@if (siblings.previous) {\n <div\n class=\"nav-panel previous\"\n role=\"link\"\n tabindex=\"0\"\n (click)=\"navigateToDoc(siblings.previous)\"\n (keydown.enter)=\"navigateToDoc(siblings.previous)\"\n ><p class=\"label\">Previous</p\n ><p class=\"name\"\n ><span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >arrow_back</span\n >{{ previous }}</p\n ></div\n >\n}\n@if (siblings.next) {\n <div\n class=\"nav-panel next\"\n role=\"link\"\n tabindex=\"0\"\n (click)=\"navigateToDoc(siblings.next)\"\n (keydown.enter)=\"navigateToDoc(siblings.next)\"\n ><p class=\"label\">Next</p\n ><p class=\"name\"\n >{{ next }}\n <span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >arrow_forward</span\n ></p\n ></div\n >\n}\n", styles: [":host{display:grid;grid-template-columns:1fr 1fr;grid-template-areas:\"previous next\";gap:1rem}.nav-panel{border:1px solid var(--hsi-adk-color-muted-primary-80);padding:1rem;border-radius:.5rem;cursor:pointer}.nav-panel:hover{background:var(--hsi-adk-color-primary-98);border:1px solid var(--hsi-adk-color-primary-70)}.nav-panel.previous{grid-area:previous}.nav-panel.next{grid-area:next;text-align:right}.nav-panel.next .name,.nav-panel.next .label{justify-content:flex-end}.label{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-medium);font-size:9pt;letter-spacing:.25pt;line-height:12pt;letter-spacing:.8pt;text-transform:uppercase;line-height:1;display:flex;align-items:center}.name{display:flex;align-items:center;position:relative;padding-top:.5rem;color:var(--hsi-adk-color-primary-40)}.arrow{transform:scale(.8);position:relative;top:-1px}.previous .name{left:-6px}.next .name{right:-6px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
677
+ }
678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NavigationSiblingsComponent, decorators: [{
679
+ type: Component,
680
+ args: [{ selector: 'hsi-adk-navigation-siblings', imports: [CommonModule], providers: [TitleCasePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (siblings.previous) {\n <div\n class=\"nav-panel previous\"\n role=\"link\"\n tabindex=\"0\"\n (click)=\"navigateToDoc(siblings.previous)\"\n (keydown.enter)=\"navigateToDoc(siblings.previous)\"\n ><p class=\"label\">Previous</p\n ><p class=\"name\"\n ><span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >arrow_back</span\n >{{ previous }}</p\n ></div\n >\n}\n@if (siblings.next) {\n <div\n class=\"nav-panel next\"\n role=\"link\"\n tabindex=\"0\"\n (click)=\"navigateToDoc(siblings.next)\"\n (keydown.enter)=\"navigateToDoc(siblings.next)\"\n ><p class=\"label\">Next</p\n ><p class=\"name\"\n >{{ next }}\n <span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >arrow_forward</span\n ></p\n ></div\n >\n}\n", styles: [":host{display:grid;grid-template-columns:1fr 1fr;grid-template-areas:\"previous next\";gap:1rem}.nav-panel{border:1px solid var(--hsi-adk-color-muted-primary-80);padding:1rem;border-radius:.5rem;cursor:pointer}.nav-panel:hover{background:var(--hsi-adk-color-primary-98);border:1px solid var(--hsi-adk-color-primary-70)}.nav-panel.previous{grid-area:previous}.nav-panel.next{grid-area:next;text-align:right}.nav-panel.next .name,.nav-panel.next .label{justify-content:flex-end}.label{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-medium);font-size:9pt;letter-spacing:.25pt;line-height:12pt;letter-spacing:.8pt;text-transform:uppercase;line-height:1;display:flex;align-items:center}.name{display:flex;align-items:center;position:relative;padding-top:.5rem;color:var(--hsi-adk-color-primary-40)}.arrow{transform:scale(.8);position:relative;top:-1px}.previous .name{left:-6px}.next .name{right:-6px}\n"] }]
681
+ }], ctorParameters: () => [{ type: i3.TitleCasePipe }], propDecorators: { siblings: [{
682
+ type: Input
683
+ }], nextDoc: [{
684
+ type: Output
685
+ }] } });
686
+
687
+ class AdkDocumentationDisplayComponent {
688
+ constructor(content, activeHeading, destroyRef, zone, document) {
689
+ this.content = content;
690
+ this.activeHeading = activeHeading;
691
+ this.destroyRef = destroyRef;
692
+ this.zone = zone;
693
+ this.document = document;
694
+ this.showPrevNextNavigation = true;
695
+ this.nextDoc = new EventEmitter();
696
+ }
697
+ ngOnInit() {
698
+ this.setContent();
699
+ }
700
+ ngAfterViewInit() {
701
+ this.activeHeading.initScrollListener(this.file.nativeElement, this.destroyRef);
702
+ }
703
+ setContent() {
704
+ this.content$ = this.content.getContentForCurrentContentPath(this.contentPath$, {
705
+ fileConfig: this.fileConfig,
706
+ basePath: this.pathFromAssetsToFile,
707
+ parsingOptions: {
708
+ highlighter: {
709
+ theme: this.highlightTheme,
710
+ },
711
+ },
712
+ });
713
+ }
714
+ scrollToHeading(update) {
715
+ const targetHeading = this.file.nativeElement.querySelector(`#${update.heading.id}`);
716
+ targetHeading.focus();
717
+ this.scrollToItemById(targetHeading, update.event.key === 'Enter');
718
+ }
719
+ scrollToItemById(item, needsChangeDetection = false) {
720
+ this.activeHeading.setActiveHeading(item);
721
+ const currentOffset = item.offsetTop;
722
+ if (needsChangeDetection) {
723
+ this.zone.run(() => {
724
+ this.scrollToItem(currentOffset);
725
+ });
726
+ }
727
+ else {
728
+ this.scrollToItem(currentOffset);
729
+ }
730
+ }
731
+ scrollToItem(top) {
732
+ this.document.getElementsByTagName('HTML')[0].scrollTo({
733
+ top,
734
+ behavior: 'smooth',
735
+ });
736
+ }
737
+ navigateToDoc(sibling) {
738
+ this.nextDoc.emit(sibling);
739
+ }
740
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationDisplayComponent, deps: [{ token: AdkDocumentationContentService }, { token: AdkActiveHeadingTracker }, { token: i0.DestroyRef }, { token: i0.NgZone }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
741
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: AdkDocumentationDisplayComponent, isStandalone: true, selector: "hsi-adk-documentation-display", inputs: { contentPath$: "contentPath$", fileConfig: "fileConfig", highlightTheme: "highlightTheme", pathFromAssetsToFile: "pathFromAssetsToFile", showPrevNextNavigation: "showPrevNextNavigation" }, outputs: { nextDoc: "nextDoc" }, queries: [{ propertyName: "escapedContentTemplateRef", first: true, predicate: ["escapedContent"], descendants: true }], viewQueries: [{ propertyName: "file", first: true, predicate: ["file"], descendants: true }], ngImport: i0, template: "<div class=\"documentation-container\" #file>\n @if (content$ | async; as content) {\n <div class=\"documentation-content\">\n <div class=\"main-content\">\n @for (section of content.sections; track $index) {\n @if (section.type === 'markdown') {\n <div class=\"injected-html\" [innerHTML]=\"section.html\"></div>\n } @else if (section.type === 'escaped') {\n <ng-container\n *ngIf=\"escapedContentTemplateRef\"\n [ngTemplateOutlet]=\"escapedContentTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: section }\"\n >\n </ng-container>\n }\n }\n @if (showPrevNextNavigation) {\n <hsi-adk-navigation-siblings\n class=\"nav-siblings\"\n [siblings]=\"content.siblings\"\n (nextDoc)=\"navigateToDoc($event)\"\n ></hsi-adk-navigation-siblings>\n }\n </div>\n <hsi-adk-document-index\n class=\"document-index\"\n [headings]=\"content.headings.slice(1)\"\n (activeHeading)=\"scrollToHeading($event)\"\n ></hsi-adk-document-index>\n </div>\n }\n</div>\n", styles: [".documentation-container{margin:0 auto;max-width:1200px}.documentation-container .documentation-content{display:flex;gap:7.5rem;margin-top:1.5rem}.documentation-container .document-index{display:block;position:sticky;top:8rem;max-height:calc(100vh - 10rem)}.documentation-container .main-content{width:75%}.documentation-container .nav-siblings{padding-top:2.5rem;padding-bottom:5rem}.documentation-container .injected-html h1{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:32pt;letter-spacing:0;line-height:40pt;margin:0 0 1.75rem;width:100%}.documentation-container .injected-html h2{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:24pt;letter-spacing:0;line-height:32pt}.documentation-container .injected-html h3{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-medium);font-size:14pt;letter-spacing:.25pt;line-height:20pt}.documentation-container .injected-html h2,.documentation-container .injected-html h3,.documentation-container .injected-html h4{margin:0;padding-top:1rem;padding-bottom:1.5rem}.documentation-container .injected-html p{padding-bottom:1.5rem;line-height:1.8}.documentation-container .injected-html ol{margin:0;padding-bottom:1.5rem}.documentation-container .injected-html li>p:not(.code-caption){padding-bottom:1rem}.documentation-container .injected-html pre{margin:0;padding-bottom:1.5rem}.documentation-container .injected-html a{cursor:pointer;color:var(--hsi-adk-color-primary-40)}.documentation-container .injected-html a:hover{text-decoration:underline}.documentation-container .injected-html .shiki{margin:0;padding:1rem;border:1px solid var(--hsi-adk-color-muted-primary-90);border-radius:.5rem;margin-bottom:2rem;white-space:pre-wrap}.documentation-container .injected-html p.code-caption{margin-bottom:0;padding-bottom:0;font-style:italic}.documentation-container .injected-html p.code-caption code{font-style:normal}.documentation-container .injected-html p.code-caption+pre.shiki{display:block;margin-top:2px}.documentation-container .injected-html p:has(>code)+hr{margin:0;border-top:1px solid var(--hsi-adk-color-muted-primary-80);margin-bottom:1.5rem}.documentation-container .injected-html P:has(>code):has(+hr){padding-bottom:.5rem}.documentation-container .injected-html h1>code,.documentation-container .injected-html h2>code,.documentation-container .injected-html h3>code,.documentation-container .injected-html h4>code,.documentation-container .injected-html h5>code,.documentation-container .injected-html h6>code,.documentation-container .injected-html li>code,.documentation-container .injected-html li>em>code,.documentation-container .injected-html p>code p>em>code{font-family:var(--hsi-adk-font-mono);font-weight:500;padding-left:.25rem;padding-right:.25rem;background:var(--hsi-adk-color-muted-primary-95);border-radius:.25rem;color:var(--hsi-adk-color-primary-40);padding:.125rem .25rem}.documentation-container .injected-html p>code,.documentation-container .injected-html p>em>code{font-size:15px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "component", type: AdkDocumentIndexComponent, selector: "hsi-adk-document-index", inputs: ["headings"], outputs: ["activeHeading"] }, { kind: "component", type: NavigationSiblingsComponent, selector: "hsi-adk-navigation-siblings", inputs: ["siblings"], outputs: ["nextDoc"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
742
+ }
743
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: AdkDocumentationDisplayComponent, decorators: [{
744
+ type: Component,
745
+ args: [{ selector: 'hsi-adk-documentation-display', imports: [
746
+ CommonModule,
747
+ AdkDocumentIndexComponent,
748
+ NavigationSiblingsComponent,
749
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"documentation-container\" #file>\n @if (content$ | async; as content) {\n <div class=\"documentation-content\">\n <div class=\"main-content\">\n @for (section of content.sections; track $index) {\n @if (section.type === 'markdown') {\n <div class=\"injected-html\" [innerHTML]=\"section.html\"></div>\n } @else if (section.type === 'escaped') {\n <ng-container\n *ngIf=\"escapedContentTemplateRef\"\n [ngTemplateOutlet]=\"escapedContentTemplateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: section }\"\n >\n </ng-container>\n }\n }\n @if (showPrevNextNavigation) {\n <hsi-adk-navigation-siblings\n class=\"nav-siblings\"\n [siblings]=\"content.siblings\"\n (nextDoc)=\"navigateToDoc($event)\"\n ></hsi-adk-navigation-siblings>\n }\n </div>\n <hsi-adk-document-index\n class=\"document-index\"\n [headings]=\"content.headings.slice(1)\"\n (activeHeading)=\"scrollToHeading($event)\"\n ></hsi-adk-document-index>\n </div>\n }\n</div>\n", styles: [".documentation-container{margin:0 auto;max-width:1200px}.documentation-container .documentation-content{display:flex;gap:7.5rem;margin-top:1.5rem}.documentation-container .document-index{display:block;position:sticky;top:8rem;max-height:calc(100vh - 10rem)}.documentation-container .main-content{width:75%}.documentation-container .nav-siblings{padding-top:2.5rem;padding-bottom:5rem}.documentation-container .injected-html h1{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:32pt;letter-spacing:0;line-height:40pt;margin:0 0 1.75rem;width:100%}.documentation-container .injected-html h2{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-regular);font-size:24pt;letter-spacing:0;line-height:32pt}.documentation-container .injected-html h3{font-family:var(--hsi-adk-font-sans);font-weight:var(--hsi-adk-font-weight-medium);font-size:14pt;letter-spacing:.25pt;line-height:20pt}.documentation-container .injected-html h2,.documentation-container .injected-html h3,.documentation-container .injected-html h4{margin:0;padding-top:1rem;padding-bottom:1.5rem}.documentation-container .injected-html p{padding-bottom:1.5rem;line-height:1.8}.documentation-container .injected-html ol{margin:0;padding-bottom:1.5rem}.documentation-container .injected-html li>p:not(.code-caption){padding-bottom:1rem}.documentation-container .injected-html pre{margin:0;padding-bottom:1.5rem}.documentation-container .injected-html a{cursor:pointer;color:var(--hsi-adk-color-primary-40)}.documentation-container .injected-html a:hover{text-decoration:underline}.documentation-container .injected-html .shiki{margin:0;padding:1rem;border:1px solid var(--hsi-adk-color-muted-primary-90);border-radius:.5rem;margin-bottom:2rem;white-space:pre-wrap}.documentation-container .injected-html p.code-caption{margin-bottom:0;padding-bottom:0;font-style:italic}.documentation-container .injected-html p.code-caption code{font-style:normal}.documentation-container .injected-html p.code-caption+pre.shiki{display:block;margin-top:2px}.documentation-container .injected-html p:has(>code)+hr{margin:0;border-top:1px solid var(--hsi-adk-color-muted-primary-80);margin-bottom:1.5rem}.documentation-container .injected-html P:has(>code):has(+hr){padding-bottom:.5rem}.documentation-container .injected-html h1>code,.documentation-container .injected-html h2>code,.documentation-container .injected-html h3>code,.documentation-container .injected-html h4>code,.documentation-container .injected-html h5>code,.documentation-container .injected-html h6>code,.documentation-container .injected-html li>code,.documentation-container .injected-html li>em>code,.documentation-container .injected-html p>code p>em>code{font-family:var(--hsi-adk-font-mono);font-weight:500;padding-left:.25rem;padding-right:.25rem;background:var(--hsi-adk-color-muted-primary-95);border-radius:.25rem;color:var(--hsi-adk-color-primary-40);padding:.125rem .25rem}.documentation-container .injected-html p>code,.documentation-container .injected-html p>em>code{font-size:15px}\n"] }]
750
+ }], ctorParameters: () => [{ type: AdkDocumentationContentService }, { type: AdkActiveHeadingTracker }, { type: i0.DestroyRef }, { type: i0.NgZone }, { type: Document, decorators: [{
751
+ type: Inject,
752
+ args: [DOCUMENT]
753
+ }] }], propDecorators: { contentPath$: [{
754
+ type: Input
755
+ }], fileConfig: [{
756
+ type: Input
757
+ }], highlightTheme: [{
758
+ type: Input
759
+ }], pathFromAssetsToFile: [{
760
+ type: Input
761
+ }], showPrevNextNavigation: [{
762
+ type: Input
763
+ }], nextDoc: [{
764
+ type: Output
765
+ }], file: [{
766
+ type: ViewChild,
767
+ args: ['file']
768
+ }], escapedContentTemplateRef: [{
769
+ type: ContentChild,
770
+ args: ['escapedContent', { static: false }]
771
+ }] } });
772
+
773
+ /**
774
+ * A utility class for detecting changes to objects in Angular's ngOnChanges lifecycle hook.
775
+ */
776
+ class NgOnChangesUtilities {
777
+ /**
778
+ * Checks if an input object has changed since the first change.
779
+ * @param changes - The SimpleChanges object containing the changes.
780
+ * @param inputName - The name of the input property to check.
781
+ * @param property - Optional specific property to check within the input object.
782
+ * @returns True if the input object has changed since the first change, otherwise false.
783
+ */
784
+ static inputObjectChangedNotFirstTime(changes, inputName, property) {
785
+ return (changes[inputName] !== undefined &&
786
+ !changes[inputName].isFirstChange() &&
787
+ this.inputObjectChanged(changes, inputName, property));
788
+ }
789
+ /**
790
+ * Checks if an input object has changed.
791
+ * @param changes - The SimpleChanges object containing the changes.
792
+ * @param inputName - The name of the input property to check.
793
+ * @param property - Optional specific property to check within the input object.
794
+ * @returns True if the input object has changed, otherwise false.
795
+ */
796
+ static inputObjectChanged(changes, inputName, property) {
797
+ let prevAccessor = `${inputName}.previousValue`;
798
+ let currAccessor = `${inputName}.currentValue`;
799
+ if (property) {
800
+ prevAccessor += `.${property}`;
801
+ currAccessor += `.${property}`;
802
+ }
803
+ return (changes[inputName] !== undefined &&
804
+ !isEqual(get(changes, prevAccessor), get(changes, currAccessor)));
805
+ }
806
+ }
807
+
808
+ /**
809
+ *
810
+ * @param zone: NgZone
811
+ * @returns (source: Observable<T>) => Observable<void>
812
+ *
813
+ * A custom RxJS operator that runs an Angular change detection cycle after the source observable emits, and waits until the change detection cycle is complete before emitting the next value.
814
+ *
815
+ * Note that this is not intended to be used frequently. It is a workaround for cases where you need to ensure that Angular has completed change detection before continuing with the next operation, for example when you need to access a DOM element that is being created through multiple levels of content projection.
816
+ *
817
+ * @example
818
+ * ```ts
819
+ * this.myObservable.pipe(
820
+ * runNgChangeDetectionThen(this.zone),
821
+ * subscribe(() => {
822
+ * console.log('a change detection cycle has completed');
823
+ * })
824
+ * );
825
+ * ```
826
+ */
827
+ function runNgChangeDetectionThen(zone) {
828
+ return function (source) {
829
+ return source.pipe(switchMap(() => new Promise((resolve) => {
830
+ zone.run(() => {
831
+ Promise.resolve().then(() => {
832
+ resolve();
833
+ });
834
+ });
835
+ })));
836
+ };
837
+ }
838
+
839
+ const STYLES_PATH = './lib/styles/_index.scss';
840
+
841
+ /**
842
+ * Generated bundle index. Do not edit.
843
+ */
844
+
845
+ export { AdkActiveHeadingTracker, AdkAssetResponse, AdkAssetsService, AdkDocumentIndexComponent, AdkDocumentationConfigParser, AdkDocumentationContentService, AdkDocumentationDisplayComponent, AdkMarkdownParser, AdkShikiHighlighter, NavigationSiblingsComponent, NgOnChangesUtilities, STYLES_PATH, ShikiTheme, deepMerge, defaultHighlighterLangs, runNgChangeDetectionThen, safeAssign };
846
+ //# sourceMappingURL=mathstack-app-kit.mjs.map