overtype 1.1.1 → 1.1.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/README.md CHANGED
@@ -140,6 +140,26 @@ editors.forEach((editor, index) => {
140
140
  });
141
141
  ```
142
142
 
143
+ ### Form Integration
144
+
145
+ ```javascript
146
+ // Use with form validation
147
+ const [editor] = new OverType('#message', {
148
+ placeholder: 'Your message...',
149
+ textareaProps: {
150
+ required: true,
151
+ maxLength: 500,
152
+ name: 'message'
153
+ }
154
+ });
155
+
156
+ // The textarea will work with native form validation
157
+ document.querySelector('form').addEventListener('submit', (e) => {
158
+ const content = editor.getValue();
159
+ // Form will automatically validate required field
160
+ });
161
+ ```
162
+
143
163
  ### Custom Theme
144
164
 
145
165
  ```javascript
@@ -270,6 +290,14 @@ new OverType(target, options)
270
290
  placeholder: 'Start typing...',
271
291
  value: '',
272
292
 
293
+ // Native textarea properties
294
+ textareaProps: {
295
+ required: true,
296
+ maxLength: 500,
297
+ name: 'content',
298
+ // Any HTML textarea attribute
299
+ },
300
+
273
301
  // Stats bar
274
302
  showStats: false, // Enable/disable stats bar
275
303
  statsFormatter: (stats) => { // Custom stats format
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v1.1.0
2
+ * OverType v1.1.4
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author Demo User
@@ -105,7 +105,7 @@ var MarkdownParser = class {
105
105
  * @returns {string|null} Parsed code fence or null
106
106
  */
107
107
  static parseCodeBlock(html) {
108
- if (html.startsWith("```")) {
108
+ if (html.match(/^```(\s*|\w*)$/)) {
109
109
  return `<div><span class="code-fence">${html}</span></div>`;
110
110
  }
111
111
  return null;
@@ -1294,7 +1294,7 @@ function generateStyles(options = {}) {
1294
1294
  const {
1295
1295
  fontSize = "14px",
1296
1296
  lineHeight = 1.6,
1297
- fontFamily = "ui-monospace, 'SFMono-Regular', 'Menlo', 'Consolas', 'Liberation Mono', monospace",
1297
+ 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',
1298
1298
  padding = "20px",
1299
1299
  theme = null,
1300
1300
  mobile = {}
@@ -1314,7 +1314,8 @@ function generateStyles(options = {}) {
1314
1314
  return `
1315
1315
  /* OverType Editor Styles */
1316
1316
  .overtype-container {
1317
- position: relative !important;
1317
+ display: grid !important;
1318
+ grid-template-rows: auto 1fr auto !important;
1318
1319
  width: 100% !important;
1319
1320
  height: 100% !important;
1320
1321
  ${themeVars ? `
@@ -1322,12 +1323,26 @@ function generateStyles(options = {}) {
1322
1323
  ${themeVars}` : ""}
1323
1324
  }
1324
1325
 
1326
+ /* Auto-resize mode styles */
1327
+ .overtype-container.overtype-auto-resize {
1328
+ height: auto !important;
1329
+ grid-template-rows: auto auto auto !important;
1330
+ }
1331
+
1332
+ .overtype-container.overtype-auto-resize .overtype-wrapper {
1333
+ height: auto !important;
1334
+ min-height: 60px !important;
1335
+ overflow: visible !important;
1336
+ }
1337
+
1325
1338
  .overtype-wrapper {
1326
1339
  position: relative !important;
1327
1340
  width: 100% !important;
1328
- height: 100% !important;
1341
+ height: 100% !important; /* Take full height of grid cell */
1342
+ min-height: 60px !important; /* Minimum usable height */
1329
1343
  overflow: hidden !important;
1330
1344
  background: var(--bg-secondary, #ffffff) !important;
1345
+ grid-row: 2 !important; /* Always second row in grid */
1331
1346
  }
1332
1347
 
1333
1348
  /* Critical alignment styles - must be identical for both layers */
@@ -1342,6 +1357,8 @@ function generateStyles(options = {}) {
1342
1357
 
1343
1358
  /* Font properties - any difference breaks alignment */
1344
1359
  font-family: ${fontFamily} !important;
1360
+ font-synthesis: none !important; /* no faux bold/italic width drift */
1361
+ font-variant-ligatures: none !important; /* keep metrics stable for code */
1345
1362
  font-size: var(--instance-font-size, ${fontSize}) !important;
1346
1363
  line-height: var(--instance-line-height, ${lineHeight}) !important;
1347
1364
  font-weight: normal !important;
@@ -1608,15 +1625,9 @@ function generateStyles(options = {}) {
1608
1625
  }
1609
1626
 
1610
1627
  /* Stats bar */
1611
- .overtype-wrapper.with-stats {
1612
- padding-bottom: 40px !important;
1613
- }
1614
1628
 
1615
- .overtype-wrapper .overtype-stats {
1616
- position: absolute !important;
1617
- bottom: 0 !important;
1618
- left: 0 !important;
1619
- right: 0 !important;
1629
+ /* Stats bar - positioned by grid, not absolute */
1630
+ .overtype-stats {
1620
1631
  height: 40px !important;
1621
1632
  padding: 0 20px !important;
1622
1633
  background: #f8f9fa !important;
@@ -1627,24 +1638,24 @@ function generateStyles(options = {}) {
1627
1638
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
1628
1639
  font-size: 0.85rem !important;
1629
1640
  color: #666 !important;
1630
- z-index: 2 !important;
1641
+ grid-row: 3 !important; /* Always third row in grid */
1631
1642
  }
1632
1643
 
1633
1644
  /* Dark theme stats bar */
1634
- .overtype-wrapper[data-theme="cave"] .overtype-stats {
1645
+ .overtype-container[data-theme="cave"] .overtype-stats {
1635
1646
  background: var(--bg-secondary, #1D2D3E) !important;
1636
1647
  border-top: 1px solid rgba(197, 221, 232, 0.1) !important;
1637
1648
  color: var(--text, #c5dde8) !important;
1638
1649
  }
1639
1650
 
1640
- .overtype-wrapper .overtype-stats .overtype-stat {
1651
+ .overtype-stats .overtype-stat {
1641
1652
  display: flex !important;
1642
1653
  align-items: center !important;
1643
1654
  gap: 5px !important;
1644
1655
  white-space: nowrap !important;
1645
1656
  }
1646
1657
 
1647
- .overtype-wrapper .overtype-stats .live-dot {
1658
+ .overtype-stats .live-dot {
1648
1659
  width: 8px !important;
1649
1660
  height: 8px !important;
1650
1661
  background: #4caf50 !important;
@@ -1657,11 +1668,6 @@ function generateStyles(options = {}) {
1657
1668
  50% { opacity: 0.6; transform: scale(1.2); }
1658
1669
  }
1659
1670
 
1660
- /* Adjust textarea and preview for stats bar */
1661
- .overtype-wrapper.with-stats .overtype-input,
1662
- .overtype-wrapper.with-stats .overtype-preview {
1663
- height: calc(100% - 40px) !important;
1664
- }
1665
1671
 
1666
1672
  /* Toolbar Styles */
1667
1673
  .overtype-toolbar {
@@ -1672,6 +1678,9 @@ function generateStyles(options = {}) {
1672
1678
  background: var(--toolbar-bg, var(--bg-primary, #f8f9fa));
1673
1679
  overflow-x: auto;
1674
1680
  -webkit-overflow-scrolling: touch;
1681
+ flex-shrink: 0;
1682
+ height: auto !important;
1683
+ grid-row: 1 !important; /* Always first row in grid */
1675
1684
  }
1676
1685
 
1677
1686
  .overtype-toolbar-button {
@@ -2223,8 +2232,16 @@ var _OverType = class _OverType {
2223
2232
  padding: "12px",
2224
2233
  lineHeight: 1.5
2225
2234
  },
2235
+ // Native textarea properties
2236
+ textareaProps: {},
2226
2237
  // Behavior
2227
2238
  autofocus: false,
2239
+ autoResize: false,
2240
+ // Auto-expand height with content
2241
+ minHeight: "100px",
2242
+ // Minimum height for autoResize mode
2243
+ maxHeight: null,
2244
+ // Maximum height for autoResize mode (null = unlimited)
2228
2245
  placeholder: "Start typing...",
2229
2246
  value: "",
2230
2247
  // Callbacks
@@ -2341,9 +2358,6 @@ var _OverType = class _OverType {
2341
2358
  }
2342
2359
  this.wrapper = document.createElement("div");
2343
2360
  this.wrapper.className = "overtype-wrapper";
2344
- if (this.options.showStats) {
2345
- this.wrapper.classList.add("with-stats");
2346
- }
2347
2361
  if (this.options.fontSize) {
2348
2362
  this.wrapper.style.setProperty("--instance-font-size", this.options.fontSize);
2349
2363
  }
@@ -2358,19 +2372,47 @@ var _OverType = class _OverType {
2358
2372
  this.textarea.className = "overtype-input";
2359
2373
  this.textarea.placeholder = this.options.placeholder;
2360
2374
  this._configureTextarea();
2375
+ if (this.options.textareaProps) {
2376
+ Object.entries(this.options.textareaProps).forEach(([key, value]) => {
2377
+ if (key === "className" || key === "class") {
2378
+ this.textarea.className += " " + value;
2379
+ } else if (key === "style" && typeof value === "object") {
2380
+ Object.assign(this.textarea.style, value);
2381
+ } else {
2382
+ this.textarea.setAttribute(key, value);
2383
+ }
2384
+ });
2385
+ }
2361
2386
  this.preview = document.createElement("div");
2362
2387
  this.preview.className = "overtype-preview";
2363
2388
  this.preview.setAttribute("aria-hidden", "true");
2364
2389
  this.wrapper.appendChild(this.textarea);
2365
2390
  this.wrapper.appendChild(this.preview);
2391
+ this.container.appendChild(this.wrapper);
2366
2392
  if (this.options.showStats) {
2367
2393
  this.statsBar = document.createElement("div");
2368
2394
  this.statsBar.className = "overtype-stats";
2369
- this.wrapper.appendChild(this.statsBar);
2395
+ this.container.appendChild(this.statsBar);
2370
2396
  this._updateStats();
2371
2397
  }
2372
- this.container.appendChild(this.wrapper);
2373
2398
  this.element.appendChild(this.container);
2399
+ if (window.location.pathname.includes("demo.html")) {
2400
+ console.log("_createDOM completed:", {
2401
+ elementId: this.element.id,
2402
+ autoResize: this.options.autoResize,
2403
+ containerClasses: this.container.className,
2404
+ hasStats: !!this.statsBar,
2405
+ hasToolbar: this.options.toolbar
2406
+ });
2407
+ }
2408
+ if (this.options.autoResize) {
2409
+ this._setupAutoResize();
2410
+ } else {
2411
+ this.container.classList.remove("overtype-auto-resize");
2412
+ if (window.location.pathname.includes("demo.html")) {
2413
+ console.log("Removed auto-resize class from:", this.element.id);
2414
+ }
2415
+ }
2374
2416
  }
2375
2417
  /**
2376
2418
  * Configure textarea attributes
@@ -2393,6 +2435,13 @@ var _OverType = class _OverType {
2393
2435
  if (this.options.autofocus) {
2394
2436
  this.textarea.focus();
2395
2437
  }
2438
+ if (this.options.autoResize) {
2439
+ if (!this.container.classList.contains("overtype-auto-resize")) {
2440
+ this._setupAutoResize();
2441
+ }
2442
+ } else {
2443
+ this.container.classList.remove("overtype-auto-resize");
2444
+ }
2396
2445
  this.updatePreview();
2397
2446
  }
2398
2447
  /**
@@ -2433,6 +2482,8 @@ var _OverType = class _OverType {
2433
2482
  while (currentDiv && currentDiv !== closeParent) {
2434
2483
  if (currentDiv.tagName === "DIV") {
2435
2484
  currentDiv.classList.add("code-block-line");
2485
+ const plainText = currentDiv.textContent;
2486
+ currentDiv.textContent = plainText;
2436
2487
  }
2437
2488
  currentDiv = currentDiv.nextElementSibling;
2438
2489
  if (!currentDiv)
@@ -2517,6 +2568,9 @@ var _OverType = class _OverType {
2517
2568
  setValue(value) {
2518
2569
  this.textarea.value = value;
2519
2570
  this.updatePreview();
2571
+ if (this.options.autoResize) {
2572
+ this._updateAutoHeight();
2573
+ }
2520
2574
  }
2521
2575
  /**
2522
2576
  * Focus the editor
@@ -2580,6 +2634,57 @@ var _OverType = class _OverType {
2580
2634
  `;
2581
2635
  }
2582
2636
  }
2637
+ /**
2638
+ * Setup auto-resize functionality
2639
+ * @private
2640
+ */
2641
+ _setupAutoResize() {
2642
+ this.container.classList.add("overtype-auto-resize");
2643
+ this.previousHeight = null;
2644
+ this._updateAutoHeight();
2645
+ this.textarea.addEventListener("input", () => this._updateAutoHeight());
2646
+ window.addEventListener("resize", () => this._updateAutoHeight());
2647
+ }
2648
+ /**
2649
+ * Update height based on scrollHeight
2650
+ * @private
2651
+ */
2652
+ _updateAutoHeight() {
2653
+ if (!this.options.autoResize)
2654
+ return;
2655
+ const textarea = this.textarea;
2656
+ const preview = this.preview;
2657
+ const wrapper = this.wrapper;
2658
+ const computed = window.getComputedStyle(textarea);
2659
+ const paddingTop = parseFloat(computed.paddingTop);
2660
+ const paddingBottom = parseFloat(computed.paddingBottom);
2661
+ const scrollTop = textarea.scrollTop;
2662
+ textarea.style.setProperty("height", "auto", "important");
2663
+ let newHeight = textarea.scrollHeight;
2664
+ if (this.options.minHeight) {
2665
+ const minHeight = parseInt(this.options.minHeight);
2666
+ newHeight = Math.max(newHeight, minHeight);
2667
+ }
2668
+ let overflow = "hidden";
2669
+ if (this.options.maxHeight) {
2670
+ const maxHeight = parseInt(this.options.maxHeight);
2671
+ if (newHeight > maxHeight) {
2672
+ newHeight = maxHeight;
2673
+ overflow = "auto";
2674
+ }
2675
+ }
2676
+ const heightPx = newHeight + "px";
2677
+ textarea.style.setProperty("height", heightPx, "important");
2678
+ textarea.style.setProperty("overflow-y", overflow, "important");
2679
+ preview.style.setProperty("height", heightPx, "important");
2680
+ preview.style.setProperty("overflow-y", overflow, "important");
2681
+ wrapper.style.setProperty("height", heightPx, "important");
2682
+ textarea.scrollTop = scrollTop;
2683
+ preview.scrollTop = scrollTop;
2684
+ if (this.previousHeight !== newHeight) {
2685
+ this.previousHeight = newHeight;
2686
+ }
2687
+ }
2583
2688
  /**
2584
2689
  * Show or hide stats bar
2585
2690
  * @param {boolean} show - Whether to show stats
@@ -2589,13 +2694,11 @@ var _OverType = class _OverType {
2589
2694
  if (show && !this.statsBar) {
2590
2695
  this.statsBar = document.createElement("div");
2591
2696
  this.statsBar.className = "overtype-stats";
2592
- this.wrapper.appendChild(this.statsBar);
2593
- this.wrapper.classList.add("with-stats");
2697
+ this.container.appendChild(this.statsBar);
2594
2698
  this._updateStats();
2595
2699
  } else if (!show && this.statsBar) {
2596
2700
  this.statsBar.remove();
2597
2701
  this.statsBar = null;
2598
- this.wrapper.classList.remove("with-stats");
2599
2702
  }
2600
2703
  }
2601
2704
  /**