overtype 1.1.6 → 1.1.8

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v1.1.6
2
+ * OverType v1.1.8
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author Demo User
@@ -140,6 +140,28 @@ var MarkdownParser = class {
140
140
  static parseInlineCode(html) {
141
141
  return html.replace(new RegExp("(?<!`)(`+)(?!`)((?:(?!\\1).)+?)(\\1)(?!`)", "g"), '<code><span class="syntax-marker">$1</span>$2<span class="syntax-marker">$3</span></code>');
142
142
  }
143
+ /**
144
+ * Sanitize URL to prevent XSS attacks
145
+ * @param {string} url - URL to sanitize
146
+ * @returns {string} Safe URL or '#' if dangerous
147
+ */
148
+ static sanitizeUrl(url) {
149
+ const trimmed = url.trim();
150
+ const lower = trimmed.toLowerCase();
151
+ const safeProtocols = [
152
+ "http://",
153
+ "https://",
154
+ "mailto:",
155
+ "ftp://",
156
+ "ftps://"
157
+ ];
158
+ const hasSafeProtocol = safeProtocols.some((protocol) => lower.startsWith(protocol));
159
+ const isRelative = trimmed.startsWith("/") || trimmed.startsWith("#") || trimmed.startsWith("?") || trimmed.startsWith(".") || !trimmed.includes(":") && !trimmed.includes("//");
160
+ if (hasSafeProtocol || isRelative) {
161
+ return url;
162
+ }
163
+ return "#";
164
+ }
143
165
  /**
144
166
  * Parse links
145
167
  * @param {string} html - HTML with potential link markdown
@@ -148,7 +170,8 @@ var MarkdownParser = class {
148
170
  static parseLinks(html) {
149
171
  return html.replace(/\[(.+?)\]\((.+?)\)/g, (match, text, url) => {
150
172
  const anchorName = `--link-${this.linkIndex++}`;
151
- return `<a href="${url}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${text}<span class="syntax-marker">](</span><span class="syntax-marker link-url">${url}</span><span class="syntax-marker">)</span></a>`;
173
+ const safeUrl = this.sanitizeUrl(url);
174
+ return `<a href="${safeUrl}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${text}<span class="syntax-marker">](</span><span class="syntax-marker link-url">${url}</span><span class="syntax-marker">)</span></a>`;
152
175
  });
153
176
  }
154
177
  /**
@@ -1300,6 +1323,7 @@ function generateStyles(options = {}) {
1300
1323
  const {
1301
1324
  fontSize = "14px",
1302
1325
  lineHeight = 1.6,
1326
+ /* System-first, guaranteed monospaced; avoids Android 'ui-monospace' pitfalls */
1303
1327
  fontFamily = '"SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace',
1304
1328
  padding = "20px",
1305
1329
  theme = null,
@@ -1363,7 +1387,6 @@ function generateStyles(options = {}) {
1363
1387
 
1364
1388
  /* Font properties - any difference breaks alignment */
1365
1389
  font-family: ${fontFamily} !important;
1366
- font-synthesis: none !important; /* no faux bold/italic width drift */
1367
1390
  font-variant-ligatures: none !important; /* keep metrics stable for code */
1368
1391
  font-size: var(--instance-font-size, ${fontSize}) !important;
1369
1392
  line-height: var(--instance-line-height, ${lineHeight}) !important;
@@ -1759,6 +1782,23 @@ function generateStyles(options = {}) {
1759
1782
  margin: 0 2px;
1760
1783
  }
1761
1784
  }
1785
+
1786
+ /* Plain mode - hide preview and show textarea text */
1787
+ .overtype-container.plain-mode .overtype-preview {
1788
+ display: none !important;
1789
+ }
1790
+
1791
+ .overtype-container.plain-mode .overtype-input {
1792
+ color: var(--text, #0d3b66) !important;
1793
+ /* Use system font stack for better plain text readability */
1794
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
1795
+ "Helvetica Neue", Arial, sans-serif !important;
1796
+ }
1797
+
1798
+ /* Ensure textarea remains transparent in overlay mode */
1799
+ .overtype-container:not(.plain-mode) .overtype-input {
1800
+ color: transparent !important;
1801
+ }
1762
1802
 
1763
1803
  ${mobileStyles}
1764
1804
  `;
@@ -1822,6 +1862,10 @@ var taskListIcon = `<svg viewBox="0 0 18 18">
1822
1862
  <rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="13" width="3" height="3" rx="0.5"></rect>
1823
1863
  <polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" points="2.65 9.5 3.5 10.5 5 8.5"></polyline>
1824
1864
  </svg>`;
1865
+ var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1866
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
1867
+ <circle cx="12" cy="12" r="3" fill="none"></circle>
1868
+ </svg>`;
1825
1869
 
1826
1870
  // src/toolbar.js
1827
1871
  var Toolbar = class {
@@ -1853,7 +1897,9 @@ var Toolbar = class {
1853
1897
  { separator: true },
1854
1898
  { name: "bulletList", icon: bulletListIcon, title: "Bullet List", action: "toggleBulletList" },
1855
1899
  { name: "orderedList", icon: orderedListIcon, title: "Numbered List", action: "toggleNumberedList" },
1856
- { name: "taskList", icon: taskListIcon, title: "Task List", action: "toggleTaskList" }
1900
+ { name: "taskList", icon: taskListIcon, title: "Task List", action: "toggleTaskList" },
1901
+ { separator: true },
1902
+ { name: "togglePlain", icon: eyeIcon, title: "Show plain textarea", action: "toggle-plain" }
1857
1903
  ];
1858
1904
  buttonConfig.forEach((config) => {
1859
1905
  if (config.separator) {
@@ -1934,6 +1980,10 @@ var Toolbar = class {
1934
1980
  case "toggleTaskList":
1935
1981
  toggleTaskList(textarea);
1936
1982
  break;
1983
+ case "toggle-plain":
1984
+ const isPlain = this.editor.container.classList.contains("plain-mode");
1985
+ this.editor.showPlainTextarea(!isPlain);
1986
+ break;
1937
1987
  }
1938
1988
  textarea.dispatchEvent(new Event("input", { bubbles: true }));
1939
1989
  } catch (error) {
@@ -1982,6 +2032,9 @@ var Toolbar = class {
1982
2032
  case "h3":
1983
2033
  isActive = activeFormats.includes("header-3");
1984
2034
  break;
2035
+ case "togglePlain":
2036
+ isActive = !this.editor.container.classList.contains("plain-mode");
2037
+ break;
1985
2038
  }
1986
2039
  button.classList.toggle("active", isActive);
1987
2040
  button.setAttribute("aria-pressed", isActive.toString());
@@ -2230,7 +2283,8 @@ var _OverType = class _OverType {
2230
2283
  // Typography
2231
2284
  fontSize: "14px",
2232
2285
  lineHeight: 1.6,
2233
- fontFamily: "ui-monospace, 'SFMono-Regular', 'Menlo', 'Consolas', 'Liberation Mono', monospace",
2286
+ /* System-first, guaranteed monospaced; avoids Android 'ui-monospace' pitfalls */
2287
+ fontFamily: '"SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace',
2234
2288
  padding: "16px",
2235
2289
  // Mobile styles
2236
2290
  mobile: {
@@ -2708,6 +2762,26 @@ var _OverType = class _OverType {
2708
2762
  this.statsBar = null;
2709
2763
  }
2710
2764
  }
2765
+ /**
2766
+ * Show or hide the plain textarea (toggle overlay visibility)
2767
+ * @param {boolean} show - true to show plain textarea (hide overlay), false to show overlay
2768
+ * @returns {boolean} Current plain textarea state
2769
+ */
2770
+ showPlainTextarea(show) {
2771
+ if (show) {
2772
+ this.container.classList.add("plain-mode");
2773
+ } else {
2774
+ this.container.classList.remove("plain-mode");
2775
+ }
2776
+ if (this.toolbar) {
2777
+ const toggleBtn = this.container.querySelector('[data-action="toggle-plain"]');
2778
+ if (toggleBtn) {
2779
+ toggleBtn.classList.toggle("active", !show);
2780
+ toggleBtn.title = show ? "Show markdown preview" : "Show plain textarea";
2781
+ }
2782
+ }
2783
+ return show;
2784
+ }
2711
2785
  /**
2712
2786
  * Destroy the editor instance
2713
2787
  */