vue3-markdown-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js ADDED
@@ -0,0 +1,331 @@
1
+ // src/preview.js
2
+ import { defineComponent, h, shallowRef, watch } from "vue";
3
+
4
+ // src/core/renderer.js
5
+ import MarkdownIt from "markdown-it";
6
+ import markdownItAttrs from "markdown-it-attrs";
7
+ function escapeHtml(value) {
8
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
9
+ }
10
+ function slugifyHeading(value) {
11
+ const slug = String(value || "").normalize("NFKC").trim().toLowerCase().replace(/\s+/g, "-").replace(/[^\p{Letter}\p{Number}_-]+/gu, "").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
12
+ return slug || "section";
13
+ }
14
+ function highlightCode(code, language, options) {
15
+ const {
16
+ Hljs,
17
+ codeHighlightExtensionMap = {},
18
+ codeBlockClass = (lang) => `v-md-hljs-${lang || ""}`
19
+ } = options;
20
+ const normalizedLanguage = codeHighlightExtensionMap[language] || language;
21
+ let highlighted = escapeHtml(code);
22
+ if (Hljs && normalizedLanguage && typeof Hljs.getLanguage === "function" && Hljs.getLanguage(normalizedLanguage)) {
23
+ try {
24
+ highlighted = Hljs.highlight(code, {
25
+ language: normalizedLanguage,
26
+ ignoreIllegals: true
27
+ }).value;
28
+ } catch {
29
+ highlighted = Hljs.highlight(normalizedLanguage, code, true).value;
30
+ }
31
+ }
32
+ return `<pre class="${escapeHtml(codeBlockClass(normalizedLanguage))}"><code>${highlighted}</code></pre>`;
33
+ }
34
+ function installHeadingAnchors(parser) {
35
+ parser.core.ruler.before("block", "vue_markdown_kit_heading_state", (state) => {
36
+ state.env.__vueMarkdownKitHeadingSlugs = /* @__PURE__ */ new Map();
37
+ });
38
+ const fallback = parser.renderer.rules.heading_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
39
+ parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {
40
+ const inline = tokens[index + 1];
41
+ const baseSlug = slugifyHeading(inline && inline.content);
42
+ const slugs = env.__vueMarkdownKitHeadingSlugs || /* @__PURE__ */ new Map();
43
+ const count = slugs.get(baseSlug) || 0;
44
+ const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`;
45
+ slugs.set(baseSlug, count + 1);
46
+ env.__vueMarkdownKitHeadingSlugs = slugs;
47
+ tokens[index].attrSet("id", slug);
48
+ tokens[index].attrSet("data-v-md-heading", slug);
49
+ return fallback(tokens, index, options, env, self);
50
+ };
51
+ }
52
+ function installSafeExternalLinks(parser) {
53
+ const fallback = parser.renderer.rules.link_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
54
+ parser.renderer.rules.link_open = (tokens, index, options, env, self) => {
55
+ const token = tokens[index];
56
+ const href = token.attrGet("href") || "";
57
+ if (/^https?:\/\//i.test(href)) {
58
+ token.attrSet("target", "_blank");
59
+ token.attrSet("rel", "noopener noreferrer");
60
+ }
61
+ return fallback(tokens, index, options, env, self);
62
+ };
63
+ }
64
+ function createMarkdownRenderer(options = {}) {
65
+ var _a, _b, _c, _d;
66
+ const parser = new MarkdownIt({
67
+ html: (_a = options.html) != null ? _a : true,
68
+ breaks: (_b = options.breaks) != null ? _b : true,
69
+ linkify: (_c = options.linkify) != null ? _c : false,
70
+ typographer: (_d = options.typographer) != null ? _d : true,
71
+ highlight: (code, language) => highlightCode(code, language, options)
72
+ });
73
+ if (options.attrs !== false) {
74
+ parser.use(markdownItAttrs, {
75
+ leftDelimiter: "{{{",
76
+ rightDelimiter: "}}}",
77
+ allowedAttributes: [
78
+ "class",
79
+ "height",
80
+ "id",
81
+ "title",
82
+ "width",
83
+ ...options.allowedAttributes || []
84
+ ]
85
+ });
86
+ }
87
+ installHeadingAnchors(parser);
88
+ installSafeExternalLinks(parser);
89
+ return parser;
90
+ }
91
+
92
+ // src/core/sanitize.js
93
+ import createDOMPurify from "dompurify";
94
+ var BASE_SANITIZE_OPTIONS = Object.freeze({
95
+ USE_PROFILES: {
96
+ html: true
97
+ },
98
+ ADD_ATTR: [
99
+ "data-mention-id",
100
+ "data-v-md-anchor",
101
+ "data-v-md-heading",
102
+ "data-v-md-line",
103
+ "rel",
104
+ "target"
105
+ ],
106
+ FORBID_TAGS: ["script"]
107
+ });
108
+ var sharedOptions = {};
109
+ function mergeOptions(base, extra) {
110
+ const merged = {
111
+ ...base,
112
+ ...extra
113
+ };
114
+ for (const key of ["ADD_ATTR", "ADD_TAGS", "FORBID_ATTR", "FORBID_TAGS"]) {
115
+ if (base[key] || extra[key]) {
116
+ merged[key] = [.../* @__PURE__ */ new Set([...base[key] || [], ...extra[key] || []])];
117
+ }
118
+ }
119
+ if (base.USE_PROFILES || extra.USE_PROFILES) {
120
+ merged.USE_PROFILES = {
121
+ ...base.USE_PROFILES || {},
122
+ ...extra.USE_PROFILES || {}
123
+ };
124
+ }
125
+ return merged;
126
+ }
127
+ function resolvePurifier(windowLike) {
128
+ if (typeof createDOMPurify.sanitize === "function") {
129
+ return createDOMPurify;
130
+ }
131
+ if (windowLike && typeof createDOMPurify === "function") {
132
+ return createDOMPurify(windowLike);
133
+ }
134
+ return null;
135
+ }
136
+ function escapeHtml2(value) {
137
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
138
+ }
139
+ function sanitizeHtml(dirtyHtml, options = {}, windowLike = typeof window === "undefined" ? void 0 : window) {
140
+ const purifier = resolvePurifier(windowLike);
141
+ if (!purifier || typeof purifier.sanitize !== "function") {
142
+ return escapeHtml2(dirtyHtml || "");
143
+ }
144
+ return purifier.sanitize(
145
+ dirtyHtml || "",
146
+ mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options)
147
+ );
148
+ }
149
+ var sanitizer = {
150
+ process(dirtyHtml, options) {
151
+ return sanitizeHtml(dirtyHtml, options);
152
+ },
153
+ extend(options = {}) {
154
+ sharedOptions = mergeOptions(sharedOptions, options);
155
+ return this;
156
+ },
157
+ reset() {
158
+ sharedOptions = {};
159
+ return this;
160
+ }
161
+ };
162
+
163
+ // src/version.js
164
+ var version = "0.1.0";
165
+
166
+ // src/preview.js
167
+ var defaultThemeConfig = {
168
+ name: "base",
169
+ previewClass: "vmk-markdown-body",
170
+ markdownParser: createMarkdownRenderer(),
171
+ extend(callback) {
172
+ callback(this.markdownParser);
173
+ }
174
+ };
175
+ var markdownExtenders = [];
176
+ var activeThemeConfig = defaultThemeConfig;
177
+ function installTheme(theme, options) {
178
+ if (!theme) return;
179
+ if (typeof theme === "function") {
180
+ theme(VMdPreview, options);
181
+ } else if (typeof theme.install === "function") {
182
+ theme.install(VMdPreview, options);
183
+ } else if (theme.markdownParser) {
184
+ VMdPreview.theme(theme);
185
+ }
186
+ }
187
+ var VMdPreview = defineComponent({
188
+ name: "v-md-preview",
189
+ props: {
190
+ text: {
191
+ type: String,
192
+ default: ""
193
+ },
194
+ theme: {
195
+ type: Object,
196
+ default: void 0
197
+ },
198
+ tabSize: {
199
+ type: Number,
200
+ default: 2
201
+ },
202
+ scrollContainer: {
203
+ type: Function,
204
+ default: () => window
205
+ },
206
+ top: {
207
+ type: Number,
208
+ default: 0
209
+ },
210
+ sanitizeOptions: {
211
+ type: Object,
212
+ default: () => ({})
213
+ }
214
+ },
215
+ emits: {
216
+ change: (_text, _html) => true,
217
+ "image-click": (_images, _index) => true
218
+ },
219
+ setup(props, { emit }) {
220
+ const rootElement = shallowRef(null);
221
+ const html = shallowRef("");
222
+ if (props.theme) {
223
+ installTheme(props.theme);
224
+ }
225
+ for (const extender of markdownExtenders) {
226
+ extender(activeThemeConfig.markdownParser);
227
+ }
228
+ const renderMarkdown = () => {
229
+ const rawHtml = activeThemeConfig.markdownParser.render(props.text || "");
230
+ html.value = sanitizer.process(rawHtml, props.sanitizeOptions);
231
+ emit("change", props.text, html.value);
232
+ };
233
+ watch([() => props.text, () => props.sanitizeOptions], renderMarkdown, {
234
+ deep: true,
235
+ immediate: true
236
+ });
237
+ const handlePreviewClick = (event) => {
238
+ const target = event.target;
239
+ const root = rootElement.value;
240
+ if (!root || !target || target.tagName !== "IMG") {
241
+ return;
242
+ }
243
+ const imageElements = Array.from(root.querySelectorAll("img"));
244
+ const images = imageElements.map((image) => image.getAttribute("src")).filter(Boolean);
245
+ const index = imageElements.indexOf(target);
246
+ emit("image-click", images, index);
247
+ };
248
+ return () => h(
249
+ "div",
250
+ {
251
+ ref: rootElement,
252
+ class: "vue-markdown-kit-preview",
253
+ style: {
254
+ tabSize: props.tabSize,
255
+ MozTabSize: props.tabSize
256
+ },
257
+ onClick: handlePreviewClick
258
+ },
259
+ [
260
+ h("div", {
261
+ class: activeThemeConfig.previewClass,
262
+ innerHTML: html.value
263
+ })
264
+ ]
265
+ );
266
+ }
267
+ });
268
+ VMdPreview.version = version;
269
+ VMdPreview.install = (app) => {
270
+ app.component(VMdPreview.name, VMdPreview);
271
+ };
272
+ VMdPreview.theme = (themeConfig) => {
273
+ activeThemeConfig = themeConfig || defaultThemeConfig;
274
+ return VMdPreview;
275
+ };
276
+ VMdPreview.use = (theme, options) => {
277
+ installTheme(theme, options);
278
+ return VMdPreview;
279
+ };
280
+ VMdPreview.extendMarkdown = (extender) => {
281
+ markdownExtenders.push(extender);
282
+ return VMdPreview;
283
+ };
284
+ VMdPreview.xss = sanitizer;
285
+ VMdPreview.lang = {
286
+ use() {
287
+ },
288
+ add() {
289
+ }
290
+ };
291
+ var preview_default = VMdPreview;
292
+
293
+ // src/theme/github.js
294
+ function createGithubTheme(options = {}) {
295
+ const markdownParser = createMarkdownRenderer(options);
296
+ return {
297
+ name: "github",
298
+ previewClass: "github-markdown-body",
299
+ markdownParser,
300
+ extend(callback) {
301
+ callback(markdownParser, options.Hljs);
302
+ }
303
+ };
304
+ }
305
+ var githubTheme = {
306
+ install(VMdPreview2, options = {}) {
307
+ VMdPreview2.theme(createGithubTheme(options));
308
+ }
309
+ };
310
+ var github_default = githubTheme;
311
+
312
+ // src/index.js
313
+ var VueMarkdownKit = {
314
+ version: preview_default.version,
315
+ install(Vue) {
316
+ preview_default.install(Vue);
317
+ }
318
+ };
319
+ var src_default = VueMarkdownKit;
320
+ export {
321
+ preview_default as VMdPreview,
322
+ VueMarkdownKit,
323
+ createGithubTheme,
324
+ createMarkdownRenderer,
325
+ src_default as default,
326
+ github_default as githubTheme,
327
+ sanitizeHtml,
328
+ sanitizer,
329
+ slugifyHeading
330
+ };
331
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/preview.js", "../src/core/renderer.js", "../src/core/sanitize.js", "../src/version.js", "../src/theme/github.js", "../src/index.js"],
4
+ "sourcesContent": ["import { defineComponent, h, shallowRef, watch } from 'vue'\nimport { createMarkdownRenderer } from './core/renderer.js'\nimport { sanitizer } from './core/sanitize.js'\nimport { version } from './version.js'\n\nconst defaultThemeConfig = {\n name: 'base',\n previewClass: 'vmk-markdown-body',\n markdownParser: createMarkdownRenderer(),\n extend(callback) {\n callback(this.markdownParser)\n },\n}\n\nconst markdownExtenders = []\nlet activeThemeConfig = defaultThemeConfig\n\nfunction installTheme(theme, options) {\n if (!theme) return\n\n if (typeof theme === 'function') {\n theme(VMdPreview, options)\n } else if (typeof theme.install === 'function') {\n theme.install(VMdPreview, options)\n } else if (theme.markdownParser) {\n VMdPreview.theme(theme)\n }\n}\n\nconst VMdPreview = defineComponent({\n name: 'v-md-preview',\n\n props: {\n text: {\n type: String,\n default: '',\n },\n theme: {\n type: Object,\n default: undefined,\n },\n tabSize: {\n type: Number,\n default: 2,\n },\n scrollContainer: {\n type: Function,\n default: () => window,\n },\n top: {\n type: Number,\n default: 0,\n },\n sanitizeOptions: {\n type: Object,\n default: () => ({}),\n },\n },\n\n emits: {\n change: (_text, _html) => true,\n 'image-click': (_images, _index) => true,\n },\n\n setup(props, { emit }) {\n const rootElement = shallowRef(null)\n const html = shallowRef('')\n\n if (props.theme) {\n installTheme(props.theme)\n }\n\n for (const extender of markdownExtenders) {\n extender(activeThemeConfig.markdownParser)\n }\n\n const renderMarkdown = () => {\n const rawHtml = activeThemeConfig.markdownParser.render(props.text || '')\n html.value = sanitizer.process(rawHtml, props.sanitizeOptions)\n emit('change', props.text, html.value)\n }\n\n watch([() => props.text, () => props.sanitizeOptions], renderMarkdown, {\n deep: true,\n immediate: true,\n })\n\n const handlePreviewClick = (event) => {\n const target = event.target\n const root = rootElement.value\n\n if (!root || !target || target.tagName !== 'IMG') {\n return\n }\n\n const imageElements = Array.from(root.querySelectorAll('img'))\n const images = imageElements\n .map((image) => image.getAttribute('src'))\n .filter(Boolean)\n const index = imageElements.indexOf(target)\n\n emit('image-click', images, index)\n }\n\n return () =>\n h(\n 'div',\n {\n ref: rootElement,\n class: 'vue-markdown-kit-preview',\n style: {\n tabSize: props.tabSize,\n MozTabSize: props.tabSize,\n },\n onClick: handlePreviewClick,\n },\n [\n h('div', {\n class: activeThemeConfig.previewClass,\n innerHTML: html.value,\n }),\n ],\n )\n },\n})\n\nVMdPreview.version = version\nVMdPreview.install = (app) => {\n app.component(VMdPreview.name, VMdPreview)\n}\nVMdPreview.theme = (themeConfig) => {\n activeThemeConfig = themeConfig || defaultThemeConfig\n return VMdPreview\n}\nVMdPreview.use = (theme, options) => {\n installTheme(theme, options)\n return VMdPreview\n}\nVMdPreview.extendMarkdown = (extender) => {\n markdownExtenders.push(extender)\n return VMdPreview\n}\nVMdPreview.xss = sanitizer\nVMdPreview.lang = {\n use() {},\n add() {},\n}\n\nexport default VMdPreview\n", "import MarkdownIt from 'markdown-it'\nimport markdownItAttrs from 'markdown-it-attrs'\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nexport function slugifyHeading(value) {\n const slug = String(value || '')\n .normalize('NFKC')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^\\p{Letter}\\p{Number}_-]+/gu, '')\n .replace(/-{2,}/g, '-')\n .replace(/^-|-$/g, '')\n\n return slug || 'section'\n}\n\nfunction highlightCode(code, language, options) {\n const {\n Hljs,\n codeHighlightExtensionMap = {},\n codeBlockClass = (lang) => `v-md-hljs-${lang || ''}`,\n } = options\n\n const normalizedLanguage = codeHighlightExtensionMap[language] || language\n let highlighted = escapeHtml(code)\n\n if (\n Hljs &&\n normalizedLanguage &&\n typeof Hljs.getLanguage === 'function' &&\n Hljs.getLanguage(normalizedLanguage)\n ) {\n try {\n highlighted = Hljs.highlight(code, {\n language: normalizedLanguage,\n ignoreIllegals: true,\n }).value\n } catch {\n // highlight.js 10 compatibility.\n highlighted = Hljs.highlight(normalizedLanguage, code, true).value\n }\n }\n\n return `<pre class=\"${escapeHtml(codeBlockClass(normalizedLanguage))}\"><code>${highlighted}</code></pre>`\n}\n\nfunction installHeadingAnchors(parser) {\n parser.core.ruler.before('block', 'vue_markdown_kit_heading_state', (state) => {\n state.env.__vueMarkdownKitHeadingSlugs = new Map()\n })\n\n const fallback =\n parser.renderer.rules.heading_open ||\n ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options))\n\n parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {\n const inline = tokens[index + 1]\n const baseSlug = slugifyHeading(inline && inline.content)\n const slugs = env.__vueMarkdownKitHeadingSlugs || new Map()\n const count = slugs.get(baseSlug) || 0\n const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`\n\n slugs.set(baseSlug, count + 1)\n env.__vueMarkdownKitHeadingSlugs = slugs\n\n tokens[index].attrSet('id', slug)\n tokens[index].attrSet('data-v-md-heading', slug)\n\n return fallback(tokens, index, options, env, self)\n }\n}\n\nfunction installSafeExternalLinks(parser) {\n const fallback =\n parser.renderer.rules.link_open ||\n ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options))\n\n parser.renderer.rules.link_open = (tokens, index, options, env, self) => {\n const token = tokens[index]\n const href = token.attrGet('href') || ''\n\n if (/^https?:\\/\\//i.test(href)) {\n token.attrSet('target', '_blank')\n token.attrSet('rel', 'noopener noreferrer')\n }\n\n return fallback(tokens, index, options, env, self)\n }\n}\n\nexport function createMarkdownRenderer(options = {}) {\n const parser = new MarkdownIt({\n html: options.html ?? true,\n breaks: options.breaks ?? true,\n linkify: options.linkify ?? false,\n typographer: options.typographer ?? true,\n highlight: (code, language) => highlightCode(code, language, options),\n })\n\n if (options.attrs !== false) {\n parser.use(markdownItAttrs, {\n leftDelimiter: '{{{',\n rightDelimiter: '}}}',\n allowedAttributes: [\n 'class',\n 'height',\n 'id',\n 'title',\n 'width',\n ...(options.allowedAttributes || []),\n ],\n })\n }\n\n installHeadingAnchors(parser)\n installSafeExternalLinks(parser)\n\n return parser\n}\n", "import createDOMPurify from 'dompurify'\n\nconst BASE_SANITIZE_OPTIONS = Object.freeze({\n USE_PROFILES: {\n html: true,\n },\n ADD_ATTR: [\n 'data-mention-id',\n 'data-v-md-anchor',\n 'data-v-md-heading',\n 'data-v-md-line',\n 'rel',\n 'target',\n ],\n FORBID_TAGS: ['script'],\n})\n\nlet sharedOptions = {}\n\nfunction mergeOptions(base, extra) {\n const merged = {\n ...base,\n ...extra,\n }\n\n for (const key of ['ADD_ATTR', 'ADD_TAGS', 'FORBID_ATTR', 'FORBID_TAGS']) {\n if (base[key] || extra[key]) {\n merged[key] = [...new Set([...(base[key] || []), ...(extra[key] || [])])]\n }\n }\n\n if (base.USE_PROFILES || extra.USE_PROFILES) {\n merged.USE_PROFILES = {\n ...(base.USE_PROFILES || {}),\n ...(extra.USE_PROFILES || {}),\n }\n }\n\n return merged\n}\n\nfunction resolvePurifier(windowLike) {\n if (typeof createDOMPurify.sanitize === 'function') {\n return createDOMPurify\n }\n\n if (windowLike && typeof createDOMPurify === 'function') {\n return createDOMPurify(windowLike)\n }\n\n return null\n}\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\nexport function sanitizeHtml(\n dirtyHtml,\n options = {},\n windowLike = typeof window === 'undefined' ? undefined : window,\n) {\n const purifier = resolvePurifier(windowLike)\n\n // Fail closed in non-DOM environments rather than returning executable HTML.\n if (!purifier || typeof purifier.sanitize !== 'function') {\n return escapeHtml(dirtyHtml || '')\n }\n\n return purifier.sanitize(\n dirtyHtml || '',\n mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options),\n )\n}\n\nexport const sanitizer = {\n process(dirtyHtml, options) {\n return sanitizeHtml(dirtyHtml, options)\n },\n\n extend(options = {}) {\n sharedOptions = mergeOptions(sharedOptions, options)\n return this\n },\n\n reset() {\n sharedOptions = {}\n return this\n },\n}\n", "export const version = '0.1.0'\n", "import { createMarkdownRenderer } from '../core/renderer.js'\n\nexport function createGithubTheme(options = {}) {\n const markdownParser = createMarkdownRenderer(options)\n\n return {\n name: 'github',\n previewClass: 'github-markdown-body',\n markdownParser,\n extend(callback) {\n callback(markdownParser, options.Hljs)\n },\n }\n}\n\nconst githubTheme = {\n install(VMdPreview, options = {}) {\n VMdPreview.theme(createGithubTheme(options))\n },\n}\n\nexport default githubTheme\n", "import VMdPreview from './preview.js'\nimport githubTheme, { createGithubTheme } from './theme/github.js'\n\nconst VueMarkdownKit = {\n version: VMdPreview.version,\n install(Vue) {\n VMdPreview.install(Vue)\n },\n}\n\nexport { VMdPreview, VueMarkdownKit, createGithubTheme, githubTheme }\nexport * from './core/index.js'\nexport default VueMarkdownKit\n"],
5
+ "mappings": "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",
6
+ "names": ["escapeHtml", "VMdPreview"]
7
+ }
@@ -0,0 +1,325 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/preview.js
30
+ var preview_exports = {};
31
+ __export(preview_exports, {
32
+ default: () => preview_default
33
+ });
34
+ module.exports = __toCommonJS(preview_exports);
35
+ var import_vue = require("vue");
36
+
37
+ // src/core/renderer.js
38
+ var import_markdown_it = __toESM(require("markdown-it"), 1);
39
+ var import_markdown_it_attrs = __toESM(require("markdown-it-attrs"), 1);
40
+ function escapeHtml(value) {
41
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
42
+ }
43
+ function slugifyHeading(value) {
44
+ const slug = String(value || "").normalize("NFKC").trim().toLowerCase().replace(/\s+/g, "-").replace(/[^\p{Letter}\p{Number}_-]+/gu, "").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
45
+ return slug || "section";
46
+ }
47
+ function highlightCode(code, language, options) {
48
+ const {
49
+ Hljs,
50
+ codeHighlightExtensionMap = {},
51
+ codeBlockClass = (lang) => `v-md-hljs-${lang || ""}`
52
+ } = options;
53
+ const normalizedLanguage = codeHighlightExtensionMap[language] || language;
54
+ let highlighted = escapeHtml(code);
55
+ if (Hljs && normalizedLanguage && typeof Hljs.getLanguage === "function" && Hljs.getLanguage(normalizedLanguage)) {
56
+ try {
57
+ highlighted = Hljs.highlight(code, {
58
+ language: normalizedLanguage,
59
+ ignoreIllegals: true
60
+ }).value;
61
+ } catch {
62
+ highlighted = Hljs.highlight(normalizedLanguage, code, true).value;
63
+ }
64
+ }
65
+ return `<pre class="${escapeHtml(codeBlockClass(normalizedLanguage))}"><code>${highlighted}</code></pre>`;
66
+ }
67
+ function installHeadingAnchors(parser) {
68
+ parser.core.ruler.before("block", "vue_markdown_kit_heading_state", (state) => {
69
+ state.env.__vueMarkdownKitHeadingSlugs = /* @__PURE__ */ new Map();
70
+ });
71
+ const fallback = parser.renderer.rules.heading_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
72
+ parser.renderer.rules.heading_open = (tokens, index, options, env, self) => {
73
+ const inline = tokens[index + 1];
74
+ const baseSlug = slugifyHeading(inline && inline.content);
75
+ const slugs = env.__vueMarkdownKitHeadingSlugs || /* @__PURE__ */ new Map();
76
+ const count = slugs.get(baseSlug) || 0;
77
+ const slug = count === 0 ? baseSlug : `${baseSlug}-${count}`;
78
+ slugs.set(baseSlug, count + 1);
79
+ env.__vueMarkdownKitHeadingSlugs = slugs;
80
+ tokens[index].attrSet("id", slug);
81
+ tokens[index].attrSet("data-v-md-heading", slug);
82
+ return fallback(tokens, index, options, env, self);
83
+ };
84
+ }
85
+ function installSafeExternalLinks(parser) {
86
+ const fallback = parser.renderer.rules.link_open || ((tokens, index, options, _env, self) => self.renderToken(tokens, index, options));
87
+ parser.renderer.rules.link_open = (tokens, index, options, env, self) => {
88
+ const token = tokens[index];
89
+ const href = token.attrGet("href") || "";
90
+ if (/^https?:\/\//i.test(href)) {
91
+ token.attrSet("target", "_blank");
92
+ token.attrSet("rel", "noopener noreferrer");
93
+ }
94
+ return fallback(tokens, index, options, env, self);
95
+ };
96
+ }
97
+ function createMarkdownRenderer(options = {}) {
98
+ var _a, _b, _c, _d;
99
+ const parser = new import_markdown_it.default({
100
+ html: (_a = options.html) != null ? _a : true,
101
+ breaks: (_b = options.breaks) != null ? _b : true,
102
+ linkify: (_c = options.linkify) != null ? _c : false,
103
+ typographer: (_d = options.typographer) != null ? _d : true,
104
+ highlight: (code, language) => highlightCode(code, language, options)
105
+ });
106
+ if (options.attrs !== false) {
107
+ parser.use(import_markdown_it_attrs.default, {
108
+ leftDelimiter: "{{{",
109
+ rightDelimiter: "}}}",
110
+ allowedAttributes: [
111
+ "class",
112
+ "height",
113
+ "id",
114
+ "title",
115
+ "width",
116
+ ...options.allowedAttributes || []
117
+ ]
118
+ });
119
+ }
120
+ installHeadingAnchors(parser);
121
+ installSafeExternalLinks(parser);
122
+ return parser;
123
+ }
124
+
125
+ // src/core/sanitize.js
126
+ var import_dompurify = __toESM(require("dompurify"), 1);
127
+ var BASE_SANITIZE_OPTIONS = Object.freeze({
128
+ USE_PROFILES: {
129
+ html: true
130
+ },
131
+ ADD_ATTR: [
132
+ "data-mention-id",
133
+ "data-v-md-anchor",
134
+ "data-v-md-heading",
135
+ "data-v-md-line",
136
+ "rel",
137
+ "target"
138
+ ],
139
+ FORBID_TAGS: ["script"]
140
+ });
141
+ var sharedOptions = {};
142
+ function mergeOptions(base, extra) {
143
+ const merged = {
144
+ ...base,
145
+ ...extra
146
+ };
147
+ for (const key of ["ADD_ATTR", "ADD_TAGS", "FORBID_ATTR", "FORBID_TAGS"]) {
148
+ if (base[key] || extra[key]) {
149
+ merged[key] = [.../* @__PURE__ */ new Set([...base[key] || [], ...extra[key] || []])];
150
+ }
151
+ }
152
+ if (base.USE_PROFILES || extra.USE_PROFILES) {
153
+ merged.USE_PROFILES = {
154
+ ...base.USE_PROFILES || {},
155
+ ...extra.USE_PROFILES || {}
156
+ };
157
+ }
158
+ return merged;
159
+ }
160
+ function resolvePurifier(windowLike) {
161
+ if (typeof import_dompurify.default.sanitize === "function") {
162
+ return import_dompurify.default;
163
+ }
164
+ if (windowLike && typeof import_dompurify.default === "function") {
165
+ return (0, import_dompurify.default)(windowLike);
166
+ }
167
+ return null;
168
+ }
169
+ function escapeHtml2(value) {
170
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
171
+ }
172
+ function sanitizeHtml(dirtyHtml, options = {}, windowLike = typeof window === "undefined" ? void 0 : window) {
173
+ const purifier = resolvePurifier(windowLike);
174
+ if (!purifier || typeof purifier.sanitize !== "function") {
175
+ return escapeHtml2(dirtyHtml || "");
176
+ }
177
+ return purifier.sanitize(
178
+ dirtyHtml || "",
179
+ mergeOptions(mergeOptions(BASE_SANITIZE_OPTIONS, sharedOptions), options)
180
+ );
181
+ }
182
+ var sanitizer = {
183
+ process(dirtyHtml, options) {
184
+ return sanitizeHtml(dirtyHtml, options);
185
+ },
186
+ extend(options = {}) {
187
+ sharedOptions = mergeOptions(sharedOptions, options);
188
+ return this;
189
+ },
190
+ reset() {
191
+ sharedOptions = {};
192
+ return this;
193
+ }
194
+ };
195
+
196
+ // src/version.js
197
+ var version = "0.1.0";
198
+
199
+ // src/preview.js
200
+ var defaultThemeConfig = {
201
+ name: "base",
202
+ previewClass: "vmk-markdown-body",
203
+ markdownParser: createMarkdownRenderer(),
204
+ extend(callback) {
205
+ callback(this.markdownParser);
206
+ }
207
+ };
208
+ var markdownExtenders = [];
209
+ var activeThemeConfig = defaultThemeConfig;
210
+ function installTheme(theme, options) {
211
+ if (!theme) return;
212
+ if (typeof theme === "function") {
213
+ theme(VMdPreview, options);
214
+ } else if (typeof theme.install === "function") {
215
+ theme.install(VMdPreview, options);
216
+ } else if (theme.markdownParser) {
217
+ VMdPreview.theme(theme);
218
+ }
219
+ }
220
+ var VMdPreview = (0, import_vue.defineComponent)({
221
+ name: "v-md-preview",
222
+ props: {
223
+ text: {
224
+ type: String,
225
+ default: ""
226
+ },
227
+ theme: {
228
+ type: Object,
229
+ default: void 0
230
+ },
231
+ tabSize: {
232
+ type: Number,
233
+ default: 2
234
+ },
235
+ scrollContainer: {
236
+ type: Function,
237
+ default: () => window
238
+ },
239
+ top: {
240
+ type: Number,
241
+ default: 0
242
+ },
243
+ sanitizeOptions: {
244
+ type: Object,
245
+ default: () => ({})
246
+ }
247
+ },
248
+ emits: {
249
+ change: (_text, _html) => true,
250
+ "image-click": (_images, _index) => true
251
+ },
252
+ setup(props, { emit }) {
253
+ const rootElement = (0, import_vue.shallowRef)(null);
254
+ const html = (0, import_vue.shallowRef)("");
255
+ if (props.theme) {
256
+ installTheme(props.theme);
257
+ }
258
+ for (const extender of markdownExtenders) {
259
+ extender(activeThemeConfig.markdownParser);
260
+ }
261
+ const renderMarkdown = () => {
262
+ const rawHtml = activeThemeConfig.markdownParser.render(props.text || "");
263
+ html.value = sanitizer.process(rawHtml, props.sanitizeOptions);
264
+ emit("change", props.text, html.value);
265
+ };
266
+ (0, import_vue.watch)([() => props.text, () => props.sanitizeOptions], renderMarkdown, {
267
+ deep: true,
268
+ immediate: true
269
+ });
270
+ const handlePreviewClick = (event) => {
271
+ const target = event.target;
272
+ const root = rootElement.value;
273
+ if (!root || !target || target.tagName !== "IMG") {
274
+ return;
275
+ }
276
+ const imageElements = Array.from(root.querySelectorAll("img"));
277
+ const images = imageElements.map((image) => image.getAttribute("src")).filter(Boolean);
278
+ const index = imageElements.indexOf(target);
279
+ emit("image-click", images, index);
280
+ };
281
+ return () => (0, import_vue.h)(
282
+ "div",
283
+ {
284
+ ref: rootElement,
285
+ class: "vue-markdown-kit-preview",
286
+ style: {
287
+ tabSize: props.tabSize,
288
+ MozTabSize: props.tabSize
289
+ },
290
+ onClick: handlePreviewClick
291
+ },
292
+ [
293
+ (0, import_vue.h)("div", {
294
+ class: activeThemeConfig.previewClass,
295
+ innerHTML: html.value
296
+ })
297
+ ]
298
+ );
299
+ }
300
+ });
301
+ VMdPreview.version = version;
302
+ VMdPreview.install = (app) => {
303
+ app.component(VMdPreview.name, VMdPreview);
304
+ };
305
+ VMdPreview.theme = (themeConfig) => {
306
+ activeThemeConfig = themeConfig || defaultThemeConfig;
307
+ return VMdPreview;
308
+ };
309
+ VMdPreview.use = (theme, options) => {
310
+ installTheme(theme, options);
311
+ return VMdPreview;
312
+ };
313
+ VMdPreview.extendMarkdown = (extender) => {
314
+ markdownExtenders.push(extender);
315
+ return VMdPreview;
316
+ };
317
+ VMdPreview.xss = sanitizer;
318
+ VMdPreview.lang = {
319
+ use() {
320
+ },
321
+ add() {
322
+ }
323
+ };
324
+ var preview_default = VMdPreview;
325
+ //# sourceMappingURL=preview.cjs.map