overtype 1.2.3 → 1.2.4

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/dist/overtype.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v1.2.2
2
+ * OverType v1.2.4
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author Demo User
@@ -155,6 +155,17 @@ var OverType = (() => {
155
155
  html = html.replace(new RegExp("(?<!_)_(?!_)(.+?)(?<!_)_(?!_)", "g"), '<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>');
156
156
  return html;
157
157
  }
158
+ /**
159
+ * Parse strikethrough text
160
+ * Supports both single (~) and double (~~) tildes, but rejects 3+ tildes
161
+ * @param {string} html - HTML with potential strikethrough markdown
162
+ * @returns {string} HTML with strikethrough styling
163
+ */
164
+ static parseStrikethrough(html) {
165
+ html = html.replace(new RegExp("(?<!~)~~(?!~)(.+?)(?<!~)~~(?!~)", "g"), '<del><span class="syntax-marker">~~</span>$1<span class="syntax-marker">~~</span></del>');
166
+ html = html.replace(new RegExp("(?<!~)~(?!~)(.+?)(?<!~)~(?!~)", "g"), '<del><span class="syntax-marker">~</span>$1<span class="syntax-marker">~</span></del>');
167
+ return html;
168
+ }
158
169
  /**
159
170
  * Parse inline code
160
171
  * @param {string} html - HTML with potential code markdown
@@ -217,6 +228,7 @@ var OverType = (() => {
217
228
  sanctuaries.set(placeholder, match);
218
229
  return placeholder;
219
230
  });
231
+ html = this.parseStrikethrough(html);
220
232
  html = this.parseBold(html);
221
233
  html = this.parseItalic(html);
222
234
  sanctuaries.forEach((content, placeholder) => {
@@ -351,6 +363,17 @@ var OverType = (() => {
351
363
  container.insertBefore(currentList, child);
352
364
  listType = newType;
353
365
  }
366
+ const indentationNodes = [];
367
+ for (const node of child.childNodes) {
368
+ if (node.nodeType === 3 && node.textContent.match(/^\u00A0+$/)) {
369
+ indentationNodes.push(node.cloneNode(true));
370
+ } else if (node === listItem) {
371
+ break;
372
+ }
373
+ }
374
+ indentationNodes.forEach((node) => {
375
+ listItem.insertBefore(node, listItem.firstChild);
376
+ });
354
377
  currentList.appendChild(listItem);
355
378
  child.remove();
356
379
  } else {
@@ -368,15 +391,35 @@ var OverType = (() => {
368
391
  static postProcessHTMLManual(html) {
369
392
  let processed = html;
370
393
  processed = processed.replace(/((?:<div>(?:&nbsp;)*<li class="bullet-list">.*?<\/li><\/div>\s*)+)/gs, (match) => {
371
- const items = match.match(/<li class="bullet-list">.*?<\/li>/gs) || [];
372
- if (items.length > 0) {
394
+ const divs = match.match(/<div>(?:&nbsp;)*<li class="bullet-list">.*?<\/li><\/div>/gs) || [];
395
+ if (divs.length > 0) {
396
+ const items = divs.map((div) => {
397
+ const indentMatch = div.match(/<div>((?:&nbsp;)*)<li/);
398
+ const listItemMatch = div.match(/<li class="bullet-list">.*?<\/li>/);
399
+ if (indentMatch && listItemMatch) {
400
+ const indentation = indentMatch[1];
401
+ const listItem = listItemMatch[0];
402
+ return listItem.replace(/<li class="bullet-list">/, `<li class="bullet-list">${indentation}`);
403
+ }
404
+ return listItemMatch ? listItemMatch[0] : "";
405
+ }).filter(Boolean);
373
406
  return "<ul>" + items.join("") + "</ul>";
374
407
  }
375
408
  return match;
376
409
  });
377
410
  processed = processed.replace(/((?:<div>(?:&nbsp;)*<li class="ordered-list">.*?<\/li><\/div>\s*)+)/gs, (match) => {
378
- const items = match.match(/<li class="ordered-list">.*?<\/li>/gs) || [];
379
- if (items.length > 0) {
411
+ const divs = match.match(/<div>(?:&nbsp;)*<li class="ordered-list">.*?<\/li><\/div>/gs) || [];
412
+ if (divs.length > 0) {
413
+ const items = divs.map((div) => {
414
+ const indentMatch = div.match(/<div>((?:&nbsp;)*)<li/);
415
+ const listItemMatch = div.match(/<li class="ordered-list">.*?<\/li>/);
416
+ if (indentMatch && listItemMatch) {
417
+ const indentation = indentMatch[1];
418
+ const listItem = listItemMatch[0];
419
+ return listItem.replace(/<li class="ordered-list">/, `<li class="ordered-list">${indentation}`);
420
+ }
421
+ return listItemMatch ? listItemMatch[0] : "";
422
+ }).filter(Boolean);
380
423
  return "<ol>" + items.join("") + "</ol>";
381
424
  }
382
425
  return match;
@@ -1918,6 +1961,14 @@ ${blockSuffix}` : suffix;
1918
1961
  font-style: italic !important;
1919
1962
  }
1920
1963
 
1964
+ /* Strikethrough text */
1965
+ .overtype-wrapper .overtype-preview del {
1966
+ color: var(--del, #ee964b) !important;
1967
+ text-decoration: line-through !important;
1968
+ text-decoration-color: var(--del, #ee964b) !important;
1969
+ text-decoration-thickness: 1px !important;
1970
+ }
1971
+
1921
1972
  /* Inline code */
1922
1973
  .overtype-wrapper .overtype-preview code {
1923
1974
  background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
@@ -2061,10 +2112,10 @@ ${blockSuffix}` : suffix;
2061
2112
  height: 8px !important;
2062
2113
  background: #4caf50 !important;
2063
2114
  border-radius: 50% !important;
2064
- animation: pulse 2s infinite !important;
2115
+ animation: overtype-pulse 2s infinite !important;
2065
2116
  }
2066
2117
 
2067
- @keyframes pulse {
2118
+ @keyframes overtype-pulse {
2068
2119
  0%, 100% { opacity: 1; transform: scale(1); }
2069
2120
  50% { opacity: 0.6; transform: scale(1.2); }
2070
2121
  }
@@ -2072,19 +2123,19 @@ ${blockSuffix}` : suffix;
2072
2123
 
2073
2124
  /* Toolbar Styles */
2074
2125
  .overtype-toolbar {
2075
- display: flex;
2076
- align-items: center;
2077
- gap: 4px;
2126
+ display: flex !important;
2127
+ align-items: center !important;
2128
+ gap: 4px !important;
2078
2129
  padding: 8px !important; /* Override reset */
2079
2130
  background: var(--toolbar-bg, var(--bg-primary, #f8f9fa)) !important; /* Override reset */
2080
2131
  overflow-x: auto !important; /* Allow horizontal scrolling */
2081
2132
  overflow-y: hidden !important; /* Hide vertical overflow */
2082
- -webkit-overflow-scrolling: touch;
2083
- flex-shrink: 0;
2133
+ -webkit-overflow-scrolling: touch !important;
2134
+ flex-shrink: 0 !important;
2084
2135
  height: auto !important;
2085
2136
  grid-row: 1 !important; /* Always first row in grid */
2086
2137
  position: relative !important; /* Override reset */
2087
- z-index: 100; /* Ensure toolbar is above wrapper */
2138
+ z-index: 100 !important; /* Ensure toolbar is above wrapper */
2088
2139
  scrollbar-width: thin; /* Thin scrollbar on Firefox */
2089
2140
  }
2090
2141
 
@@ -2466,20 +2517,67 @@ ${blockSuffix}` : suffix;
2466
2517
 
2467
2518
  // src/toolbar.js
2468
2519
  var Toolbar = class {
2469
- constructor(editor) {
2520
+ constructor(editor, buttonConfig = null) {
2470
2521
  this.editor = editor;
2471
2522
  this.container = null;
2472
2523
  this.buttons = {};
2524
+ this.buttonConfig = buttonConfig;
2525
+ }
2526
+ /**
2527
+ * Check if cursor/selection is inside a markdown link
2528
+ * @param {HTMLTextAreaElement} textarea - The textarea element
2529
+ * @returns {boolean} True if inside a link
2530
+ */
2531
+ isInsideLink(textarea) {
2532
+ const value = textarea.value;
2533
+ const start = textarea.selectionStart;
2534
+ const end = textarea.selectionEnd;
2535
+ let insideLink = false;
2536
+ let openBracket = -1;
2537
+ let closeBracket = -1;
2538
+ for (let i = start - 1; i >= 0; i--) {
2539
+ if (value[i] === "[") {
2540
+ openBracket = i;
2541
+ break;
2542
+ }
2543
+ if (value[i] === "\n") {
2544
+ break;
2545
+ }
2546
+ }
2547
+ if (openBracket >= 0) {
2548
+ for (let i = end; i < value.length - 1; i++) {
2549
+ if (value[i] === "]" && value[i + 1] === "(") {
2550
+ closeBracket = i;
2551
+ break;
2552
+ }
2553
+ if (value[i] === "\n") {
2554
+ break;
2555
+ }
2556
+ }
2557
+ }
2558
+ if (openBracket >= 0 && closeBracket >= 0) {
2559
+ for (let i = closeBracket + 2; i < value.length; i++) {
2560
+ if (value[i] === ")") {
2561
+ insideLink = true;
2562
+ break;
2563
+ }
2564
+ if (value[i] === "\n" || value[i] === " ") {
2565
+ break;
2566
+ }
2567
+ }
2568
+ }
2569
+ return insideLink;
2473
2570
  }
2474
2571
  /**
2475
2572
  * Create and attach toolbar to editor
2476
2573
  */
2477
2574
  create() {
2575
+ var _a;
2478
2576
  this.container = document.createElement("div");
2479
2577
  this.container.className = "overtype-toolbar";
2480
2578
  this.container.setAttribute("role", "toolbar");
2481
2579
  this.container.setAttribute("aria-label", "Text formatting");
2482
- const buttonConfig = [
2580
+ const buttonConfig = (_a = this.buttonConfig) != null ? _a : [
2483
2581
  { name: "bold", icon: boldIcon, title: "Bold (Ctrl+B)", action: "toggleBold" },
2484
2582
  { name: "italic", icon: italicIcon, title: "Italic (Ctrl+I)", action: "toggleItalic" },
2485
2583
  { separator: true },
@@ -2573,6 +2671,9 @@ ${blockSuffix}` : suffix;
2573
2671
  insertLink(textarea);
2574
2672
  break;
2575
2673
  case "toggleCode":
2674
+ if (this.isInsideLink(textarea)) {
2675
+ return;
2676
+ }
2576
2677
  toggleCode(textarea);
2577
2678
  break;
2578
2679
  case "toggleBulletList":
@@ -2788,29 +2889,29 @@ ${blockSuffix}` : suffix;
2788
2889
  position: absolute;
2789
2890
  position-anchor: var(--target-anchor, --link-0);
2790
2891
  position-area: block-end center;
2791
- margin-top: 8px;
2892
+ margin-top: 8px !important;
2792
2893
 
2793
- background: #333;
2794
- color: white;
2795
- padding: 6px 10px;
2796
- border-radius: 16px;
2797
- font-size: 12px;
2798
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
2799
- display: none;
2800
- z-index: 10000;
2801
- cursor: pointer;
2802
- box-shadow: 0 2px 8px rgba(0,0,0,0.3);
2803
- max-width: 300px;
2804
- white-space: nowrap;
2805
- overflow: hidden;
2806
- text-overflow: ellipsis;
2894
+ background: #333 !important;
2895
+ color: white !important;
2896
+ padding: 6px 10px !important;
2897
+ border-radius: 16px !important;
2898
+ font-size: 12px !important;
2899
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
2900
+ display: none !important;
2901
+ z-index: 10000 !important;
2902
+ cursor: pointer !important;
2903
+ box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
2904
+ max-width: 300px !important;
2905
+ white-space: nowrap !important;
2906
+ overflow: hidden !important;
2907
+ text-overflow: ellipsis !important;
2807
2908
 
2808
2909
  position-try: most-width block-end inline-end, flip-inline, block-start center;
2809
2910
  position-visibility: anchors-visible;
2810
2911
  }
2811
2912
 
2812
2913
  .overtype-link-tooltip.visible {
2813
- display: flex;
2914
+ display: flex !important;
2814
2915
  }
2815
2916
  }
2816
2917
  `;
@@ -2958,7 +3059,8 @@ ${blockSuffix}` : suffix;
2958
3059
  this.shortcuts = new ShortcutsManager(this);
2959
3060
  this.linkTooltip = new LinkTooltip(this);
2960
3061
  if (this.options.toolbar) {
2961
- this.toolbar = new Toolbar(this);
3062
+ const toolbarButtons = typeof this.options.toolbar === "object" ? this.options.toolbar.buttons : null;
3063
+ this.toolbar = new Toolbar(this, toolbarButtons);
2962
3064
  this.toolbar.create();
2963
3065
  this.textarea.addEventListener("selectionchange", () => {
2964
3066
  this.toolbar.updateButtonStates();
@@ -3440,24 +3542,36 @@ ${blockSuffix}` : suffix;
3440
3542
  }
3441
3543
  /**
3442
3544
  * Get the rendered HTML of the current content
3443
- * @param {boolean} processForPreview - If true, post-processes HTML for preview mode (consolidates lists/code blocks)
3545
+ * @param {Object} options - Rendering options
3546
+ * @param {boolean} options.cleanHTML - If true, removes syntax markers and OverType-specific classes
3444
3547
  * @returns {string} Rendered HTML
3445
3548
  */
3446
- getRenderedHTML(processForPreview = false) {
3549
+ getRenderedHTML(options = {}) {
3447
3550
  const markdown = this.getValue();
3448
3551
  let html = MarkdownParser.parse(markdown);
3449
- if (processForPreview) {
3450
- html = MarkdownParser.postProcessHTML(html);
3552
+ if (options.cleanHTML) {
3553
+ html = html.replace(/<span class="syntax-marker[^"]*">.*?<\/span>/g, "");
3554
+ html = html.replace(/\sclass="(bullet-list|ordered-list|code-fence|hr-marker|blockquote|url-part)"/g, "");
3555
+ html = html.replace(/\sclass=""/g, "");
3451
3556
  }
3452
3557
  return html;
3453
3558
  }
3454
3559
  /**
3455
3560
  * Get the current preview element's HTML
3561
+ * This includes all syntax markers and OverType styling
3456
3562
  * @returns {string} Current preview HTML (as displayed)
3457
3563
  */
3458
3564
  getPreviewHTML() {
3459
3565
  return this.preview.innerHTML;
3460
3566
  }
3567
+ /**
3568
+ * Get clean HTML without any OverType-specific markup
3569
+ * Useful for exporting to other formats or storage
3570
+ * @returns {string} Clean HTML suitable for export
3571
+ */
3572
+ getCleanHTML() {
3573
+ return this.getRenderedHTML({ cleanHTML: true });
3574
+ }
3461
3575
  /**
3462
3576
  * Focus the editor
3463
3577
  */
@@ -3776,9 +3890,6 @@ ${blockSuffix}` : suffix;
3776
3890
  OverType.themes = { solar, cave: getTheme("cave") };
3777
3891
  OverType.getTheme = getTheme;
3778
3892
  OverType.currentTheme = solar;
3779
- if (typeof window !== "undefined" && typeof window.document !== "undefined") {
3780
- window.OverType = OverType;
3781
- }
3782
3893
  var overtype_default = OverType;
3783
3894
  return __toCommonJS(overtype_exports);
3784
3895
  })();
@@ -3787,4 +3898,9 @@ ${blockSuffix}` : suffix;
3787
3898
  * @version 1.0.0
3788
3899
  * @license MIT
3789
3900
  */
3901
+
3902
+ if (typeof window !== "undefined" && typeof window.document !== "undefined") {
3903
+ window.OverType = OverType.default ? OverType.default : OverType;
3904
+ }
3905
+
3790
3906
  //# sourceMappingURL=overtype.js.map