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 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. ~78KB minified with all features.
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** - ~78KB minified
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** | ~78KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |
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.1
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 || "&nbsp;"}</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
- child.remove();
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.innerHTML.replace(/&nbsp;/g, " ").replace(/<[^>]*>/g, "");
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">```([^<]*)<\/span><\/div>(.*?)<div><span class="code-fence">```<\/span><\/div>/gs;
375
- processed = processed.replace(codeBlockRegex, (match, lang, content) => {
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(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
388
+ const text = line.replace(/<div>(.*?)<\/div>/s, "$1").replace(/&nbsp;/g, " ");
379
389
  return text;
380
390
  }).join("\n");
381
- const langClass = lang ? ` class="language-${lang.trim()}"` : "";
382
- return `<pre class="code-block"><code${langClass}>${this.escapeHtml(codeContent)}</code></pre>`;
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
  /**