overtype 1.2.1 → 1.2.2
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 +23 -3
- package/dist/overtype.cjs +31 -22
- package/dist/overtype.cjs.map +2 -2
- package/dist/overtype.esm.js +31 -22
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +31 -22
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +47 -41
- package/package.json +5 -2
- package/src/overtype.js +3 -19
- package/src/parser.js +48 -19
- package/src/styles.js +6 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OverType
|
|
2
2
|
|
|
3
|
-
A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~
|
|
3
|
+
A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~79KB minified with all features.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ A lightweight markdown editor library with perfect WYSIWYG alignment using an in
|
|
|
9
9
|
- ⌨️ **Keyboard shortcuts** - Common markdown shortcuts (Cmd/Ctrl+B for bold, etc.)
|
|
10
10
|
- 📱 **Mobile optimized** - Responsive design with mobile-specific styles
|
|
11
11
|
- 🔄 **DOM persistence aware** - Recovers from existing DOM (perfect for HyperClay and similar platforms)
|
|
12
|
-
- 🚀 **Lightweight** - ~
|
|
12
|
+
- 🚀 **Lightweight** - ~79KB minified
|
|
13
13
|
- 🎯 **Optional toolbar** - Clean, minimal toolbar with all essential formatting
|
|
14
14
|
- ✨ **Smart shortcuts** - Keyboard shortcuts with selection preservation
|
|
15
15
|
- 🔧 **Framework agnostic** - Works with React, Vue, vanilla JS, and more
|
|
@@ -24,7 +24,7 @@ We overlap an invisible textarea on top of styled output, giving the illusion of
|
|
|
24
24
|
|
|
25
25
|
| Feature | OverType | HyperMD | Milkdown | TUI Editor | EasyMDE |
|
|
26
26
|
|---------|----------|---------|----------|------------|---------|
|
|
27
|
-
| **Size** | ~
|
|
27
|
+
| **Size** | ~79KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |
|
|
28
28
|
| **Dependencies** | Bundled | CodeMirror | ProseMirror + plugins | Multiple libs | CodeMirror |
|
|
29
29
|
| **Setup** | Single file | Complex config | Build step required | Complex config | Moderate |
|
|
30
30
|
| **Approach** | Invisible textarea | ContentEditable | ContentEditable | ContentEditable | CodeMirror |
|
|
@@ -552,6 +552,26 @@ Special thanks to:
|
|
|
552
552
|
|
|
553
553
|
MIT
|
|
554
554
|
|
|
555
|
+
## Related Projects
|
|
556
|
+
|
|
557
|
+
### Synesthesia
|
|
558
|
+
|
|
559
|
+
[Synesthesia](https://github.com/panphora/synesthesia) is a lightweight syntax highlighting editor library that extracted and refined the core textarea overlay technique from OverType. While OverType is focused on markdown editing with toolbar features, Synesthesia provides a more generalized code editing solution with:
|
|
560
|
+
|
|
561
|
+
- **Pluggable parser system** - Support for any programming language or syntax
|
|
562
|
+
- **Parser registry** - Automatic language detection by file extension or MIME type
|
|
563
|
+
- **Cleaner separation** - Extracted the overlay technique without markdown-specific features
|
|
564
|
+
- **Smaller footprint** - ~79KB minified (vs OverType's ~78KB)
|
|
565
|
+
|
|
566
|
+
Key components extracted from OverType to Synesthesia:
|
|
567
|
+
- The transparent textarea overlay technique for perfect WYSIWYG alignment
|
|
568
|
+
- Theme system with CSS variable support
|
|
569
|
+
- DOM persistence and recovery mechanisms
|
|
570
|
+
- Auto-resize functionality
|
|
571
|
+
- Event delegation for efficient multi-instance support
|
|
572
|
+
|
|
573
|
+
If you need a markdown editor with toolbar and formatting features, use OverType. If you need a lightweight code editor with custom syntax highlighting, check out Synesthesia.
|
|
574
|
+
|
|
555
575
|
## Contributing
|
|
556
576
|
|
|
557
577
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/dist/overtype.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OverType v1.2.
|
|
2
|
+
* OverType v1.2.2
|
|
3
3
|
* A lightweight markdown editor library with perfect WYSIWYG alignment
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @author Demo User
|
|
@@ -258,11 +258,22 @@ var MarkdownParser = class {
|
|
|
258
258
|
static parse(text, activeLine = -1, showActiveLineRaw = false) {
|
|
259
259
|
this.resetLinkIndex();
|
|
260
260
|
const lines = text.split("\n");
|
|
261
|
+
let inCodeBlock = false;
|
|
261
262
|
const parsedLines = lines.map((line, index) => {
|
|
262
263
|
if (showActiveLineRaw && index === activeLine) {
|
|
263
264
|
const content = this.escapeHtml(line) || " ";
|
|
264
265
|
return `<div class="raw-line">${content}</div>`;
|
|
265
266
|
}
|
|
267
|
+
const codeFenceRegex = /^```[^`]*$/;
|
|
268
|
+
if (codeFenceRegex.test(line)) {
|
|
269
|
+
inCodeBlock = !inCodeBlock;
|
|
270
|
+
return this.parseLine(line);
|
|
271
|
+
}
|
|
272
|
+
if (inCodeBlock) {
|
|
273
|
+
const escaped = this.escapeHtml(line);
|
|
274
|
+
const indented = this.preserveIndentation(escaped, line);
|
|
275
|
+
return `<div>${indented || " "}</div>`;
|
|
276
|
+
}
|
|
266
277
|
return this.parseLine(line);
|
|
267
278
|
});
|
|
268
279
|
const html = parsedLines.join("");
|
|
@@ -302,23 +313,22 @@ var MarkdownParser = class {
|
|
|
302
313
|
if (lang) {
|
|
303
314
|
codeElement.className = `language-${lang}`;
|
|
304
315
|
}
|
|
305
|
-
container.insertBefore(currentCodeBlock, child);
|
|
306
|
-
|
|
316
|
+
container.insertBefore(currentCodeBlock, child.nextSibling);
|
|
317
|
+
currentCodeBlock._codeElement = codeElement;
|
|
307
318
|
continue;
|
|
308
319
|
} else {
|
|
309
320
|
inCodeBlock = false;
|
|
310
321
|
currentCodeBlock = null;
|
|
311
|
-
child.remove();
|
|
312
322
|
continue;
|
|
313
323
|
}
|
|
314
324
|
}
|
|
315
325
|
}
|
|
316
326
|
if (inCodeBlock && currentCodeBlock && child.tagName === "DIV" && !child.querySelector(".code-fence")) {
|
|
317
|
-
const codeElement = currentCodeBlock.querySelector("code");
|
|
327
|
+
const codeElement = currentCodeBlock._codeElement || currentCodeBlock.querySelector("code");
|
|
318
328
|
if (codeElement.textContent.length > 0) {
|
|
319
329
|
codeElement.textContent += "\n";
|
|
320
330
|
}
|
|
321
|
-
const lineText = child.
|
|
331
|
+
const lineText = child.textContent.replace(/\u00A0/g, " ");
|
|
322
332
|
codeElement.textContent += lineText;
|
|
323
333
|
child.remove();
|
|
324
334
|
continue;
|
|
@@ -371,15 +381,19 @@ var MarkdownParser = class {
|
|
|
371
381
|
}
|
|
372
382
|
return match;
|
|
373
383
|
});
|
|
374
|
-
const codeBlockRegex = /<div><span class="code-fence"
|
|
375
|
-
processed = processed.replace(codeBlockRegex, (match,
|
|
384
|
+
const codeBlockRegex = /<div><span class="code-fence">(```[^<]*)<\/span><\/div>(.*?)<div><span class="code-fence">(```)<\/span><\/div>/gs;
|
|
385
|
+
processed = processed.replace(codeBlockRegex, (match, openFence, content, closeFence) => {
|
|
376
386
|
const lines = content.match(/<div>(.*?)<\/div>/gs) || [];
|
|
377
387
|
const codeContent = lines.map((line) => {
|
|
378
|
-
const text = line.replace(/<div>(.*?)<\/div>/s, "$1").replace(/ /g, " ")
|
|
388
|
+
const text = line.replace(/<div>(.*?)<\/div>/s, "$1").replace(/ /g, " ");
|
|
379
389
|
return text;
|
|
380
390
|
}).join("\n");
|
|
381
|
-
const
|
|
382
|
-
|
|
391
|
+
const lang = openFence.slice(3).trim();
|
|
392
|
+
const langClass = lang ? ` class="language-${lang}"` : "";
|
|
393
|
+
let result = `<div><span class="code-fence">${openFence}</span></div>`;
|
|
394
|
+
result += `<pre class="code-block"><code${langClass}>${codeContent}</code></pre>`;
|
|
395
|
+
result += `<div><span class="code-fence">${closeFence}</span></div>`;
|
|
396
|
+
return result;
|
|
383
397
|
});
|
|
384
398
|
return processed;
|
|
385
399
|
}
|
|
@@ -1520,11 +1534,17 @@ function generateStyles(options = {}) {
|
|
|
1520
1534
|
position: relative !important; /* Override reset - needed for absolute children */
|
|
1521
1535
|
overflow: visible !important; /* Allow dropdown to overflow container */
|
|
1522
1536
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
1537
|
+
text-align: left !important;
|
|
1523
1538
|
${themeVars ? `
|
|
1524
1539
|
/* Theme Variables */
|
|
1525
1540
|
${themeVars}` : ""}
|
|
1526
1541
|
}
|
|
1527
1542
|
|
|
1543
|
+
/* Force left alignment for all elements in the editor */
|
|
1544
|
+
.overtype-container .overtype-wrapper * {
|
|
1545
|
+
text-align: left !important;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1528
1548
|
/* Auto-resize mode styles */
|
|
1529
1549
|
.overtype-container.overtype-auto-resize {
|
|
1530
1550
|
height: auto !important;
|
|
@@ -3079,17 +3099,6 @@ var _OverType = class _OverType {
|
|
|
3079
3099
|
closeFence.style.display = "block";
|
|
3080
3100
|
openParent.classList.add("code-block-line");
|
|
3081
3101
|
closeParent.classList.add("code-block-line");
|
|
3082
|
-
let currentDiv = openParent.nextElementSibling;
|
|
3083
|
-
while (currentDiv && currentDiv !== closeParent) {
|
|
3084
|
-
if (currentDiv.tagName === "DIV") {
|
|
3085
|
-
currentDiv.classList.add("code-block-line");
|
|
3086
|
-
const plainText = currentDiv.textContent;
|
|
3087
|
-
currentDiv.textContent = plainText;
|
|
3088
|
-
}
|
|
3089
|
-
currentDiv = currentDiv.nextElementSibling;
|
|
3090
|
-
if (!currentDiv)
|
|
3091
|
-
break;
|
|
3092
|
-
}
|
|
3093
3102
|
}
|
|
3094
3103
|
}
|
|
3095
3104
|
/**
|