@mathstack/app-kit 1.1.2 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +34 -0
- package/LICENSE +21 -21
- package/README.md +36 -31
- package/ng-package.json +15 -0
- package/package.json +9 -13
- package/project.json +76 -0
- package/src/lib/assets/assets-resource.ts +18 -0
- package/src/lib/assets/assets-service.spec.ts +54 -0
- package/src/lib/assets/assets-service.ts +73 -0
- package/src/lib/assets/index.ts +2 -0
- package/{baseline-styles → src/lib/baseline-styles}/_css-reset.scss +118 -118
- package/{baseline-styles → src/lib/baseline-styles}/_grid.scss +4 -4
- package/{baseline-styles → src/lib/baseline-styles}/_index.scss +6 -6
- package/{baseline-styles → src/lib/baseline-styles}/_sass-utils.scss +23 -23
- package/{baseline-styles → src/lib/baseline-styles}/_themes.scss +19 -19
- package/{baseline-styles → src/lib/baseline-styles}/_typography.scss +232 -232
- package/{baseline-styles → src/lib/baseline-styles}/_webkit-scrollbar.scss +22 -22
- package/{baseline-styles → src/lib/baseline-styles}/theming/_colors.scss +46 -46
- package/{baseline-styles → src/lib/baseline-styles}/theming/_index.scss +2 -2
- package/{baseline-styles → src/lib/baseline-styles}/theming/_typography.scss +32 -32
- package/{lib/content-parsing/index.d.ts → src/lib/content-parsing/index.ts} +2 -2
- package/src/lib/content-parsing/markdown-parser.ts +197 -0
- package/src/lib/content-parsing/shiki-highlighter.ts +219 -0
- package/src/lib/core/scss/_colors.scss +37 -0
- package/src/lib/core/scss/_functions.scss +4 -0
- package/src/lib/core/scss/_placeholders.scss +1 -0
- package/src/lib/core/scss/_vars.scss +15 -0
- package/src/lib/core/testing/stubs/services/assets.resource.stub.ts +3 -0
- package/src/lib/core/testing/stubs/services/main.service.stub.ts +5 -0
- package/src/lib/core/utilities/deep-merge.spec.ts +29 -0
- package/src/lib/core/utilities/deep-merge.ts +21 -0
- package/{lib/core/utilities/index.d.ts → src/lib/core/utilities/index.ts} +2 -2
- package/src/lib/core/utilities/safe-assign.spec.ts +41 -0
- package/{lib/core/utilities/safe-assign.d.ts → src/lib/core/utilities/safe-assign.ts} +42 -18
- package/src/lib/documentation-display/active-heading-tracker.ts +61 -0
- package/src/lib/documentation-display/document-index/document-index.component.html +34 -0
- package/src/lib/documentation-display/document-index/document-index.component.scss +56 -0
- package/src/lib/documentation-display/document-index/document-index.component.spec.ts +0 -0
- package/src/lib/documentation-display/document-index/document-index.component.ts +39 -0
- package/src/lib/documentation-display/documentation-config-parser.ts +92 -0
- package/src/lib/documentation-display/documentation-content-service.ts +118 -0
- package/src/lib/documentation-display/documentation-display.component.html +33 -0
- package/src/lib/documentation-display/documentation-display.component.scss +142 -0
- package/src/lib/documentation-display/documentation-display.component.spec.ts +0 -0
- package/src/lib/documentation-display/documentation-display.component.ts +129 -0
- package/{lib/documentation-display/index.d.ts → src/lib/documentation-display/index.ts} +6 -6
- package/src/lib/documentation-display/navigation-siblings/navigation-siblings.component.html +31 -0
- package/src/lib/documentation-display/navigation-siblings/navigation-siblings.component.scss +68 -0
- package/src/lib/documentation-display/navigation-siblings/navigation-siblings.component.spec.ts +0 -0
- package/src/lib/documentation-display/navigation-siblings/navigation-siblings.component.ts +52 -0
- package/{lib/ng-utilities/index.d.ts → src/lib/ng-utilities/index.ts} +2 -2
- package/src/lib/ng-utilities/ng-on-changes.spec.ts +117 -0
- package/src/lib/ng-utilities/ng-on-changes.ts +50 -0
- package/{lib/ng-utilities/run-ng-change-detection-then.d.ts → src/lib/ng-utilities/run-ng-change-detection-then.ts} +40 -22
- package/{public-api.d.ts → src/public-api.ts} +6 -6
- package/tsconfig.lib.json +16 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +10 -0
- package/fesm2022/mathstack-app-kit.mjs +0 -846
- package/fesm2022/mathstack-app-kit.mjs.map +0 -1
- package/index.d.ts +0 -5
- package/lib/assets/assets-resource.d.ts +0 -11
- package/lib/assets/assets-service.d.ts +0 -35
- package/lib/assets/index.d.ts +0 -1
- package/lib/content-parsing/markdown-parser.d.ts +0 -54
- package/lib/content-parsing/shiki-highlighter.d.ts +0 -77
- package/lib/core/utilities/deep-merge.d.ts +0 -1
- package/lib/documentation-display/active-heading-tracker.d.ts +0 -14
- package/lib/documentation-display/document-index/document-index.component.d.ts +0 -17
- package/lib/documentation-display/documentation-config-parser.d.ts +0 -41
- package/lib/documentation-display/documentation-content-service.d.ts +0 -50
- package/lib/documentation-display/documentation-display.component.d.ts +0 -39
- package/lib/documentation-display/navigation-siblings/navigation-siblings.component.d.ts +0 -18
- package/lib/ng-utilities/ng-on-changes.d.ts +0 -22
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
$primary: (
|
|
2
|
-
0: #000000,
|
|
3
|
-
5: #000c38,
|
|
4
|
-
10: #001550,
|
|
5
|
-
15: #001e68,
|
|
6
|
-
20: #002780,
|
|
7
|
-
25: #003099,
|
|
8
|
-
30: #003ab3,
|
|
9
|
-
35: #0043ce,
|
|
10
|
-
40: #1550e1,
|
|
11
|
-
50: #3d6bfb,
|
|
12
|
-
60: #6889ff,
|
|
13
|
-
70: #90a7ff,
|
|
14
|
-
80: #b6c4ff,
|
|
15
|
-
90: #dce1ff,
|
|
16
|
-
95: #eff0ff,
|
|
17
|
-
98: #faf8ff,
|
|
18
|
-
99: #fefbff,
|
|
19
|
-
100: #ffffff,
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
$muted-primary: (
|
|
23
|
-
0: #000000,
|
|
24
|
-
5: #141821,
|
|
25
|
-
10: #20283c,
|
|
26
|
-
15: #2b3246,
|
|
27
|
-
20: #353c4f,
|
|
28
|
-
25: #404759,
|
|
29
|
-
30: #4c5263,
|
|
30
|
-
35: #575d6e,
|
|
31
|
-
40: #636878,
|
|
32
|
-
50: #7b7f8e,
|
|
33
|
-
60: #9397a4,
|
|
34
|
-
70: #adb0ba,
|
|
35
|
-
80: #c7cad1,
|
|
36
|
-
90: #e1e4e9,
|
|
37
|
-
95: #eff1f5,
|
|
38
|
-
98: #f9f9fb,
|
|
39
|
-
99: #fcfcfd,
|
|
40
|
-
100: #ffffff,
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
$colors: (
|
|
44
|
-
'primary': $primary,
|
|
45
|
-
'muted-primary': $muted-primary,
|
|
46
|
-
);
|
|
1
|
+
$primary: (
|
|
2
|
+
0: #000000,
|
|
3
|
+
5: #000c38,
|
|
4
|
+
10: #001550,
|
|
5
|
+
15: #001e68,
|
|
6
|
+
20: #002780,
|
|
7
|
+
25: #003099,
|
|
8
|
+
30: #003ab3,
|
|
9
|
+
35: #0043ce,
|
|
10
|
+
40: #1550e1,
|
|
11
|
+
50: #3d6bfb,
|
|
12
|
+
60: #6889ff,
|
|
13
|
+
70: #90a7ff,
|
|
14
|
+
80: #b6c4ff,
|
|
15
|
+
90: #dce1ff,
|
|
16
|
+
95: #eff0ff,
|
|
17
|
+
98: #faf8ff,
|
|
18
|
+
99: #fefbff,
|
|
19
|
+
100: #ffffff,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
$muted-primary: (
|
|
23
|
+
0: #000000,
|
|
24
|
+
5: #141821,
|
|
25
|
+
10: #20283c,
|
|
26
|
+
15: #2b3246,
|
|
27
|
+
20: #353c4f,
|
|
28
|
+
25: #404759,
|
|
29
|
+
30: #4c5263,
|
|
30
|
+
35: #575d6e,
|
|
31
|
+
40: #636878,
|
|
32
|
+
50: #7b7f8e,
|
|
33
|
+
60: #9397a4,
|
|
34
|
+
70: #adb0ba,
|
|
35
|
+
80: #c7cad1,
|
|
36
|
+
90: #e1e4e9,
|
|
37
|
+
95: #eff1f5,
|
|
38
|
+
98: #f9f9fb,
|
|
39
|
+
99: #fcfcfd,
|
|
40
|
+
100: #ffffff,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
$colors: (
|
|
44
|
+
'primary': $primary,
|
|
45
|
+
'muted-primary': $muted-primary,
|
|
46
|
+
);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@forward 'colors';
|
|
2
|
-
@forward 'typography';
|
|
1
|
+
@forward 'colors';
|
|
2
|
+
@forward 'typography';
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@100..900&family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Noto+Serif:ital,wght@0,100..900;1,100..900&display=swap');
|
|
2
|
-
|
|
3
|
-
// Fonts
|
|
4
|
-
$font: (
|
|
5
|
-
'sans': (
|
|
6
|
-
'Noto Sans',
|
|
7
|
-
sans-serif,
|
|
8
|
-
),
|
|
9
|
-
'serif': (
|
|
10
|
-
'Noto Serif',
|
|
11
|
-
serif,
|
|
12
|
-
),
|
|
13
|
-
'mono': (
|
|
14
|
-
'Noto Sans Mono',
|
|
15
|
-
monospace,
|
|
16
|
-
),
|
|
17
|
-
'weight': (
|
|
18
|
-
'light': 100,
|
|
19
|
-
'regular': 400,
|
|
20
|
-
'medium': 500,
|
|
21
|
-
'semibold': 600,
|
|
22
|
-
'bold': 700,
|
|
23
|
-
),
|
|
24
|
-
'line-height': (
|
|
25
|
-
0: 1,
|
|
26
|
-
1: 1.125,
|
|
27
|
-
2: 1.25,
|
|
28
|
-
3: 1.5,
|
|
29
|
-
4: 1.75,
|
|
30
|
-
5: 2,
|
|
31
|
-
),
|
|
32
|
-
);
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@100..900&family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Noto+Serif:ital,wght@0,100..900;1,100..900&display=swap');
|
|
2
|
+
|
|
3
|
+
// Fonts
|
|
4
|
+
$font: (
|
|
5
|
+
'sans': (
|
|
6
|
+
'Noto Sans',
|
|
7
|
+
sans-serif,
|
|
8
|
+
),
|
|
9
|
+
'serif': (
|
|
10
|
+
'Noto Serif',
|
|
11
|
+
serif,
|
|
12
|
+
),
|
|
13
|
+
'mono': (
|
|
14
|
+
'Noto Sans Mono',
|
|
15
|
+
monospace,
|
|
16
|
+
),
|
|
17
|
+
'weight': (
|
|
18
|
+
'light': 100,
|
|
19
|
+
'regular': 400,
|
|
20
|
+
'medium': 500,
|
|
21
|
+
'semibold': 600,
|
|
22
|
+
'bold': 700,
|
|
23
|
+
),
|
|
24
|
+
'line-height': (
|
|
25
|
+
0: 1,
|
|
26
|
+
1: 1.125,
|
|
27
|
+
2: 1.25,
|
|
28
|
+
3: 1.5,
|
|
29
|
+
4: 1.75,
|
|
30
|
+
5: 2,
|
|
31
|
+
),
|
|
32
|
+
);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './markdown-parser';
|
|
2
|
-
export * from './shiki-highlighter';
|
|
1
|
+
export * from './markdown-parser';
|
|
2
|
+
export * from './shiki-highlighter';
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { inject, Injectable } from '@angular/core';
|
|
2
|
+
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
|
3
|
+
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
|
|
4
|
+
import rehypeRaw from 'rehype-raw';
|
|
5
|
+
import rehypeSlug from 'rehype-slug';
|
|
6
|
+
import rehypeStringify from 'rehype-stringify';
|
|
7
|
+
import remarkGfm from 'remark-gfm';
|
|
8
|
+
import remarkParse from 'remark-parse';
|
|
9
|
+
import remarkRehype from 'remark-rehype';
|
|
10
|
+
import { forkJoin, from, map, mergeMap, Observable, of, switchMap } from 'rxjs';
|
|
11
|
+
import { BundledLanguage } from 'shiki/langs';
|
|
12
|
+
import { BundledTheme } from 'shiki/themes';
|
|
13
|
+
import { HighlighterGeneric } from 'shiki/types.mjs';
|
|
14
|
+
import { unified } from 'unified';
|
|
15
|
+
import { deepMerge } from '../core/utilities/deep-merge';
|
|
16
|
+
import { AdkShikiHighlighter, ShikiTheme } from './shiki-highlighter';
|
|
17
|
+
|
|
18
|
+
export interface AdkParsedContentSection<Content = string> {
|
|
19
|
+
type: string;
|
|
20
|
+
content: Content;
|
|
21
|
+
html?: SafeHtml;
|
|
22
|
+
headers: { id: string; text: string; level: number }[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface AdkMarkdownParsingOptions {
|
|
26
|
+
highlighter?: AdkShikiHighlighterOptions;
|
|
27
|
+
gfm?: boolean;
|
|
28
|
+
headingIds?: boolean;
|
|
29
|
+
headingFragmentLinks?: AdkHeadingFragmentLinkOptions;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AdkShikiHighlighterOptions {
|
|
33
|
+
highlighter?: HighlighterGeneric<BundledLanguage, BundledTheme>;
|
|
34
|
+
theme?: ShikiTheme;
|
|
35
|
+
type?: 'html' | 'markdown';
|
|
36
|
+
ignoreUnknownLanguage?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AdkHeadingFragmentLinkOptions {
|
|
40
|
+
createLinks?: boolean;
|
|
41
|
+
behavior?: 'append' | 'prepend' | 'wrap' | 'before' | 'after';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const DEFAULT_HIGHLIGHTER_OPTIONS: AdkShikiHighlighterOptions = {
|
|
45
|
+
highlighter: undefined,
|
|
46
|
+
theme: ShikiTheme.GitHubLight,
|
|
47
|
+
type: 'markdown',
|
|
48
|
+
ignoreUnknownLanguage: true,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const DEFAULT_PARSING_OPTIONS: AdkMarkdownParsingOptions = {
|
|
52
|
+
gfm: true,
|
|
53
|
+
headingIds: true,
|
|
54
|
+
headingFragmentLinks: { createLinks: false },
|
|
55
|
+
highlighter: DEFAULT_HIGHLIGHTER_OPTIONS,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
@Injectable()
|
|
59
|
+
export class AdkMarkdownParser {
|
|
60
|
+
parser: typeof unified;
|
|
61
|
+
|
|
62
|
+
private sanitizer = inject(DomSanitizer);
|
|
63
|
+
private shikiHighlighter = inject(AdkShikiHighlighter);
|
|
64
|
+
|
|
65
|
+
constructor() {
|
|
66
|
+
this.parser = unified;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
parse(
|
|
70
|
+
markdown: string,
|
|
71
|
+
options?: AdkMarkdownParsingOptions
|
|
72
|
+
): Observable<AdkParsedContentSection[]> {
|
|
73
|
+
const mergedOptions = deepMerge(DEFAULT_PARSING_OPTIONS, options || {});
|
|
74
|
+
|
|
75
|
+
return of(mergedOptions).pipe(
|
|
76
|
+
mergeMap((_options) => {
|
|
77
|
+
if (_options.highlighter && !_options.highlighter.highlighter) {
|
|
78
|
+
return from(this.shikiHighlighter.getHighlighter()).pipe(
|
|
79
|
+
map((highlighter) => ({
|
|
80
|
+
..._options,
|
|
81
|
+
highlighter: {
|
|
82
|
+
..._options.highlighter,
|
|
83
|
+
highlighter,
|
|
84
|
+
},
|
|
85
|
+
}))
|
|
86
|
+
);
|
|
87
|
+
} else {
|
|
88
|
+
return of(_options);
|
|
89
|
+
}
|
|
90
|
+
}),
|
|
91
|
+
switchMap((_options) => {
|
|
92
|
+
const sections = this.getSections(markdown);
|
|
93
|
+
const parsedSections$ = sections.map((section) => {
|
|
94
|
+
return this.parseSection(section, _options);
|
|
95
|
+
});
|
|
96
|
+
return forkJoin(parsedSections$);
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private getSections(markdown: string): AdkParsedContentSection[] {
|
|
102
|
+
const sections: AdkParsedContentSection[] = [];
|
|
103
|
+
let currentMarkdown = '';
|
|
104
|
+
|
|
105
|
+
const lines = markdown.split('\n');
|
|
106
|
+
|
|
107
|
+
for (const line of lines) {
|
|
108
|
+
currentMarkdown += line + '\n';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Add any remaining markdown
|
|
112
|
+
if (currentMarkdown.trim()) {
|
|
113
|
+
sections.push({
|
|
114
|
+
type: 'markdown',
|
|
115
|
+
content: currentMarkdown,
|
|
116
|
+
html: undefined,
|
|
117
|
+
headers: this.getHeaders(currentMarkdown),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return sections;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private parseSection(
|
|
125
|
+
section: AdkParsedContentSection,
|
|
126
|
+
options: AdkMarkdownParsingOptions
|
|
127
|
+
): Observable<AdkParsedContentSection> {
|
|
128
|
+
const parsedContent$ = from(
|
|
129
|
+
unified()
|
|
130
|
+
.use(remarkParse)
|
|
131
|
+
.use(options.gfm ? remarkGfm : undefined)
|
|
132
|
+
.use(
|
|
133
|
+
options.highlighter && options.highlighter.type === 'markdown'
|
|
134
|
+
? this.shikiHighlighter.remarkHighlight
|
|
135
|
+
: undefined,
|
|
136
|
+
options.highlighter
|
|
137
|
+
)
|
|
138
|
+
.use(remarkRehype, { allowDangerousHtml: true })
|
|
139
|
+
.use(rehypeRaw)
|
|
140
|
+
.use(options.headingIds ? rehypeSlug : undefined)
|
|
141
|
+
.use(
|
|
142
|
+
options.headingFragmentLinks ? rehypeAutolinkHeadings : undefined,
|
|
143
|
+
{ behavior: options.headingFragmentLinks?.behavior }
|
|
144
|
+
)
|
|
145
|
+
.use(rehypeStringify)
|
|
146
|
+
.process(section.content)
|
|
147
|
+
.then((file) => String(file))
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return parsedContent$.pipe(
|
|
151
|
+
map((parsedContent) => {
|
|
152
|
+
const toReturn = {
|
|
153
|
+
...section,
|
|
154
|
+
html: this.sanitizer.bypassSecurityTrustHtml(parsedContent),
|
|
155
|
+
};
|
|
156
|
+
return toReturn;
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getHeaders(markdown: string): { id: string; text: string; level: number }[] {
|
|
162
|
+
const headerRegex =
|
|
163
|
+
/^(#{1,6})\s*(.+)$|<h([1-6])(?:\s+[^>]*)?>(.*?)<\/h[1-6]>/gm;
|
|
164
|
+
const headers: { id: string; text: string; level: number }[] = [];
|
|
165
|
+
let match;
|
|
166
|
+
|
|
167
|
+
while ((match = headerRegex.exec(markdown)) !== null) {
|
|
168
|
+
let level: number;
|
|
169
|
+
let text: string;
|
|
170
|
+
|
|
171
|
+
if (match[1]) {
|
|
172
|
+
// Markdown header, e.g., ## Heading
|
|
173
|
+
level = match[1].length;
|
|
174
|
+
text = match[2].trim();
|
|
175
|
+
} else {
|
|
176
|
+
// HTML header, e.g., <h2>Heading</h2>
|
|
177
|
+
level = parseInt(match[3], 10);
|
|
178
|
+
text = match[4].trim();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const id = text
|
|
182
|
+
.toLowerCase()
|
|
183
|
+
.replace(/\s+/g, '-')
|
|
184
|
+
.replace(/[^\w-]+/g, '');
|
|
185
|
+
headers.push({ id, text, level });
|
|
186
|
+
}
|
|
187
|
+
return headers;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
parseComponent(content: string): { name: string; pathTo: string } {
|
|
191
|
+
const cleanedLine = content.trim().slice(2, -2).trim();
|
|
192
|
+
const [nameKV, pathToKV] = cleanedLine.split(',');
|
|
193
|
+
const name = nameKV.split(':')[1]?.trim();
|
|
194
|
+
const pathTo = pathToKV.split(':')[1]?.trim();
|
|
195
|
+
return { name, pathTo };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { Root } from 'hast';
|
|
3
|
+
import { fromParse5 } from 'hast-util-from-parse5';
|
|
4
|
+
import { parse } from 'parse5';
|
|
5
|
+
import { createHighlighter } from 'shiki/index.mjs';
|
|
6
|
+
import { BundledLanguage } from 'shiki/langs';
|
|
7
|
+
import { BundledTheme } from 'shiki/themes';
|
|
8
|
+
import { HighlighterGeneric } from 'shiki/types.mjs';
|
|
9
|
+
import { visit } from 'unist-util-visit';
|
|
10
|
+
import { AdkShikiHighlighterOptions } from './markdown-parser';
|
|
11
|
+
|
|
12
|
+
export const defaultHighlighterLangs = [
|
|
13
|
+
'json',
|
|
14
|
+
'ts',
|
|
15
|
+
'js',
|
|
16
|
+
'html',
|
|
17
|
+
'css',
|
|
18
|
+
'scss',
|
|
19
|
+
'yaml',
|
|
20
|
+
'angular-html',
|
|
21
|
+
'angular-ts',
|
|
22
|
+
'mermaid',
|
|
23
|
+
'bash',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export enum ShikiTheme {
|
|
27
|
+
Andromeeda = 'andromeeda',
|
|
28
|
+
AuroraX = 'aurora-x',
|
|
29
|
+
AyuDark = 'ayu-dark',
|
|
30
|
+
CatppuccinFrappe = 'catppuccin-frappe',
|
|
31
|
+
CatppuccinLatte = 'catppuccin-latte',
|
|
32
|
+
CatppuccinMacchiato = 'catppuccin-macchiato',
|
|
33
|
+
CatppuccinMocha = 'catppuccin-mocha',
|
|
34
|
+
DarkPlus = 'dark-plus',
|
|
35
|
+
DraculaTheme = 'dracula',
|
|
36
|
+
DraculaThemeSoft = 'dracula-soft',
|
|
37
|
+
EverforestDark = 'everforest-dark',
|
|
38
|
+
EverforestLight = 'everforest-light',
|
|
39
|
+
GitHubDark = 'github-dark',
|
|
40
|
+
GitHubDarkDefault = 'github-dark-default',
|
|
41
|
+
GitHubDarkDimmed = 'github-dark-dimmed',
|
|
42
|
+
GitHubDarkHighContrast = 'github-dark-high-contrast',
|
|
43
|
+
GitHubLight = 'github-light',
|
|
44
|
+
GitHubLightDefault = 'github-light-default',
|
|
45
|
+
GitHubLightHighContrast = 'github-light-high-contrast',
|
|
46
|
+
Houston = 'houston',
|
|
47
|
+
LaserWave = 'laserwave',
|
|
48
|
+
LightPlus = 'light-plus',
|
|
49
|
+
MaterialTheme = 'material-theme',
|
|
50
|
+
MaterialThemeDarker = 'material-theme-darker',
|
|
51
|
+
MaterialThemeLighter = 'material-theme-lighter',
|
|
52
|
+
MaterialThemeOcean = 'material-theme-ocean',
|
|
53
|
+
MaterialThemePalenight = 'material-theme-palenight',
|
|
54
|
+
MinDark = 'min-dark',
|
|
55
|
+
MinLight = 'min-light',
|
|
56
|
+
Monokai = 'monokai',
|
|
57
|
+
NightOwl = 'night-owl',
|
|
58
|
+
Nord = 'nord',
|
|
59
|
+
OneDarkPro = 'one-dark-pro',
|
|
60
|
+
OneLight = 'one-light',
|
|
61
|
+
Plastic = 'plastic',
|
|
62
|
+
Poimandres = 'poimandres',
|
|
63
|
+
Red = 'red',
|
|
64
|
+
RosePine = 'rose-pine',
|
|
65
|
+
RosePineDawn = 'rose-pine-dawn',
|
|
66
|
+
RosePineMoon = 'rose-pine-moon',
|
|
67
|
+
SlackDark = 'slack-dark',
|
|
68
|
+
SlackOchin = 'slack-ochin',
|
|
69
|
+
SnazzyLight = 'snazzy-light',
|
|
70
|
+
SolarizedDark = 'solarized-dark',
|
|
71
|
+
SolarizedLight = 'solarized-light',
|
|
72
|
+
Synthwave84 = 'synthwave-84',
|
|
73
|
+
TokyoNight = 'tokyo-night',
|
|
74
|
+
Vesper = 'vesper',
|
|
75
|
+
VitesseBlack = 'vitesse-black',
|
|
76
|
+
VitesseDark = 'vitesse-dark',
|
|
77
|
+
VitesseLight = 'vitesse-light',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const MISSING_HIGHLIGHTER = `Please provide a \`shiki\` highlighter instance via \`options\`.`;
|
|
81
|
+
|
|
82
|
+
@Injectable({
|
|
83
|
+
providedIn: 'root',
|
|
84
|
+
})
|
|
85
|
+
export class AdkShikiHighlighter {
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
private highlighterPromise: Promise<
|
|
88
|
+
HighlighterGeneric<BundledLanguage, BundledTheme>
|
|
89
|
+
> | null = null;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Initialize the highlighter. This should only be called one in an application.
|
|
93
|
+
*
|
|
94
|
+
* @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.
|
|
95
|
+
*
|
|
96
|
+
* @returns void
|
|
97
|
+
*/
|
|
98
|
+
async initialize(
|
|
99
|
+
themes: ShikiTheme[],
|
|
100
|
+
langs: string[] = defaultHighlighterLangs
|
|
101
|
+
): Promise<void> {
|
|
102
|
+
if (!this.highlighterPromise) {
|
|
103
|
+
this.highlighterPromise = createHighlighter({
|
|
104
|
+
langs,
|
|
105
|
+
themes: themes.length ? themes : [ShikiTheme.GitHubLight],
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
await this.highlighterPromise;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async getHighlighter(): Promise<
|
|
112
|
+
HighlighterGeneric<BundledLanguage, BundledTheme>
|
|
113
|
+
> {
|
|
114
|
+
if (!this.highlighterPromise) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
'Highlighter is not initialized. Please call initialize() once in your application first.'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return this.highlighterPromise;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
remarkHighlight(options: AdkShikiHighlighterOptions): (tree: Root) => void {
|
|
123
|
+
const highlighter = options.highlighter;
|
|
124
|
+
if (!options.highlighter) {
|
|
125
|
+
throw new Error(MISSING_HIGHLIGHTER);
|
|
126
|
+
}
|
|
127
|
+
const loadedLanguages = highlighter.getLoadedLanguages();
|
|
128
|
+
const ignoreUnknownLanguage =
|
|
129
|
+
options.ignoreUnknownLanguage === undefined
|
|
130
|
+
? true
|
|
131
|
+
: options.ignoreUnknownLanguage;
|
|
132
|
+
|
|
133
|
+
const visitor = (node) => {
|
|
134
|
+
if (!loadedLanguages.includes(node.lang)) {
|
|
135
|
+
if (ignoreUnknownLanguage) {
|
|
136
|
+
node.lang = null;
|
|
137
|
+
} else {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const highlighted = highlighter.codeToHtml(node.value, {
|
|
143
|
+
lang: node.lang,
|
|
144
|
+
theme: options.theme,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
node.type = 'html';
|
|
148
|
+
node.value = highlighted;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const transformer = (tree: Root) => {
|
|
152
|
+
visit(tree, 'code', visitor);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return transformer;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
rehypeHighlight(options: AdkShikiHighlighterOptions): (tree: Root) => void {
|
|
159
|
+
const highlighter = options.highlighter;
|
|
160
|
+
if (!options.highlighter) {
|
|
161
|
+
throw new Error(MISSING_HIGHLIGHTER);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const visitor = (node, _index, parent) => {
|
|
165
|
+
if (!parent || parent.tagName !== 'pre' || node.tagName !== 'code') {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const [langClass] = node.properties.className;
|
|
170
|
+
const lang = langClass.replace('language-', '');
|
|
171
|
+
|
|
172
|
+
if (highlighter.getLoadedLanguages().includes(lang)) {
|
|
173
|
+
const code = node.children[0]?.value;
|
|
174
|
+
if (!code) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const highlighted = highlighter.codeToHtml(code, {
|
|
178
|
+
lang,
|
|
179
|
+
theme: options.theme,
|
|
180
|
+
});
|
|
181
|
+
const parsed = parse(highlighted);
|
|
182
|
+
const hastTree = fromParse5(parsed);
|
|
183
|
+
|
|
184
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
+
const content = (hastTree as any).children[0].children[1].children[0]
|
|
186
|
+
.children[0];
|
|
187
|
+
|
|
188
|
+
content.properties.class = ['shiki', 'shiki-' + lang, langClass];
|
|
189
|
+
|
|
190
|
+
node.properties = content.properties;
|
|
191
|
+
node.children = content.children;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const transformer = (tree: Root) => {
|
|
196
|
+
visit(tree, 'element', visitor);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return transformer;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getLanguage(node): string {
|
|
203
|
+
const dataLanguage = node.properties.dataLanguage;
|
|
204
|
+
|
|
205
|
+
if (dataLanguage != null) {
|
|
206
|
+
return dataLanguage;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const className = node.properties.className || [];
|
|
210
|
+
|
|
211
|
+
for (const classListItem of className) {
|
|
212
|
+
if (classListItem.slice(0, 9) === 'language-') {
|
|
213
|
+
return classListItem.slice(9).toLowerCase();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
$primary-0: var(--hsi-adk-color-primary-0);
|
|
2
|
+
$primary-5: var(--hsi-adk-color-primary-5);
|
|
3
|
+
$primary-10: var(--hsi-adk-color-primary-10);
|
|
4
|
+
$primary-15: var(--hsi-adk-color-primary-15);
|
|
5
|
+
$primary-20: var(--hsi-adk-color-primary-20);
|
|
6
|
+
$primary-25: var(--hsi-adk-color-primary-25);
|
|
7
|
+
$primary-30: var(--hsi-adk-color-primary-30);
|
|
8
|
+
$primary-35: var(--hsi-adk-color-primary-35);
|
|
9
|
+
$primary-40: var(--hsi-adk-color-primary-40);
|
|
10
|
+
$primary-50: var(--hsi-adk-color-primary-50);
|
|
11
|
+
$primary-60: var(--hsi-adk-color-primary-60);
|
|
12
|
+
$primary-70: var(--hsi-adk-color-primary-70);
|
|
13
|
+
$primary-80: var(--hsi-adk-color-primary-80);
|
|
14
|
+
$primary-90: var(--hsi-adk-color-primary-90);
|
|
15
|
+
$primary-95: var(--hsi-adk-color-primary-95);
|
|
16
|
+
$primary-98: var(--hsi-adk-color-primary-98);
|
|
17
|
+
$primary-99: var(--hsi-adk-color-primary-99);
|
|
18
|
+
$primary-100: var(--hsi-adk-color-primary-100);
|
|
19
|
+
|
|
20
|
+
$muted-primary-0: var(--hsi-adk-color-muted-primary-0);
|
|
21
|
+
$muted-primary-5: var(--hsi-adk-color-muted-primary-5);
|
|
22
|
+
$muted-primary-10: var(--hsi-adk-color-muted-primary-10);
|
|
23
|
+
$muted-primary-15: var(--hsi-adk-color-muted-primary-15);
|
|
24
|
+
$muted-primary-20: var(--hsi-adk-color-muted-primary-20);
|
|
25
|
+
$muted-primary-25: var(--hsi-adk-color-muted-primary-25);
|
|
26
|
+
$muted-primary-30: var(--hsi-adk-color-muted-primary-30);
|
|
27
|
+
$muted-primary-35: var(--hsi-adk-color-muted-primary-35);
|
|
28
|
+
$muted-primary-40: var(--hsi-adk-color-muted-primary-40);
|
|
29
|
+
$muted-primary-50: var(--hsi-adk-color-muted-primary-50);
|
|
30
|
+
$muted-primary-60: var(--hsi-adk-color-muted-primary-60);
|
|
31
|
+
$muted-primary-70: var(--hsi-adk-color-muted-primary-70);
|
|
32
|
+
$muted-primary-80: var(--hsi-adk-color-muted-primary-80);
|
|
33
|
+
$muted-primary-90: var(--hsi-adk-color-muted-primary-90);
|
|
34
|
+
$muted-primary-95: var(--hsi-adk-color-muted-primary-95);
|
|
35
|
+
$muted-primary-98: var(--hsi-adk-color-muted-primary-98);
|
|
36
|
+
$muted-primary-99: var(--hsi-adk-color-muted-primary-99);
|
|
37
|
+
$muted-primary-100: var(--hsi-adk-color-muted-primary-100);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@forward '../../baseline-styles/typography';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
$font-sans: var(--hsi-adk-font-sans);
|
|
2
|
+
$font-serif: var(--hsi-adk-font-serif);
|
|
3
|
+
$font-mono: var(--hsi-adk-font-mono);
|
|
4
|
+
$font-weight-light: var(--hsi-adk-font-weight-light);
|
|
5
|
+
$font-weight-regular: var(--hsi-adk-font-weight-regular);
|
|
6
|
+
$font-weight-medium: var(--hsi-adk-font-weight-medium);
|
|
7
|
+
$font-weight-semibold: var(--hsi-adk-font-weight-semibold);
|
|
8
|
+
$font-weight-bold: var(--hsi-adk-font-weight-bold);
|
|
9
|
+
$font-weight-black: var(--hsi-adk-font-weight-black);
|
|
10
|
+
$font-line-height-0: var(--hsi-adk-font-line-height-0);
|
|
11
|
+
$font-line-height-1: var(--hsi-adk-font-line-height-1);
|
|
12
|
+
$font-line-height-2: var(--hsi-adk-font-line-height-2);
|
|
13
|
+
$font-line-height-3: var(--hsi-adk-font-line-height-3);
|
|
14
|
+
$font-line-height-4: var(--hsi-adk-font-line-height-4);
|
|
15
|
+
$font-line-height-5: var(--hsi-adk-font-line-height-5);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { deepMerge } from './deep-merge';
|
|
2
|
+
|
|
3
|
+
describe('deepMerge', () => {
|
|
4
|
+
it('should merge two objects without the source overwriting undefined properties on the target', () => {
|
|
5
|
+
const target = {
|
|
6
|
+
a: 1,
|
|
7
|
+
b: 2,
|
|
8
|
+
c: {
|
|
9
|
+
d: 3,
|
|
10
|
+
e: 4,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
const source = {
|
|
14
|
+
b: 5,
|
|
15
|
+
c: {
|
|
16
|
+
e: 6,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const result = deepMerge(target, source as unknown);
|
|
20
|
+
expect(result).toEqual({
|
|
21
|
+
a: 1,
|
|
22
|
+
b: 5,
|
|
23
|
+
c: {
|
|
24
|
+
d: 3,
|
|
25
|
+
e: 6,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|