overtype 1.2.6 → 2.0.0

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,6 +1,6 @@
1
1
  {
2
2
  "name": "overtype",
3
- "version": "1.2.6",
3
+ "version": "2.0.0",
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",
@@ -10,24 +10,35 @@
10
10
  "jsdelivr": "dist/overtype.min.js",
11
11
  "exports": {
12
12
  ".": {
13
+ "types": "./dist/overtype.d.ts",
13
14
  "import": "./dist/overtype.esm.js",
14
15
  "require": "./dist/overtype.cjs",
15
16
  "browser": "./dist/overtype.iife.min.js"
17
+ },
18
+ "./parser": {
19
+ "import": "./src/parser.js",
20
+ "require": "./src/parser.js"
21
+ },
22
+ "./webcomponent": {
23
+ "import": "./dist/overtype-webcomponent.esm.js",
24
+ "browser": "./dist/overtype-webcomponent.min.js"
16
25
  }
17
26
  },
18
27
  "type": "module",
19
28
  "scripts": {
20
29
  "build": "node build.js",
21
30
  "build:prod": "npm test && npm run build",
22
- "dev": "http-server -p 8080 -c-1",
31
+ "dev": "http-server website -p 8080 -c-1",
23
32
  "watch": "node build.js --watch",
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 && node test/sanctuary-parsing.test.js && npm run test:types",
33
+ "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 && node test/sanctuary-parsing.test.js && node test/mode-switching.test.js && node test/syntax-highlighting.test.js && node test/webcomponent.test.js && npm run test:types",
25
34
  "test:main": "node test/overtype.test.js",
26
35
  "test:preview": "node test/preview-mode.test.js",
27
36
  "test:links": "node test/links.test.js",
28
37
  "test:api": "node test/api-methods.test.js",
29
38
  "test:alignment": "node test/comprehensive-alignment.test.js",
30
39
  "test:sanctuary": "node test/sanctuary-parsing.test.js",
40
+ "test:modes": "node test/mode-switching.test.js",
41
+ "test:webcomponent": "node test/webcomponent.test.js",
31
42
  "test:types": "tsc --noEmit test-types.ts",
32
43
  "preversion": "npm test",
33
44
  "size": "gzip-size dist/overtype.min.js",
@@ -40,7 +51,10 @@
40
51
  "lightweight",
41
52
  "ghost-caret",
42
53
  "textarea",
43
- "markdown-editor"
54
+ "markdown-editor",
55
+ "web-components",
56
+ "custom-elements",
57
+ "shadow-dom"
44
58
  ],
45
59
  "author": "David Miranda",
46
60
  "license": "MIT",
@@ -10,82 +10,50 @@ export class LinkTooltip {
10
10
  this.tooltip = null;
11
11
  this.currentLink = null;
12
12
  this.hideTimeout = null;
13
-
13
+ this.visibilityChangeHandler = null;
14
+
14
15
  this.init();
15
16
  }
16
-
17
+
17
18
  init() {
18
- // Check for CSS anchor positioning support
19
- const supportsAnchor =
20
- CSS.supports('position-anchor: --x') &&
21
- CSS.supports('position-area: center');
22
-
23
- if (!supportsAnchor) {
24
- // Don't show anything if not supported
25
- return;
26
- }
27
-
28
19
  // Create tooltip element
20
+ // Note: Styles are now in the main stylesheet (styles.js) with @supports wrapper
29
21
  this.createTooltip();
30
-
22
+
31
23
  // Listen for cursor position changes
32
24
  this.editor.textarea.addEventListener('selectionchange', () => this.checkCursorPosition());
33
- this.editor.textarea.addEventListener('keyup', (e) => {
25
+ this.editor.textarea.addEventListener('keyup', e => {
34
26
  if (e.key.includes('Arrow') || e.key === 'Home' || e.key === 'End') {
35
27
  this.checkCursorPosition();
36
28
  }
37
29
  });
38
-
30
+
39
31
  // Hide tooltip when typing or scrolling
40
32
  this.editor.textarea.addEventListener('input', () => this.hide());
41
33
  this.editor.textarea.addEventListener('scroll', () => this.hide());
42
-
34
+
35
+ // Hide tooltip when textarea loses focus
36
+ this.editor.textarea.addEventListener('blur', () => this.hide());
37
+
38
+ // Hide tooltip when page loses visibility (tab switch, minimize, etc.)
39
+ this.visibilityChangeHandler = () => {
40
+ if (document.hidden) {
41
+ this.hide();
42
+ }
43
+ };
44
+ document.addEventListener('visibilitychange', this.visibilityChangeHandler);
45
+
43
46
  // Keep tooltip visible on hover
44
47
  this.tooltip.addEventListener('mouseenter', () => this.cancelHide());
45
48
  this.tooltip.addEventListener('mouseleave', () => this.scheduleHide());
46
49
  }
47
-
50
+
48
51
  createTooltip() {
49
52
  // Create tooltip element
53
+ // Styles are now included in the main stylesheet (styles.js)
50
54
  this.tooltip = document.createElement('div');
51
55
  this.tooltip.className = 'overtype-link-tooltip';
52
-
53
- // Add CSS anchor positioning styles
54
- const tooltipStyles = document.createElement('style');
55
- tooltipStyles.textContent = `
56
- @supports (position-anchor: --x) and (position-area: center) {
57
- .overtype-link-tooltip {
58
- position: absolute;
59
- position-anchor: var(--target-anchor, --link-0);
60
- position-area: block-end center;
61
- margin-top: 8px !important;
62
-
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
-
78
- position-try: most-width block-end inline-end, flip-inline, block-start center;
79
- position-visibility: anchors-visible;
80
- }
81
-
82
- .overtype-link-tooltip.visible {
83
- display: flex !important;
84
- }
85
- }
86
- `;
87
- document.head.appendChild(tooltipStyles);
88
-
56
+
89
57
  // Add link icon and text container
90
58
  this.tooltip.innerHTML = `
91
59
  <span style="display: flex; align-items: center; gap: 6px;">
@@ -96,9 +64,9 @@ export class LinkTooltip {
96
64
  <span class="overtype-link-tooltip-url"></span>
97
65
  </span>
98
66
  `;
99
-
67
+
100
68
  // Click handler to open link
101
- this.tooltip.addEventListener('click', (e) => {
69
+ this.tooltip.addEventListener('click', e => {
102
70
  e.preventDefault();
103
71
  e.stopPropagation();
104
72
  if (this.currentLink) {
@@ -106,18 +74,18 @@ export class LinkTooltip {
106
74
  this.hide();
107
75
  }
108
76
  });
109
-
77
+
110
78
  // Append tooltip to editor container
111
79
  this.editor.container.appendChild(this.tooltip);
112
80
  }
113
-
81
+
114
82
  checkCursorPosition() {
115
83
  const cursorPos = this.editor.textarea.selectionStart;
116
84
  const text = this.editor.textarea.value;
117
-
85
+
118
86
  // Find if cursor is within a markdown link
119
87
  const linkInfo = this.findLinkAtPosition(text, cursorPos);
120
-
88
+
121
89
  if (linkInfo) {
122
90
  if (!this.currentLink || this.currentLink.url !== linkInfo.url || this.currentLink.index !== linkInfo.index) {
123
91
  this.show(linkInfo);
@@ -126,17 +94,17 @@ export class LinkTooltip {
126
94
  this.scheduleHide();
127
95
  }
128
96
  }
129
-
97
+
130
98
  findLinkAtPosition(text, position) {
131
99
  // Regex to find markdown links: [text](url)
132
100
  const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
133
101
  let match;
134
102
  let linkIndex = 0;
135
-
103
+
136
104
  while ((match = linkRegex.exec(text)) !== null) {
137
105
  const start = match.index;
138
106
  const end = match.index + match[0].length;
139
-
107
+
140
108
  if (position >= start && position <= end) {
141
109
  return {
142
110
  text: match[1],
@@ -148,48 +116,55 @@ export class LinkTooltip {
148
116
  }
149
117
  linkIndex++;
150
118
  }
151
-
119
+
152
120
  return null;
153
121
  }
154
-
122
+
155
123
  show(linkInfo) {
156
124
  this.currentLink = linkInfo;
157
125
  this.cancelHide();
158
-
126
+
159
127
  // Update tooltip content
160
128
  const urlSpan = this.tooltip.querySelector('.overtype-link-tooltip-url');
161
129
  urlSpan.textContent = linkInfo.url;
162
-
130
+
163
131
  // Set the CSS variable to point to the correct anchor
164
132
  this.tooltip.style.setProperty('--target-anchor', `--link-${linkInfo.index}`);
165
-
133
+
166
134
  // Show tooltip (CSS anchor positioning handles the rest)
167
135
  this.tooltip.classList.add('visible');
168
136
  }
169
-
137
+
170
138
  hide() {
171
139
  this.tooltip.classList.remove('visible');
172
140
  this.currentLink = null;
173
141
  }
174
-
142
+
175
143
  scheduleHide() {
176
144
  this.cancelHide();
177
145
  this.hideTimeout = setTimeout(() => this.hide(), 300);
178
146
  }
179
-
147
+
180
148
  cancelHide() {
181
149
  if (this.hideTimeout) {
182
150
  clearTimeout(this.hideTimeout);
183
151
  this.hideTimeout = null;
184
152
  }
185
153
  }
186
-
154
+
187
155
  destroy() {
188
156
  this.cancelHide();
157
+
158
+ // Remove visibility change listener
159
+ if (this.visibilityChangeHandler) {
160
+ document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
161
+ this.visibilityChangeHandler = null;
162
+ }
163
+
189
164
  if (this.tooltip && this.tooltip.parentNode) {
190
165
  this.tooltip.parentNode.removeChild(this.tooltip);
191
166
  }
192
167
  this.tooltip = null;
193
168
  this.currentLink = null;
194
169
  }
195
- }
170
+ }