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.
Files changed (79) hide show
  1. package/README.md +12 -0
  2. package/dist/chunk-3T55CBNZ.cjs +33 -0
  3. package/dist/chunk-3T55CBNZ.cjs.map +1 -0
  4. package/dist/chunk-5MC4T7JH.cjs +58 -0
  5. package/dist/chunk-5MC4T7JH.cjs.map +1 -0
  6. package/dist/{chunk-KBQDZ5IW.cjs → chunk-CLW73JRX.cjs} +100 -75
  7. package/dist/chunk-CLW73JRX.cjs.map +1 -0
  8. package/dist/{chunk-72ZYRGRT.cjs → chunk-EQUQHE2E.cjs} +30 -26
  9. package/dist/chunk-EQUQHE2E.cjs.map +1 -0
  10. package/dist/{chunk-HPSMS2WB.js → chunk-I563H35S.js} +101 -75
  11. package/dist/chunk-I563H35S.js.map +1 -0
  12. package/dist/chunk-IAXF4SJL.js +55 -0
  13. package/dist/chunk-IAXF4SJL.js.map +1 -0
  14. package/dist/chunk-JF3WXXMJ.js +31 -0
  15. package/dist/chunk-JF3WXXMJ.js.map +1 -0
  16. package/dist/{chunk-N3WL3XPB.js → chunk-NRPI5O6Y.js} +2603 -604
  17. package/dist/chunk-NRPI5O6Y.js.map +1 -0
  18. package/dist/{chunk-2B3A3VSQ.cjs → chunk-OMFUE4AQ.cjs} +2642 -622
  19. package/dist/chunk-OMFUE4AQ.cjs.map +1 -0
  20. package/dist/{chunk-DFQYXFOP.js → chunk-TD3L5C45.js} +28 -3
  21. package/dist/chunk-TD3L5C45.js.map +1 -0
  22. package/dist/{chunk-CG4M4TC7.js → chunk-UCHBDJ4R.js} +26 -22
  23. package/dist/chunk-UCHBDJ4R.js.map +1 -0
  24. package/dist/{chunk-KDEDLC3D.cjs → chunk-W75QUUQC.cjs} +29 -2
  25. package/dist/chunk-W75QUUQC.cjs.map +1 -0
  26. package/dist/{draftly-BLnx3uGX.d.cts → draftly-BBL-AdOl.d.cts} +5 -1
  27. package/dist/{draftly-BLnx3uGX.d.ts → draftly-BBL-AdOl.d.ts} +5 -1
  28. package/dist/editor/index.cjs +22 -14
  29. package/dist/editor/index.d.cts +2 -1
  30. package/dist/editor/index.d.ts +2 -1
  31. package/dist/editor/index.js +2 -2
  32. package/dist/index.cjs +65 -39
  33. package/dist/index.d.cts +6 -3
  34. package/dist/index.d.ts +6 -3
  35. package/dist/index.js +6 -4
  36. package/dist/lib/index.cjs +12 -0
  37. package/dist/lib/index.cjs.map +1 -0
  38. package/dist/lib/index.d.cts +16 -0
  39. package/dist/lib/index.d.ts +16 -0
  40. package/dist/lib/index.js +3 -0
  41. package/dist/lib/index.js.map +1 -0
  42. package/dist/plugins/index.cjs +27 -17
  43. package/dist/plugins/index.d.cts +180 -10
  44. package/dist/plugins/index.d.ts +180 -10
  45. package/dist/plugins/index.js +5 -3
  46. package/dist/preview/index.cjs +16 -11
  47. package/dist/preview/index.d.cts +19 -4
  48. package/dist/preview/index.d.ts +19 -4
  49. package/dist/preview/index.js +3 -2
  50. package/package.json +8 -1
  51. package/src/editor/draftly.ts +30 -27
  52. package/src/editor/plugin.ts +5 -1
  53. package/src/editor/theme.ts +1 -0
  54. package/src/editor/utils.ts +33 -0
  55. package/src/index.ts +5 -4
  56. package/src/lib/index.ts +2 -0
  57. package/src/lib/input-handler.ts +45 -0
  58. package/src/plugins/code-plugin.theme.ts +426 -0
  59. package/src/plugins/code-plugin.ts +810 -561
  60. package/src/plugins/emoji-plugin.ts +140 -0
  61. package/src/plugins/index.ts +63 -57
  62. package/src/plugins/inline-plugin.ts +305 -291
  63. package/src/plugins/math-plugin.ts +12 -0
  64. package/src/plugins/table-plugin.ts +1759 -0
  65. package/src/preview/context.ts +4 -1
  66. package/src/preview/css-generator.ts +14 -1
  67. package/src/preview/index.ts +9 -1
  68. package/src/preview/preview.ts +2 -1
  69. package/src/preview/renderer.ts +21 -20
  70. package/src/preview/syntax-theme.ts +110 -0
  71. package/src/preview/types.ts +14 -0
  72. package/dist/chunk-2B3A3VSQ.cjs.map +0 -1
  73. package/dist/chunk-72ZYRGRT.cjs.map +0 -1
  74. package/dist/chunk-CG4M4TC7.js.map +0 -1
  75. package/dist/chunk-DFQYXFOP.js.map +0 -1
  76. package/dist/chunk-HPSMS2WB.js.map +0 -1
  77. package/dist/chunk-KBQDZ5IW.cjs.map +0 -1
  78. package/dist/chunk-KDEDLC3D.cjs.map +0 -1
  79. package/dist/chunk-N3WL3XPB.js.map +0 -1
@@ -1,11 +1,14 @@
1
1
  import * as _lezer_markdown from '@lezer/markdown';
2
2
  import { MarkdownConfig } from '@lezer/markdown';
3
- import { d as DraftlyPlugin, T as ThemeEnum } from '../draftly-BLnx3uGX.cjs';
3
+ import { d as DraftlyPlugin, T as ThemeEnum } from '../draftly-BBL-AdOl.cjs';
4
+ import * as _lezer_highlight from '@lezer/highlight';
5
+ import * as _codemirror_state from '@codemirror/state';
6
+ import * as _codemirror_language from '@codemirror/language';
4
7
  import { SyntaxNode } from '@lezer/common';
5
- import '@codemirror/state';
6
8
  import '@codemirror/view';
7
9
  import 'style-mod';
8
10
 
11
+ type SyntaxThemeInput = _codemirror_language.HighlightStyle | _codemirror_state.Extension | readonly _codemirror_state.Extension[];
9
12
  /**
10
13
  * Context passed to plugin preview methods
11
14
  */
@@ -20,6 +23,8 @@ interface PreviewContext {
20
23
  sanitize(html: string): string;
21
24
  /** Render children of a node to HTML */
22
25
  renderChildren(node: SyntaxNode): Promise<string>;
26
+ /** Active syntax highlighters used for code rendering */
27
+ readonly syntaxHighlighters?: readonly _lezer_highlight.Highlighter[];
23
28
  }
24
29
  /**
25
30
  * Configuration for the preview renderer
@@ -37,6 +42,8 @@ interface PreviewConfig {
37
42
  sanitize?: boolean;
38
43
  /** Theme to use */
39
44
  theme?: ThemeEnum;
45
+ /** CodeMirror syntax theme input used for static preview highlighting */
46
+ syntaxTheme?: SyntaxThemeInput | SyntaxThemeInput[];
40
47
  }
41
48
  /**
42
49
  * Result of CSS generation
@@ -50,6 +57,8 @@ interface GenerateCSSConfig {
50
57
  wrapperClass?: string;
51
58
  /** Include base styles */
52
59
  includeBase?: boolean;
60
+ /** CodeMirror syntax theme input used for static preview syntax highlighting */
61
+ syntaxTheme?: SyntaxThemeInput | SyntaxThemeInput[];
53
62
  }
54
63
  /**
55
64
  * Node renderer function type
@@ -100,6 +109,11 @@ declare function preview(markdown: string, config?: PreviewConfig): Promise<stri
100
109
  */
101
110
  declare function generateCSS(config?: GenerateCSSConfig): string;
102
111
 
112
+ /**
113
+ * Extract syntax highlight CSS from resolved CodeMirror HighlightStyle modules.
114
+ */
115
+ declare function generateSyntaxThemeCSS(syntaxTheme: SyntaxThemeInput | SyntaxThemeInput[] | undefined, _wrapperClass: string): string;
116
+
103
117
  /**
104
118
  * Escape HTML special characters
105
119
  */
@@ -118,10 +132,11 @@ declare class PreviewRenderer {
118
132
  private plugins;
119
133
  private markdown;
120
134
  private sanitizeHtml;
135
+ private syntaxTheme;
121
136
  private renderers;
122
137
  private ctx;
123
138
  private nodeToPlugins;
124
- constructor(doc: string, plugins: DraftlyPlugin[] | undefined, markdown: MarkdownConfig[], theme?: ThemeEnum, sanitize?: boolean);
139
+ constructor(doc: string, plugins: DraftlyPlugin[] | undefined, markdown: MarkdownConfig[], theme?: ThemeEnum, sanitize?: boolean, syntaxTheme?: SyntaxThemeInput | SyntaxThemeInput[]);
125
140
  /**
126
141
  * Build a map from node names to plugins that handle them
127
142
  */
@@ -140,4 +155,4 @@ declare class PreviewRenderer {
140
155
  private renderChildren;
141
156
  }
142
157
 
143
- export { type GenerateCSSConfig, type NodeRenderer, type NodeRendererMap, type PreviewConfig, type PreviewContext, PreviewRenderer, defaultRenderers, escapeHtml, generateCSS, preview };
158
+ export { type GenerateCSSConfig, type NodeRenderer, type NodeRendererMap, type PreviewConfig, type PreviewContext, PreviewRenderer, type SyntaxThemeInput, defaultRenderers, escapeHtml, generateCSS, generateSyntaxThemeCSS, preview };
@@ -1,11 +1,14 @@
1
1
  import * as _lezer_markdown from '@lezer/markdown';
2
2
  import { MarkdownConfig } from '@lezer/markdown';
3
- import { d as DraftlyPlugin, T as ThemeEnum } from '../draftly-BLnx3uGX.js';
3
+ import { d as DraftlyPlugin, T as ThemeEnum } from '../draftly-BBL-AdOl.js';
4
+ import * as _lezer_highlight from '@lezer/highlight';
5
+ import * as _codemirror_state from '@codemirror/state';
6
+ import * as _codemirror_language from '@codemirror/language';
4
7
  import { SyntaxNode } from '@lezer/common';
5
- import '@codemirror/state';
6
8
  import '@codemirror/view';
7
9
  import 'style-mod';
8
10
 
11
+ type SyntaxThemeInput = _codemirror_language.HighlightStyle | _codemirror_state.Extension | readonly _codemirror_state.Extension[];
9
12
  /**
10
13
  * Context passed to plugin preview methods
11
14
  */
@@ -20,6 +23,8 @@ interface PreviewContext {
20
23
  sanitize(html: string): string;
21
24
  /** Render children of a node to HTML */
22
25
  renderChildren(node: SyntaxNode): Promise<string>;
26
+ /** Active syntax highlighters used for code rendering */
27
+ readonly syntaxHighlighters?: readonly _lezer_highlight.Highlighter[];
23
28
  }
24
29
  /**
25
30
  * Configuration for the preview renderer
@@ -37,6 +42,8 @@ interface PreviewConfig {
37
42
  sanitize?: boolean;
38
43
  /** Theme to use */
39
44
  theme?: ThemeEnum;
45
+ /** CodeMirror syntax theme input used for static preview highlighting */
46
+ syntaxTheme?: SyntaxThemeInput | SyntaxThemeInput[];
40
47
  }
41
48
  /**
42
49
  * Result of CSS generation
@@ -50,6 +57,8 @@ interface GenerateCSSConfig {
50
57
  wrapperClass?: string;
51
58
  /** Include base styles */
52
59
  includeBase?: boolean;
60
+ /** CodeMirror syntax theme input used for static preview syntax highlighting */
61
+ syntaxTheme?: SyntaxThemeInput | SyntaxThemeInput[];
53
62
  }
54
63
  /**
55
64
  * Node renderer function type
@@ -100,6 +109,11 @@ declare function preview(markdown: string, config?: PreviewConfig): Promise<stri
100
109
  */
101
110
  declare function generateCSS(config?: GenerateCSSConfig): string;
102
111
 
112
+ /**
113
+ * Extract syntax highlight CSS from resolved CodeMirror HighlightStyle modules.
114
+ */
115
+ declare function generateSyntaxThemeCSS(syntaxTheme: SyntaxThemeInput | SyntaxThemeInput[] | undefined, _wrapperClass: string): string;
116
+
103
117
  /**
104
118
  * Escape HTML special characters
105
119
  */
@@ -118,10 +132,11 @@ declare class PreviewRenderer {
118
132
  private plugins;
119
133
  private markdown;
120
134
  private sanitizeHtml;
135
+ private syntaxTheme;
121
136
  private renderers;
122
137
  private ctx;
123
138
  private nodeToPlugins;
124
- constructor(doc: string, plugins: DraftlyPlugin[] | undefined, markdown: MarkdownConfig[], theme?: ThemeEnum, sanitize?: boolean);
139
+ constructor(doc: string, plugins: DraftlyPlugin[] | undefined, markdown: MarkdownConfig[], theme?: ThemeEnum, sanitize?: boolean, syntaxTheme?: SyntaxThemeInput | SyntaxThemeInput[]);
125
140
  /**
126
141
  * Build a map from node names to plugins that handle them
127
142
  */
@@ -140,4 +155,4 @@ declare class PreviewRenderer {
140
155
  private renderChildren;
141
156
  }
142
157
 
143
- export { type GenerateCSSConfig, type NodeRenderer, type NodeRendererMap, type PreviewConfig, type PreviewContext, PreviewRenderer, defaultRenderers, escapeHtml, generateCSS, preview };
158
+ export { type GenerateCSSConfig, type NodeRenderer, type NodeRendererMap, type PreviewConfig, type PreviewContext, PreviewRenderer, type SyntaxThemeInput, defaultRenderers, escapeHtml, generateCSS, generateSyntaxThemeCSS, preview };
@@ -1,4 +1,5 @@
1
- export { PreviewRenderer, defaultRenderers, escapeHtml, generateCSS, preview } from '../chunk-HPSMS2WB.js';
2
- import '../chunk-DFQYXFOP.js';
1
+ export { generateCSS, preview } from '../chunk-IAXF4SJL.js';
2
+ export { PreviewRenderer, defaultRenderers, escapeHtml, generateSyntaxThemeCSS } from '../chunk-I563H35S.js';
3
+ import '../chunk-TD3L5C45.js';
3
4
  //# sourceMappingURL=index.js.map
4
5
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "draftly",
3
- "version": "1.0.7",
3
+ "version": "2.1.0",
4
4
  "description": "Core library for draftly",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,6 +35,7 @@
35
35
  "dompurify": "^3.3.1",
36
36
  "katex": "^0.16.28",
37
37
  "mermaid": "^11.12.2",
38
+ "node-emoji": "^2.2.0",
38
39
  "style-mod": "^4.1.3",
39
40
  "zod": "^4.3.6"
40
41
  },
@@ -63,6 +64,12 @@
63
64
  "require": "./dist/preview/index.cjs",
64
65
  "default": "./dist/preview/index.js"
65
66
  },
67
+ "./lib": {
68
+ "types": "./dist/lib/index.d.ts",
69
+ "import": "./dist/lib/index.js",
70
+ "require": "./dist/lib/index.cjs",
71
+ "default": "./dist/lib/index.js"
72
+ },
66
73
  "./src": {
67
74
  "types": "./src/index.ts",
68
75
  "default": "./src/index.ts"
@@ -114,33 +114,35 @@ export function draftly(config: DraftlyConfig = {}): Extension[] {
114
114
  // Create plugin context for lifecycle methods
115
115
  const pluginContext: PluginContext = { config };
116
116
 
117
- // Process each plugin
118
- for (const plugin of allPlugins) {
119
- // Call onRegister lifecycle hook
120
- plugin.onRegister(pluginContext);
121
-
122
- // Collect extensions via class method
123
- const exts = plugin.getExtensions();
124
- if (exts.length > 0) {
125
- pluginExtensions.push(...exts);
126
- }
127
-
128
- // Collect keymaps via class method
129
- const keys = plugin.getKeymap();
130
- if (keys.length > 0) {
131
- pluginKeymaps.push(...keys);
132
- }
133
-
134
- // Collect theme via class method
135
- const theme = plugin.theme;
136
- if (baseStyles && theme && typeof theme === "function") {
137
- pluginExtensions.push(EditorView.theme(theme(configTheme)));
138
- }
139
-
140
- // Collect markdown parser extensions via class method
141
- const md = plugin.getMarkdownConfig();
142
- if (md) {
143
- markdownExtensions.push(md);
117
+ if (!disableViewPlugin) {
118
+ // Process each plugin
119
+ for (const plugin of allPlugins) {
120
+ // Call onRegister lifecycle hook
121
+ plugin.onRegister(pluginContext);
122
+
123
+ // Collect extensions via class method
124
+ const exts = plugin.getExtensions();
125
+ if (exts.length > 0) {
126
+ pluginExtensions.push(...exts);
127
+ }
128
+
129
+ // Collect keymaps via class method
130
+ const keys = plugin.getKeymap();
131
+ if (keys.length > 0) {
132
+ pluginKeymaps.push(...keys);
133
+ }
134
+
135
+ // Collect theme via class method
136
+ const theme = plugin.theme;
137
+ if (baseStyles && theme && typeof theme === "function") {
138
+ pluginExtensions.push(EditorView.theme(theme(configTheme)));
139
+ }
140
+
141
+ // Collect markdown parser extensions via class method
142
+ const md = plugin.getMarkdownConfig();
143
+ if (md) {
144
+ markdownExtensions.push(md);
145
+ }
144
146
  }
145
147
  }
146
148
 
@@ -156,6 +158,7 @@ export function draftly(config: DraftlyConfig = {}): Extension[] {
156
158
  extensions: markdownExtensions,
157
159
  addKeymap: true,
158
160
  completeHTMLTags: true,
161
+ pasteURLAsLink: true,
159
162
  });
160
163
 
161
164
  // Core CodeMirror extensions (in order)
@@ -214,7 +214,11 @@ export abstract class DraftlyPlugin {
214
214
  renderToHTML?(
215
215
  node: SyntaxNode,
216
216
  children: string,
217
- ctx: { sliceDoc(from: number, to: number): string; sanitize(html: string): string }
217
+ ctx: {
218
+ sliceDoc(from: number, to: number): string;
219
+ sanitize(html: string): string;
220
+ syntaxHighlighters?: readonly import("@lezer/highlight").Highlighter[];
221
+ }
218
222
  ): string | null | Promise<string | null>;
219
223
 
220
224
  /**
@@ -9,6 +9,7 @@ export const draftlyBaseTheme = EditorView.theme({
9
9
  "&.cm-draftly": {
10
10
  fontSize: "16px",
11
11
  lineHeight: "1.6",
12
+ backgroundColor: "transparent !important",
12
13
  },
13
14
 
14
15
  "&.cm-draftly .cm-content": {
@@ -59,6 +59,10 @@ export function createTheme({
59
59
  light?: ThemeStyle;
60
60
  }): (theme: ThemeEnum) => ThemeStyle {
61
61
  return (theme: ThemeEnum) => {
62
+ defaultTheme = flattenThemeStyles(defaultTheme);
63
+ darkTheme = flattenThemeStyles(darkTheme || {});
64
+ lightTheme = flattenThemeStyles(lightTheme || {});
65
+
62
66
  let style: ThemeStyle = defaultTheme;
63
67
 
64
68
  if (theme === ThemeEnum.DARK) {
@@ -73,6 +77,35 @@ export function createTheme({
73
77
  };
74
78
  }
75
79
 
80
+ export function flattenThemeStyles(themeStyles: ThemeStyle, parentSelector?: string): ThemeStyle {
81
+ const flattened: ThemeStyle = {};
82
+
83
+ for (const [selectors, styles] of Object.entries(themeStyles)) {
84
+ for (const selector of selectors.split(",")) {
85
+ if (typeof styles === "object" && !Array.isArray(styles)) {
86
+ // Flatten nested styles
87
+ const fullSelector = fixSelector(parentSelector ? `${parentSelector} ${selector}` : selector);
88
+ const nestedStyles = flattenThemeStyles(styles as ThemeStyle, fullSelector);
89
+ Object.assign(flattened, nestedStyles);
90
+ } else {
91
+ // Add styles to the flattened object
92
+ if (parentSelector) {
93
+ flattened[parentSelector] = { ...flattened[parentSelector], [selector]: styles };
94
+ } else {
95
+ flattened[selector] = styles as StyleSpec;
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ return flattened;
102
+ }
103
+
104
+ export function fixSelector(selector: string): string {
105
+ // Replace all occurrences of "&" with the parent selector
106
+ return selector.replace(/\s&/g, "");
107
+ }
108
+
76
109
  /**
77
110
  * Check if cursor is within the given range
78
111
  */
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
- // Re-export everything for backward compatibility
2
- export * from "./editor";
3
- export * from "./plugins";
4
- export * from "./preview";
1
+ // Re-export everything for backward compatibility
2
+ export * from "./editor";
3
+ export * from "./plugins";
4
+ export * from "./preview";
5
+ export * from "./lib";
@@ -0,0 +1,2 @@
1
+ export { createWrapSelectionInputHandler } from "./input-handler";
2
+ export type { WrapSelectionMarkerMap } from "./input-handler";
@@ -0,0 +1,45 @@
1
+ import { EditorSelection, Extension } from "@codemirror/state";
2
+ import { EditorView } from "@codemirror/view";
3
+
4
+ /**
5
+ * Mapping of typed input characters to surrounding markers.
6
+ *
7
+ * Example:
8
+ * { "*": "*", "=": "==" }
9
+ */
10
+ export type WrapSelectionMarkerMap = Record<string, string>;
11
+
12
+ /**
13
+ * Creates an input handler that wraps non-empty selections with markdown markers
14
+ * when a mapped character is typed.
15
+ */
16
+ export function createWrapSelectionInputHandler(markersByInput: WrapSelectionMarkerMap): Extension {
17
+ return EditorView.inputHandler.of((view, _from, _to, text) => {
18
+ const marker = markersByInput[text];
19
+ if (!marker) {
20
+ return false;
21
+ }
22
+
23
+ const ranges = view.state.selection.ranges;
24
+ if (ranges.length === 0 || ranges.some((range) => range.empty)) {
25
+ return false;
26
+ }
27
+
28
+ const changes = ranges
29
+ .map((range) => ({
30
+ from: range.from,
31
+ to: range.to,
32
+ insert: `${marker}${view.state.sliceDoc(range.from, range.to)}${marker}`,
33
+ }))
34
+ .reverse();
35
+
36
+ const nextRanges = ranges.map((range) => EditorSelection.range(range.from + marker.length, range.to + marker.length));
37
+
38
+ view.dispatch({
39
+ changes,
40
+ selection: EditorSelection.create(nextRanges, view.state.selection.mainIndex),
41
+ });
42
+
43
+ return true;
44
+ });
45
+ }