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/README.md +23 -3
- package/dist/overtype.cjs +851 -977
- package/dist/overtype.cjs.map +4 -4
- package/dist/overtype.esm.js +53 -30
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +53 -30
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +45 -39
- package/package.json +5 -2
- package/src/overtype.js +33 -28
- package/src/parser.js +48 -19
- package/src/styles.js +6 -0
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> </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 || ' '}</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
|
-
|
|
375
|
-
child.
|
|
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
|
-
|
|
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"
|
|
470
|
-
processed = processed.replace(codeBlockRegex, (match,
|
|
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(/ /g, ' ')
|
|
477
|
-
.replace(/</g, '<')
|
|
478
|
-
.replace(/>/g, '>')
|
|
479
|
-
.replace(/"/g, '"')
|
|
480
|
-
.replace(/'/g, "'")
|
|
481
|
-
.replace(/&/g, '&');
|
|
501
|
+
.replace(/ /g, ' ');
|
|
482
502
|
return text;
|
|
483
503
|
}).join('\n');
|
|
484
504
|
|
|
485
|
-
|
|
486
|
-
|
|
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;
|