markdown-text-editor 0.1.5 → 0.2.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 +114 -61
- package/dist/index.css +2 -7
- package/dist/index.css.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/markdown-text-editor.css +2 -7
- package/dist/markdown-text-editor.css.map +1 -1
- package/dist/markdown-text-editor.js +1 -1
- package/dist/markdown-text-editor.js.map +1 -1
- package/package.json +14 -15
- package/src/plugins/index.js +0 -2
- package/src/plugins/markdown/Toolbar/MakeTool.js +0 -22
- package/src/plugins/markdown/Toolbar/index.js +0 -56
- package/src/plugins/markdown/Toolbar/tools/BlockQuoteTool.js +0 -31
- package/src/plugins/markdown/Toolbar/tools/BoldTool.js +0 -33
- package/src/plugins/markdown/Toolbar/tools/CheckListTool.js +0 -31
- package/src/plugins/markdown/Toolbar/tools/HeadingTool.js +0 -55
- package/src/plugins/markdown/Toolbar/tools/ItalicTool.js +0 -31
- package/src/plugins/markdown/Toolbar/tools/LinkTool.js +0 -47
- package/src/plugins/markdown/Toolbar/tools/OLTool.js +0 -31
- package/src/plugins/markdown/Toolbar/tools/PreviewTool.js +0 -108
- package/src/plugins/markdown/Toolbar/tools/StrikethroughTool.js +0 -31
- package/src/plugins/markdown/Toolbar/tools/ULTool.js +0 -31
- package/src/plugins/markdown/editor.js +0 -172
- package/src/plugins/markdown/preview.js +0 -17
- package/src/plugins/markdown/styles/main.css +0 -21
- package/src/plugins/markdown/utils/markdownUtils.js +0 -7
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
// #markdown\editor.js
|
|
2
|
-
import './styles/main.css';
|
|
3
|
-
import { marked } from 'marked';
|
|
4
|
-
import Toolbar from './Toolbar/index.js';
|
|
5
|
-
import Preview from './preview.js';
|
|
6
|
-
|
|
7
|
-
marked.setOptions({
|
|
8
|
-
breaks: true
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
class MarkdownEditor {
|
|
12
|
-
constructor(selector, options = {}) {
|
|
13
|
-
this.usertextarea = typeof selector === 'string' ? document.querySelector(selector) : selector;
|
|
14
|
-
this.options = options;
|
|
15
|
-
this.preview = this.options.toolbar.includes('preview');
|
|
16
|
-
this.init();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
init() {
|
|
20
|
-
this.createEditor();
|
|
21
|
-
if (this.options.toolbar) this.addToolbar();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
createEditor() {
|
|
25
|
-
if (!this.isTextareaValid()) return;
|
|
26
|
-
|
|
27
|
-
this.applyDefaultAttributes();
|
|
28
|
-
this.buildEditorLayout();
|
|
29
|
-
this.addInputListener();
|
|
30
|
-
this.render();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
isTextareaValid() {
|
|
34
|
-
return this.usertextarea.tagName === 'TEXTAREA';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
applyDefaultAttributes() {
|
|
38
|
-
this.usertextarea.classList.add(
|
|
39
|
-
"focus:ring-0",
|
|
40
|
-
"focus:outline-0",
|
|
41
|
-
"border-0",
|
|
42
|
-
"p-1.5",
|
|
43
|
-
"max-w-full",
|
|
44
|
-
"size-full",
|
|
45
|
-
"bg-transparent",
|
|
46
|
-
"outline-0",
|
|
47
|
-
"appearance-none",
|
|
48
|
-
"prose",
|
|
49
|
-
"prose-sm",
|
|
50
|
-
"md:prose-base",
|
|
51
|
-
"dark:prose-invert",
|
|
52
|
-
"text-stone-700",
|
|
53
|
-
"dark:text-stone-200",
|
|
54
|
-
"overflow-y-auto",
|
|
55
|
-
"placeholder:text-stone-300",
|
|
56
|
-
"dark:placeholder:text-stone-700"
|
|
57
|
-
);
|
|
58
|
-
if (!this.usertextarea.hasAttribute('placeholder')) {
|
|
59
|
-
this.usertextarea.placeholder = this.options.placeholder || 'Write your markdown...';
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
buildEditorLayout() {
|
|
64
|
-
this.editorContainer = document.createElement('div');
|
|
65
|
-
this.editorContainer.className = `
|
|
66
|
-
markdown-editor-wrapper
|
|
67
|
-
border border-stone-200
|
|
68
|
-
dark:border-stone-700
|
|
69
|
-
rounded-md
|
|
70
|
-
overflow-hidden
|
|
71
|
-
`;
|
|
72
|
-
this.usertextarea.parentNode.insertBefore(this.editorContainer, this.usertextarea);
|
|
73
|
-
|
|
74
|
-
this.markdownEditorDiv = document.createElement('div');
|
|
75
|
-
this.markdownEditorDiv.className = `editor-layout`;
|
|
76
|
-
this.editorContainer.appendChild(this.markdownEditorDiv);
|
|
77
|
-
|
|
78
|
-
this.addTextareaWrapper();
|
|
79
|
-
if (this.preview) this.addPreviewWrapper();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
addTextareaWrapper() {
|
|
83
|
-
const textareaContainer = document.createElement('div');
|
|
84
|
-
textareaContainer.className = `
|
|
85
|
-
textarea-wrapper
|
|
86
|
-
p-2
|
|
87
|
-
bg-white
|
|
88
|
-
dark:bg-stone-800
|
|
89
|
-
grid
|
|
90
|
-
after:px-3.5
|
|
91
|
-
after:py-2.5
|
|
92
|
-
after:text-inherit
|
|
93
|
-
[&>textarea]:resize-none
|
|
94
|
-
[&>textarea]:[grid-area:1/1/2/2]
|
|
95
|
-
after:[grid-area:1/1/2/2]
|
|
96
|
-
after:whitespace-pre-wrap
|
|
97
|
-
after:invisible
|
|
98
|
-
after:content-[attr(data-cloned-val)_'_']
|
|
99
|
-
after:border
|
|
100
|
-
`;
|
|
101
|
-
textareaContainer.appendChild(this.usertextarea);
|
|
102
|
-
this.markdownEditorDiv.appendChild(textareaContainer);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
addPreviewWrapper() {
|
|
108
|
-
const preview = new Preview(this.markdownEditorDiv);
|
|
109
|
-
this.previewContent = preview.getPreviewContent();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
addInputListener() {
|
|
113
|
-
this.usertextarea.addEventListener('input', () => this.render());
|
|
114
|
-
this.usertextarea.addEventListener('scroll', () => {
|
|
115
|
-
const textarea = this.usertextarea;
|
|
116
|
-
const previewPane = this.previewContent;
|
|
117
|
-
|
|
118
|
-
// Calculate the proportion of the textarea that has been scrolled
|
|
119
|
-
const textareaScrollRatio = textarea.scrollTop / (textarea.scrollHeight - textarea.clientHeight);
|
|
120
|
-
|
|
121
|
-
// Apply the same scroll ratio to the preview pane
|
|
122
|
-
previewPane.scrollTop = textareaScrollRatio * (previewPane.scrollHeight - previewPane.clientHeight);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
addToolbar() {
|
|
127
|
-
new Toolbar(this, this.options.toolbar || ['bold', 'italic', 'strikethrough']);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
insertText(text) {
|
|
131
|
-
const { selectionStart, selectionEnd } = this.usertextarea;
|
|
132
|
-
const value = this.usertextarea.value;
|
|
133
|
-
this.usertextarea.value = `${value.substring(0, selectionStart)}${text}${value.substring(selectionEnd)}`;
|
|
134
|
-
this.usertextarea.focus();
|
|
135
|
-
this.usertextarea.setSelectionRange(selectionStart, selectionStart + text.length);
|
|
136
|
-
|
|
137
|
-
// Scroll the textarea to the inserted text
|
|
138
|
-
this.scrollToView();
|
|
139
|
-
|
|
140
|
-
this.render();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
scrollToView() {
|
|
144
|
-
const textarea = this.usertextarea;
|
|
145
|
-
|
|
146
|
-
// Calculate the position of the inserted text
|
|
147
|
-
const selectionStart = textarea.selectionStart;
|
|
148
|
-
|
|
149
|
-
// Get the line height (height of each row of text)
|
|
150
|
-
const lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight);
|
|
151
|
-
|
|
152
|
-
// Get how many rows fit into the visible area of the textarea
|
|
153
|
-
const rowsInView = Math.floor(textarea.clientHeight / lineHeight);
|
|
154
|
-
|
|
155
|
-
// Calculate the current line number of the selectionStart
|
|
156
|
-
const currentLine = Math.floor(selectionStart / textarea.cols);
|
|
157
|
-
|
|
158
|
-
// Scroll to the line number that places the inserted text in the center
|
|
159
|
-
const targetScrollTop = (currentLine - Math.floor(rowsInView / 2)) * lineHeight;
|
|
160
|
-
|
|
161
|
-
// Adjust scrollTop to center the cursor's line in the view
|
|
162
|
-
textarea.scrollTop = targetScrollTop;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
render() {
|
|
167
|
-
const html = marked(this.usertextarea.value);
|
|
168
|
-
this.previewContent.innerHTML = html;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export default MarkdownEditor;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// markdown\preview.js
|
|
2
|
-
class Preview {
|
|
3
|
-
constructor(container) {
|
|
4
|
-
this.previewContainer = document.createElement('div');
|
|
5
|
-
this.previewContainer.className = 'preview-wrapper bg-white dark:bg-stone-800 p-2 hidden';
|
|
6
|
-
this.previewContent = document.createElement('div');
|
|
7
|
-
this.previewContent.className = 'preview-content prose prose-sm md:prose-base dark:prose-invert p-1.5 overflow-y-auto h-[90lvh] max-w-full';
|
|
8
|
-
this.previewContainer.appendChild(this.previewContent);
|
|
9
|
-
container.appendChild(this.previewContainer);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
getPreviewContent() {
|
|
13
|
-
return this.previewContent;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default Preview;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
@import 'tailwindcss';
|
|
2
|
-
|
|
3
|
-
@plugin '@tailwindcss/typography';
|
|
4
|
-
|
|
5
|
-
/*
|
|
6
|
-
The default border color has changed to `currentColor` in Tailwind CSS v4,
|
|
7
|
-
so we've added these compatibility styles to make sure everything still
|
|
8
|
-
looks the same as it did with Tailwind CSS v3.
|
|
9
|
-
|
|
10
|
-
If we ever want to remove these styles, we need to add an explicit border
|
|
11
|
-
color utility to any element that depends on these defaults.
|
|
12
|
-
*/
|
|
13
|
-
@layer base {
|
|
14
|
-
*,
|
|
15
|
-
::after,
|
|
16
|
-
::before,
|
|
17
|
-
::backdrop,
|
|
18
|
-
::file-selector-button {
|
|
19
|
-
border-color: var(--color-gray-200, currentColor);
|
|
20
|
-
}
|
|
21
|
-
}
|