overtype 1.2.2 → 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/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "overtype",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay",
5
5
  "main": "dist/overtype.cjs",
6
6
  "module": "dist/overtype.esm.js",
7
7
  "browser": "dist/overtype.min.js",
8
+ "types": "dist/overtype.d.ts",
8
9
  "unpkg": "dist/overtype.min.js",
9
10
  "jsdelivr": "dist/overtype.min.js",
10
11
  "exports": {
@@ -20,12 +21,13 @@
20
21
  "build:prod": "npm test && npm run build",
21
22
  "dev": "http-server -p 8080 -c-1",
22
23
  "watch": "node build.js --watch",
23
- "test": "node test/overtype.test.js && node test/preview-mode.test.js && node test/links.test.js && node test/api-methods.test.js && node test/comprehensive-alignment.test.js",
24
+ "test": "node test/overtype.test.js && node test/preview-mode.test.js && node test/links.test.js && node test/api-methods.test.js && node test/comprehensive-alignment.test.js && npm run test:types",
24
25
  "test:main": "node test/overtype.test.js",
25
26
  "test:preview": "node test/preview-mode.test.js",
26
27
  "test:links": "node test/links.test.js",
27
28
  "test:api": "node test/api-methods.test.js",
28
29
  "test:alignment": "node test/comprehensive-alignment.test.js",
30
+ "test:types": "tsc --noEmit test-types.ts",
29
31
  "preversion": "npm test",
30
32
  "size": "gzip-size dist/overtype.min.js",
31
33
  "serve": "http-server -p 8080 -c-1"
@@ -58,29 +58,29 @@ export class LinkTooltip {
58
58
  position: absolute;
59
59
  position-anchor: var(--target-anchor, --link-0);
60
60
  position-area: block-end center;
61
- margin-top: 8px;
61
+ margin-top: 8px !important;
62
62
 
63
- background: #333;
64
- color: white;
65
- padding: 6px 10px;
66
- border-radius: 16px;
67
- font-size: 12px;
68
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
69
- display: none;
70
- z-index: 10000;
71
- cursor: pointer;
72
- box-shadow: 0 2px 8px rgba(0,0,0,0.3);
73
- max-width: 300px;
74
- white-space: nowrap;
75
- overflow: hidden;
76
- text-overflow: ellipsis;
63
+ background: #333 !important;
64
+ color: white !important;
65
+ padding: 6px 10px !important;
66
+ border-radius: 16px !important;
67
+ font-size: 12px !important;
68
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
69
+ display: none !important;
70
+ z-index: 10000 !important;
71
+ cursor: pointer !important;
72
+ box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
73
+ max-width: 300px !important;
74
+ white-space: nowrap !important;
75
+ overflow: hidden !important;
76
+ text-overflow: ellipsis !important;
77
77
 
78
78
  position-try: most-width block-end inline-end, flip-inline, block-start center;
79
79
  position-visibility: anchors-visible;
80
80
  }
81
81
 
82
82
  .overtype-link-tooltip.visible {
83
- display: flex;
83
+ display: flex !important;
84
84
  }
85
85
  }
86
86
  `;
package/src/overtype.d.ts CHANGED
@@ -71,7 +71,16 @@ export interface Options {
71
71
  // Features
72
72
  showActiveLineRaw?: boolean;
73
73
  showStats?: boolean;
74
- toolbar?: boolean;
74
+ toolbar?: boolean | {
75
+ buttons?: Array<{
76
+ name?: string;
77
+ icon?: string;
78
+ title?: string;
79
+ action?: string;
80
+ separator?: boolean;
81
+ }>;
82
+ };
83
+ smartLists?: boolean; // v1.2.3+ Smart list continuation
75
84
  statsFormatter?: (stats: Stats) => string;
76
85
 
77
86
  // Theme (deprecated in favor of global theme)
@@ -107,6 +116,10 @@ export interface OverTypeConstructor {
107
116
  getTheme(name: string): Theme;
108
117
  }
109
118
 
119
+ export interface RenderOptions {
120
+ cleanHTML?: boolean;
121
+ }
122
+
110
123
  export interface OverTypeInstance {
111
124
  // Public properties
112
125
  container: HTMLElement;
@@ -135,6 +148,15 @@ export interface OverTypeInstance {
135
148
  showStats(show: boolean): void;
136
149
  setTheme(theme: string | Theme): void;
137
150
  updatePreview(): void;
151
+
152
+ // HTML output methods
153
+ getRenderedHTML(options?: RenderOptions): string;
154
+ getCleanHTML(): string;
155
+ getPreviewHTML(): string;
156
+
157
+ // View mode methods
158
+ showPlainTextarea(show: boolean): void;
159
+ showPreviewMode(show: boolean): void;
138
160
  }
139
161
 
140
162
  // Declare the constructor as a constant with proper typing
package/src/overtype.js CHANGED
@@ -104,7 +104,8 @@ class OverType {
104
104
 
105
105
  // Setup toolbar if enabled
106
106
  if (this.options.toolbar) {
107
- this.toolbar = new Toolbar(this);
107
+ const toolbarButtons = typeof this.options.toolbar === 'object' ? this.options.toolbar.buttons : null;
108
+ this.toolbar = new Toolbar(this, toolbarButtons);
108
109
  this.toolbar.create();
109
110
 
110
111
  // Update toolbar states on selection change
@@ -164,7 +165,8 @@ class OverType {
164
165
  showActiveLineRaw: false,
165
166
  showStats: false,
166
167
  toolbar: false,
167
- statsFormatter: null
168
+ statsFormatter: null,
169
+ smartLists: true // Enable smart list continuation
168
170
  };
169
171
 
170
172
  // Remove theme and colors from options - these are now global
@@ -583,6 +585,14 @@ class OverType {
583
585
  return;
584
586
  }
585
587
 
588
+ // Handle Enter key for smart list continuation
589
+ if (event.key === 'Enter' && !event.shiftKey && !event.metaKey && !event.ctrlKey && this.options.smartLists) {
590
+ if (this.handleSmartListContinuation()) {
591
+ event.preventDefault();
592
+ return;
593
+ }
594
+ }
595
+
586
596
  // Let shortcuts manager handle other keys
587
597
  const handled = this.shortcuts.handleKeydown(event);
588
598
 
@@ -592,6 +602,141 @@ class OverType {
592
602
  }
593
603
  }
594
604
 
605
+ /**
606
+ * Handle smart list continuation
607
+ * @returns {boolean} Whether the event was handled
608
+ */
609
+ handleSmartListContinuation() {
610
+ const textarea = this.textarea;
611
+ const cursorPos = textarea.selectionStart;
612
+ const context = MarkdownParser.getListContext(textarea.value, cursorPos);
613
+
614
+ if (!context || !context.inList) return false;
615
+
616
+ // Handle empty list item (exit list)
617
+ if (context.content.trim() === '' && cursorPos >= context.markerEndPos) {
618
+ this.deleteListMarker(context);
619
+ return true;
620
+ }
621
+
622
+ // Handle text splitting if cursor is in middle of content
623
+ if (cursorPos > context.markerEndPos && cursorPos < context.lineEnd) {
624
+ this.splitListItem(context, cursorPos);
625
+ } else {
626
+ // Just add new item after current line
627
+ this.insertNewListItem(context);
628
+ }
629
+
630
+ // Handle numbered list renumbering
631
+ if (context.listType === 'numbered') {
632
+ this.scheduleNumberedListUpdate();
633
+ }
634
+
635
+ return true;
636
+ }
637
+
638
+ /**
639
+ * Delete list marker and exit list
640
+ * @private
641
+ */
642
+ deleteListMarker(context) {
643
+ // Select from line start to marker end
644
+ this.textarea.setSelectionRange(context.lineStart, context.markerEndPos);
645
+ document.execCommand('delete');
646
+
647
+ // Trigger input event
648
+ this.textarea.dispatchEvent(new Event('input', { bubbles: true }));
649
+ }
650
+
651
+ /**
652
+ * Insert new list item
653
+ * @private
654
+ */
655
+ insertNewListItem(context) {
656
+ const newItem = MarkdownParser.createNewListItem(context);
657
+ document.execCommand('insertText', false, '\n' + newItem);
658
+
659
+ // Trigger input event
660
+ this.textarea.dispatchEvent(new Event('input', { bubbles: true }));
661
+ }
662
+
663
+ /**
664
+ * Split list item at cursor position
665
+ * @private
666
+ */
667
+ splitListItem(context, cursorPos) {
668
+ // Get text after cursor
669
+ const textAfterCursor = context.content.substring(cursorPos - context.markerEndPos);
670
+
671
+ // Delete text after cursor
672
+ this.textarea.setSelectionRange(cursorPos, context.lineEnd);
673
+ document.execCommand('delete');
674
+
675
+ // Insert new list item with remaining text
676
+ const newItem = MarkdownParser.createNewListItem(context);
677
+ document.execCommand('insertText', false, '\n' + newItem + textAfterCursor);
678
+
679
+ // Position cursor after new list marker
680
+ const newCursorPos = this.textarea.selectionStart - textAfterCursor.length;
681
+ this.textarea.setSelectionRange(newCursorPos, newCursorPos);
682
+
683
+ // Trigger input event
684
+ this.textarea.dispatchEvent(new Event('input', { bubbles: true }));
685
+ }
686
+
687
+ /**
688
+ * Schedule numbered list renumbering
689
+ * @private
690
+ */
691
+ scheduleNumberedListUpdate() {
692
+ // Clear any pending update
693
+ if (this.numberUpdateTimeout) {
694
+ clearTimeout(this.numberUpdateTimeout);
695
+ }
696
+
697
+ // Schedule update after current input cycle
698
+ this.numberUpdateTimeout = setTimeout(() => {
699
+ this.updateNumberedLists();
700
+ }, 10);
701
+ }
702
+
703
+ /**
704
+ * Update/renumber all numbered lists
705
+ * @private
706
+ */
707
+ updateNumberedLists() {
708
+ const value = this.textarea.value;
709
+ const cursorPos = this.textarea.selectionStart;
710
+
711
+ const newValue = MarkdownParser.renumberLists(value);
712
+
713
+ if (newValue !== value) {
714
+ // Calculate cursor offset
715
+ let offset = 0;
716
+ const oldLines = value.split('\n');
717
+ const newLines = newValue.split('\n');
718
+ let charCount = 0;
719
+
720
+ for (let i = 0; i < oldLines.length && charCount < cursorPos; i++) {
721
+ if (oldLines[i] !== newLines[i]) {
722
+ const diff = newLines[i].length - oldLines[i].length;
723
+ if (charCount + oldLines[i].length < cursorPos) {
724
+ offset += diff;
725
+ }
726
+ }
727
+ charCount += oldLines[i].length + 1; // +1 for newline
728
+ }
729
+
730
+ // Update textarea
731
+ this.textarea.value = newValue;
732
+ const newCursorPos = cursorPos + offset;
733
+ this.textarea.setSelectionRange(newCursorPos, newCursorPos);
734
+
735
+ // Trigger update
736
+ this.textarea.dispatchEvent(new Event('input', { bubbles: true }));
737
+ }
738
+ }
739
+
595
740
  /**
596
741
  * Handle scroll events
597
742
  * @private
@@ -627,16 +772,21 @@ class OverType {
627
772
 
628
773
  /**
629
774
  * Get the rendered HTML of the current content
630
- * @param {boolean} processForPreview - If true, post-processes HTML for preview mode (consolidates lists/code blocks)
775
+ * @param {Object} options - Rendering options
776
+ * @param {boolean} options.cleanHTML - If true, removes syntax markers and OverType-specific classes
631
777
  * @returns {string} Rendered HTML
632
778
  */
633
- getRenderedHTML(processForPreview = false) {
779
+ getRenderedHTML(options = {}) {
634
780
  const markdown = this.getValue();
635
781
  let html = MarkdownParser.parse(markdown);
636
782
 
637
- if (processForPreview) {
638
- // Post-process HTML for preview mode
639
- html = MarkdownParser.postProcessHTML(html);
783
+ if (options.cleanHTML) {
784
+ // Remove all syntax marker spans for clean HTML export
785
+ html = html.replace(/<span class="syntax-marker[^"]*">.*?<\/span>/g, '');
786
+ // Remove OverType-specific classes
787
+ html = html.replace(/\sclass="(bullet-list|ordered-list|code-fence|hr-marker|blockquote|url-part)"/g, '');
788
+ // Clean up empty class attributes
789
+ html = html.replace(/\sclass=""/g, '');
640
790
  }
641
791
 
642
792
  return html;
@@ -644,11 +794,21 @@ class OverType {
644
794
 
645
795
  /**
646
796
  * Get the current preview element's HTML
797
+ * This includes all syntax markers and OverType styling
647
798
  * @returns {string} Current preview HTML (as displayed)
648
799
  */
649
800
  getPreviewHTML() {
650
801
  return this.preview.innerHTML;
651
802
  }
803
+
804
+ /**
805
+ * Get clean HTML without any OverType-specific markup
806
+ * Useful for exporting to other formats or storage
807
+ * @returns {string} Clean HTML suitable for export
808
+ */
809
+ getCleanHTML() {
810
+ return this.getRenderedHTML({ cleanHTML: true });
811
+ }
652
812
 
653
813
  /**
654
814
  * Focus the editor
@@ -1065,12 +1225,6 @@ OverType.getTheme = getTheme;
1065
1225
  // Set default theme
1066
1226
  OverType.currentTheme = solar;
1067
1227
 
1068
- // Only attach to global in browser environments (not Node.js)
1069
- if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
1070
- // Browser environment - attach to window
1071
- window.OverType = OverType;
1072
- }
1073
-
1074
1228
  // Export for module systems
1075
1229
  export default OverType;
1076
1230
  export { OverType };