@cocoar/markdown-viewer 0.1.0-beta.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # @cocoar/markdown-viewer
2
+
3
+ Angular Markdown viewer for Cocoar.
4
+
5
+ ## Usage
6
+
7
+ This component renders a pre-parsed document:
8
+
9
+ ```ts
10
+ import { Component } from '@angular/core';
11
+ import { CoarMarkdownComponent } from '@cocoar/markdown-viewer';
12
+ import { parse, type MarkdownDocument } from '@cocoar/markdown-core';
13
+
14
+ @Component({
15
+ standalone: true,
16
+ imports: [CoarMarkdownComponent],
17
+ template: `<coar-markdown [doc]="doc" />`,
18
+ })
19
+ export class ExampleComponent {
20
+ doc: MarkdownDocument = parse('Hello **world**');
21
+ }
22
+ ```
23
+
24
+ Link rendering opens external `http(s)` links in a new tab with `rel="noopener noreferrer"`.
25
+ In-document anchors (e.g. `#overview`) and other non-external links do not force a new tab.
26
+
27
+ ## Nx targets
28
+
29
+ - `nx test markdown-viewer`
30
+ - `nx build markdown-viewer`
@@ -0,0 +1,132 @@
1
+ import * as i1 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { input, ChangeDetectionStrategy, Component } from '@angular/core';
5
+ import { CoarCodeBlockComponent, CoarTableComponent } from '@cocoar/ui-components';
6
+
7
+ class CoarMarkdownComponent {
8
+ doc = input.required(...(ngDevMode ? [{ debugName: "doc" }] : []));
9
+ codeBlockLanguage(node) {
10
+ const language = node.attrs?.['language'];
11
+ return typeof language === 'string' && language.trim().length > 0 ? language.trim() : 'text';
12
+ }
13
+ headingAnchor(node) {
14
+ const anchor = node.attrs?.['anchor'];
15
+ return typeof anchor === 'string' && anchor.length > 0 ? anchor : null;
16
+ }
17
+ headingDepth(node) {
18
+ const depth = node.attrs?.['depth'];
19
+ if (typeof depth !== 'number')
20
+ return 1;
21
+ const value = Math.trunc(depth);
22
+ if (value <= 1)
23
+ return 1;
24
+ if (value === 2)
25
+ return 2;
26
+ if (value === 3)
27
+ return 3;
28
+ if (value === 4)
29
+ return 4;
30
+ if (value === 5)
31
+ return 5;
32
+ return 6;
33
+ }
34
+ isOrderedList(node) {
35
+ return Boolean(node.attrs?.['ordered']);
36
+ }
37
+ listStart(node) {
38
+ const start = node.attrs?.['start'];
39
+ return typeof start === 'number' ? start : null;
40
+ }
41
+ isTaskListItem(node) {
42
+ return typeof node.attrs?.['checked'] === 'boolean';
43
+ }
44
+ taskChecked(node) {
45
+ return node.attrs?.['checked'] === true;
46
+ }
47
+ linkUrl(node) {
48
+ const url = node.attrs?.['url'];
49
+ return typeof url === 'string' && url.length > 0 ? url : null;
50
+ }
51
+ linkHref(node) {
52
+ const url = this.linkUrl(node);
53
+ if (!url)
54
+ return null;
55
+ // With <base href="/">, fragment-only hrefs resolve to the app root (e.g. /#overview),
56
+ // which can navigate away from the current route. Keep anchors on the current page.
57
+ if (url.startsWith('#') && typeof window !== 'undefined') {
58
+ return `${window.location.pathname}${window.location.search}${url}`;
59
+ }
60
+ return url;
61
+ }
62
+ linkTarget(node) {
63
+ const url = this.linkUrl(node);
64
+ if (!url)
65
+ return null;
66
+ return this.isExternalLink(url) ? '_blank' : null;
67
+ }
68
+ linkRel(node) {
69
+ const url = this.linkUrl(node);
70
+ if (!url)
71
+ return null;
72
+ return this.isExternalLink(url) ? 'noopener noreferrer' : null;
73
+ }
74
+ imageSrc(node) {
75
+ const url = node.attrs?.['url'];
76
+ return typeof url === 'string' && url.trim().length > 0 ? url.trim() : null;
77
+ }
78
+ imageAlt(node) {
79
+ const alt = node.attrs?.['alt'];
80
+ return typeof alt === 'string' ? alt : '';
81
+ }
82
+ imageTitle(node) {
83
+ const title = node.attrs?.['title'];
84
+ return typeof title === 'string' && title.trim().length > 0 ? title.trim() : null;
85
+ }
86
+ isTableColumnRightAligned(tableNode, columnIndex) {
87
+ return this.getTableColumnAlign(tableNode, columnIndex) === 'right';
88
+ }
89
+ isTableColumnCenterAligned(tableNode, columnIndex) {
90
+ return this.getTableColumnAlign(tableNode, columnIndex) === 'center';
91
+ }
92
+ getTableColumnAlign(tableNode, columnIndex) {
93
+ const align = tableNode.attrs?.['align'];
94
+ if (!Array.isArray(align))
95
+ return null;
96
+ const value = align[columnIndex];
97
+ if (value === 'left' || value === 'right' || value === 'center')
98
+ return value;
99
+ return null;
100
+ }
101
+ isExternalLink(url) {
102
+ const trimmed = url.trim();
103
+ if (trimmed.startsWith('#'))
104
+ return false;
105
+ if (trimmed.startsWith('/'))
106
+ return false;
107
+ if (trimmed.startsWith('./') || trimmed.startsWith('../'))
108
+ return false;
109
+ if (trimmed.startsWith('mailto:'))
110
+ return false;
111
+ if (trimmed.startsWith('tel:'))
112
+ return false;
113
+ return trimmed.startsWith('http://') || trimmed.startsWith('https://');
114
+ }
115
+ unsupportedType(node) {
116
+ const originalType = node.attrs?.['originalType'];
117
+ return typeof originalType === 'string' ? originalType : String(node.type);
118
+ }
119
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoarMarkdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
120
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CoarMarkdownComponent, isStandalone: true, selector: "coar-markdown", inputs: { doc: { classPropertyName: "doc", publicName: "doc", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"coar-markdown\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: doc().nodes }\"\n ></ng-container>\n</div>\n\n<ng-template #blockNodesTpl let-nodes>\n @for (node of nodes; track node.id) {\n @switch (node.type) {\n @case ('heading') {\n @switch (headingDepth(node)) {\n @case (1) {\n <h1 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h1>\n }\n @case (2) {\n <h2 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h2>\n }\n @case (3) {\n <h3 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h3>\n }\n @case (4) {\n <h4 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h4>\n }\n @case (5) {\n <h5 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h5>\n }\n @default {\n <h6 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h6>\n }\n }\n }\n @case ('paragraph') {\n <p class=\"coar-markdown-paragraph\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </p>\n }\n @case ('blockquote') {\n <blockquote class=\"coar-markdown-blockquote\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </blockquote>\n }\n @case ('list') {\n @if (isOrderedList(node)) {\n <ol\n class=\"coar-markdown-list coar-markdown-list--ordered\"\n [attr.start]=\"listStart(node)\"\n >\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </ol>\n } @else {\n <ul class=\"coar-markdown-list coar-markdown-list--unordered\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </ul>\n }\n }\n @case ('listItem') {\n <li\n class=\"coar-markdown-list-item\"\n [class.coar-markdown-list-item--task]=\"isTaskListItem(node)\"\n >\n @if (isTaskListItem(node)) {\n <input\n class=\"coar-markdown-task-checkbox\"\n type=\"checkbox\"\n [checked]=\"taskChecked(node)\"\n disabled\n aria-hidden=\"true\"\n tabindex=\"-1\"\n />\n }\n <div class=\"coar-markdown-list-item-content\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </div>\n </li>\n }\n @case ('codeBlock') {\n <coar-code-block\n class=\"coar-markdown-code-block\"\n [code]=\"node.text ?? ''\"\n [language]=\"codeBlockLanguage(node)\"\n [collapsible]=\"false\"\n [showCopy]=\"true\"\n />\n }\n @case ('thematicBreak') {\n <hr class=\"coar-markdown-hr\" />\n }\n @case ('table') {\n <coar-table variant=\"plain\" hover>\n @if ((node.children ?? []).length > 0) {\n <thead>\n <tr>\n @for (cell of ((node.children ?? [])[0]?.children ?? []); track cell.id; let colIndex = $index) {\n <th\n [class.text-right]=\"isTableColumnRightAligned(node, colIndex)\"\n [class.text-center]=\"isTableColumnCenterAligned(node, colIndex)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: cell.children ?? [] }\"\n ></ng-container>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of (node.children ?? []).slice(1); track row.id) {\n <tr>\n @for (cell of (row.children ?? []); track cell.id; let colIndex = $index) {\n <td\n [class.text-right]=\"isTableColumnRightAligned(node, colIndex)\"\n [class.text-center]=\"isTableColumnCenterAligned(node, colIndex)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: cell.children ?? [] }\"\n ></ng-container>\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </coar-table>\n }\n @case ('tableRow') {\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n }\n @case ('tableCell') {\n <td class=\"coar-markdown-table-cell\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </td>\n }\n @case ('unsupported') {\n <div class=\"coar-markdown-unsupported\">\n Unsupported markdown node: {{ unsupportedType(node) }}\n </div>\n }\n @default {\n <div class=\"coar-markdown-unsupported\">\n Unsupported markdown node: {{ unsupportedType(node) }}\n </div>\n }\n }\n }\n</ng-template>\n\n<ng-template #inlineNodesTpl let-nodes>\n @for (node of nodes; track node.id) {\n @switch (node.type) {\n @case ('text') {\n {{ node.text ?? '' }}\n }\n @case ('emphasis') {\n <em>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </em>\n }\n @case ('strong') {\n <strong>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </strong>\n }\n @case ('strikethrough') {\n <del>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </del>\n }\n @case ('inlineCode') {\n <code class=\"coar-markdown-inline-code\">{{ node.text ?? '' }}</code>\n }\n @case ('lineBreak') {\n <br />\n }\n @case ('link') {\n @if (linkHref(node)) {\n <a\n class=\"coar-markdown-link\"\n [href]=\"linkHref(node)\"\n [attr.target]=\"linkTarget(node)\"\n [attr.rel]=\"linkRel(node)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </a>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n }\n }\n @case ('image') {\n @if (imageSrc(node)) {\n <img\n class=\"coar-markdown-image\"\n [src]=\"imageSrc(node)\"\n [attr.alt]=\"imageAlt(node)\"\n [attr.title]=\"imageTitle(node)\"\n loading=\"lazy\"\n />\n }\n }\n @default {\n <span class=\"coar-markdown-unsupported-inline\">[unsupported]</span>\n }\n }\n }\n</ng-template>\n", styles: [":host{display:block;--coar-markdown-text: var(--coar-text-neutral-primary);--coar-markdown-link: var(--coar-text-brand-primary, var(--coar-text-neutral-primary));--coar-markdown-muted-text: var(--coar-text-neutral-tertiary);--coar-markdown-border: var(--coar-border-neutral-tertiary);--coar-markdown-surface: var(--coar-background-neutral-primary);--coar-markdown-surface-muted: var( --coar-background-neutral-tertiary, var(--coar-background-neutral-primary) );--coar-markdown-radius: var(--coar-radius-xs);--coar-markdown-space-1: var(--coar-spacing-s, .5rem);--coar-markdown-space-2: var(--coar-spacing-m, 1rem);--coar-markdown-heading-block-start: var(--coar-spacing-xxxl, 4rem)}.coar-markdown{display:block;color:var(--coar-markdown-text)}.coar-markdown :where(h1,h2,h3,h4,h5,h6){font-family:var(--coar-font-family-title, inherit);color:var(--coar-markdown-text)}.coar-markdown h1{font-size:var(--coar-font-size-xl);font-weight:var(--coar-font-weight-bold);line-height:1.2}.coar-markdown h2{font-size:var(--coar-font-size-l);font-weight:var(--coar-font-weight-bold);line-height:1.25}.coar-markdown h3{font-size:var(--coar-font-size-m);font-weight:var(--coar-font-weight-semi-bold);line-height:1.3}.coar-markdown h4{font-size:var(--coar-font-size-s);font-weight:var(--coar-font-weight-semi-bold);line-height:1.35}.coar-markdown h5{font-size:var(--coar-font-size-xs);font-weight:var(--coar-font-weight-semi-bold);line-height:1.4}.coar-markdown h6{font-size:var(--coar-font-size-xxs);font-weight:var(--coar-font-weight-medium);line-height:1.45}.coar-markdown-heading,.coar-markdown-paragraph,.coar-markdown-blockquote,.coar-markdown-list,.coar-markdown-code-block,.coar-markdown-table,.coar-markdown-hr{margin:0}.coar-markdown>:where(h1,h2,h3,h4,h5,h6,p,blockquote,ul,ol,pre,table,hr,coar-code-block,coar-table){margin-block:0 var(--coar-markdown-space-2)}.coar-markdown>:where(h1,h2,h3,h4,h5,h6){margin-block-start:var(--coar-markdown-heading-block-start)}.coar-markdown>:where(h1,h2,h3,h4,h5,h6)+:where(h1,h2,h3,h4,h5,h6){margin-block-start:var(--coar-markdown-space-1)}.coar-markdown>:where(h1,h2,h3,h4,h5,h6):first-child{margin-block-start:0}.coar-markdown-blockquote{padding-inline:var(--coar-markdown-space-2);border-left:2px solid var(--coar-markdown-border)}.coar-markdown-list{padding-inline-start:var(--coar-spacing-l, 1.5rem);list-style-position:outside}.coar-markdown-list--unordered{list-style-type:disc}.coar-markdown-list--ordered{list-style-type:decimal}.coar-markdown-list-item{display:list-item;margin-block:.25em}.coar-markdown-list-item--task{list-style:none;display:flex;align-items:flex-start;gap:var(--coar-spacing-s, .5rem)}.coar-markdown-list-item-content{min-width:0}.coar-markdown-task-checkbox{margin-top:.15em}.coar-markdown-code-block,.coar-markdown-code{display:block}.coar-markdown-inline-code{padding:0;border:0;border-radius:0;background:transparent;color:var(--coar-text-accent-secondary, var(--coar-markdown-link))}.coar-markdown-link{text-decoration:underline;color:var(--coar-markdown-link)}.coar-markdown-image{max-width:100%;height:auto;vertical-align:middle}.coar-markdown-table{width:100%;border:1px solid var(--coar-markdown-border);border-radius:var(--coar-markdown-radius);border-collapse:separate;border-spacing:0;overflow:hidden}.coar-markdown-table-cell{padding:var(--coar-markdown-space-1);vertical-align:top;border-right:1px solid var(--coar-markdown-border);border-bottom:1px solid var(--coar-markdown-border)}.coar-markdown-table :where(tr) .coar-markdown-table-cell:last-child{border-right:0}.coar-markdown-table :where(tbody) tr:last-child .coar-markdown-table-cell{border-bottom:0}.coar-markdown-table :where(thead) .coar-markdown-table-cell{background:var(--coar-markdown-surface-muted);font-weight:600}.coar-markdown-hr{border:0;border-top:1px solid var(--coar-markdown-border)}.coar-markdown-unsupported,.coar-markdown-unsupported-inline{font-style:italic;color:var(--coar-markdown-muted-text)}.coar-markdown-unsupported{padding:var(--coar-markdown-space-1);border:1px dashed var(--coar-markdown-border);border-radius:var(--coar-markdown-radius);background:var(--coar-markdown-surface)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CoarCodeBlockComponent, selector: "coar-code-block", inputs: ["code", "language", "title", "collapsible", "collapsed", "showCopy", "showLineNumbers", "maxHeight"] }, { kind: "component", type: CoarTableComponent, selector: "coar-table", inputs: ["variant", "compact", "hover"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
121
+ }
122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoarMarkdownComponent, decorators: [{
123
+ type: Component,
124
+ args: [{ selector: 'coar-markdown', standalone: true, imports: [CommonModule, CoarCodeBlockComponent, CoarTableComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"coar-markdown\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: doc().nodes }\"\n ></ng-container>\n</div>\n\n<ng-template #blockNodesTpl let-nodes>\n @for (node of nodes; track node.id) {\n @switch (node.type) {\n @case ('heading') {\n @switch (headingDepth(node)) {\n @case (1) {\n <h1 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h1>\n }\n @case (2) {\n <h2 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h2>\n }\n @case (3) {\n <h3 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h3>\n }\n @case (4) {\n <h4 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h4>\n }\n @case (5) {\n <h5 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h5>\n }\n @default {\n <h6 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h6>\n }\n }\n }\n @case ('paragraph') {\n <p class=\"coar-markdown-paragraph\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </p>\n }\n @case ('blockquote') {\n <blockquote class=\"coar-markdown-blockquote\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </blockquote>\n }\n @case ('list') {\n @if (isOrderedList(node)) {\n <ol\n class=\"coar-markdown-list coar-markdown-list--ordered\"\n [attr.start]=\"listStart(node)\"\n >\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </ol>\n } @else {\n <ul class=\"coar-markdown-list coar-markdown-list--unordered\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </ul>\n }\n }\n @case ('listItem') {\n <li\n class=\"coar-markdown-list-item\"\n [class.coar-markdown-list-item--task]=\"isTaskListItem(node)\"\n >\n @if (isTaskListItem(node)) {\n <input\n class=\"coar-markdown-task-checkbox\"\n type=\"checkbox\"\n [checked]=\"taskChecked(node)\"\n disabled\n aria-hidden=\"true\"\n tabindex=\"-1\"\n />\n }\n <div class=\"coar-markdown-list-item-content\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </div>\n </li>\n }\n @case ('codeBlock') {\n <coar-code-block\n class=\"coar-markdown-code-block\"\n [code]=\"node.text ?? ''\"\n [language]=\"codeBlockLanguage(node)\"\n [collapsible]=\"false\"\n [showCopy]=\"true\"\n />\n }\n @case ('thematicBreak') {\n <hr class=\"coar-markdown-hr\" />\n }\n @case ('table') {\n <coar-table variant=\"plain\" hover>\n @if ((node.children ?? []).length > 0) {\n <thead>\n <tr>\n @for (cell of ((node.children ?? [])[0]?.children ?? []); track cell.id; let colIndex = $index) {\n <th\n [class.text-right]=\"isTableColumnRightAligned(node, colIndex)\"\n [class.text-center]=\"isTableColumnCenterAligned(node, colIndex)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: cell.children ?? [] }\"\n ></ng-container>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of (node.children ?? []).slice(1); track row.id) {\n <tr>\n @for (cell of (row.children ?? []); track cell.id; let colIndex = $index) {\n <td\n [class.text-right]=\"isTableColumnRightAligned(node, colIndex)\"\n [class.text-center]=\"isTableColumnCenterAligned(node, colIndex)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: cell.children ?? [] }\"\n ></ng-container>\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </coar-table>\n }\n @case ('tableRow') {\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n }\n @case ('tableCell') {\n <td class=\"coar-markdown-table-cell\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </td>\n }\n @case ('unsupported') {\n <div class=\"coar-markdown-unsupported\">\n Unsupported markdown node: {{ unsupportedType(node) }}\n </div>\n }\n @default {\n <div class=\"coar-markdown-unsupported\">\n Unsupported markdown node: {{ unsupportedType(node) }}\n </div>\n }\n }\n }\n</ng-template>\n\n<ng-template #inlineNodesTpl let-nodes>\n @for (node of nodes; track node.id) {\n @switch (node.type) {\n @case ('text') {\n {{ node.text ?? '' }}\n }\n @case ('emphasis') {\n <em>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </em>\n }\n @case ('strong') {\n <strong>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </strong>\n }\n @case ('strikethrough') {\n <del>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </del>\n }\n @case ('inlineCode') {\n <code class=\"coar-markdown-inline-code\">{{ node.text ?? '' }}</code>\n }\n @case ('lineBreak') {\n <br />\n }\n @case ('link') {\n @if (linkHref(node)) {\n <a\n class=\"coar-markdown-link\"\n [href]=\"linkHref(node)\"\n [attr.target]=\"linkTarget(node)\"\n [attr.rel]=\"linkRel(node)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </a>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n }\n }\n @case ('image') {\n @if (imageSrc(node)) {\n <img\n class=\"coar-markdown-image\"\n [src]=\"imageSrc(node)\"\n [attr.alt]=\"imageAlt(node)\"\n [attr.title]=\"imageTitle(node)\"\n loading=\"lazy\"\n />\n }\n }\n @default {\n <span class=\"coar-markdown-unsupported-inline\">[unsupported]</span>\n }\n }\n }\n</ng-template>\n", styles: [":host{display:block;--coar-markdown-text: var(--coar-text-neutral-primary);--coar-markdown-link: var(--coar-text-brand-primary, var(--coar-text-neutral-primary));--coar-markdown-muted-text: var(--coar-text-neutral-tertiary);--coar-markdown-border: var(--coar-border-neutral-tertiary);--coar-markdown-surface: var(--coar-background-neutral-primary);--coar-markdown-surface-muted: var( --coar-background-neutral-tertiary, var(--coar-background-neutral-primary) );--coar-markdown-radius: var(--coar-radius-xs);--coar-markdown-space-1: var(--coar-spacing-s, .5rem);--coar-markdown-space-2: var(--coar-spacing-m, 1rem);--coar-markdown-heading-block-start: var(--coar-spacing-xxxl, 4rem)}.coar-markdown{display:block;color:var(--coar-markdown-text)}.coar-markdown :where(h1,h2,h3,h4,h5,h6){font-family:var(--coar-font-family-title, inherit);color:var(--coar-markdown-text)}.coar-markdown h1{font-size:var(--coar-font-size-xl);font-weight:var(--coar-font-weight-bold);line-height:1.2}.coar-markdown h2{font-size:var(--coar-font-size-l);font-weight:var(--coar-font-weight-bold);line-height:1.25}.coar-markdown h3{font-size:var(--coar-font-size-m);font-weight:var(--coar-font-weight-semi-bold);line-height:1.3}.coar-markdown h4{font-size:var(--coar-font-size-s);font-weight:var(--coar-font-weight-semi-bold);line-height:1.35}.coar-markdown h5{font-size:var(--coar-font-size-xs);font-weight:var(--coar-font-weight-semi-bold);line-height:1.4}.coar-markdown h6{font-size:var(--coar-font-size-xxs);font-weight:var(--coar-font-weight-medium);line-height:1.45}.coar-markdown-heading,.coar-markdown-paragraph,.coar-markdown-blockquote,.coar-markdown-list,.coar-markdown-code-block,.coar-markdown-table,.coar-markdown-hr{margin:0}.coar-markdown>:where(h1,h2,h3,h4,h5,h6,p,blockquote,ul,ol,pre,table,hr,coar-code-block,coar-table){margin-block:0 var(--coar-markdown-space-2)}.coar-markdown>:where(h1,h2,h3,h4,h5,h6){margin-block-start:var(--coar-markdown-heading-block-start)}.coar-markdown>:where(h1,h2,h3,h4,h5,h6)+:where(h1,h2,h3,h4,h5,h6){margin-block-start:var(--coar-markdown-space-1)}.coar-markdown>:where(h1,h2,h3,h4,h5,h6):first-child{margin-block-start:0}.coar-markdown-blockquote{padding-inline:var(--coar-markdown-space-2);border-left:2px solid var(--coar-markdown-border)}.coar-markdown-list{padding-inline-start:var(--coar-spacing-l, 1.5rem);list-style-position:outside}.coar-markdown-list--unordered{list-style-type:disc}.coar-markdown-list--ordered{list-style-type:decimal}.coar-markdown-list-item{display:list-item;margin-block:.25em}.coar-markdown-list-item--task{list-style:none;display:flex;align-items:flex-start;gap:var(--coar-spacing-s, .5rem)}.coar-markdown-list-item-content{min-width:0}.coar-markdown-task-checkbox{margin-top:.15em}.coar-markdown-code-block,.coar-markdown-code{display:block}.coar-markdown-inline-code{padding:0;border:0;border-radius:0;background:transparent;color:var(--coar-text-accent-secondary, var(--coar-markdown-link))}.coar-markdown-link{text-decoration:underline;color:var(--coar-markdown-link)}.coar-markdown-image{max-width:100%;height:auto;vertical-align:middle}.coar-markdown-table{width:100%;border:1px solid var(--coar-markdown-border);border-radius:var(--coar-markdown-radius);border-collapse:separate;border-spacing:0;overflow:hidden}.coar-markdown-table-cell{padding:var(--coar-markdown-space-1);vertical-align:top;border-right:1px solid var(--coar-markdown-border);border-bottom:1px solid var(--coar-markdown-border)}.coar-markdown-table :where(tr) .coar-markdown-table-cell:last-child{border-right:0}.coar-markdown-table :where(tbody) tr:last-child .coar-markdown-table-cell{border-bottom:0}.coar-markdown-table :where(thead) .coar-markdown-table-cell{background:var(--coar-markdown-surface-muted);font-weight:600}.coar-markdown-hr{border:0;border-top:1px solid var(--coar-markdown-border)}.coar-markdown-unsupported,.coar-markdown-unsupported-inline{font-style:italic;color:var(--coar-markdown-muted-text)}.coar-markdown-unsupported{padding:var(--coar-markdown-space-1);border:1px dashed var(--coar-markdown-border);border-radius:var(--coar-markdown-radius);background:var(--coar-markdown-surface)}\n"] }]
125
+ }], propDecorators: { doc: [{ type: i0.Input, args: [{ isSignal: true, alias: "doc", required: true }] }] } });
126
+
127
+ /**
128
+ * Generated bundle index. Do not edit.
129
+ */
130
+
131
+ export { CoarMarkdownComponent };
132
+ //# sourceMappingURL=cocoar-markdown-viewer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cocoar-markdown-viewer.mjs","sources":["../../../../libs/markdown-viewer/src/lib/coar-markdown/coar-markdown.component.ts","../../../../libs/markdown-viewer/src/lib/coar-markdown/coar-markdown.component.html","../../../../libs/markdown-viewer/src/cocoar-markdown-viewer.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport type { MarkdownDocument, MarkdownNode } from '@cocoar/markdown-core';\nimport { CoarCodeBlockComponent, CoarTableComponent } from '@cocoar/ui-components';\n\n@Component({\n selector: 'coar-markdown',\n standalone: true,\n imports: [CommonModule, CoarCodeBlockComponent, CoarTableComponent],\n templateUrl: './coar-markdown.component.html',\n styleUrl: './coar-markdown.component.css',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CoarMarkdownComponent {\n doc = input.required<MarkdownDocument>();\n\n protected codeBlockLanguage(node: MarkdownNode): string {\n const language = node.attrs?.['language'];\n return typeof language === 'string' && language.trim().length > 0 ? language.trim() : 'text';\n }\n\n protected headingAnchor(node: MarkdownNode): string | null {\n const anchor = node.attrs?.['anchor'];\n return typeof anchor === 'string' && anchor.length > 0 ? anchor : null;\n }\n\n protected headingDepth(node: MarkdownNode): 1 | 2 | 3 | 4 | 5 | 6 {\n const depth = node.attrs?.['depth'];\n if (typeof depth !== 'number') return 1;\n const value = Math.trunc(depth);\n if (value <= 1) return 1;\n if (value === 2) return 2;\n if (value === 3) return 3;\n if (value === 4) return 4;\n if (value === 5) return 5;\n return 6;\n }\n\n protected isOrderedList(node: MarkdownNode): boolean {\n return Boolean(node.attrs?.['ordered']);\n }\n\n protected listStart(node: MarkdownNode): number | null {\n const start = node.attrs?.['start'];\n return typeof start === 'number' ? start : null;\n }\n\n protected isTaskListItem(node: MarkdownNode): boolean {\n return typeof node.attrs?.['checked'] === 'boolean';\n }\n\n protected taskChecked(node: MarkdownNode): boolean {\n return node.attrs?.['checked'] === true;\n }\n\n protected linkUrl(node: MarkdownNode): string | null {\n const url = node.attrs?.['url'];\n return typeof url === 'string' && url.length > 0 ? url : null;\n }\n\n protected linkHref(node: MarkdownNode): string | null {\n const url = this.linkUrl(node);\n if (!url) return null;\n\n // With <base href=\"/\">, fragment-only hrefs resolve to the app root (e.g. /#overview),\n // which can navigate away from the current route. Keep anchors on the current page.\n if (url.startsWith('#') && typeof window !== 'undefined') {\n return `${window.location.pathname}${window.location.search}${url}`;\n }\n\n return url;\n }\n\n protected linkTarget(node: MarkdownNode): string | null {\n const url = this.linkUrl(node);\n if (!url) return null;\n return this.isExternalLink(url) ? '_blank' : null;\n }\n\n protected linkRel(node: MarkdownNode): string | null {\n const url = this.linkUrl(node);\n if (!url) return null;\n return this.isExternalLink(url) ? 'noopener noreferrer' : null;\n }\n\n protected imageSrc(node: MarkdownNode): string | null {\n const url = node.attrs?.['url'];\n return typeof url === 'string' && url.trim().length > 0 ? url.trim() : null;\n }\n\n protected imageAlt(node: MarkdownNode): string {\n const alt = node.attrs?.['alt'];\n return typeof alt === 'string' ? alt : '';\n }\n\n protected imageTitle(node: MarkdownNode): string | null {\n const title = node.attrs?.['title'];\n return typeof title === 'string' && title.trim().length > 0 ? title.trim() : null;\n }\n\n protected isTableColumnRightAligned(tableNode: MarkdownNode, columnIndex: number): boolean {\n return this.getTableColumnAlign(tableNode, columnIndex) === 'right';\n }\n\n protected isTableColumnCenterAligned(tableNode: MarkdownNode, columnIndex: number): boolean {\n return this.getTableColumnAlign(tableNode, columnIndex) === 'center';\n }\n\n private getTableColumnAlign(\n tableNode: MarkdownNode,\n columnIndex: number\n ): 'left' | 'right' | 'center' | null {\n const align = tableNode.attrs?.['align'];\n if (!Array.isArray(align)) return null;\n\n const value = align[columnIndex];\n if (value === 'left' || value === 'right' || value === 'center') return value;\n return null;\n }\n\n private isExternalLink(url: string): boolean {\n const trimmed = url.trim();\n if (trimmed.startsWith('#')) return false;\n if (trimmed.startsWith('/')) return false;\n if (trimmed.startsWith('./') || trimmed.startsWith('../')) return false;\n if (trimmed.startsWith('mailto:')) return false;\n if (trimmed.startsWith('tel:')) return false;\n\n return trimmed.startsWith('http://') || trimmed.startsWith('https://');\n }\n\n protected unsupportedType(node: MarkdownNode): string {\n const originalType = node.attrs?.['originalType'];\n return typeof originalType === 'string' ? originalType : String(node.type);\n }\n}\n","<div class=\"coar-markdown\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: doc().nodes }\"\n ></ng-container>\n</div>\n\n<ng-template #blockNodesTpl let-nodes>\n @for (node of nodes; track node.id) {\n @switch (node.type) {\n @case ('heading') {\n @switch (headingDepth(node)) {\n @case (1) {\n <h1 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h1>\n }\n @case (2) {\n <h2 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h2>\n }\n @case (3) {\n <h3 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h3>\n }\n @case (4) {\n <h4 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h4>\n }\n @case (5) {\n <h5 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h5>\n }\n @default {\n <h6 class=\"coar-markdown-heading\" [attr.id]=\"headingAnchor(node)\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </h6>\n }\n }\n }\n @case ('paragraph') {\n <p class=\"coar-markdown-paragraph\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </p>\n }\n @case ('blockquote') {\n <blockquote class=\"coar-markdown-blockquote\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </blockquote>\n }\n @case ('list') {\n @if (isOrderedList(node)) {\n <ol\n class=\"coar-markdown-list coar-markdown-list--ordered\"\n [attr.start]=\"listStart(node)\"\n >\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </ol>\n } @else {\n <ul class=\"coar-markdown-list coar-markdown-list--unordered\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </ul>\n }\n }\n @case ('listItem') {\n <li\n class=\"coar-markdown-list-item\"\n [class.coar-markdown-list-item--task]=\"isTaskListItem(node)\"\n >\n @if (isTaskListItem(node)) {\n <input\n class=\"coar-markdown-task-checkbox\"\n type=\"checkbox\"\n [checked]=\"taskChecked(node)\"\n disabled\n aria-hidden=\"true\"\n tabindex=\"-1\"\n />\n }\n <div class=\"coar-markdown-list-item-content\">\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </div>\n </li>\n }\n @case ('codeBlock') {\n <coar-code-block\n class=\"coar-markdown-code-block\"\n [code]=\"node.text ?? ''\"\n [language]=\"codeBlockLanguage(node)\"\n [collapsible]=\"false\"\n [showCopy]=\"true\"\n />\n }\n @case ('thematicBreak') {\n <hr class=\"coar-markdown-hr\" />\n }\n @case ('table') {\n <coar-table variant=\"plain\" hover>\n @if ((node.children ?? []).length > 0) {\n <thead>\n <tr>\n @for (cell of ((node.children ?? [])[0]?.children ?? []); track cell.id; let colIndex = $index) {\n <th\n [class.text-right]=\"isTableColumnRightAligned(node, colIndex)\"\n [class.text-center]=\"isTableColumnCenterAligned(node, colIndex)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: cell.children ?? [] }\"\n ></ng-container>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of (node.children ?? []).slice(1); track row.id) {\n <tr>\n @for (cell of (row.children ?? []); track cell.id; let colIndex = $index) {\n <td\n [class.text-right]=\"isTableColumnRightAligned(node, colIndex)\"\n [class.text-center]=\"isTableColumnCenterAligned(node, colIndex)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: cell.children ?? [] }\"\n ></ng-container>\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </coar-table>\n }\n @case ('tableRow') {\n <ng-container\n *ngTemplateOutlet=\"blockNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n }\n @case ('tableCell') {\n <td class=\"coar-markdown-table-cell\">\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </td>\n }\n @case ('unsupported') {\n <div class=\"coar-markdown-unsupported\">\n Unsupported markdown node: {{ unsupportedType(node) }}\n </div>\n }\n @default {\n <div class=\"coar-markdown-unsupported\">\n Unsupported markdown node: {{ unsupportedType(node) }}\n </div>\n }\n }\n }\n</ng-template>\n\n<ng-template #inlineNodesTpl let-nodes>\n @for (node of nodes; track node.id) {\n @switch (node.type) {\n @case ('text') {\n {{ node.text ?? '' }}\n }\n @case ('emphasis') {\n <em>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </em>\n }\n @case ('strong') {\n <strong>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </strong>\n }\n @case ('strikethrough') {\n <del>\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </del>\n }\n @case ('inlineCode') {\n <code class=\"coar-markdown-inline-code\">{{ node.text ?? '' }}</code>\n }\n @case ('lineBreak') {\n <br />\n }\n @case ('link') {\n @if (linkHref(node)) {\n <a\n class=\"coar-markdown-link\"\n [href]=\"linkHref(node)\"\n [attr.target]=\"linkTarget(node)\"\n [attr.rel]=\"linkRel(node)\"\n >\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n </a>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"inlineNodesTpl; context: { $implicit: node.children ?? [] }\"\n ></ng-container>\n }\n }\n @case ('image') {\n @if (imageSrc(node)) {\n <img\n class=\"coar-markdown-image\"\n [src]=\"imageSrc(node)\"\n [attr.alt]=\"imageAlt(node)\"\n [attr.title]=\"imageTitle(node)\"\n loading=\"lazy\"\n />\n }\n }\n @default {\n <span class=\"coar-markdown-unsupported-inline\">[unsupported]</span>\n }\n }\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@cocoar/markdown-viewer",
3
+ "version": "0.1.0-beta.100",
4
+ "description": "Angular Markdown viewer for the Cocoar Design System",
5
+ "author": "Cocoar",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/cocoar-dev/cocoar-ui.git",
10
+ "directory": "libs/markdown-viewer"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/cocoar-dev/cocoar-ui/issues"
14
+ },
15
+ "homepage": "https://github.com/cocoar-dev/cocoar-ui",
16
+ "keywords": [
17
+ "angular",
18
+ "markdown",
19
+ "viewer",
20
+ "cocoar"
21
+ ],
22
+ "peerDependencies": {
23
+ "@angular/common": "^21.0.0",
24
+ "@angular/core": "^21.0.0",
25
+ "@cocoar/markdown-core": "^0.0.2",
26
+ "@cocoar/ui-components": "^0.0.2"
27
+ },
28
+ "sideEffects": false,
29
+ "module": "fesm2022/cocoar-markdown-viewer.mjs",
30
+ "typings": "types/cocoar-markdown-viewer.d.ts",
31
+ "exports": {
32
+ "./package.json": {
33
+ "default": "./package.json"
34
+ },
35
+ ".": {
36
+ "types": "./types/cocoar-markdown-viewer.d.ts",
37
+ "default": "./fesm2022/cocoar-markdown-viewer.mjs"
38
+ }
39
+ },
40
+ "dependencies": {
41
+ "tslib": "^2.3.0"
42
+ }
43
+ }
@@ -0,0 +1,29 @@
1
+ import * as i0 from '@angular/core';
2
+ import { MarkdownDocument, MarkdownNode } from '@cocoar/markdown-core';
3
+
4
+ declare class CoarMarkdownComponent {
5
+ doc: i0.InputSignal<MarkdownDocument>;
6
+ protected codeBlockLanguage(node: MarkdownNode): string;
7
+ protected headingAnchor(node: MarkdownNode): string | null;
8
+ protected headingDepth(node: MarkdownNode): 1 | 2 | 3 | 4 | 5 | 6;
9
+ protected isOrderedList(node: MarkdownNode): boolean;
10
+ protected listStart(node: MarkdownNode): number | null;
11
+ protected isTaskListItem(node: MarkdownNode): boolean;
12
+ protected taskChecked(node: MarkdownNode): boolean;
13
+ protected linkUrl(node: MarkdownNode): string | null;
14
+ protected linkHref(node: MarkdownNode): string | null;
15
+ protected linkTarget(node: MarkdownNode): string | null;
16
+ protected linkRel(node: MarkdownNode): string | null;
17
+ protected imageSrc(node: MarkdownNode): string | null;
18
+ protected imageAlt(node: MarkdownNode): string;
19
+ protected imageTitle(node: MarkdownNode): string | null;
20
+ protected isTableColumnRightAligned(tableNode: MarkdownNode, columnIndex: number): boolean;
21
+ protected isTableColumnCenterAligned(tableNode: MarkdownNode, columnIndex: number): boolean;
22
+ private getTableColumnAlign;
23
+ private isExternalLink;
24
+ protected unsupportedType(node: MarkdownNode): string;
25
+ static ɵfac: i0.ɵɵFactoryDeclaration<CoarMarkdownComponent, never>;
26
+ static ɵcmp: i0.ɵɵComponentDeclaration<CoarMarkdownComponent, "coar-markdown", never, { "doc": { "alias": "doc"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
27
+ }
28
+
29
+ export { CoarMarkdownComponent };