overtype 1.1.1 → 1.1.3

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.3
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
  /**
@@ -2517,6 +2566,9 @@ var _OverType = class _OverType {
2517
2566
  setValue(value) {
2518
2567
  this.textarea.value = value;
2519
2568
  this.updatePreview();
2569
+ if (this.options.autoResize) {
2570
+ this._updateAutoHeight();
2571
+ }
2520
2572
  }
2521
2573
  /**
2522
2574
  * Focus the editor
@@ -2580,6 +2632,57 @@ var _OverType = class _OverType {
2580
2632
  `;
2581
2633
  }
2582
2634
  }
2635
+ /**
2636
+ * Setup auto-resize functionality
2637
+ * @private
2638
+ */
2639
+ _setupAutoResize() {
2640
+ this.container.classList.add("overtype-auto-resize");
2641
+ this.previousHeight = null;
2642
+ this._updateAutoHeight();
2643
+ this.textarea.addEventListener("input", () => this._updateAutoHeight());
2644
+ window.addEventListener("resize", () => this._updateAutoHeight());
2645
+ }
2646
+ /**
2647
+ * Update height based on scrollHeight
2648
+ * @private
2649
+ */
2650
+ _updateAutoHeight() {
2651
+ if (!this.options.autoResize)
2652
+ return;
2653
+ const textarea = this.textarea;
2654
+ const preview = this.preview;
2655
+ const wrapper = this.wrapper;
2656
+ const computed = window.getComputedStyle(textarea);
2657
+ const paddingTop = parseFloat(computed.paddingTop);
2658
+ const paddingBottom = parseFloat(computed.paddingBottom);
2659
+ const scrollTop = textarea.scrollTop;
2660
+ textarea.style.setProperty("height", "auto", "important");
2661
+ let newHeight = textarea.scrollHeight;
2662
+ if (this.options.minHeight) {
2663
+ const minHeight = parseInt(this.options.minHeight);
2664
+ newHeight = Math.max(newHeight, minHeight);
2665
+ }
2666
+ let overflow = "hidden";
2667
+ if (this.options.maxHeight) {
2668
+ const maxHeight = parseInt(this.options.maxHeight);
2669
+ if (newHeight > maxHeight) {
2670
+ newHeight = maxHeight;
2671
+ overflow = "auto";
2672
+ }
2673
+ }
2674
+ const heightPx = newHeight + "px";
2675
+ textarea.style.setProperty("height", heightPx, "important");
2676
+ textarea.style.setProperty("overflow-y", overflow, "important");
2677
+ preview.style.setProperty("height", heightPx, "important");
2678
+ preview.style.setProperty("overflow-y", overflow, "important");
2679
+ wrapper.style.setProperty("height", heightPx, "important");
2680
+ textarea.scrollTop = scrollTop;
2681
+ preview.scrollTop = scrollTop;
2682
+ if (this.previousHeight !== newHeight) {
2683
+ this.previousHeight = newHeight;
2684
+ }
2685
+ }
2583
2686
  /**
2584
2687
  * Show or hide stats bar
2585
2688
  * @param {boolean} show - Whether to show stats
@@ -2589,13 +2692,11 @@ var _OverType = class _OverType {
2589
2692
  if (show && !this.statsBar) {
2590
2693
  this.statsBar = document.createElement("div");
2591
2694
  this.statsBar.className = "overtype-stats";
2592
- this.wrapper.appendChild(this.statsBar);
2593
- this.wrapper.classList.add("with-stats");
2695
+ this.container.appendChild(this.statsBar);
2594
2696
  this._updateStats();
2595
2697
  } else if (!show && this.statsBar) {
2596
2698
  this.statsBar.remove();
2597
2699
  this.statsBar = null;
2598
- this.wrapper.classList.remove("with-stats");
2599
2700
  }
2600
2701
  }
2601
2702
  /**