draftly 1.0.7 → 2.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/README.md +12 -0
- package/dist/chunk-3T55CBNZ.cjs +33 -0
- package/dist/chunk-3T55CBNZ.cjs.map +1 -0
- package/dist/chunk-5MC4T7JH.cjs +58 -0
- package/dist/chunk-5MC4T7JH.cjs.map +1 -0
- package/dist/{chunk-KBQDZ5IW.cjs → chunk-CLW73JRX.cjs} +100 -75
- package/dist/chunk-CLW73JRX.cjs.map +1 -0
- package/dist/{chunk-72ZYRGRT.cjs → chunk-EQUQHE2E.cjs} +30 -26
- package/dist/chunk-EQUQHE2E.cjs.map +1 -0
- package/dist/{chunk-HPSMS2WB.js → chunk-I563H35S.js} +101 -75
- package/dist/chunk-I563H35S.js.map +1 -0
- package/dist/chunk-IAXF4SJL.js +55 -0
- package/dist/chunk-IAXF4SJL.js.map +1 -0
- package/dist/chunk-JF3WXXMJ.js +31 -0
- package/dist/chunk-JF3WXXMJ.js.map +1 -0
- package/dist/{chunk-N3WL3XPB.js → chunk-NRPI5O6Y.js} +2603 -604
- package/dist/chunk-NRPI5O6Y.js.map +1 -0
- package/dist/{chunk-2B3A3VSQ.cjs → chunk-OMFUE4AQ.cjs} +2642 -622
- package/dist/chunk-OMFUE4AQ.cjs.map +1 -0
- package/dist/{chunk-DFQYXFOP.js → chunk-TD3L5C45.js} +28 -3
- package/dist/chunk-TD3L5C45.js.map +1 -0
- package/dist/{chunk-CG4M4TC7.js → chunk-UCHBDJ4R.js} +26 -22
- package/dist/chunk-UCHBDJ4R.js.map +1 -0
- package/dist/{chunk-KDEDLC3D.cjs → chunk-W75QUUQC.cjs} +29 -2
- package/dist/chunk-W75QUUQC.cjs.map +1 -0
- package/dist/{draftly-BLnx3uGX.d.cts → draftly-BBL-AdOl.d.cts} +5 -1
- package/dist/{draftly-BLnx3uGX.d.ts → draftly-BBL-AdOl.d.ts} +5 -1
- package/dist/editor/index.cjs +22 -14
- package/dist/editor/index.d.cts +2 -1
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/index.js +2 -2
- package/dist/index.cjs +65 -39
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +6 -4
- package/dist/lib/index.cjs +12 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +16 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/plugins/index.cjs +27 -17
- package/dist/plugins/index.d.cts +180 -10
- package/dist/plugins/index.d.ts +180 -10
- package/dist/plugins/index.js +5 -3
- package/dist/preview/index.cjs +16 -11
- package/dist/preview/index.d.cts +19 -4
- package/dist/preview/index.d.ts +19 -4
- package/dist/preview/index.js +3 -2
- package/package.json +8 -1
- package/src/editor/draftly.ts +30 -27
- package/src/editor/plugin.ts +5 -1
- package/src/editor/theme.ts +1 -0
- package/src/editor/utils.ts +33 -0
- package/src/index.ts +5 -4
- package/src/lib/index.ts +2 -0
- package/src/lib/input-handler.ts +45 -0
- package/src/plugins/code-plugin.theme.ts +426 -0
- package/src/plugins/code-plugin.ts +810 -561
- package/src/plugins/emoji-plugin.ts +140 -0
- package/src/plugins/index.ts +63 -57
- package/src/plugins/inline-plugin.ts +305 -291
- package/src/plugins/math-plugin.ts +12 -0
- package/src/plugins/table-plugin.ts +1759 -0
- package/src/preview/context.ts +4 -1
- package/src/preview/css-generator.ts +14 -1
- package/src/preview/index.ts +9 -1
- package/src/preview/preview.ts +2 -1
- package/src/preview/renderer.ts +21 -20
- package/src/preview/syntax-theme.ts +110 -0
- package/src/preview/types.ts +14 -0
- package/dist/chunk-2B3A3VSQ.cjs.map +0 -1
- package/dist/chunk-72ZYRGRT.cjs.map +0 -1
- package/dist/chunk-CG4M4TC7.js.map +0 -1
- package/dist/chunk-DFQYXFOP.js.map +0 -1
- package/dist/chunk-HPSMS2WB.js.map +0 -1
- package/dist/chunk-KBQDZ5IW.cjs.map +0 -1
- package/dist/chunk-KDEDLC3D.cjs.map +0 -1
- package/dist/chunk-N3WL3XPB.js.map +0 -1
package/README.md
CHANGED
|
@@ -148,6 +148,7 @@ Render markdown to semantic HTML for server-side rendering, static site generati
|
|
|
148
148
|
|
|
149
149
|
```tsx
|
|
150
150
|
import { preview, generateCSS, allPlugins, ThemeEnum } from "draftly";
|
|
151
|
+
import { githubLight } from "@uiw/codemirror-theme-github";
|
|
151
152
|
|
|
152
153
|
const markdown = `
|
|
153
154
|
# Hello World
|
|
@@ -173,6 +174,7 @@ const css = generateCSS({
|
|
|
173
174
|
plugins: allPlugins,
|
|
174
175
|
wrapperClass: "prose",
|
|
175
176
|
includeBase: true,
|
|
177
|
+
syntaxTheme: githubLight,
|
|
176
178
|
});
|
|
177
179
|
|
|
178
180
|
// Use in your app
|
|
@@ -197,6 +199,16 @@ function ArticlePreview() {
|
|
|
197
199
|
| `wrapperTag` | `string` | `"article"` | HTML tag for the wrapper element. |
|
|
198
200
|
| `markdown` | `MarkdownConfig[]` | `[]` | Additional parser extensions. |
|
|
199
201
|
|
|
202
|
+
#### CSS Configuration (`GenerateCSSConfig`)
|
|
203
|
+
|
|
204
|
+
| Option | Type | Default | Description |
|
|
205
|
+
| -------------- | -------------------------------------------- | ------------------- | ----------------------------------------------------------------------------- |
|
|
206
|
+
| `plugins` | `DraftlyPlugin[]` | `[]` | Plugins to collect preview styles from. |
|
|
207
|
+
| `theme` | `ThemeEnum` | `ThemeEnum.AUTO` | Theme mode for plugin preview styles. |
|
|
208
|
+
| `wrapperClass` | `string` | `"draftly-preview"` | Wrapper class used for CSS scoping. |
|
|
209
|
+
| `includeBase` | `boolean` | `true` | Include Draftly base preview layout styles. |
|
|
210
|
+
| `syntaxTheme` | `HighlightStyle \| Extension \| Extension[]` | `undefined` | CodeMirror syntax theme/extensions used to generate `tok-*` syntax token CSS. |
|
|
211
|
+
|
|
200
212
|
---
|
|
201
213
|
|
|
202
214
|
## Features
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var state = require('@codemirror/state');
|
|
4
|
+
var view = require('@codemirror/view');
|
|
5
|
+
|
|
6
|
+
// src/lib/input-handler.ts
|
|
7
|
+
function createWrapSelectionInputHandler(markersByInput) {
|
|
8
|
+
return view.EditorView.inputHandler.of((view, _from, _to, text) => {
|
|
9
|
+
const marker = markersByInput[text];
|
|
10
|
+
if (!marker) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const ranges = view.state.selection.ranges;
|
|
14
|
+
if (ranges.length === 0 || ranges.some((range) => range.empty)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const changes = ranges.map((range) => ({
|
|
18
|
+
from: range.from,
|
|
19
|
+
to: range.to,
|
|
20
|
+
insert: `${marker}${view.state.sliceDoc(range.from, range.to)}${marker}`
|
|
21
|
+
})).reverse();
|
|
22
|
+
const nextRanges = ranges.map((range) => state.EditorSelection.range(range.from + marker.length, range.to + marker.length));
|
|
23
|
+
view.dispatch({
|
|
24
|
+
changes,
|
|
25
|
+
selection: state.EditorSelection.create(nextRanges, view.state.selection.mainIndex)
|
|
26
|
+
});
|
|
27
|
+
return true;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.createWrapSelectionInputHandler = createWrapSelectionInputHandler;
|
|
32
|
+
//# sourceMappingURL=chunk-3T55CBNZ.cjs.map
|
|
33
|
+
//# sourceMappingURL=chunk-3T55CBNZ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/input-handler.ts"],"names":["EditorView","EditorSelection"],"mappings":";;;;;;AAeO,SAAS,gCAAgC,cAAA,EAAmD;AACjG,EAAA,OAAOA,gBAAW,YAAA,CAAa,EAAA,CAAG,CAAC,IAAA,EAAM,KAAA,EAAO,KAAK,IAAA,KAAS;AAC5D,IAAA,MAAM,MAAA,GAAS,eAAe,IAAI,CAAA;AAClC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,MAAA;AACpC,IAAA,IAAI,MAAA,CAAO,WAAW,CAAA,IAAK,MAAA,CAAO,KAAK,CAAC,KAAA,KAAU,KAAA,CAAM,KAAK,CAAA,EAAG;AAC9D,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,OAAA,GAAU,MAAA,CACb,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,MACf,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,IAAI,KAAA,CAAM,EAAA;AAAA,MACV,MAAA,EAAQ,CAAA,EAAG,MAAM,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,KAAA,CAAM,EAAE,CAAC,GAAG,MAAM,CAAA;AAAA,KACxE,CAAE,EACD,OAAA,EAAQ;AAEX,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,GAAA,CAAI,CAAC,UAAUC,qBAAA,CAAgB,KAAA,CAAM,KAAA,CAAM,IAAA,GAAO,OAAO,MAAA,EAAQ,KAAA,CAAM,EAAA,GAAK,MAAA,CAAO,MAAM,CAAC,CAAA;AAEpH,IAAA,IAAA,CAAK,QAAA,CAAS;AAAA,MACZ,OAAA;AAAA,MACA,WAAWA,qBAAA,CAAgB,MAAA,CAAO,YAAY,IAAA,CAAK,KAAA,CAAM,UAAU,SAAS;AAAA,KAC7E,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACH","file":"chunk-3T55CBNZ.cjs","sourcesContent":["import { EditorSelection, Extension } from \"@codemirror/state\";\r\nimport { EditorView } from \"@codemirror/view\";\r\n\r\n/**\r\n * Mapping of typed input characters to surrounding markers.\r\n *\r\n * Example:\r\n * { \"*\": \"*\", \"=\": \"==\" }\r\n */\r\nexport type WrapSelectionMarkerMap = Record<string, string>;\r\n\r\n/**\r\n * Creates an input handler that wraps non-empty selections with markdown markers\r\n * when a mapped character is typed.\r\n */\r\nexport function createWrapSelectionInputHandler(markersByInput: WrapSelectionMarkerMap): Extension {\r\n return EditorView.inputHandler.of((view, _from, _to, text) => {\r\n const marker = markersByInput[text];\r\n if (!marker) {\r\n return false;\r\n }\r\n\r\n const ranges = view.state.selection.ranges;\r\n if (ranges.length === 0 || ranges.some((range) => range.empty)) {\r\n return false;\r\n }\r\n\r\n const changes = ranges\r\n .map((range) => ({\r\n from: range.from,\r\n to: range.to,\r\n insert: `${marker}${view.state.sliceDoc(range.from, range.to)}${marker}`,\r\n }))\r\n .reverse();\r\n\r\n const nextRanges = ranges.map((range) => EditorSelection.range(range.from + marker.length, range.to + marker.length));\r\n\r\n view.dispatch({\r\n changes,\r\n selection: EditorSelection.create(nextRanges, view.state.selection.mainIndex),\r\n });\r\n\r\n return true;\r\n });\r\n}\r\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkCLW73JRX_cjs = require('./chunk-CLW73JRX.cjs');
|
|
4
|
+
|
|
5
|
+
// src/preview/preview.ts
|
|
6
|
+
async function preview(markdown, config = {}) {
|
|
7
|
+
const {
|
|
8
|
+
plugins = [],
|
|
9
|
+
markdown: markdownConfig = [],
|
|
10
|
+
wrapperClass = "draftly-preview",
|
|
11
|
+
wrapperTag = "article",
|
|
12
|
+
sanitize = true,
|
|
13
|
+
theme = "auto" /* AUTO */,
|
|
14
|
+
syntaxTheme
|
|
15
|
+
} = config;
|
|
16
|
+
const renderer = new chunkCLW73JRX_cjs.PreviewRenderer(markdown, plugins, markdownConfig, theme, sanitize, syntaxTheme);
|
|
17
|
+
const content = await renderer.render();
|
|
18
|
+
const classAttr = wrapperClass ? ` class="${wrapperClass}"` : "";
|
|
19
|
+
return `<${wrapperTag}${classAttr}>
|
|
20
|
+
${content}</${wrapperTag}>`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/preview/css-generator.ts
|
|
24
|
+
var baseStyles = `.draftly-preview {
|
|
25
|
+
padding: 0 0.5rem;
|
|
26
|
+
}`;
|
|
27
|
+
function generateCSS(config = {}) {
|
|
28
|
+
const {
|
|
29
|
+
plugins = [],
|
|
30
|
+
theme = "auto" /* AUTO */,
|
|
31
|
+
wrapperClass = "draftly-preview",
|
|
32
|
+
includeBase = true,
|
|
33
|
+
syntaxTheme
|
|
34
|
+
} = config;
|
|
35
|
+
const cssChunks = [];
|
|
36
|
+
if (includeBase) {
|
|
37
|
+
if (wrapperClass !== "draftly-preview") {
|
|
38
|
+
cssChunks.push(baseStyles.replace(/\.draftly-preview/g, `.${wrapperClass}`));
|
|
39
|
+
} else {
|
|
40
|
+
cssChunks.push(baseStyles);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const syntaxCSS = chunkCLW73JRX_cjs.generateSyntaxThemeCSS(syntaxTheme, wrapperClass);
|
|
44
|
+
if (syntaxCSS) {
|
|
45
|
+
cssChunks.push("/* syntax-theme */\n" + syntaxCSS);
|
|
46
|
+
}
|
|
47
|
+
for (const plugin of plugins) {
|
|
48
|
+
const pluginCSS = plugin.getPreviewStyles(theme, wrapperClass);
|
|
49
|
+
if (pluginCSS) cssChunks.push(`/* ${plugin.name} - ${plugin.version} */
|
|
50
|
+
` + pluginCSS);
|
|
51
|
+
}
|
|
52
|
+
return cssChunks.join("\n\n");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
exports.generateCSS = generateCSS;
|
|
56
|
+
exports.preview = preview;
|
|
57
|
+
//# sourceMappingURL=chunk-5MC4T7JH.cjs.map
|
|
58
|
+
//# sourceMappingURL=chunk-5MC4T7JH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/preview/preview.ts","../src/preview/css-generator.ts"],"names":["PreviewRenderer","generateSyntaxThemeCSS"],"mappings":";;;;;AAsBA,eAAsB,OAAA,CAAQ,QAAA,EAAkB,MAAA,GAAwB,EAAC,EAAoB;AAC3F,EAAA,MAAM;AAAA,IACJ,UAAU,EAAC;AAAA,IACX,QAAA,EAAU,iBAAiB,EAAC;AAAA,IAC5B,YAAA,GAAe,iBAAA;AAAA,IACf,UAAA,GAAa,SAAA;AAAA,IACb,QAAA,GAAW,IAAA;AAAA,IACX,KAAA,GAAA,MAAA;AAAA,IACA;AAAA,GACF,GAAI,MAAA;AAGJ,EAAA,MAAM,QAAA,GAAW,IAAIA,iCAAA,CAAgB,QAAA,EAAU,SAAS,cAAA,EAAgB,KAAA,EAAO,UAAU,WAAW,CAAA;AACpG,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,MAAA,EAAO;AAGtC,EAAA,MAAM,SAAA,GAAY,YAAA,GAAe,CAAA,QAAA,EAAW,YAAY,CAAA,CAAA,CAAA,GAAM,EAAA;AAC9D,EAAA,OAAO,CAAA,CAAA,EAAI,UAAU,CAAA,EAAG,SAAS,CAAA;AAAA,EAAM,OAAO,KAAK,UAAU,CAAA,CAAA,CAAA;AAC/D;;;ACjCA,IAAM,UAAA,GAAa,CAAA;AAAA;AAAA,CAAA,CAAA;AAsBZ,SAAS,WAAA,CAAY,MAAA,GAA4B,EAAC,EAAW;AAClE,EAAA,MAAM;AAAA,IACJ,UAAU,EAAC;AAAA,IACX,KAAA,GAAA,MAAA;AAAA,IACA,YAAA,GAAe,iBAAA;AAAA,IACf,WAAA,GAAc,IAAA;AAAA,IACd;AAAA,GACF,GAAI,MAAA;AAEJ,EAAA,MAAM,YAAsB,EAAC;AAG7B,EAAA,IAAI,WAAA,EAAa;AAEf,IAAA,IAAI,iBAAiB,iBAAA,EAAmB;AACtC,MAAA,SAAA,CAAU,KAAK,UAAA,CAAW,OAAA,CAAQ,sBAAsB,CAAA,CAAA,EAAI,YAAY,EAAE,CAAC,CAAA;AAAA,IAC7E,CAAA,MAAO;AACL,MAAA,SAAA,CAAU,KAAK,UAAU,CAAA;AAAA,IAC3B;AAAA,EACF;AAGA,EAAA,MAAM,SAAA,GAAYC,wCAAA,CAAuB,WAAA,EAAa,YAAY,CAAA;AAClE,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,SAAA,CAAU,IAAA,CAAK,yBAAyB,SAAS,CAAA;AAAA,EACnD;AAGA,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,gBAAA,CAAiB,KAAA,EAAO,YAAY,CAAA;AAC7D,IAAA,IAAI,SAAA,YAAqB,IAAA,CAAK,CAAA,GAAA,EAAM,OAAO,IAAI,CAAA,GAAA,EAAM,OAAO,OAAO,CAAA;AAAA,CAAA,GAAU,SAAS,CAAA;AAAA,EACxF;AAEA,EAAA,OAAO,SAAA,CAAU,KAAK,MAAM,CAAA;AAC9B","file":"chunk-5MC4T7JH.cjs","sourcesContent":["import { ThemeEnum } from \"../editor/utils\";\r\nimport { PreviewRenderer } from \"./renderer\";\r\nimport { PreviewConfig } from \"./types\";\r\n\r\n/**\r\n * Render markdown to semantic HTML\r\n *\r\n * @param markdown - Markdown string to render\r\n * @param config - Preview configuration\r\n * @returns HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * import { preview } from 'draftly/preview';\r\n * import { HeadingPlugin, ListPlugin } from 'draftly/plugins';\r\n *\r\n * const html = preview('# Hello World', {\r\n * plugins: [new HeadingPlugin(), new ListPlugin()],\r\n * wrapperClass: 'draftly-preview',\r\n * });\r\n * ```\r\n */\r\nexport async function preview(markdown: string, config: PreviewConfig = {}): Promise<string> {\r\n const {\r\n plugins = [],\r\n markdown: markdownConfig = [],\r\n wrapperClass = \"draftly-preview\",\r\n wrapperTag = \"article\",\r\n sanitize = true,\r\n theme = ThemeEnum.AUTO,\r\n syntaxTheme,\r\n } = config;\r\n\r\n // Create renderer and generate HTML\r\n const renderer = new PreviewRenderer(markdown, plugins, markdownConfig, theme, sanitize, syntaxTheme);\r\n const content = await renderer.render();\r\n\r\n // Wrap in container\r\n const classAttr = wrapperClass ? ` class=\"${wrapperClass}\"` : \"\";\r\n return `<${wrapperTag}${classAttr}>\\n${content}</${wrapperTag}>`;\r\n}\r\n","import { ThemeEnum } from \"../editor/utils\";\r\nimport { GenerateCSSConfig } from \"./types\";\r\nimport { generateSyntaxThemeCSS } from \"./syntax-theme\";\r\n\r\n/**\r\n * Base CSS styles for preview rendering\r\n */\r\nconst baseStyles = `.draftly-preview {\r\n padding: 0 0.5rem;\r\n}`;\r\n\r\n/**\r\n * Generate CSS for preview rendering\r\n *\r\n * @param config - CSS generation configuration\r\n * @returns CSS string\r\n *\r\n * @example\r\n * ```ts\r\n * import { generateCSS } from 'draftly/preview';\r\n * import { HeadingPlugin, ListPlugin } from 'draftly/plugins';\r\n *\r\n * const css = generateCSS({\r\n * plugins: [new HeadingPlugin(), new ListPlugin()],\r\n * theme: ThemeEnum.AUTO,\r\n * includeBase: true,\r\n * });\r\n * ```\r\n */\r\nexport function generateCSS(config: GenerateCSSConfig = {}): string {\r\n const {\r\n plugins = [],\r\n theme = ThemeEnum.AUTO,\r\n wrapperClass = \"draftly-preview\",\r\n includeBase = true,\r\n syntaxTheme,\r\n } = config;\r\n\r\n const cssChunks: string[] = [];\r\n\r\n // Include base styles\r\n if (includeBase) {\r\n // Replace default wrapper class if custom one is provided\r\n if (wrapperClass !== \"draftly-preview\") {\r\n cssChunks.push(baseStyles.replace(/\\.draftly-preview/g, `.${wrapperClass}`));\r\n } else {\r\n cssChunks.push(baseStyles);\r\n }\r\n }\r\n\r\n // Collect syntax highlight styles (`tok-*` classes) from CodeMirror theme/extensions\r\n const syntaxCSS = generateSyntaxThemeCSS(syntaxTheme, wrapperClass);\r\n if (syntaxCSS) {\r\n cssChunks.push(\"/* syntax-theme */\\n\" + syntaxCSS);\r\n }\r\n\r\n // Collect styles from plugins\r\n for (const plugin of plugins) {\r\n const pluginCSS = plugin.getPreviewStyles(theme, wrapperClass);\r\n if (pluginCSS) cssChunks.push(`/* ${plugin.name} - ${plugin.version} */\\n` + pluginCSS);\r\n }\r\n\r\n return cssChunks.join(\"\\n\\n\");\r\n}\r\n"]}
|
|
@@ -1,18 +1,95 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var highlight = require('@lezer/highlight');
|
|
4
|
+
var langMarkdown = require('@codemirror/lang-markdown');
|
|
5
|
+
var languageData = require('@codemirror/language-data');
|
|
4
6
|
var DOMPurify = require('dompurify');
|
|
5
|
-
var language = require('@codemirror/language');
|
|
6
7
|
|
|
7
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
|
|
9
10
|
var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
|
|
10
11
|
|
|
11
|
-
// src/preview/
|
|
12
|
-
function
|
|
12
|
+
// src/preview/default-renderers.ts
|
|
13
|
+
function escapeHtml(text) {
|
|
14
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
15
|
+
}
|
|
16
|
+
var renderDocument = (_node, children) => {
|
|
17
|
+
return children;
|
|
18
|
+
};
|
|
19
|
+
var defaultRenderers = {
|
|
20
|
+
// Document structure
|
|
21
|
+
Document: renderDocument
|
|
22
|
+
};
|
|
23
|
+
var MAX_WALK_DEPTH = 8;
|
|
24
|
+
function generateSyntaxThemeCSS(syntaxTheme, _wrapperClass) {
|
|
25
|
+
if (!syntaxTheme) return "";
|
|
26
|
+
const styles = extractRuntimeHighlightStyles(syntaxTheme);
|
|
27
|
+
if (!styles.length) return "";
|
|
28
|
+
const cssChunks = [];
|
|
29
|
+
for (const style of styles) {
|
|
30
|
+
const rules = style.module?.getRules();
|
|
31
|
+
if (!rules) continue;
|
|
32
|
+
cssChunks.push(rules);
|
|
33
|
+
}
|
|
34
|
+
if (!cssChunks.length) return "";
|
|
35
|
+
return Array.from(new Set(cssChunks)).join("\n");
|
|
36
|
+
}
|
|
37
|
+
function resolveSyntaxHighlighters(syntaxTheme, includeLegacyClassHighlighter = true) {
|
|
38
|
+
const resolved = [];
|
|
39
|
+
if (includeLegacyClassHighlighter) {
|
|
40
|
+
resolved.push(highlight.classHighlighter);
|
|
41
|
+
}
|
|
42
|
+
const styles = extractRuntimeHighlightStyles(syntaxTheme);
|
|
43
|
+
for (const style of styles) {
|
|
44
|
+
if (typeof style.style === "function") {
|
|
45
|
+
resolved.push(style);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return Array.from(new Set(resolved));
|
|
49
|
+
}
|
|
50
|
+
function extractRuntimeHighlightStyles(input) {
|
|
51
|
+
if (!input) return [];
|
|
52
|
+
const values = Array.isArray(input) ? input : [input];
|
|
53
|
+
const styles = [];
|
|
54
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
55
|
+
for (const value of values) {
|
|
56
|
+
walk(value, 0, visited, styles);
|
|
57
|
+
}
|
|
58
|
+
return styles;
|
|
59
|
+
}
|
|
60
|
+
function walk(value, depth, visited, out) {
|
|
61
|
+
if (value === null || value === void 0) return;
|
|
62
|
+
if (depth > MAX_WALK_DEPTH) return;
|
|
63
|
+
if (isRuntimeHighlightStyle(value)) {
|
|
64
|
+
out.push(value);
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
for (const item of value) {
|
|
68
|
+
walk(item, depth + 1, visited, out);
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (typeof value !== "object") return;
|
|
73
|
+
if (visited.has(value)) return;
|
|
74
|
+
visited.add(value);
|
|
75
|
+
const keys = Object.getOwnPropertyNames(value);
|
|
76
|
+
for (const key of keys) {
|
|
77
|
+
try {
|
|
78
|
+
walk(value[key], depth + 1, visited, out);
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function isRuntimeHighlightStyle(value) {
|
|
84
|
+
if (!value || typeof value !== "object") return false;
|
|
85
|
+
const style = value;
|
|
86
|
+
return Array.isArray(style.specs) && typeof style.style === "function";
|
|
87
|
+
}
|
|
88
|
+
function createPreviewContext(doc, theme, renderChildren, sanitizeHtml = true, syntaxHighlighters = []) {
|
|
13
89
|
return {
|
|
14
90
|
doc,
|
|
15
91
|
theme,
|
|
92
|
+
syntaxHighlighters,
|
|
16
93
|
sliceDoc(from, to) {
|
|
17
94
|
return doc.slice(from, to);
|
|
18
95
|
},
|
|
@@ -27,34 +104,27 @@ function createPreviewContext(doc, theme, renderChildren, sanitizeHtml = true) {
|
|
|
27
104
|
};
|
|
28
105
|
}
|
|
29
106
|
|
|
30
|
-
// src/preview/
|
|
31
|
-
function escapeHtml(text) {
|
|
32
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
33
|
-
}
|
|
34
|
-
var renderDocument = (_node, children) => {
|
|
35
|
-
return children;
|
|
36
|
-
};
|
|
37
|
-
var defaultRenderers = {
|
|
38
|
-
// Document structure
|
|
39
|
-
Document: renderDocument
|
|
40
|
-
};
|
|
107
|
+
// src/preview/renderer.ts
|
|
41
108
|
var PreviewRenderer = class {
|
|
42
109
|
doc;
|
|
43
110
|
theme;
|
|
44
111
|
plugins;
|
|
45
112
|
markdown;
|
|
46
113
|
sanitizeHtml;
|
|
114
|
+
syntaxTheme;
|
|
47
115
|
renderers;
|
|
48
116
|
ctx;
|
|
49
117
|
nodeToPlugins;
|
|
50
|
-
constructor(doc, plugins = [],
|
|
118
|
+
constructor(doc, plugins = [], markdown2, theme = "auto" /* AUTO */, sanitize = true, syntaxTheme) {
|
|
51
119
|
this.doc = doc;
|
|
52
120
|
this.theme = theme;
|
|
53
121
|
this.plugins = plugins;
|
|
54
|
-
this.markdown =
|
|
122
|
+
this.markdown = markdown2;
|
|
55
123
|
this.sanitizeHtml = sanitize;
|
|
124
|
+
this.syntaxTheme = syntaxTheme;
|
|
56
125
|
this.renderers = { ...defaultRenderers };
|
|
57
|
-
|
|
126
|
+
const syntaxHighlighters = resolveSyntaxHighlighters(this.syntaxTheme, true);
|
|
127
|
+
this.ctx = createPreviewContext(doc, theme, this.renderChildren.bind(this), sanitize, syntaxHighlighters);
|
|
58
128
|
this.nodeToPlugins = this.buildNodePluginMap();
|
|
59
129
|
}
|
|
60
130
|
/**
|
|
@@ -81,20 +151,15 @@ var PreviewRenderer = class {
|
|
|
81
151
|
...this.markdown,
|
|
82
152
|
...this.plugins.map((p) => p.getMarkdownConfig()).filter((ext) => ext !== null)
|
|
83
153
|
];
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
})
|
|
94
|
-
]
|
|
95
|
-
}
|
|
96
|
-
]);
|
|
97
|
-
const parser = extensions.length > 0 ? baseParser.configure(extensions) : baseParser;
|
|
154
|
+
const markdownSupport = langMarkdown.markdown({
|
|
155
|
+
base: langMarkdown.markdownLanguage,
|
|
156
|
+
codeLanguages: languageData.languages,
|
|
157
|
+
extensions,
|
|
158
|
+
addKeymap: true,
|
|
159
|
+
completeHTMLTags: true,
|
|
160
|
+
pasteURLAsLink: true
|
|
161
|
+
});
|
|
162
|
+
const parser = markdownSupport.language.parser;
|
|
98
163
|
const tree = parser.parse(this.doc);
|
|
99
164
|
return await this.renderNode(tree.topNode);
|
|
100
165
|
}
|
|
@@ -144,49 +209,9 @@ var PreviewRenderer = class {
|
|
|
144
209
|
}
|
|
145
210
|
};
|
|
146
211
|
|
|
147
|
-
// src/preview/preview.ts
|
|
148
|
-
async function preview(markdown, config = {}) {
|
|
149
|
-
const {
|
|
150
|
-
plugins = [],
|
|
151
|
-
markdown: markdownConfig = [],
|
|
152
|
-
wrapperClass = "draftly-preview",
|
|
153
|
-
wrapperTag = "article",
|
|
154
|
-
sanitize = true,
|
|
155
|
-
theme = "auto" /* AUTO */
|
|
156
|
-
} = config;
|
|
157
|
-
const renderer = new PreviewRenderer(markdown, plugins, markdownConfig, theme, sanitize);
|
|
158
|
-
const content = await renderer.render();
|
|
159
|
-
const classAttr = wrapperClass ? ` class="${wrapperClass}"` : "";
|
|
160
|
-
return `<${wrapperTag}${classAttr}>
|
|
161
|
-
${content}</${wrapperTag}>`;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/preview/css-generator.ts
|
|
165
|
-
var baseStyles = `.draftly-preview {
|
|
166
|
-
padding: 0 0.5rem;
|
|
167
|
-
}`;
|
|
168
|
-
function generateCSS(config = {}) {
|
|
169
|
-
const { plugins = [], theme = "auto" /* AUTO */, wrapperClass = "draftly-preview", includeBase = true } = config;
|
|
170
|
-
const cssChunks = [];
|
|
171
|
-
if (includeBase) {
|
|
172
|
-
if (wrapperClass !== "draftly-preview") {
|
|
173
|
-
cssChunks.push(baseStyles.replace(/\.draftly-preview/g, `.${wrapperClass}`));
|
|
174
|
-
} else {
|
|
175
|
-
cssChunks.push(baseStyles);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
for (const plugin of plugins) {
|
|
179
|
-
const pluginCSS = plugin.getPreviewStyles(theme, wrapperClass);
|
|
180
|
-
if (pluginCSS) cssChunks.push(`/* ${plugin.name} - ${plugin.version} */
|
|
181
|
-
` + pluginCSS);
|
|
182
|
-
}
|
|
183
|
-
return cssChunks.join("\n\n");
|
|
184
|
-
}
|
|
185
|
-
|
|
186
212
|
exports.PreviewRenderer = PreviewRenderer;
|
|
187
213
|
exports.defaultRenderers = defaultRenderers;
|
|
188
214
|
exports.escapeHtml = escapeHtml;
|
|
189
|
-
exports.
|
|
190
|
-
|
|
191
|
-
//# sourceMappingURL=chunk-
|
|
192
|
-
//# sourceMappingURL=chunk-KBQDZ5IW.cjs.map
|
|
215
|
+
exports.generateSyntaxThemeCSS = generateSyntaxThemeCSS;
|
|
216
|
+
//# sourceMappingURL=chunk-CLW73JRX.cjs.map
|
|
217
|
+
//# sourceMappingURL=chunk-CLW73JRX.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/preview/default-renderers.ts","../src/preview/syntax-theme.ts","../src/preview/context.ts","../src/preview/renderer.ts"],"names":["classHighlighter","DOMPurify","markdown","markdownLanguage","languages"],"mappings":"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","file":"chunk-CLW73JRX.cjs","sourcesContent":["import { NodeRenderer, NodeRendererMap } from \"./types\";\r\n\r\n/**\r\n * Escape HTML special characters\r\n */\r\nexport function escapeHtml(text: string): string {\r\n return text\r\n .replace(/&/g, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"'\");\r\n}\r\n\r\n// ============================================\r\n// DEFAULT RENDERERS\r\n// ============================================\r\n\r\nconst renderDocument: NodeRenderer = (_node, children) => {\r\n return children;\r\n};\r\n\r\n/**\r\n * Default node renderers for all markdown node types\r\n */\r\nexport const defaultRenderers: NodeRendererMap = {\r\n // Document structure\r\n Document: renderDocument,\r\n};\r\n","import { classHighlighter, Highlighter } from \"@lezer/highlight\";\r\nimport type { SyntaxThemeInput } from \"./types\";\r\n\r\ntype HighlightSpec = {\r\n tag?: unknown;\r\n class?: string;\r\n [key: string]: unknown;\r\n};\r\n\r\ntype RuntimeHighlightStyle = {\r\n specs?: HighlightSpec[];\r\n style?: (tags: readonly import(\"@lezer/highlight\").Tag[]) => string | null;\r\n module?: { getRules(): string } | null;\r\n};\r\n\r\nconst MAX_WALK_DEPTH = 8;\r\n\r\n/**\r\n * Extract syntax highlight CSS from resolved CodeMirror HighlightStyle modules.\r\n */\r\nexport function generateSyntaxThemeCSS(\r\n syntaxTheme: SyntaxThemeInput | SyntaxThemeInput[] | undefined,\r\n _wrapperClass: string\r\n): string {\r\n if (!syntaxTheme) return \"\";\r\n\r\n const styles = extractRuntimeHighlightStyles(syntaxTheme);\r\n if (!styles.length) return \"\";\r\n\r\n const cssChunks: string[] = [];\r\n\r\n for (const style of styles) {\r\n const rules = style.module?.getRules();\r\n if (!rules) continue;\r\n cssChunks.push(rules);\r\n }\r\n\r\n if (!cssChunks.length) return \"\";\r\n\r\n return Array.from(new Set(cssChunks))\r\n .join(\"\\n\");\r\n}\r\n\r\nexport function resolveSyntaxHighlighters(\r\n syntaxTheme: SyntaxThemeInput | SyntaxThemeInput[] | undefined,\r\n includeLegacyClassHighlighter: boolean = true\r\n): readonly Highlighter[] {\r\n const resolved: Highlighter[] = [];\r\n if (includeLegacyClassHighlighter) {\r\n resolved.push(classHighlighter);\r\n }\r\n\r\n const styles = extractRuntimeHighlightStyles(syntaxTheme);\r\n for (const style of styles) {\r\n if (typeof style.style === \"function\") {\r\n resolved.push(style as unknown as Highlighter);\r\n }\r\n }\r\n\r\n return Array.from(new Set(resolved));\r\n}\r\n\r\nfunction extractRuntimeHighlightStyles(input: SyntaxThemeInput | SyntaxThemeInput[] | undefined): RuntimeHighlightStyle[] {\r\n if (!input) return [];\r\n\r\n const values = Array.isArray(input) ? input : [input];\r\n const styles: RuntimeHighlightStyle[] = [];\r\n const visited = new WeakSet<object>();\r\n\r\n for (const value of values) {\r\n walk(value, 0, visited, styles);\r\n }\r\n\r\n return styles;\r\n}\r\n\r\nfunction walk(value: unknown, depth: number, visited: WeakSet<object>, out: RuntimeHighlightStyle[]): void {\r\n if (value === null || value === undefined) return;\r\n if (depth > MAX_WALK_DEPTH) return;\r\n\r\n if (isRuntimeHighlightStyle(value)) {\r\n out.push(value);\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n for (const item of value) {\r\n walk(item, depth + 1, visited, out);\r\n }\r\n return;\r\n }\r\n\r\n if (typeof value !== \"object\") return;\r\n if (visited.has(value)) return;\r\n visited.add(value);\r\n\r\n const keys = Object.getOwnPropertyNames(value);\r\n for (const key of keys) {\r\n try {\r\n walk((value as Record<string, unknown>)[key], depth + 1, visited, out);\r\n } catch {\r\n // Ignore inaccessible properties\r\n }\r\n }\r\n}\r\n\r\nfunction isRuntimeHighlightStyle(value: unknown): value is RuntimeHighlightStyle {\r\n if (!value || typeof value !== \"object\") return false;\r\n const style = value as RuntimeHighlightStyle;\r\n return Array.isArray(style.specs) && typeof style.style === \"function\";\r\n}\r\n","import { SyntaxNode } from \"@lezer/common\";\r\nimport { Highlighter } from \"@lezer/highlight\";\r\nimport { ThemeEnum } from \"../editor/utils\";\r\nimport { PreviewContext } from \"./types\";\r\nimport DOMPurify from \"dompurify\";\r\n\r\n/**\r\n * Creates a PreviewContext for rendering\r\n */\r\nexport function createPreviewContext(\r\n doc: string,\r\n theme: ThemeEnum,\r\n renderChildren: (node: SyntaxNode) => Promise<string>,\r\n sanitizeHtml: boolean = true,\r\n syntaxHighlighters: readonly Highlighter[] = []\r\n): PreviewContext {\r\n return {\r\n doc,\r\n theme,\r\n syntaxHighlighters,\r\n\r\n sliceDoc(from: number, to: number): string {\r\n return doc.slice(from, to);\r\n },\r\n\r\n sanitize(html: string): string {\r\n if (!sanitizeHtml) return html;\r\n\r\n // DOMPurify works in browser; in Node, it needs jsdom\r\n if (typeof window !== \"undefined\") {\r\n return DOMPurify.sanitize(html);\r\n }\r\n\r\n // Server-side: return as-is (user should sanitize at application level)\r\n // or use isomorphic-dompurify in their setup\r\n return html;\r\n },\r\n\r\n renderChildren,\r\n };\r\n}\r\n","import { SyntaxNode } from \"@lezer/common\";\r\nimport { markdown, markdownLanguage } from \"@codemirror/lang-markdown\";\r\nimport { MarkdownConfig } from \"@lezer/markdown\";\r\nimport { languages } from \"@codemirror/language-data\";\r\n\r\nimport { DraftlyPlugin } from \"../editor/plugin\";\r\nimport { ThemeEnum } from \"../editor/utils\";\r\nimport { createPreviewContext } from \"./context\";\r\nimport { defaultRenderers, escapeHtml } from \"./default-renderers\";\r\nimport { resolveSyntaxHighlighters } from \"./syntax-theme\";\r\nimport { NodeRendererMap, PreviewContext } from \"./types\";\r\n\r\n/**\r\n * Renderer class that walks the syntax tree and produces HTML\r\n */\r\nexport class PreviewRenderer {\r\n private doc: string;\r\n private theme: ThemeEnum;\r\n private plugins: DraftlyPlugin[];\r\n private markdown: MarkdownConfig[];\r\n private sanitizeHtml: boolean;\r\n private syntaxTheme: import(\"./types\").SyntaxThemeInput | import(\"./types\").SyntaxThemeInput[] | undefined;\r\n private renderers: NodeRendererMap;\r\n private ctx: PreviewContext;\r\n private nodeToPlugins: Map<string, DraftlyPlugin[]>;\r\n\r\n constructor(\r\n doc: string,\r\n plugins: DraftlyPlugin[] = [],\r\n markdown: MarkdownConfig[],\r\n theme: ThemeEnum = ThemeEnum.AUTO,\r\n sanitize: boolean = true,\r\n syntaxTheme?: import(\"./types\").SyntaxThemeInput | import(\"./types\").SyntaxThemeInput[]\r\n ) {\r\n this.doc = doc;\r\n this.theme = theme;\r\n this.plugins = plugins;\r\n this.markdown = markdown;\r\n this.sanitizeHtml = sanitize;\r\n this.syntaxTheme = syntaxTheme;\r\n this.renderers = { ...defaultRenderers };\r\n\r\n const syntaxHighlighters = resolveSyntaxHighlighters(this.syntaxTheme, true);\r\n\r\n // Create context with reference to renderChildren\r\n this.ctx = createPreviewContext(doc, theme, this.renderChildren.bind(this), sanitize, syntaxHighlighters);\r\n\r\n // Build node-to-plugin map for O(1) lookup\r\n this.nodeToPlugins = this.buildNodePluginMap();\r\n }\r\n\r\n /**\r\n * Build a map from node names to plugins that handle them\r\n */\r\n private buildNodePluginMap(): Map<string, DraftlyPlugin[]> {\r\n const map = new Map<string, DraftlyPlugin[]>();\r\n for (const plugin of this.plugins) {\r\n if (plugin.renderToHTML && plugin.requiredNodes.length > 0) {\r\n for (const nodeName of plugin.requiredNodes) {\r\n const list = map.get(nodeName) || [];\r\n list.push(plugin);\r\n map.set(nodeName, list);\r\n }\r\n }\r\n }\r\n return map;\r\n }\r\n\r\n /**\r\n * Render the document to HTML\r\n */\r\n async render(): Promise<string> {\r\n // Collect markdown extensions from plugins\r\n const extensions = [\r\n ...this.markdown,\r\n ...this.plugins.map((p) => p.getMarkdownConfig()).filter((ext): ext is NonNullable<typeof ext> => ext !== null),\r\n ];\r\n\r\n // Build parser through @codemirror/lang-markdown to match editor behavior exactly\r\n const markdownSupport = markdown({\r\n base: markdownLanguage,\r\n codeLanguages: languages,\r\n extensions,\r\n addKeymap: true,\r\n completeHTMLTags: true,\r\n pasteURLAsLink: true,\r\n });\r\n const parser = markdownSupport.language.parser;\r\n\r\n // Parse the document\r\n const tree = parser.parse(this.doc);\r\n\r\n // Render from root\r\n return await this.renderNode(tree.topNode);\r\n }\r\n\r\n /**\r\n * Render a single node to HTML\r\n */\r\n private async renderNode(node: SyntaxNode): Promise<string> {\r\n // Get plugins that handle this node type (O(1) lookup)\r\n const plugins = this.nodeToPlugins.get(node.name);\r\n if (plugins) {\r\n for (const plugin of plugins) {\r\n const children = await this.renderChildren(node);\r\n const result = await plugin.renderToHTML!(node, children, this.ctx);\r\n if (result !== null) {\r\n return result;\r\n }\r\n }\r\n }\r\n\r\n // Use default renderer\r\n const renderer = this.renderers[node.name];\r\n if (renderer) {\r\n const children = await this.renderChildren(node);\r\n return renderer(node, children, this.ctx);\r\n }\r\n\r\n // Unknown node - render children or text\r\n if (node.firstChild) {\r\n return await this.renderChildren(node);\r\n }\r\n\r\n // Leaf node - return text content\r\n return this.ctx.sliceDoc(node.from, node.to);\r\n }\r\n\r\n /**\r\n * Render all children of a node, including text between nodes\r\n */\r\n private async renderChildren(node: SyntaxNode): Promise<string> {\r\n let result = \"\";\r\n let pos = node.from; // Track position to find text gaps\r\n let child = node.firstChild;\r\n\r\n while (child) {\r\n // Add any text between the last position and this child\r\n if (child.from > pos) {\r\n result += escapeHtml(this.ctx.sliceDoc(pos, child.from));\r\n }\r\n\r\n // Render the child node\r\n result += await this.renderNode(child);\r\n\r\n // Update position to end of this child\r\n pos = child.to;\r\n child = child.nextSibling;\r\n }\r\n\r\n // Add any trailing text after the last child\r\n if (pos < node.to) {\r\n result += escapeHtml(this.ctx.sliceDoc(pos, node.to));\r\n }\r\n\r\n return result;\r\n }\r\n}\r\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkW75QUUQC_cjs = require('./chunk-W75QUUQC.cjs');
|
|
4
4
|
var state = require('@codemirror/state');
|
|
5
5
|
var view = require('@codemirror/view');
|
|
6
6
|
var langMarkdown = require('@codemirror/lang-markdown');
|
|
@@ -14,7 +14,8 @@ var draftlyBaseTheme = view.EditorView.theme({
|
|
|
14
14
|
// Container styles - only apply when view plugin is enabled
|
|
15
15
|
"&.cm-draftly": {
|
|
16
16
|
fontSize: "16px",
|
|
17
|
-
lineHeight: "1.6"
|
|
17
|
+
lineHeight: "1.6",
|
|
18
|
+
backgroundColor: "transparent !important"
|
|
18
19
|
},
|
|
19
20
|
"&.cm-draftly .cm-content": {
|
|
20
21
|
width: "100%",
|
|
@@ -72,8 +73,8 @@ function buildDecorations(view, plugins = []) {
|
|
|
72
73
|
const ctx = {
|
|
73
74
|
view,
|
|
74
75
|
decorations,
|
|
75
|
-
selectionOverlapsRange: (from, to) =>
|
|
76
|
-
cursorInRange: (from, to) =>
|
|
76
|
+
selectionOverlapsRange: (from, to) => chunkW75QUUQC_cjs.selectionOverlapsRange(view, from, to),
|
|
77
|
+
cursorInRange: (from, to) => chunkW75QUUQC_cjs.cursorInRange(view, from, to)
|
|
77
78
|
};
|
|
78
79
|
const sortedPlugins = [...plugins].sort((a, b) => a.decorationPriority - b.decorationPriority);
|
|
79
80
|
for (const plugin of sortedPlugins) {
|
|
@@ -128,7 +129,7 @@ var draftlyViewPluginClass = class {
|
|
|
128
129
|
to: nodeRef.to,
|
|
129
130
|
name: nodeRef.name,
|
|
130
131
|
children: [],
|
|
131
|
-
isSelected:
|
|
132
|
+
isSelected: chunkW75QUUQC_cjs.selectionOverlapsRange(view, nodeRef.from, nodeRef.to)
|
|
132
133
|
};
|
|
133
134
|
if (stack.length > 0) {
|
|
134
135
|
stack[stack.length - 1].children.push(node);
|
|
@@ -179,23 +180,25 @@ function draftly(config = {}) {
|
|
|
179
180
|
const pluginKeymaps = [];
|
|
180
181
|
const markdownExtensions = [];
|
|
181
182
|
const pluginContext = { config };
|
|
182
|
-
|
|
183
|
-
plugin
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
183
|
+
if (!disableViewPlugin) {
|
|
184
|
+
for (const plugin of allPlugins) {
|
|
185
|
+
plugin.onRegister(pluginContext);
|
|
186
|
+
const exts = plugin.getExtensions();
|
|
187
|
+
if (exts.length > 0) {
|
|
188
|
+
pluginExtensions.push(...exts);
|
|
189
|
+
}
|
|
190
|
+
const keys = plugin.getKeymap();
|
|
191
|
+
if (keys.length > 0) {
|
|
192
|
+
pluginKeymaps.push(...keys);
|
|
193
|
+
}
|
|
194
|
+
const theme = plugin.theme;
|
|
195
|
+
if (baseStyles && theme && typeof theme === "function") {
|
|
196
|
+
pluginExtensions.push(view.EditorView.theme(theme(configTheme)));
|
|
197
|
+
}
|
|
198
|
+
const md = plugin.getMarkdownConfig();
|
|
199
|
+
if (md) {
|
|
200
|
+
markdownExtensions.push(md);
|
|
201
|
+
}
|
|
199
202
|
}
|
|
200
203
|
}
|
|
201
204
|
if (config.markdown) {
|
|
@@ -206,7 +209,8 @@ function draftly(config = {}) {
|
|
|
206
209
|
codeLanguages: languageData.languages,
|
|
207
210
|
extensions: markdownExtensions,
|
|
208
211
|
addKeymap: true,
|
|
209
|
-
completeHTMLTags: true
|
|
212
|
+
completeHTMLTags: true,
|
|
213
|
+
pasteURLAsLink: true
|
|
210
214
|
});
|
|
211
215
|
const baseExtensions = [
|
|
212
216
|
...defaultKeybindings ? [view.keymap.of(commands.defaultKeymap)] : [],
|
|
@@ -262,7 +266,7 @@ var DraftlyPlugin = class {
|
|
|
262
266
|
}
|
|
263
267
|
/** Plugin theme */
|
|
264
268
|
get theme() {
|
|
265
|
-
return
|
|
269
|
+
return chunkW75QUUQC_cjs.createTheme({
|
|
266
270
|
default: {},
|
|
267
271
|
dark: {},
|
|
268
272
|
light: {}
|
|
@@ -395,5 +399,5 @@ exports.SyntaxPlugin = SyntaxPlugin;
|
|
|
395
399
|
exports.draftly = draftly;
|
|
396
400
|
exports.draftlyBaseTheme = draftlyBaseTheme;
|
|
397
401
|
exports.markdownResetExtension = markdownResetExtension;
|
|
398
|
-
//# sourceMappingURL=chunk-
|
|
399
|
-
//# sourceMappingURL=chunk-
|
|
402
|
+
//# sourceMappingURL=chunk-EQUQHE2E.cjs.map
|
|
403
|
+
//# sourceMappingURL=chunk-EQUQHE2E.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/editor/theme.ts","../src/editor/view-plugin.ts","../src/editor/draftly.ts","../src/editor/plugin.ts"],"names":["EditorView","HighlightStyle","t","syntaxHighlighting","Facet","RangeSetBuilder","selectionOverlapsRange","cursorInRange","syntaxTree","ViewPlugin","markdown","markdownLanguage","languages","keymap","defaultKeymap","history","historyKeymap","indentOnInput","indentWithTab","highlightActiveLine","Prec","markdownKeymap","createTheme","styleMod","StyleModule"],"mappings":"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","file":"chunk-EQUQHE2E.cjs","sourcesContent":["import { EditorView } from \"@codemirror/view\";\n\n/**\n * Base theme for draftly styling\n * Note: Layout styles are scoped under .cm-draftly which is added by the view plugin\n */\nexport const draftlyBaseTheme = EditorView.theme({\n // Container styles - only apply when view plugin is enabled\n \"&.cm-draftly\": {\n fontSize: \"16px\",\n lineHeight: \"1.6\",\n backgroundColor: \"transparent !important\",\n },\n\n \"&.cm-draftly .cm-content\": {\n width: \"100%\",\n maxWidth: \"48rem\",\n padding: \"0 0.5rem\",\n margin: \"0 auto\",\n fontFamily: \"var(--font-sans, sans-serif)\",\n fontSize: \"16px\",\n lineHeight: \"1.6\",\n },\n\n \"&.cm-draftly .cm-content .cm-line\": {\n paddingInline: 0,\n },\n\n \"&.cm-draftly .cm-content .cm-widgetBuffer\": {\n display: \"none !important\",\n },\n});\n\nimport { HighlightStyle, syntaxHighlighting } from \"@codemirror/language\";\nimport { tags as t } from \"@lezer/highlight\";\n\n/**\n * Reset syntax highlighting for markdown elements\n * Used to disable theme colors for markdown syntax\n */\nconst markdownResetStyle = HighlightStyle.define([\n {\n tag: [\n t.heading,\n t.strong,\n t.emphasis,\n t.strikethrough,\n t.link,\n t.url,\n t.quote,\n t.list,\n t.meta,\n t.contentSeparator,\n t.labelName,\n ],\n color: \"inherit\",\n fontWeight: \"inherit\",\n fontStyle: \"inherit\",\n textDecoration: \"none\",\n },\n]);\n\nexport const markdownResetExtension = syntaxHighlighting(markdownResetStyle, { fallback: false });\n","import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate } from \"@codemirror/view\";\nimport { Extension, Facet, Range, RangeSetBuilder } from \"@codemirror/state\";\nimport { syntaxTree } from \"@codemirror/language\";\nimport { cursorInRange, selectionOverlapsRange, ThemeEnum } from \"./utils\";\nimport { draftlyBaseTheme } from \"./theme\";\nimport { DecorationContext, DraftlyPlugin } from \"./plugin\";\nimport { DraftlyNode } from \"./draftly\";\n\n/**\n * Facet to register plugins with the view plugin\n */\nexport const DraftlyPluginsFacet = Facet.define<DraftlyPlugin[], DraftlyPlugin[]>({\n combine: (values) => values.flat(),\n});\n\n/**\n * Facet to register the onNodesChange callback\n */\nexport const draftlyOnNodesChangeFacet = Facet.define<\n ((nodes: DraftlyNode[]) => void) | undefined,\n ((nodes: DraftlyNode[]) => void) | undefined\n>({\n combine: (values) => values.find((v) => v !== undefined),\n});\n\n/**\n * Facet to register the theme\n */\nexport const draftlyThemeFacet = Facet.define<ThemeEnum, ThemeEnum>({\n combine: (values) => values.find((v) => v !== undefined) || ThemeEnum.AUTO,\n});\n\n/**\n * Build decorations for the visible viewport\n * @param view - The EditorView instance\n * @param plugins - Optional array of plugins to invoke for decorations\n */\nfunction buildDecorations(view: EditorView, plugins: DraftlyPlugin[] = []): DecorationSet {\n const builder = new RangeSetBuilder<Decoration>();\n const decorations: Range<Decoration>[] = [];\n\n // Allow plugins to contribute decorations\n if (plugins.length > 0) {\n const ctx: DecorationContext = {\n view,\n decorations,\n selectionOverlapsRange: (from, to) => selectionOverlapsRange(view, from, to),\n cursorInRange: (from, to) => cursorInRange(view, from, to),\n };\n\n // Sort plugins by priority and invoke each one's decoration builder\n const sortedPlugins = [...plugins].sort((a, b) => a.decorationPriority - b.decorationPriority);\n\n for (const plugin of sortedPlugins) {\n try {\n plugin.buildDecorations(ctx);\n } catch {\n // Silently ignore errors from partial tree states (e.g., Lezer TreeBuffer\n // \"Invalid child in posBefore\"). These resolve on the next update cycle.\n }\n }\n }\n\n // Sort decorations by position (required for RangeSetBuilder)\n decorations.sort((a, b) => a.from - b.from || a.value.startSide - b.value.startSide);\n\n // Build the decoration set\n for (const decoration of decorations) {\n builder.add(decoration.from, decoration.to, decoration.value);\n }\n\n return builder.finish();\n}\n\n/**\n * draftly View Plugin\n * Handles rich markdown rendering with decorations\n */\nclass draftlyViewPluginClass {\n decorations: DecorationSet;\n private plugins: DraftlyPlugin[];\n private onNodesChange: ((nodes: DraftlyNode[]) => void) | undefined;\n\n constructor(view: EditorView) {\n this.plugins = view.state.facet(DraftlyPluginsFacet);\n this.onNodesChange = view.state.facet(draftlyOnNodesChangeFacet);\n this.decorations = buildDecorations(view, this.plugins);\n\n // Notify plugins that view is ready\n for (const plugin of this.plugins) {\n plugin.onViewReady(view);\n }\n\n // Call onNodesChange callback with initial nodes\n if (this.onNodesChange && typeof this.onNodesChange === \"function\") {\n this.onNodesChange(this.buildNodes(view));\n }\n }\n\n update(update: ViewUpdate) {\n // Update plugins list if facet changed\n this.plugins = update.view.state.facet(DraftlyPluginsFacet);\n this.onNodesChange = update.view.state.facet(draftlyOnNodesChangeFacet);\n\n // Notify plugins of the update\n for (const plugin of this.plugins) {\n plugin.onViewUpdate(update);\n }\n\n // Rebuild decorations when:\n // - Document changes\n // - Selection changes (to show/hide syntax markers)\n // - Viewport changes\n if (update.docChanged || update.selectionSet || update.viewportChanged) {\n this.decorations = buildDecorations(update.view, this.plugins);\n\n // Call onNodesChange callback\n if (this.onNodesChange) {\n this.onNodesChange(this.buildNodes(update.view));\n }\n }\n }\n\n private buildNodes(view: EditorView): DraftlyNode[] {\n const tree = syntaxTree(view.state);\n const roots: DraftlyNode[] = [];\n const stack: DraftlyNode[] = [];\n\n tree.iterate({\n enter: (nodeRef) => {\n const node: DraftlyNode = {\n from: nodeRef.from,\n to: nodeRef.to,\n name: nodeRef.name,\n children: [],\n isSelected: selectionOverlapsRange(view, nodeRef.from, nodeRef.to),\n };\n\n if (stack.length > 0) {\n stack[stack.length - 1]!.children.push(node);\n } else {\n roots.push(node);\n }\n\n stack.push(node);\n },\n leave: () => {\n stack.pop();\n },\n });\n\n return roots;\n }\n}\n\n/**\n * The main draftly ViewPlugin extension\n */\nexport const draftlyViewPlugin = ViewPlugin.fromClass(draftlyViewPluginClass, {\n decorations: (v) => v.decorations,\n provide: () => [],\n});\n\n/**\n * Extension to add the cm-draftly-enabled class to the editor\n */\nconst draftlyEditorClass = EditorView.editorAttributes.of({ class: \"cm-draftly\" });\n\n/**\n * Create draftly view extension bundle with plugin support\n * @param plugins - Optional array of DraftlyPlugin instances\n * @param onNodesChange - Optional callback to receive nodes on every update\n * @returns Extension array including view plugin, theme, and plugin facet\n */\nexport function createDraftlyViewExtension(\n theme: ThemeEnum = ThemeEnum.AUTO,\n baseStyles: boolean = true,\n plugins: DraftlyPlugin[] = [],\n onNodesChange?: (nodes: DraftlyNode[]) => void\n): Extension[] {\n return [\n draftlyEditorClass,\n DraftlyPluginsFacet.of(plugins),\n draftlyOnNodesChangeFacet.of(onNodesChange),\n draftlyThemeFacet.of(theme),\n draftlyViewPlugin,\n ...(baseStyles ? [draftlyBaseTheme] : []),\n ];\n}\n","import { Extension, Prec } from \"@codemirror/state\";\nimport { EditorView, highlightActiveLine, KeyBinding, keymap } from \"@codemirror/view\";\nimport { markdown, markdownKeymap, markdownLanguage } from \"@codemirror/lang-markdown\";\nimport type { MarkdownConfig } from \"@lezer/markdown\";\nimport { DraftlyPlugin, PluginContext } from \"./plugin\";\nimport { createDraftlyViewExtension } from \"./view-plugin\";\nimport { defaultKeymap, history, historyKeymap, indentWithTab } from \"@codemirror/commands\";\nimport { indentOnInput } from \"@codemirror/language\";\nimport { languages } from \"@codemirror/language-data\";\nimport { ThemeEnum } from \"./utils\";\nimport { markdownResetExtension } from \"./theme\";\n\n/**\n * DraftlyNode: represents a node in the markdown tree\n *\n * Useful for debugging and development\n */\nexport type DraftlyNode = {\n from: number;\n to: number;\n name: string;\n children: DraftlyNode[];\n isSelected: boolean;\n};\n\n/**\n * Configuration options for the draftly editor\n */\nexport interface DraftlyConfig {\n /** Theme */\n theme?: ThemeEnum;\n\n /** Weather to load base styles */\n baseStyles?: boolean;\n\n /** Plugins to load */\n plugins?: DraftlyPlugin[];\n\n /** Additional markdown extensions for the parser */\n markdown?: MarkdownConfig[];\n\n /** Additional CodeMirror extensions */\n extensions?: Extension[];\n\n /** Additional keybindings */\n keymap?: KeyBinding[];\n\n /** Disable the built-in view plugin (for raw markdown mode) */\n disableViewPlugin?: boolean;\n\n /** Enable default keybindings */\n defaultKeybindings?: boolean;\n\n /** Enable history */\n history?: boolean;\n\n /** Enable indent with tab */\n indentWithTab?: boolean;\n\n /** Highlight active line */\n highlightActiveLine?: boolean;\n\n /** Line wrapping in raw markdown mode */\n lineWrapping?: boolean;\n\n /** Callback to receive the nodes on every update */\n onNodesChange?: (nodes: DraftlyNode[]) => void;\n}\n\n/**\n * Creates a draftly editor extension bundle for CodeMirror 6\n *\n * @param config - Configuration options for the editor\n * @returns CodeMirror Extension that can be added to EditorState\n *\n * @example\n * ```ts\n * import { EditorView } from '@codemirror/view';\n * import { EditorState } from '@codemirror/state';\n * import { draftly } from 'draftly';\n *\n * const view = new EditorView({\n * state: EditorState.create({\n * doc: '# Hello draftly',\n * extensions: [draftly()]\n * }),\n * parent: document.getElementById('editor')\n * });\n * ```\n */\nexport function draftly(config: DraftlyConfig = {}): Extension[] {\n const {\n theme: configTheme = ThemeEnum.AUTO,\n baseStyles = true,\n plugins = [],\n extensions = [],\n keymap: configKeymap = [],\n disableViewPlugin = false,\n defaultKeybindings = true,\n history: configHistory = true,\n indentWithTab: configIndentWithTab = true,\n highlightActiveLine: configHighlightActiveLine = true,\n lineWrapping: configLineWrapping = true,\n onNodesChange: configOnNodesChange = undefined,\n } = config;\n\n const allPlugins = [...plugins];\n\n // Collect all extensions from plugins\n const pluginExtensions: Extension[] = [];\n const pluginKeymaps: KeyBinding[] = [];\n const markdownExtensions: MarkdownConfig[] = [];\n\n // Create plugin context for lifecycle methods\n const pluginContext: PluginContext = { config };\n\n if (!disableViewPlugin) {\n // Process each plugin\n for (const plugin of allPlugins) {\n // Call onRegister lifecycle hook\n plugin.onRegister(pluginContext);\n\n // Collect extensions via class method\n const exts = plugin.getExtensions();\n if (exts.length > 0) {\n pluginExtensions.push(...exts);\n }\n\n // Collect keymaps via class method\n const keys = plugin.getKeymap();\n if (keys.length > 0) {\n pluginKeymaps.push(...keys);\n }\n\n // Collect theme via class method\n const theme = plugin.theme;\n if (baseStyles && theme && typeof theme === \"function\") {\n pluginExtensions.push(EditorView.theme(theme(configTheme)));\n }\n\n // Collect markdown parser extensions via class method\n const md = plugin.getMarkdownConfig();\n if (md) {\n markdownExtensions.push(md);\n }\n }\n }\n\n // Add config-level markdown extensions\n if (config.markdown) {\n markdownExtensions.push(...config.markdown);\n }\n\n // Build the base markdown language support\n const markdownSupport = markdown({\n base: markdownLanguage,\n codeLanguages: languages,\n extensions: markdownExtensions,\n addKeymap: true,\n completeHTMLTags: true,\n pasteURLAsLink: true,\n });\n\n // Core CodeMirror extensions (in order)\n const baseExtensions: Extension[] = [\n ...(defaultKeybindings ? [keymap.of(defaultKeymap)] : []),\n ...(configHistory ? [history(), keymap.of(historyKeymap)] : []),\n ...(configIndentWithTab ? [indentOnInput(), keymap.of([indentWithTab])] : []),\n ...(configHighlightActiveLine && disableViewPlugin ? [highlightActiveLine()] : []),\n ];\n\n // draftly extensions (pass plugins for decoration support)\n const draftlyExtensions: Extension[] = [];\n if (!disableViewPlugin) {\n draftlyExtensions.push(createDraftlyViewExtension(configTheme, baseStyles, allPlugins, configOnNodesChange));\n draftlyExtensions.push(Prec.highest(markdownResetExtension));\n }\n if (!disableViewPlugin || configLineWrapping) draftlyExtensions.push(EditorView.lineWrapping);\n\n // Compose all extensions together\n const composedExtensions: Extension[] = [\n // Core markdown support (highest priority)\n Prec.high(markdownSupport),\n Prec.high(keymap.of(markdownKeymap)),\n\n // draftly view plugin for rich rendering\n draftlyExtensions,\n\n // Core CodeMirror extensions\n baseExtensions,\n\n // Plugin extensions & keymaps\n pluginExtensions,\n pluginKeymaps.length > 0 ? keymap.of(pluginKeymaps) : [],\n\n // Config keymaps & extensions\n configKeymap.length > 0 ? keymap.of(configKeymap) : [],\n extensions,\n ];\n\n return composedExtensions;\n}\n","import { Decoration, EditorView, KeyBinding, ViewUpdate } from \"@codemirror/view\";\nimport { Extension, Range } from \"@codemirror/state\";\nimport { MarkdownConfig } from \"@lezer/markdown\";\nimport { SyntaxNode } from \"@lezer/common\";\nimport { DraftlyConfig } from \"./draftly\";\nimport { createTheme, ThemeEnum, ThemeStyle } from \"./utils\";\nimport { StyleModule } from \"style-mod\";\n\n/**\n * Context passed to plugin lifecycle methods\n */\nexport interface PluginContext {\n /** Current configuration */\n readonly config: DraftlyConfig;\n}\n\n/**\n * Plugin configuration schema\n */\nexport interface PluginConfig {\n [key: string]: unknown;\n}\n\n/**\n * Decoration context passed to plugin decoration builders\n * Provides access to view state and decoration collection\n */\nexport interface DecorationContext {\n /** The EditorView instance (readonly) */\n readonly view: EditorView;\n\n /** Array to push decorations into (will be sorted automatically) */\n readonly decorations: Range<Decoration>[];\n\n /** Check if selection overlaps with a range (to show raw markdown) */\n selectionOverlapsRange(from: number, to: number): boolean;\n\n /** Check if cursor is within a range */\n cursorInRange(from: number, to: number): boolean;\n}\n\n/**\n * Abstract base class for all draftly plugins\n *\n * Implements OOP principles:\n * - Abstraction: abstract name/version must be implemented by subclasses\n * - Encapsulation: private _config, protected _context\n * - Inheritance: specialized plugin classes can extend this\n */\nexport abstract class DraftlyPlugin {\n /** Unique plugin identifier (abstract - must be implemented) */\n abstract readonly name: string;\n\n /** Plugin version (abstract - must be implemented) */\n abstract readonly version: string;\n\n /** Decoration priority (higher = applied later) */\n readonly decorationPriority: number = 100;\n\n /** Plugin dependencies - names of required plugins */\n readonly dependencies: string[] = [];\n\n /** Node types this plugin handles for decorations and preview rendering */\n readonly requiredNodes: readonly string[] = [];\n\n /** Private configuration storage */\n private _config: PluginConfig = {};\n\n /** Protected context - accessible to subclasses */\n protected _context: PluginContext | null = null;\n\n /** Get plugin configuration */\n get config(): PluginConfig {\n return this._config;\n }\n\n /** Set plugin configuration */\n set config(value: PluginConfig) {\n this._config = value;\n }\n\n /** Get plugin context */\n get context(): PluginContext | null {\n return this._context;\n }\n\n /** Plugin theme */\n get theme(): (theme: ThemeEnum) => ThemeStyle {\n return createTheme({\n default: {},\n dark: {},\n light: {},\n });\n }\n\n // ============================================\n // EXTENSION METHODS (overridable by subclasses)\n // ============================================\n\n /**\n * Return CodeMirror extensions for this plugin\n * Override to provide custom extensions\n */\n getExtensions(): Extension[] {\n return [];\n }\n\n /**\n * Return markdown parser extensions\n * Override to extend markdown parsing\n */\n getMarkdownConfig(): MarkdownConfig | null {\n return null;\n }\n\n /**\n * Return keybindings for this plugin\n * Override to add custom keyboard shortcuts\n */\n getKeymap(): KeyBinding[] {\n return [];\n }\n\n // ============================================\n // DECORATION METHODS (overridable by subclasses)\n // ============================================\n\n /**\n * Build decorations for the current view state\n * Override to contribute decorations to the editor\n *\n * @param ctx - Decoration context with view and decoration array\n */\n buildDecorations(_ctx: DecorationContext): void {\n // Default implementation does nothing\n // Subclasses override to add decorations\n }\n\n // ============================================\n // LIFECYCLE HOOKS (overridable by subclasses)\n // ============================================\n\n /**\n * Called when plugin is registered with draftly\n * Override to perform initialization\n *\n * @param context - Plugin context with configuration\n */\n onRegister(context: PluginContext): void | Promise<void> {\n this._context = context;\n }\n\n /**\n * Called when plugin is unregistered\n * Override to perform cleanup\n */\n onUnregister(): void {\n this._context = null;\n }\n\n /**\n * Called when EditorView is created and ready\n * Override to perform view-specific initialization\n *\n * @param view - The EditorView instance\n */\n onViewReady(_view: EditorView): void {\n // Default implementation does nothing\n }\n\n /**\n * Called on view updates (document changes, selection changes, etc.)\n * Override to react to editor changes\n *\n * @param update - The ViewUpdate with change information\n */\n onViewUpdate(_update: ViewUpdate): void {\n // Default implementation does nothing\n }\n\n // ============================================\n // PROTECTED UTILITIES (for subclasses)\n // ============================================\n\n /**\n * Helper to get current editor state\n * @param view - The EditorView instance\n */\n protected getState(view: EditorView) {\n return view.state;\n }\n\n /**\n * Helper to get current document\n * @param view - The EditorView instance\n */\n protected getDocument(view: EditorView) {\n return view.state.doc;\n }\n\n // ============================================\n // PREVIEW RENDERING METHODS (for draftly/preview)\n // ============================================\n\n /**\n * Render a syntax node to HTML for preview mode\n * Override to provide custom HTML rendering for specific node types\n *\n * @param node - The syntax node to render\n * @param children - Pre-rendered children HTML\n * @param ctx - Preview context with document and utilities\n * @returns HTML string to use, or null to use default rendering\n */\n renderToHTML?(\n node: SyntaxNode,\n children: string,\n ctx: {\n sliceDoc(from: number, to: number): string;\n sanitize(html: string): string;\n syntaxHighlighters?: readonly import(\"@lezer/highlight\").Highlighter[];\n }\n ): string | null | Promise<string | null>;\n\n /**\n * Get CSS styles for preview mode\n * Override to provide custom CSS for preview rendering\n *\n * @param theme - Current theme enum\n * @returns CSS string for preview styles\n */\n getPreviewStyles(theme: ThemeEnum, wrapperClass: string): string {\n const themeStyles = this.theme(theme);\n return this.transformToCss(themeStyles, wrapperClass);\n }\n\n /**\n * Transform ThemeStyle object to CSS string for preview\n * Uses cssClassMap to convert CM selectors to semantic selectors\n */\n protected transformToCss(themeStyles: ThemeStyle, wrapperClass: string): string {\n const styleMod = new StyleModule(themeStyles, {\n finish: (sel) => {\n return `.${wrapperClass} ${sel}`;\n },\n });\n return styleMod.getRules();\n }\n}\n\n/**\n * Base class for plugins that primarily contribute decorations\n * Extends DraftlyPlugin with decoration-focused defaults\n */\nexport abstract class DecorationPlugin extends DraftlyPlugin {\n /**\n * Decoration priority - lower than default for decoration plugins\n * Override to customize\n */\n override decorationPriority = 50;\n\n /**\n * Subclasses must implement this to provide decorations\n * @param ctx - Decoration context\n */\n abstract override buildDecorations(ctx: DecorationContext): void;\n}\n\n/**\n * Base class for plugins that add syntax/parser extensions\n * Extends DraftlyPlugin with syntax-focused requirements\n */\nexport abstract class SyntaxPlugin extends DraftlyPlugin {\n /**\n * Subclasses must implement this to provide markdown config\n */\n abstract override getMarkdownConfig(): MarkdownConfig;\n}\n"]}
|