markdown-text-editor 0.1.5 → 0.2.1

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.
@@ -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
- }
@@ -1,7 +0,0 @@
1
- // utils/markdownUtils.js
2
-
3
- import { marked } from 'marked';
4
-
5
- export function renderMarkdown(content) {
6
- return marked(content);
7
- }