@aquera/nile-elements 1.8.5 → 1.8.6
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 +4 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +848 -299
- package/dist/nile-markdown/index.cjs.js +2 -0
- package/dist/nile-markdown/index.cjs.js.map +1 -0
- package/dist/nile-markdown/index.esm.js +1 -0
- package/dist/nile-markdown/nile-markdown.cjs.js +30 -0
- package/dist/nile-markdown/nile-markdown.cjs.js.map +1 -0
- package/dist/nile-markdown/nile-markdown.css.cjs.js +2 -0
- package/dist/nile-markdown/nile-markdown.css.cjs.js.map +1 -0
- package/dist/nile-markdown/nile-markdown.css.esm.js +152 -0
- package/dist/nile-markdown/nile-markdown.esm.js +3 -0
- package/dist/nile-markdown-editor/index.cjs.js +2 -0
- package/dist/nile-markdown-editor/index.cjs.js.map +1 -0
- package/dist/nile-markdown-editor/index.esm.js +1 -0
- package/dist/nile-markdown-editor/nile-markdown-editor.cjs.js +2 -0
- package/dist/nile-markdown-editor/nile-markdown-editor.cjs.js.map +1 -0
- package/dist/nile-markdown-editor/nile-markdown-editor.css.cjs.js +2 -0
- package/dist/nile-markdown-editor/nile-markdown-editor.css.cjs.js.map +1 -0
- package/dist/nile-markdown-editor/nile-markdown-editor.css.esm.js +255 -0
- package/dist/nile-markdown-editor/nile-markdown-editor.esm.js +143 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/nile-markdown/index.d.ts +1 -0
- package/dist/src/nile-markdown/index.js +2 -0
- package/dist/src/nile-markdown/index.js.map +1 -0
- package/dist/src/nile-markdown/nile-markdown.css.d.ts +10 -0
- package/dist/src/nile-markdown/nile-markdown.css.js +163 -0
- package/dist/src/nile-markdown/nile-markdown.css.js.map +1 -0
- package/dist/src/nile-markdown/nile-markdown.d.ts +91 -0
- package/dist/src/nile-markdown/nile-markdown.js +167 -0
- package/dist/src/nile-markdown/nile-markdown.js.map +1 -0
- package/dist/src/nile-markdown/nile-markdown.test.d.ts +1 -0
- package/dist/src/nile-markdown/nile-markdown.test.js +192 -0
- package/dist/src/nile-markdown/nile-markdown.test.js.map +1 -0
- package/dist/src/nile-markdown-editor/index.d.ts +1 -0
- package/dist/src/nile-markdown-editor/index.js +2 -0
- package/dist/src/nile-markdown-editor/index.js.map +1 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.css.d.ts +10 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.css.js +266 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.css.js.map +1 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.d.ts +121 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.js +615 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.js.map +1 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.test.d.ts +1 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.test.js +268 -0
- package/dist/src/nile-markdown-editor/nile-markdown-editor.test.js.map +1 -0
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/index.ts +3 -1
- package/src/nile-markdown/index.ts +1 -0
- package/src/nile-markdown/nile-markdown.css.ts +164 -0
- package/src/nile-markdown/nile-markdown.test.ts +252 -0
- package/src/nile-markdown/nile-markdown.ts +179 -0
- package/src/nile-markdown-editor/index.ts +1 -0
- package/src/nile-markdown-editor/nile-markdown-editor.css.ts +267 -0
- package/src/nile-markdown-editor/nile-markdown-editor.test.ts +402 -0
- package/src/nile-markdown-editor/nile-markdown-editor.ts +710 -0
- package/vscode-html-custom-data.json +82 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Aquera Inc 2023
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the BSD-3-Clause license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
var NileMarkdown_1;
|
|
8
|
+
import { __decorate } from "tslib";
|
|
9
|
+
import { html } from 'lit';
|
|
10
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
11
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
12
|
+
import { Marked } from 'marked';
|
|
13
|
+
import { styles } from './nile-markdown.css';
|
|
14
|
+
import NileElement from '../internal/nile-element';
|
|
15
|
+
/**
|
|
16
|
+
* Nile markdown component.
|
|
17
|
+
*
|
|
18
|
+
* @tag nile-markdown
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* @summary Renders markdown content as HTML in the browser using GitHub Flavored Markdown.
|
|
22
|
+
* @status experimental
|
|
23
|
+
*
|
|
24
|
+
* Content can be provided either through the `value` property or through a
|
|
25
|
+
* `<script type="text/markdown">` element placed as a direct child:
|
|
26
|
+
*
|
|
27
|
+
* ```html
|
|
28
|
+
* <nile-markdown>
|
|
29
|
+
* <script type="text/markdown">
|
|
30
|
+
* # Hello
|
|
31
|
+
* This is **markdown**.
|
|
32
|
+
* </script>
|
|
33
|
+
* </nile-markdown>
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* Leading whitespace common to all lines is stripped, so the markdown can be
|
|
37
|
+
* indented to match the surrounding HTML without rendering as a code block.
|
|
38
|
+
*
|
|
39
|
+
* All instances share a single Marked parser. Use `NileMarkdown.getMarked()`
|
|
40
|
+
* to customize it (extensions, renderers, etc.) and `NileMarkdown.updateAll()`
|
|
41
|
+
* to re-render existing instances after changing the configuration.
|
|
42
|
+
*
|
|
43
|
+
* WARNING: The markdown is converted to HTML without sanitization. Do not
|
|
44
|
+
* render unsanitized user input, as this can expose users to XSS attacks.
|
|
45
|
+
*
|
|
46
|
+
* @event nile-markdown-rendered - Emitted after the markdown has been parsed and rendered.
|
|
47
|
+
*
|
|
48
|
+
* @csspart base - The component's base wrapper containing the rendered HTML.
|
|
49
|
+
*/
|
|
50
|
+
let NileMarkdown = NileMarkdown_1 = class NileMarkdown extends NileElement {
|
|
51
|
+
constructor() {
|
|
52
|
+
super(...arguments);
|
|
53
|
+
/**
|
|
54
|
+
* The markdown to render. Takes precedence over a
|
|
55
|
+
* `<script type="text/markdown">` child when set.
|
|
56
|
+
*/
|
|
57
|
+
this.value = '';
|
|
58
|
+
/** Number of spaces a tab is converted to during whitespace normalization. */
|
|
59
|
+
this.tabSize = 4;
|
|
60
|
+
this.renderedHtml = '';
|
|
61
|
+
/** Re-renders automatically when the markdown script child changes. */
|
|
62
|
+
this.mutationObserver = new MutationObserver(() => this.renderMarkdown());
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the shared Marked instance so it can be configured with custom
|
|
66
|
+
* options, extensions, or renderers. Changes affect all instances; call
|
|
67
|
+
* `NileMarkdown.updateAll()` afterwards to re-render existing ones.
|
|
68
|
+
*/
|
|
69
|
+
static getMarked() {
|
|
70
|
+
if (!NileMarkdown_1.marked) {
|
|
71
|
+
NileMarkdown_1.marked = new Marked({ gfm: true, async: false });
|
|
72
|
+
}
|
|
73
|
+
return NileMarkdown_1.marked;
|
|
74
|
+
}
|
|
75
|
+
/** Re-renders every connected nile-markdown instance. */
|
|
76
|
+
static updateAll() {
|
|
77
|
+
NileMarkdown_1.instances.forEach(instance => instance.renderMarkdown());
|
|
78
|
+
}
|
|
79
|
+
connectedCallback() {
|
|
80
|
+
super.connectedCallback();
|
|
81
|
+
NileMarkdown_1.instances.add(this);
|
|
82
|
+
this.mutationObserver.observe(this, {
|
|
83
|
+
childList: true,
|
|
84
|
+
subtree: true,
|
|
85
|
+
characterData: true,
|
|
86
|
+
});
|
|
87
|
+
this.renderMarkdown();
|
|
88
|
+
}
|
|
89
|
+
disconnectedCallback() {
|
|
90
|
+
this.mutationObserver.disconnect();
|
|
91
|
+
NileMarkdown_1.instances.delete(this);
|
|
92
|
+
super.disconnectedCallback();
|
|
93
|
+
}
|
|
94
|
+
willUpdate(changed) {
|
|
95
|
+
super.willUpdate(changed);
|
|
96
|
+
if (changed.has('value') || changed.has('tabSize')) {
|
|
97
|
+
this.computeHtml();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
updated(changed) {
|
|
101
|
+
super.updated(changed);
|
|
102
|
+
if (changed.has('renderedHtml')) {
|
|
103
|
+
this.emit('nile-markdown-rendered', undefined, true, true);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Reads the markdown source from `value` or the script child. */
|
|
107
|
+
getSource() {
|
|
108
|
+
if (this.value)
|
|
109
|
+
return this.value;
|
|
110
|
+
const script = this.querySelector(':scope > script[type="text/markdown"]');
|
|
111
|
+
return script?.textContent ?? '';
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Converts tabs to spaces and removes the leading indentation common to all
|
|
115
|
+
* lines, so markdown indented to match the HTML doesn't render as code.
|
|
116
|
+
*/
|
|
117
|
+
normalizeWhitespace(text) {
|
|
118
|
+
const tab = ' '.repeat(Math.max(1, this.tabSize));
|
|
119
|
+
const lines = text.replace(/\t/g, tab).split('\n');
|
|
120
|
+
let minIndent = Infinity;
|
|
121
|
+
for (const line of lines) {
|
|
122
|
+
if (!line.trim())
|
|
123
|
+
continue;
|
|
124
|
+
const indent = line.length - line.trimStart().length;
|
|
125
|
+
minIndent = Math.min(minIndent, indent);
|
|
126
|
+
}
|
|
127
|
+
if (!Number.isFinite(minIndent) || minIndent === 0) {
|
|
128
|
+
return text.trim();
|
|
129
|
+
}
|
|
130
|
+
return lines
|
|
131
|
+
.map(line => line.slice(minIndent))
|
|
132
|
+
.join('\n')
|
|
133
|
+
.trim();
|
|
134
|
+
}
|
|
135
|
+
/** Parses the markdown source into `renderedHtml`. */
|
|
136
|
+
computeHtml() {
|
|
137
|
+
const source = this.normalizeWhitespace(this.getSource());
|
|
138
|
+
this.renderedHtml = NileMarkdown_1.getMarked().parse(source);
|
|
139
|
+
}
|
|
140
|
+
/** Parses the markdown source and renders the resulting HTML. */
|
|
141
|
+
renderMarkdown() {
|
|
142
|
+
this.computeHtml();
|
|
143
|
+
}
|
|
144
|
+
render() {
|
|
145
|
+
return html `
|
|
146
|
+
<div class="markdown" part="base">${unsafeHTML(this.renderedHtml)}</div>
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
NileMarkdown.styles = styles;
|
|
151
|
+
/** All connected instances, used by `updateAll()`. */
|
|
152
|
+
NileMarkdown.instances = new Set();
|
|
153
|
+
__decorate([
|
|
154
|
+
property()
|
|
155
|
+
], NileMarkdown.prototype, "value", void 0);
|
|
156
|
+
__decorate([
|
|
157
|
+
property({ type: Number, attribute: 'tab-size' })
|
|
158
|
+
], NileMarkdown.prototype, "tabSize", void 0);
|
|
159
|
+
__decorate([
|
|
160
|
+
state()
|
|
161
|
+
], NileMarkdown.prototype, "renderedHtml", void 0);
|
|
162
|
+
NileMarkdown = NileMarkdown_1 = __decorate([
|
|
163
|
+
customElement('nile-markdown')
|
|
164
|
+
], NileMarkdown);
|
|
165
|
+
export { NileMarkdown };
|
|
166
|
+
export default NileMarkdown;
|
|
167
|
+
//# sourceMappingURL=nile-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nile-markdown.js","sourceRoot":"","sources":["../../../src/nile-markdown/nile-markdown.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright Aquera Inc 2023\n *\n * This source code is licensed under the BSD-3-Clause license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { html } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport { Marked } from 'marked';\nimport { styles } from './nile-markdown.css';\nimport NileElement from '../internal/nile-element';\nimport type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';\n\n/**\n * Nile markdown component.\n *\n * @tag nile-markdown\n */\n\n/**\n * @summary Renders markdown content as HTML in the browser using GitHub Flavored Markdown.\n * @status experimental\n *\n * Content can be provided either through the `value` property or through a\n * `<script type=\"text/markdown\">` element placed as a direct child:\n *\n * ```html\n * <nile-markdown>\n * <script type=\"text/markdown\">\n * # Hello\n * This is **markdown**.\n * </script>\n * </nile-markdown>\n * ```\n *\n * Leading whitespace common to all lines is stripped, so the markdown can be\n * indented to match the surrounding HTML without rendering as a code block.\n *\n * All instances share a single Marked parser. Use `NileMarkdown.getMarked()`\n * to customize it (extensions, renderers, etc.) and `NileMarkdown.updateAll()`\n * to re-render existing instances after changing the configuration.\n *\n * WARNING: The markdown is converted to HTML without sanitization. Do not\n * render unsanitized user input, as this can expose users to XSS attacks.\n *\n * @event nile-markdown-rendered - Emitted after the markdown has been parsed and rendered.\n *\n * @csspart base - The component's base wrapper containing the rendered HTML.\n */\n\n@customElement('nile-markdown')\nexport class NileMarkdown extends NileElement {\n static styles: CSSResultGroup = styles;\n\n /** The shared Marked instance used by every nile-markdown on the page. */\n private static marked: Marked | undefined;\n\n /** All connected instances, used by `updateAll()`. */\n private static instances = new Set<NileMarkdown>();\n\n /**\n * Returns the shared Marked instance so it can be configured with custom\n * options, extensions, or renderers. Changes affect all instances; call\n * `NileMarkdown.updateAll()` afterwards to re-render existing ones.\n */\n static getMarked(): Marked {\n if (!NileMarkdown.marked) {\n NileMarkdown.marked = new Marked({ gfm: true, async: false });\n }\n return NileMarkdown.marked;\n }\n\n /** Re-renders every connected nile-markdown instance. */\n static updateAll(): void {\n NileMarkdown.instances.forEach(instance => instance.renderMarkdown());\n }\n\n /**\n * The markdown to render. Takes precedence over a\n * `<script type=\"text/markdown\">` child when set.\n */\n @property() value = '';\n\n /** Number of spaces a tab is converted to during whitespace normalization. */\n @property({ type: Number, attribute: 'tab-size' }) tabSize = 4;\n\n @state() private renderedHtml = '';\n\n /** Re-renders automatically when the markdown script child changes. */\n private mutationObserver = new MutationObserver(() => this.renderMarkdown());\n\n connectedCallback(): void {\n super.connectedCallback();\n NileMarkdown.instances.add(this);\n this.mutationObserver.observe(this, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n this.renderMarkdown();\n }\n\n disconnectedCallback(): void {\n this.mutationObserver.disconnect();\n NileMarkdown.instances.delete(this);\n super.disconnectedCallback();\n }\n\n protected willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n if (changed.has('value') || changed.has('tabSize')) {\n this.computeHtml();\n }\n }\n\n protected updated(changed: PropertyValues): void {\n super.updated(changed);\n if (changed.has('renderedHtml')) {\n this.emit('nile-markdown-rendered', undefined, true, true);\n }\n }\n\n /** Reads the markdown source from `value` or the script child. */\n private getSource(): string {\n if (this.value) return this.value;\n const script = this.querySelector(':scope > script[type=\"text/markdown\"]');\n return script?.textContent ?? '';\n }\n\n /**\n * Converts tabs to spaces and removes the leading indentation common to all\n * lines, so markdown indented to match the HTML doesn't render as code.\n */\n private normalizeWhitespace(text: string): string {\n const tab = ' '.repeat(Math.max(1, this.tabSize));\n const lines = text.replace(/\\t/g, tab).split('\\n');\n\n let minIndent = Infinity;\n for (const line of lines) {\n if (!line.trim()) continue;\n const indent = line.length - line.trimStart().length;\n minIndent = Math.min(minIndent, indent);\n }\n if (!Number.isFinite(minIndent) || minIndent === 0) {\n return text.trim();\n }\n return lines\n .map(line => line.slice(minIndent))\n .join('\\n')\n .trim();\n }\n\n /** Parses the markdown source into `renderedHtml`. */\n private computeHtml(): void {\n const source = this.normalizeWhitespace(this.getSource());\n this.renderedHtml = NileMarkdown.getMarked().parse(source) as string;\n }\n\n /** Parses the markdown source and renders the resulting HTML. */\n renderMarkdown(): void {\n this.computeHtml();\n }\n\n render(): TemplateResult {\n return html`\n <div class=\"markdown\" part=\"base\">${unsafeHTML(this.renderedHtml)}</div>\n `;\n }\n}\n\nexport default NileMarkdown;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nile-markdown': NileMarkdown;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './nile-markdown';
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
|
|
2
|
+
import './nile-markdown';
|
|
3
|
+
import NileMarkdown from './nile-markdown';
|
|
4
|
+
describe('NileMarkdown', () => {
|
|
5
|
+
// === RENDERING ===
|
|
6
|
+
it('1. should render without errors', async () => {
|
|
7
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
8
|
+
expect(el).to.exist;
|
|
9
|
+
});
|
|
10
|
+
it('2. should have a shadow root', async () => {
|
|
11
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
12
|
+
expect(el.shadowRoot).to.not.be.null;
|
|
13
|
+
});
|
|
14
|
+
it('3. should have base part', async () => {
|
|
15
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
16
|
+
const base = el.shadowRoot.querySelector('[part~="base"]');
|
|
17
|
+
expect(base).to.exist;
|
|
18
|
+
});
|
|
19
|
+
it('4. should be instance of NileMarkdown', async () => {
|
|
20
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
21
|
+
expect(el).to.be.instanceOf(NileMarkdown);
|
|
22
|
+
});
|
|
23
|
+
it('5. should have correct tag name', async () => {
|
|
24
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
25
|
+
expect(el.tagName.toLowerCase()).to.equal('nile-markdown');
|
|
26
|
+
});
|
|
27
|
+
// === DEFAULT PROPERTIES ===
|
|
28
|
+
it('6. should have value default to empty string', async () => {
|
|
29
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
30
|
+
expect(el.value).to.equal('');
|
|
31
|
+
});
|
|
32
|
+
it('7. should have tabSize default to 4', async () => {
|
|
33
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
34
|
+
expect(el.tabSize).to.equal(4);
|
|
35
|
+
});
|
|
36
|
+
// === VALUE PROPERTY ===
|
|
37
|
+
it('8. should render markdown from value property', async () => {
|
|
38
|
+
const el = await fixture(html `<nile-markdown value="# Heading"></nile-markdown>`);
|
|
39
|
+
await el.updateComplete;
|
|
40
|
+
const h1 = el.shadowRoot.querySelector('h1');
|
|
41
|
+
expect(h1).to.exist;
|
|
42
|
+
expect(h1.textContent).to.equal('Heading');
|
|
43
|
+
});
|
|
44
|
+
it('9. should render bold text', async () => {
|
|
45
|
+
const el = await fixture(html `<nile-markdown value="This is **bold**"></nile-markdown>`);
|
|
46
|
+
await el.updateComplete;
|
|
47
|
+
const strong = el.shadowRoot.querySelector('strong');
|
|
48
|
+
expect(strong).to.exist;
|
|
49
|
+
expect(strong.textContent).to.equal('bold');
|
|
50
|
+
});
|
|
51
|
+
it('10. should render links', async () => {
|
|
52
|
+
const el = await fixture(html `<nile-markdown value="[link](https://example.com)"></nile-markdown>`);
|
|
53
|
+
await el.updateComplete;
|
|
54
|
+
const a = el.shadowRoot.querySelector('a');
|
|
55
|
+
expect(a).to.exist;
|
|
56
|
+
expect(a.getAttribute('href')).to.equal('https://example.com');
|
|
57
|
+
});
|
|
58
|
+
it('11. should render lists', async () => {
|
|
59
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
60
|
+
el.value = '- one\n- two\n- three';
|
|
61
|
+
await el.updateComplete;
|
|
62
|
+
const items = el.shadowRoot.querySelectorAll('li');
|
|
63
|
+
expect(items.length).to.equal(3);
|
|
64
|
+
});
|
|
65
|
+
it('12. should render code blocks', async () => {
|
|
66
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
67
|
+
el.value = '```\nconst a = 1;\n```';
|
|
68
|
+
await el.updateComplete;
|
|
69
|
+
const pre = el.shadowRoot.querySelector('pre code');
|
|
70
|
+
expect(pre).to.exist;
|
|
71
|
+
});
|
|
72
|
+
it('13. should render GFM tables', async () => {
|
|
73
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
74
|
+
el.value = '| a | b |\n| - | - |\n| 1 | 2 |';
|
|
75
|
+
await el.updateComplete;
|
|
76
|
+
const table = el.shadowRoot.querySelector('table');
|
|
77
|
+
expect(table).to.exist;
|
|
78
|
+
});
|
|
79
|
+
it('14. should render blockquotes', async () => {
|
|
80
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
81
|
+
el.value = '> quoted';
|
|
82
|
+
await el.updateComplete;
|
|
83
|
+
const quote = el.shadowRoot.querySelector('blockquote');
|
|
84
|
+
expect(quote).to.exist;
|
|
85
|
+
});
|
|
86
|
+
// === SCRIPT CHILD ===
|
|
87
|
+
it('15. should render markdown from a script child', async () => {
|
|
88
|
+
const el = await fixture(html `
|
|
89
|
+
<nile-markdown>
|
|
90
|
+
<script type="text/markdown">
|
|
91
|
+
# From Script
|
|
92
|
+
</script>
|
|
93
|
+
</nile-markdown>
|
|
94
|
+
`);
|
|
95
|
+
await el.updateComplete;
|
|
96
|
+
const h1 = el.shadowRoot.querySelector('h1');
|
|
97
|
+
expect(h1).to.exist;
|
|
98
|
+
expect(h1.textContent).to.equal('From Script');
|
|
99
|
+
});
|
|
100
|
+
it('16. should normalize indented script content', async () => {
|
|
101
|
+
const el = await fixture(html `
|
|
102
|
+
<nile-markdown>
|
|
103
|
+
<script type="text/markdown">
|
|
104
|
+
# Title
|
|
105
|
+
|
|
106
|
+
Paragraph text, indented to match the HTML.
|
|
107
|
+
</script>
|
|
108
|
+
</nile-markdown>
|
|
109
|
+
`);
|
|
110
|
+
await el.updateComplete;
|
|
111
|
+
// Indented content must not be treated as a code block
|
|
112
|
+
expect(el.shadowRoot.querySelector('pre')).to.not.exist;
|
|
113
|
+
expect(el.shadowRoot.querySelector('h1')).to.exist;
|
|
114
|
+
expect(el.shadowRoot.querySelector('p')).to.exist;
|
|
115
|
+
});
|
|
116
|
+
it('17. value should take precedence over script child', async () => {
|
|
117
|
+
const el = await fixture(html `
|
|
118
|
+
<nile-markdown value="# From Value">
|
|
119
|
+
<script type="text/markdown">
|
|
120
|
+
# From Script
|
|
121
|
+
</script>
|
|
122
|
+
</nile-markdown>
|
|
123
|
+
`);
|
|
124
|
+
await el.updateComplete;
|
|
125
|
+
const h1 = el.shadowRoot.querySelector('h1');
|
|
126
|
+
expect(h1.textContent).to.equal('From Value');
|
|
127
|
+
});
|
|
128
|
+
// === DYNAMIC UPDATES ===
|
|
129
|
+
it('18. should re-render when value changes', async () => {
|
|
130
|
+
const el = await fixture(html `<nile-markdown value="# One"></nile-markdown>`);
|
|
131
|
+
await el.updateComplete;
|
|
132
|
+
el.value = '# Two';
|
|
133
|
+
await el.updateComplete;
|
|
134
|
+
await el.updateComplete;
|
|
135
|
+
const h1 = el.shadowRoot.querySelector('h1');
|
|
136
|
+
expect(h1.textContent).to.equal('Two');
|
|
137
|
+
});
|
|
138
|
+
it('19. should re-render when script content changes', async () => {
|
|
139
|
+
const el = await fixture(html `
|
|
140
|
+
<nile-markdown>
|
|
141
|
+
<script type="text/markdown">
|
|
142
|
+
# Before
|
|
143
|
+
</script>
|
|
144
|
+
</nile-markdown>
|
|
145
|
+
`);
|
|
146
|
+
await el.updateComplete;
|
|
147
|
+
const script = el.querySelector('script');
|
|
148
|
+
script.textContent = '# After';
|
|
149
|
+
// MutationObserver fires async
|
|
150
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
151
|
+
await el.updateComplete;
|
|
152
|
+
const h1 = el.shadowRoot.querySelector('h1');
|
|
153
|
+
expect(h1.textContent).to.equal('After');
|
|
154
|
+
});
|
|
155
|
+
it('20. renderMarkdown() should re-parse manually', async () => {
|
|
156
|
+
const el = await fixture(html `<nile-markdown value="# Manual"></nile-markdown>`);
|
|
157
|
+
await el.updateComplete;
|
|
158
|
+
el.renderMarkdown();
|
|
159
|
+
await el.updateComplete;
|
|
160
|
+
expect(el.shadowRoot.querySelector('h1').textContent).to.equal('Manual');
|
|
161
|
+
});
|
|
162
|
+
// === EVENTS ===
|
|
163
|
+
it('21. should emit nile-markdown-rendered after rendering', async () => {
|
|
164
|
+
const el = document.createElement('nile-markdown');
|
|
165
|
+
const listener = oneEvent(el, 'nile-markdown-rendered');
|
|
166
|
+
el.value = '# Event';
|
|
167
|
+
document.body.appendChild(el);
|
|
168
|
+
const event = await listener;
|
|
169
|
+
expect(event).to.exist;
|
|
170
|
+
el.remove();
|
|
171
|
+
});
|
|
172
|
+
// === STATIC API ===
|
|
173
|
+
it('22. getMarked() should return a shared instance', () => {
|
|
174
|
+
const a = NileMarkdown.getMarked();
|
|
175
|
+
const b = NileMarkdown.getMarked();
|
|
176
|
+
expect(a).to.equal(b);
|
|
177
|
+
});
|
|
178
|
+
it('23. updateAll() should not throw', async () => {
|
|
179
|
+
await fixture(html `<nile-markdown value="# A"></nile-markdown>`);
|
|
180
|
+
expect(() => NileMarkdown.updateAll()).to.not.throw();
|
|
181
|
+
});
|
|
182
|
+
// === EDGE CASES ===
|
|
183
|
+
it('24. should handle empty content', async () => {
|
|
184
|
+
const el = await fixture(html `<nile-markdown></nile-markdown>`);
|
|
185
|
+
const base = el.shadowRoot.querySelector('[part~="base"]');
|
|
186
|
+
expect(base.textContent.trim()).to.equal('');
|
|
187
|
+
});
|
|
188
|
+
it('25. should have static styles', () => {
|
|
189
|
+
expect(NileMarkdown.styles).to.exist;
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
//# sourceMappingURL=nile-markdown.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nile-markdown.test.js","sourceRoot":"","sources":["../../../src/nile-markdown/nile-markdown.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html, oneEvent } from '@open-wc/testing';\nimport './nile-markdown';\nimport NileMarkdown from './nile-markdown';\n\ndescribe('NileMarkdown', () => {\n // === RENDERING ===\n it('1. should render without errors', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n expect(el).to.exist;\n });\n\n it('2. should have a shadow root', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n expect(el.shadowRoot).to.not.be.null;\n });\n\n it('3. should have base part', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n const base = el.shadowRoot!.querySelector('[part~=\"base\"]');\n expect(base).to.exist;\n });\n\n it('4. should be instance of NileMarkdown', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n expect(el).to.be.instanceOf(NileMarkdown);\n });\n\n it('5. should have correct tag name', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n expect(el.tagName.toLowerCase()).to.equal('nile-markdown');\n });\n\n // === DEFAULT PROPERTIES ===\n it('6. should have value default to empty string', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n expect(el.value).to.equal('');\n });\n\n it('7. should have tabSize default to 4', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n expect(el.tabSize).to.equal(4);\n });\n\n // === VALUE PROPERTY ===\n it('8. should render markdown from value property', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown value=\"# Heading\"></nile-markdown>`\n );\n await el.updateComplete;\n const h1 = el.shadowRoot!.querySelector('h1');\n expect(h1).to.exist;\n expect(h1!.textContent).to.equal('Heading');\n });\n\n it('9. should render bold text', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown value=\"This is **bold**\"></nile-markdown>`\n );\n await el.updateComplete;\n const strong = el.shadowRoot!.querySelector('strong');\n expect(strong).to.exist;\n expect(strong!.textContent).to.equal('bold');\n });\n\n it('10. should render links', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown value=\"[link](https://example.com)\"></nile-markdown>`\n );\n await el.updateComplete;\n const a = el.shadowRoot!.querySelector('a');\n expect(a).to.exist;\n expect(a!.getAttribute('href')).to.equal('https://example.com');\n });\n\n it('11. should render lists', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n el.value = '- one\\n- two\\n- three';\n await el.updateComplete;\n const items = el.shadowRoot!.querySelectorAll('li');\n expect(items.length).to.equal(3);\n });\n\n it('12. should render code blocks', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n el.value = '```\\nconst a = 1;\\n```';\n await el.updateComplete;\n const pre = el.shadowRoot!.querySelector('pre code');\n expect(pre).to.exist;\n });\n\n it('13. should render GFM tables', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n el.value = '| a | b |\\n| - | - |\\n| 1 | 2 |';\n await el.updateComplete;\n const table = el.shadowRoot!.querySelector('table');\n expect(table).to.exist;\n });\n\n it('14. should render blockquotes', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n el.value = '> quoted';\n await el.updateComplete;\n const quote = el.shadowRoot!.querySelector('blockquote');\n expect(quote).to.exist;\n });\n\n // === SCRIPT CHILD ===\n it('15. should render markdown from a script child', async () => {\n const el = await fixture<NileMarkdown>(html`\n <nile-markdown>\n <script type=\"text/markdown\">\n # From Script\n </script>\n </nile-markdown>\n `);\n await el.updateComplete;\n const h1 = el.shadowRoot!.querySelector('h1');\n expect(h1).to.exist;\n expect(h1!.textContent).to.equal('From Script');\n });\n\n it('16. should normalize indented script content', async () => {\n const el = await fixture<NileMarkdown>(html`\n <nile-markdown>\n <script type=\"text/markdown\">\n # Title\n\n Paragraph text, indented to match the HTML.\n </script>\n </nile-markdown>\n `);\n await el.updateComplete;\n // Indented content must not be treated as a code block\n expect(el.shadowRoot!.querySelector('pre')).to.not.exist;\n expect(el.shadowRoot!.querySelector('h1')).to.exist;\n expect(el.shadowRoot!.querySelector('p')).to.exist;\n });\n\n it('17. value should take precedence over script child', async () => {\n const el = await fixture<NileMarkdown>(html`\n <nile-markdown value=\"# From Value\">\n <script type=\"text/markdown\">\n # From Script\n </script>\n </nile-markdown>\n `);\n await el.updateComplete;\n const h1 = el.shadowRoot!.querySelector('h1');\n expect(h1!.textContent).to.equal('From Value');\n });\n\n // === DYNAMIC UPDATES ===\n it('18. should re-render when value changes', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown value=\"# One\"></nile-markdown>`\n );\n await el.updateComplete;\n el.value = '# Two';\n await el.updateComplete;\n await el.updateComplete;\n const h1 = el.shadowRoot!.querySelector('h1');\n expect(h1!.textContent).to.equal('Two');\n });\n\n it('19. should re-render when script content changes', async () => {\n const el = await fixture<NileMarkdown>(html`\n <nile-markdown>\n <script type=\"text/markdown\">\n # Before\n </script>\n </nile-markdown>\n `);\n await el.updateComplete;\n const script = el.querySelector('script')!;\n script.textContent = '# After';\n // MutationObserver fires async\n await new Promise(resolve => setTimeout(resolve, 0));\n await el.updateComplete;\n const h1 = el.shadowRoot!.querySelector('h1');\n expect(h1!.textContent).to.equal('After');\n });\n\n it('20. renderMarkdown() should re-parse manually', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown value=\"# Manual\"></nile-markdown>`\n );\n await el.updateComplete;\n el.renderMarkdown();\n await el.updateComplete;\n expect(el.shadowRoot!.querySelector('h1')!.textContent).to.equal('Manual');\n });\n\n // === EVENTS ===\n it('21. should emit nile-markdown-rendered after rendering', async () => {\n const el = document.createElement('nile-markdown') as NileMarkdown;\n const listener = oneEvent(el, 'nile-markdown-rendered');\n el.value = '# Event';\n document.body.appendChild(el);\n const event = await listener;\n expect(event).to.exist;\n el.remove();\n });\n\n // === STATIC API ===\n it('22. getMarked() should return a shared instance', () => {\n const a = NileMarkdown.getMarked();\n const b = NileMarkdown.getMarked();\n expect(a).to.equal(b);\n });\n\n it('23. updateAll() should not throw', async () => {\n await fixture<NileMarkdown>(\n html`<nile-markdown value=\"# A\"></nile-markdown>`\n );\n expect(() => NileMarkdown.updateAll()).to.not.throw();\n });\n\n // === EDGE CASES ===\n it('24. should handle empty content', async () => {\n const el = await fixture<NileMarkdown>(\n html`<nile-markdown></nile-markdown>`\n );\n const base = el.shadowRoot!.querySelector('[part~=\"base\"]');\n expect(base!.textContent!.trim()).to.equal('');\n });\n\n it('25. should have static styles', () => {\n expect(NileMarkdown.styles).to.exist;\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NileMarkdownEditor } from './nile-markdown-editor';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/nile-markdown-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC","sourcesContent":["export { NileMarkdownEditor } from './nile-markdown-editor';\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Aquera Inc 2023
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the BSD-3-Clause license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Markdown editor CSS
|
|
9
|
+
*/
|
|
10
|
+
export declare const styles: import("lit").CSSResult;
|