markdown-text-editor 1.6.0 → 1.8.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/LICENSE +1 -1
- package/README.md +40 -13
- package/dist/markdown-text-editor.es.js +928 -684
- package/dist/markdown-text-editor.es.js.map +1 -1
- package/dist/markdown-text-editor.min.js +76 -72
- package/dist/markdown-text-editor.min.js.map +1 -1
- package/dist/markdown-text-editor.umd.js +76 -72
- package/dist/markdown-text-editor.umd.js.map +1 -1
- package/package.json +22 -10
- package/types/index.d.ts +185 -0
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-text-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "A markdown editor that enhances your textarea instead of replacing it, so form submission, validation and required fields keep working. WYSIWYG hybrid mode, live preview, find and replace, RTL, TypeScript types. Works with any backend.",
|
|
6
6
|
"funding": "https://ko-fi.com/nezanuha",
|
|
7
7
|
"main": "./dist/markdown-text-editor.umd.js",
|
|
8
8
|
"module": "./dist/markdown-text-editor.es.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"jsdelivr": "./dist/markdown-text-editor.min.js",
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
|
+
"types": "./types/index.d.ts",
|
|
14
15
|
"import": "./dist/markdown-text-editor.es.js",
|
|
15
16
|
"require": "./dist/markdown-text-editor.umd.js",
|
|
16
17
|
"default": "./dist/markdown-text-editor.umd.js"
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
|
20
21
|
"dist/",
|
|
22
|
+
"types/",
|
|
21
23
|
"README.md",
|
|
22
24
|
"LICENSE"
|
|
23
25
|
],
|
|
@@ -30,7 +32,9 @@
|
|
|
30
32
|
"build": "vite build",
|
|
31
33
|
"preview": "vite preview",
|
|
32
34
|
"prepublishOnly": "npm run build",
|
|
33
|
-
"postversion": "git push origin main --tags"
|
|
35
|
+
"postversion": "git push origin main --tags",
|
|
36
|
+
"test": "node test/smoke.mjs",
|
|
37
|
+
"typecheck": "tsc --noEmit --strict --lib es2020,dom --moduleResolution bundler --module esnext test/types.test.ts"
|
|
34
38
|
},
|
|
35
39
|
"publishConfig": {
|
|
36
40
|
"provenance": true,
|
|
@@ -56,7 +60,12 @@
|
|
|
56
60
|
"csp compatible",
|
|
57
61
|
"form markdown editor",
|
|
58
62
|
"live preview",
|
|
59
|
-
"mde"
|
|
63
|
+
"mde",
|
|
64
|
+
"typescript",
|
|
65
|
+
"markdown-it",
|
|
66
|
+
"template editor",
|
|
67
|
+
"merge tags",
|
|
68
|
+
"placeholders"
|
|
60
69
|
],
|
|
61
70
|
"author": "Nezanuha",
|
|
62
71
|
"license": "MIT",
|
|
@@ -65,18 +74,21 @@
|
|
|
65
74
|
"url": "https://github.com/nezanuha/markdown-text-editor/issues"
|
|
66
75
|
},
|
|
67
76
|
"dependencies": {
|
|
68
|
-
"dompurify": "^3.4.
|
|
69
|
-
"marked": "~18.0.
|
|
77
|
+
"dompurify": "^3.4.16",
|
|
78
|
+
"marked": "~18.0.14"
|
|
70
79
|
},
|
|
71
80
|
"devDependencies": {
|
|
72
81
|
"@tailwindcss/postcss": "^4.3.3",
|
|
73
82
|
"@tailwindcss/typography": "^0.5.20",
|
|
74
83
|
"@tailwindcss/vite": "^4.3.3",
|
|
75
84
|
"diff": "^9.0.0",
|
|
76
|
-
"frutjam": "^2.2.
|
|
77
|
-
"
|
|
85
|
+
"frutjam": "^2.2.6",
|
|
86
|
+
"happy-dom": "^20.14.5",
|
|
87
|
+
"postcss": "^8.5.28",
|
|
78
88
|
"tailwindcss": "^4.3.3",
|
|
79
|
-
"
|
|
89
|
+
"typescript": "^7.0.2",
|
|
90
|
+
"vite": "^8.3.1",
|
|
80
91
|
"vite-plugin-css-injected-by-js": "^5.0.2"
|
|
81
|
-
}
|
|
92
|
+
},
|
|
93
|
+
"types": "./types/index.d.ts"
|
|
82
94
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for markdown-text-editor.
|
|
3
|
+
*
|
|
4
|
+
* Options are read once, when the editor is constructed. Changing them afterwards
|
|
5
|
+
* has no effect; call destroy() and construct a new editor instead.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Tools that take no configuration, referenced by name in `toolbar`. */
|
|
9
|
+
export type ToolName =
|
|
10
|
+
| 'heading'
|
|
11
|
+
| 'bold'
|
|
12
|
+
| 'italic'
|
|
13
|
+
| 'strikethrough'
|
|
14
|
+
| 'blockquote'
|
|
15
|
+
| 'ul'
|
|
16
|
+
| 'ol'
|
|
17
|
+
| 'checklist'
|
|
18
|
+
| 'indent'
|
|
19
|
+
| 'outdent'
|
|
20
|
+
| 'code'
|
|
21
|
+
| 'codeblock'
|
|
22
|
+
| 'hr'
|
|
23
|
+
| 'table'
|
|
24
|
+
| 'link'
|
|
25
|
+
| 'image'
|
|
26
|
+
| 'undo'
|
|
27
|
+
| 'redo'
|
|
28
|
+
| 'preview';
|
|
29
|
+
|
|
30
|
+
/** A single entry in the variables dropdown. */
|
|
31
|
+
export interface Variable {
|
|
32
|
+
/** Text shown in the dropdown. Rendered as plain text, never as markup. */
|
|
33
|
+
label: string;
|
|
34
|
+
/** Inserted at the cursor when the entry is clicked. */
|
|
35
|
+
value: string;
|
|
36
|
+
/**
|
|
37
|
+
* Shown in place of `value` in the preview. The textarea keeps the real
|
|
38
|
+
* placeholder. Entries without a sample appear as written.
|
|
39
|
+
*/
|
|
40
|
+
sample?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** A headed section of variables. Groups and flat entries can be mixed. */
|
|
44
|
+
export interface VariableGroup {
|
|
45
|
+
/** Heading shown above the group. Not clickable. */
|
|
46
|
+
label: string;
|
|
47
|
+
items: Variable[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Toolbar entries that carry their own configuration. */
|
|
51
|
+
export interface VariablesTool {
|
|
52
|
+
variables: Array<Variable | VariableGroup>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ImageTool {
|
|
56
|
+
image: {
|
|
57
|
+
fileInput?: {
|
|
58
|
+
/** Allowed extensions, e.g. `['webp', 'avif', 'png']`. */
|
|
59
|
+
accept?: string[];
|
|
60
|
+
/** Endpoint the `File` is POSTed to. */
|
|
61
|
+
uploadUrl?: string;
|
|
62
|
+
};
|
|
63
|
+
/** `false` disables alt text validation. */
|
|
64
|
+
altInput?: boolean | { required?: boolean };
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type ToolbarEntry = ToolName | VariablesTool | ImageTool;
|
|
69
|
+
|
|
70
|
+
/** Status bar fields. `false` hides the bar entirely. */
|
|
71
|
+
export interface FooterOptions {
|
|
72
|
+
/** Default `true`. */
|
|
73
|
+
line?: boolean;
|
|
74
|
+
/** Default `true`. */
|
|
75
|
+
col?: boolean;
|
|
76
|
+
/** Default `true`. */
|
|
77
|
+
chars?: boolean;
|
|
78
|
+
/** Default `false`. */
|
|
79
|
+
words?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface MarkdownEditorOptions {
|
|
83
|
+
/**
|
|
84
|
+
* `'hybrid'` renders formatting live as you type, `'plain'` shows raw
|
|
85
|
+
* markdown. Default `'plain'`.
|
|
86
|
+
*/
|
|
87
|
+
mode?: 'plain' | 'hybrid';
|
|
88
|
+
|
|
89
|
+
/** Text shown when the editor is empty. */
|
|
90
|
+
placeholder?: string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Which tools appear and in what order. Omit for the default toolbar.
|
|
94
|
+
* Note that `preview` must be present for the preview pane to exist.
|
|
95
|
+
*/
|
|
96
|
+
toolbar?: ToolbarEntry[];
|
|
97
|
+
|
|
98
|
+
/** Status bar configuration, or `false` to hide it. */
|
|
99
|
+
footer?: false | FooterOptions;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Overrides the theme. Without it the editor inherits `data-theme` from the
|
|
103
|
+
* nearest ancestor, or from the textarea itself.
|
|
104
|
+
*/
|
|
105
|
+
theme?: 'light' | 'dark' | 'snowberry' | 'darkberry' | (string & {});
|
|
106
|
+
|
|
107
|
+
/** Minimum height in pixels. Default `200`. */
|
|
108
|
+
minHeight?: number;
|
|
109
|
+
|
|
110
|
+
/** Maximum height in pixels before the editor scrolls. Default `500`. */
|
|
111
|
+
maxHeight?: number;
|
|
112
|
+
|
|
113
|
+
/** Called on every content change with the current markdown. */
|
|
114
|
+
onChange?: (value: string) => void;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Translations for the editor's own interface, keyed by the English text:
|
|
118
|
+
* tooltips, menu items, modal fields and buttons. Anything not listed stays
|
|
119
|
+
* in English. CSS class names are unaffected.
|
|
120
|
+
*
|
|
121
|
+
* @example labels: { Bold: 'Negrita', 'Insert variable': 'Insertar variable' }
|
|
122
|
+
*/
|
|
123
|
+
labels?: Record<string, string>;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Replaces the markdown parser used for the preview. Must be synchronous and
|
|
127
|
+
* return an HTML string. Affects the preview pane only; hybrid mode's live
|
|
128
|
+
* formatting uses a separate internal renderer.
|
|
129
|
+
*
|
|
130
|
+
* Clickable task list checkboxes are found by looking for
|
|
131
|
+
* `input[type="checkbox"]` in the output, so a renderer without task list
|
|
132
|
+
* support will break them.
|
|
133
|
+
*
|
|
134
|
+
* @example renderer: markdown => markdownIt.render(markdown)
|
|
135
|
+
*/
|
|
136
|
+
renderer?: (markdown: string) => string;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Replaces the HTML sanitizer. Must be synchronous and return an HTML string.
|
|
140
|
+
* Defaults to DOMPurify, which still runs when only `renderer` is given.
|
|
141
|
+
*
|
|
142
|
+
* Replacing this replaces your XSS protection. A pass-through such as
|
|
143
|
+
* `html => html` disables sanitizing entirely.
|
|
144
|
+
*
|
|
145
|
+
* @example sanitizer: html => DOMPurify.sanitize(html, { ADD_TAGS: ['iframe'] })
|
|
146
|
+
*/
|
|
147
|
+
sanitizer?: (html: string) => string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default class MarkdownEditor {
|
|
151
|
+
/**
|
|
152
|
+
* @param selector A CSS selector for a `<textarea>`, or the element itself.
|
|
153
|
+
*/
|
|
154
|
+
constructor(selector: string | HTMLTextAreaElement, options?: MarkdownEditorOptions);
|
|
155
|
+
|
|
156
|
+
/** The original textarea. Its `.value` is always the current markdown. */
|
|
157
|
+
readonly usertextarea: HTMLTextAreaElement;
|
|
158
|
+
|
|
159
|
+
/** The wrapper the editor builds around the textarea. */
|
|
160
|
+
readonly editorContainer: HTMLDivElement;
|
|
161
|
+
|
|
162
|
+
/** Options exactly as passed in. */
|
|
163
|
+
readonly options: MarkdownEditorOptions;
|
|
164
|
+
|
|
165
|
+
/** Variables parsed out of the toolbar configuration. */
|
|
166
|
+
readonly variables: Array<Variable | VariableGroup>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Inserts text at the cursor, replacing any selection, then restores focus,
|
|
170
|
+
* scrolls the insertion into view, re-renders and fires `onChange`.
|
|
171
|
+
*
|
|
172
|
+
* @param selectionOffset Where the caret lands, measured from the insertion point.
|
|
173
|
+
* @param trailingLength Characters at the end to leave outside the selection.
|
|
174
|
+
*/
|
|
175
|
+
insertText(text: string, selectionOffset?: number, trailingLength?: number): void;
|
|
176
|
+
|
|
177
|
+
/** Re-renders the preview and the hybrid display layer from the textarea. */
|
|
178
|
+
render(): void;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Removes the editor UI, restores the original textarea and detaches every
|
|
182
|
+
* listener. Call this on unmount in single page applications.
|
|
183
|
+
*/
|
|
184
|
+
destroy(): void;
|
|
185
|
+
}
|