overtype 1.2.0 → 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/src/parser.js CHANGED
@@ -286,6 +286,8 @@ export class MarkdownParser {
286
286
 
287
287
  // Wrap in div to maintain line structure
288
288
  if (html.trim() === '') {
289
+ // Intentionally use   for empty lines to maintain vertical spacing
290
+ // This causes a 0->1 character count difference but preserves visual alignment
289
291
  return '<div>&nbsp;</div>';
290
292
  }
291
293
 
@@ -304,6 +306,8 @@ export class MarkdownParser {
304
306
  this.resetLinkIndex();
305
307
 
306
308
  const lines = text.split('\n');
309
+ let inCodeBlock = false;
310
+
307
311
  const parsedLines = lines.map((line, index) => {
308
312
  // Show raw markdown on active line if requested
309
313
  if (showActiveLineRaw && index === activeLine) {
@@ -311,6 +315,21 @@ export class MarkdownParser {
311
315
  return `<div class="raw-line">${content}</div>`;
312
316
  }
313
317
 
318
+ // Check if this line is a code fence
319
+ const codeFenceRegex = /^```[^`]*$/;
320
+ if (codeFenceRegex.test(line)) {
321
+ inCodeBlock = !inCodeBlock;
322
+ // Parse fence markers normally to get styled output
323
+ return this.parseLine(line);
324
+ }
325
+
326
+ // If we're inside a code block, don't parse as markdown
327
+ if (inCodeBlock) {
328
+ const escaped = this.escapeHtml(line);
329
+ const indented = this.preserveIndentation(escaped, line);
330
+ return `<div>${indented || '&nbsp;'}</div>`;
331
+ }
332
+
314
333
  // Otherwise, parse the markdown normally
315
334
  return this.parseLine(line);
316
335
  });
@@ -358,8 +377,10 @@ export class MarkdownParser {
358
377
  const fenceText = codeFence.textContent;
359
378
  if (fenceText.startsWith('```')) {
360
379
  if (!inCodeBlock) {
361
- // Start of code block
380
+ // Start of code block - keep fence visible, then add pre/code
362
381
  inCodeBlock = true;
382
+
383
+ // Create the code block that will follow the fence
363
384
  currentCodeBlock = document.createElement('pre');
364
385
  const codeElement = document.createElement('code');
365
386
  currentCodeBlock.appendChild(codeElement);
@@ -371,14 +392,16 @@ export class MarkdownParser {
371
392
  codeElement.className = `language-${lang}`;
372
393
  }
373
394
 
374
- container.insertBefore(currentCodeBlock, child);
375
- child.remove();
395
+ // Insert code block after the fence div (don't remove the fence)
396
+ container.insertBefore(currentCodeBlock, child.nextSibling);
397
+
398
+ // Store reference to the code element for adding content
399
+ currentCodeBlock._codeElement = codeElement;
376
400
  continue;
377
401
  } else {
378
- // End of code block
402
+ // End of code block - fence stays visible
379
403
  inCodeBlock = false;
380
404
  currentCodeBlock = null;
381
- child.remove();
382
405
  continue;
383
406
  }
384
407
  }
@@ -386,13 +409,15 @@ export class MarkdownParser {
386
409
 
387
410
  // Check if we're in a code block - any div that's not a code fence
388
411
  if (inCodeBlock && currentCodeBlock && child.tagName === 'DIV' && !child.querySelector('.code-fence')) {
389
- const codeElement = currentCodeBlock.querySelector('code');
412
+ const codeElement = currentCodeBlock._codeElement || currentCodeBlock.querySelector('code');
390
413
  // Add the line content to the code block
391
414
  if (codeElement.textContent.length > 0) {
392
415
  codeElement.textContent += '\n';
393
416
  }
394
417
  // Get the actual text content, preserving spaces
395
- const lineText = child.innerHTML.replace(/&nbsp;/g, ' ').replace(/<[^>]*>/g, '');
418
+ // Use textContent instead of innerHTML to avoid double-escaping
419
+ // textContent automatically decodes HTML entities
420
+ const lineText = child.textContent.replace(/\u00A0/g, ' '); // \u00A0 is nbsp
396
421
  codeElement.textContent += lineText;
397
422
  child.remove();
398
423
  continue;
@@ -465,25 +490,29 @@ export class MarkdownParser {
465
490
  return match;
466
491
  });
467
492
 
468
- // Process code blocks
469
- const codeBlockRegex = /<div><span class="code-fence">```([^<]*)<\/span><\/div>(.*?)<div><span class="code-fence">```<\/span><\/div>/gs;
470
- processed = processed.replace(codeBlockRegex, (match, lang, content) => {
493
+ // Process code blocks - KEEP the fence markers for alignment AND use semantic pre/code
494
+ const codeBlockRegex = /<div><span class="code-fence">(```[^<]*)<\/span><\/div>(.*?)<div><span class="code-fence">(```)<\/span><\/div>/gs;
495
+ processed = processed.replace(codeBlockRegex, (match, openFence, content, closeFence) => {
471
496
  // Extract the content between fences
472
497
  const lines = content.match(/<div>(.*?)<\/div>/gs) || [];
473
498
  const codeContent = lines.map(line => {
474
- // Extract text from each div
499
+ // Extract text from each div - content is already escaped
475
500
  const text = line.replace(/<div>(.*?)<\/div>/s, '$1')
476
- .replace(/&nbsp;/g, ' ')
477
- .replace(/&lt;/g, '<')
478
- .replace(/&gt;/g, '>')
479
- .replace(/&quot;/g, '"')
480
- .replace(/&#39;/g, "'")
481
- .replace(/&amp;/g, '&');
501
+ .replace(/&nbsp;/g, ' ');
482
502
  return text;
483
503
  }).join('\n');
484
504
 
485
- const langClass = lang ? ` class="language-${lang.trim()}"` : '';
486
- return `<pre class="code-block"><code${langClass}>${this.escapeHtml(codeContent)}</code></pre>`;
505
+ // Extract language from the opening fence
506
+ const lang = openFence.slice(3).trim();
507
+ const langClass = lang ? ` class="language-${lang}"` : '';
508
+
509
+ // Keep fence markers visible as separate divs, with pre/code block between them
510
+ let result = `<div><span class="code-fence">${openFence}</span></div>`;
511
+ // Content is already escaped, don't double-escape
512
+ result += `<pre class="code-block"><code${langClass}>${codeContent}</code></pre>`;
513
+ result += `<div><span class="code-fence">${closeFence}</span></div>`;
514
+
515
+ return result;
487
516
  });
488
517
 
489
518
  return processed;
package/src/styles.js CHANGED
@@ -79,11 +79,17 @@ export function generateStyles(options = {}) {
79
79
  position: relative !important; /* Override reset - needed for absolute children */
80
80
  overflow: visible !important; /* Allow dropdown to overflow container */
81
81
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
82
+ text-align: left !important;
82
83
  ${themeVars ? `
83
84
  /* Theme Variables */
84
85
  ${themeVars}` : ''}
85
86
  }
86
87
 
88
+ /* Force left alignment for all elements in the editor */
89
+ .overtype-container .overtype-wrapper * {
90
+ text-align: left !important;
91
+ }
92
+
87
93
  /* Auto-resize mode styles */
88
94
  .overtype-container.overtype-auto-resize {
89
95
  height: auto !important;