overtype 2.1.1 → 2.2.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/README.md +25 -22
- package/dist/overtype-webcomponent.esm.js +1581 -97
- package/dist/overtype-webcomponent.esm.js.map +4 -4
- package/dist/overtype-webcomponent.js +1581 -97
- package/dist/overtype-webcomponent.js.map +4 -4
- package/dist/overtype-webcomponent.min.js +104 -91
- package/dist/overtype.cjs +1551 -94
- package/dist/overtype.cjs.map +4 -4
- package/dist/overtype.d.ts +16 -0
- package/dist/overtype.esm.js +1551 -94
- package/dist/overtype.esm.js.map +4 -4
- package/dist/overtype.js +1551 -94
- package/dist/overtype.js.map +4 -4
- package/dist/overtype.min.js +107 -94
- package/package.json +4 -4
- package/src/icons.js +6 -0
- package/src/link-tooltip.js +22 -67
- package/src/overtype-webcomponent.js +32 -3
- package/src/overtype.d.ts +16 -0
- package/src/overtype.js +272 -36
- package/src/parser.js +9 -3
- package/src/styles.js +36 -28
- package/src/themes.js +14 -0
- package/src/toolbar-buttons.js +23 -0
- package/src/toolbar.js +12 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overtype",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.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",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"build:prod": "npm test && npm run build",
|
|
32
32
|
"dev": "http-server website -p 8080 -c-1",
|
|
33
33
|
"watch": "node scripts/build.js --watch",
|
|
34
|
-
"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 && node test/custom-syntax.test.js && npm run test:types",
|
|
34
|
+
"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 && node test/custom-syntax.test.js && node test/auto-theme.test.js && npm run test:types",
|
|
35
35
|
"test:main": "node test/overtype.test.js",
|
|
36
36
|
"test:preview": "node test/preview-mode.test.js",
|
|
37
37
|
"test:links": "node test/links.test.js",
|
|
@@ -45,8 +45,7 @@
|
|
|
45
45
|
"preversion": "npm test",
|
|
46
46
|
"size": "gzip-size dist/overtype.min.js",
|
|
47
47
|
"serve": "http-server -p 8080 -c-1",
|
|
48
|
-
"deploy:website": "npm run build"
|
|
49
|
-
"release": "./release.sh"
|
|
48
|
+
"deploy:website": "npm run build"
|
|
50
49
|
},
|
|
51
50
|
"keywords": [
|
|
52
51
|
"markdown",
|
|
@@ -88,6 +87,7 @@
|
|
|
88
87
|
},
|
|
89
88
|
"homepage": "https://github.com/panphora/overtype#readme",
|
|
90
89
|
"dependencies": {
|
|
90
|
+
"@floating-ui/dom": "^1.7.4",
|
|
91
91
|
"markdown-actions": "^1.1.2"
|
|
92
92
|
}
|
|
93
93
|
}
|
package/src/icons.js
CHANGED
|
@@ -72,6 +72,12 @@ export const taskListIcon = `<svg viewBox="0 0 18 18">
|
|
|
72
72
|
<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>
|
|
73
73
|
</svg>`;
|
|
74
74
|
|
|
75
|
+
export const uploadIcon = `<svg viewBox="0 0 18 18">
|
|
76
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 12.375v1.688A1.688 1.688 0 0 0 3.938 15.75h10.124a1.688 1.688 0 0 0 1.688-1.688V12.375"></path>
|
|
77
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.063 6.188L9 2.25l3.938 3.938"></path>
|
|
78
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 2.25v10.125"></path>
|
|
79
|
+
</svg>`;
|
|
80
|
+
|
|
75
81
|
export const eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
76
82
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
|
|
77
83
|
<circle cx="12" cy="12" r="3" fill="none"></circle>
|
package/src/link-tooltip.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Link Tooltip -
|
|
3
|
-
*
|
|
4
|
-
* Uses CSS anchor positioning for modern browsers, Floating UI for older browsers
|
|
2
|
+
* Link Tooltip - Shows a clickable tooltip when cursor is within a link
|
|
3
|
+
* Uses Floating UI for positioning across all browsers
|
|
5
4
|
*/
|
|
6
5
|
|
|
6
|
+
import { computePosition, offset, shift, flip } from '@floating-ui/dom';
|
|
7
|
+
|
|
7
8
|
export class LinkTooltip {
|
|
8
9
|
constructor(editor) {
|
|
9
10
|
this.editor = editor;
|
|
@@ -11,38 +12,13 @@ export class LinkTooltip {
|
|
|
11
12
|
this.currentLink = null;
|
|
12
13
|
this.hideTimeout = null;
|
|
13
14
|
this.visibilityChangeHandler = null;
|
|
14
|
-
this.useFloatingUI = false;
|
|
15
|
-
this.floatingUI = null;
|
|
16
15
|
this.isTooltipHovered = false;
|
|
17
16
|
|
|
18
17
|
this.init();
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
// Detect CSS anchor positioning support
|
|
23
|
-
const supportsAnchorPositioning = CSS.supports('position-anchor: --x') &&
|
|
24
|
-
CSS.supports('position-area: center');
|
|
25
|
-
|
|
26
|
-
// Load Floating UI if needed
|
|
27
|
-
if (!supportsAnchorPositioning) {
|
|
28
|
-
try {
|
|
29
|
-
// Use indirect eval to prevent bundler from processing the import
|
|
30
|
-
const importFn = new Function('url', 'return import(url)');
|
|
31
|
-
const { computePosition, offset, shift, flip } = await importFn(
|
|
32
|
-
'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.7.4/+esm'
|
|
33
|
-
);
|
|
34
|
-
this.floatingUI = { computePosition, offset, shift, flip };
|
|
35
|
-
this.useFloatingUI = true;
|
|
36
|
-
} catch (error) {
|
|
37
|
-
// If dynamic import fails, tooltips simply won't show
|
|
38
|
-
console.warn('Failed to load Floating UI fallback:', error);
|
|
39
|
-
this.floatingUI = null;
|
|
40
|
-
this.useFloatingUI = false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
20
|
+
init() {
|
|
44
21
|
// Create tooltip element
|
|
45
|
-
// Note: Styles are now in the main stylesheet (styles.js) with @supports wrapper
|
|
46
22
|
this.createTooltip();
|
|
47
23
|
|
|
48
24
|
// Listen for cursor position changes
|
|
@@ -56,14 +32,10 @@ export class LinkTooltip {
|
|
|
56
32
|
// Hide tooltip when typing
|
|
57
33
|
this.editor.textarea.addEventListener('input', () => this.hide());
|
|
58
34
|
|
|
59
|
-
// Reposition
|
|
35
|
+
// Reposition tooltip when scrolling
|
|
60
36
|
this.editor.textarea.addEventListener('scroll', () => {
|
|
61
|
-
if (this.
|
|
62
|
-
|
|
63
|
-
this.showWithFloatingUI(this.currentLink);
|
|
64
|
-
} else {
|
|
65
|
-
// Hide for CSS anchor positioning (native browser behavior handles this)
|
|
66
|
-
this.hide();
|
|
37
|
+
if (this.currentLink) {
|
|
38
|
+
this.positionTooltip(this.currentLink);
|
|
67
39
|
}
|
|
68
40
|
});
|
|
69
41
|
|
|
@@ -94,8 +66,6 @@ export class LinkTooltip {
|
|
|
94
66
|
}
|
|
95
67
|
|
|
96
68
|
createTooltip() {
|
|
97
|
-
// Create tooltip element
|
|
98
|
-
// Styles are now included in the main stylesheet (styles.js)
|
|
99
69
|
this.tooltip = document.createElement('div');
|
|
100
70
|
this.tooltip.className = 'overtype-link-tooltip';
|
|
101
71
|
|
|
@@ -165,7 +135,7 @@ export class LinkTooltip {
|
|
|
165
135
|
return null;
|
|
166
136
|
}
|
|
167
137
|
|
|
168
|
-
show(linkInfo) {
|
|
138
|
+
async show(linkInfo) {
|
|
169
139
|
this.currentLink = linkInfo;
|
|
170
140
|
this.cancelHide();
|
|
171
141
|
|
|
@@ -173,66 +143,54 @@ export class LinkTooltip {
|
|
|
173
143
|
const urlSpan = this.tooltip.querySelector('.overtype-link-tooltip-url');
|
|
174
144
|
urlSpan.textContent = linkInfo.url;
|
|
175
145
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
} else {
|
|
179
|
-
this.showWithAnchorPositioning(linkInfo);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
this.tooltip.classList.add('visible');
|
|
183
|
-
}
|
|
146
|
+
// Position first (tooltip is always rendered but invisible, so Floating UI can measure it)
|
|
147
|
+
await this.positionTooltip(linkInfo);
|
|
184
148
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
149
|
+
// Only reveal if we're still showing this link
|
|
150
|
+
if (this.currentLink === linkInfo) {
|
|
151
|
+
this.tooltip.classList.add('visible');
|
|
152
|
+
}
|
|
188
153
|
}
|
|
189
154
|
|
|
190
|
-
async
|
|
191
|
-
// Find the <a> element in preview that corresponds to this link
|
|
155
|
+
async positionTooltip(linkInfo) {
|
|
192
156
|
const anchorElement = this.findAnchorElement(linkInfo.index);
|
|
193
157
|
|
|
194
158
|
if (!anchorElement) {
|
|
195
159
|
return;
|
|
196
160
|
}
|
|
197
161
|
|
|
198
|
-
// Check if anchor element is visible and in viewport
|
|
199
162
|
const rect = anchorElement.getBoundingClientRect();
|
|
200
163
|
if (rect.width === 0 || rect.height === 0) {
|
|
201
164
|
return;
|
|
202
165
|
}
|
|
203
166
|
|
|
204
167
|
try {
|
|
205
|
-
|
|
206
|
-
const { x, y } = await this.floatingUI.computePosition(
|
|
168
|
+
const { x, y } = await computePosition(
|
|
207
169
|
anchorElement,
|
|
208
170
|
this.tooltip,
|
|
209
171
|
{
|
|
172
|
+
strategy: 'fixed',
|
|
210
173
|
placement: 'bottom',
|
|
211
174
|
middleware: [
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
175
|
+
offset(8),
|
|
176
|
+
shift({ padding: 8 }),
|
|
177
|
+
flip()
|
|
215
178
|
]
|
|
216
179
|
}
|
|
217
180
|
);
|
|
218
181
|
|
|
219
|
-
// Apply position
|
|
220
182
|
Object.assign(this.tooltip.style, {
|
|
221
183
|
left: `${x}px`,
|
|
222
184
|
top: `${y}px`,
|
|
223
|
-
position: '
|
|
185
|
+
position: 'fixed'
|
|
224
186
|
});
|
|
225
187
|
} catch (error) {
|
|
226
|
-
// If Floating UI computation fails, don't show tooltip
|
|
227
188
|
console.warn('Floating UI positioning failed:', error);
|
|
228
|
-
return;
|
|
229
189
|
}
|
|
230
190
|
}
|
|
231
191
|
|
|
232
192
|
findAnchorElement(linkIndex) {
|
|
233
|
-
// Find the <a> element with the matching anchor-name style
|
|
234
193
|
const preview = this.editor.preview;
|
|
235
|
-
// Direct query for the specific link - more efficient than iterating
|
|
236
194
|
return preview.querySelector(`a[style*="--link-${linkIndex}"]`);
|
|
237
195
|
}
|
|
238
196
|
|
|
@@ -257,7 +215,6 @@ export class LinkTooltip {
|
|
|
257
215
|
destroy() {
|
|
258
216
|
this.cancelHide();
|
|
259
217
|
|
|
260
|
-
// Remove visibility change listener
|
|
261
218
|
if (this.visibilityChangeHandler) {
|
|
262
219
|
document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
|
|
263
220
|
this.visibilityChangeHandler = null;
|
|
@@ -268,8 +225,6 @@ export class LinkTooltip {
|
|
|
268
225
|
}
|
|
269
226
|
this.tooltip = null;
|
|
270
227
|
this.currentLink = null;
|
|
271
|
-
this.floatingUI = null;
|
|
272
|
-
this.useFloatingUI = false;
|
|
273
228
|
this.isTooltipHovered = false;
|
|
274
229
|
}
|
|
275
230
|
}
|
|
@@ -15,7 +15,7 @@ const DEFAULT_PLACEHOLDER = 'Start typing...';
|
|
|
15
15
|
const OBSERVED_ATTRIBUTES = [
|
|
16
16
|
'value', 'theme', 'toolbar', 'height', 'min-height', 'max-height',
|
|
17
17
|
'placeholder', 'font-size', 'line-height', 'padding', 'auto-resize',
|
|
18
|
-
'autofocus', 'show-stats', 'smart-lists', 'readonly'
|
|
18
|
+
'autofocus', 'show-stats', 'smart-lists', 'readonly', 'spellcheck'
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -261,6 +261,7 @@ class OverTypeEditor extends HTMLElement {
|
|
|
261
261
|
autoResize: this.hasAttribute('auto-resize'),
|
|
262
262
|
showStats: this.hasAttribute('show-stats'),
|
|
263
263
|
smartLists: !this.hasAttribute('smart-lists') || this.getAttribute('smart-lists') !== 'false',
|
|
264
|
+
spellcheck: this.hasAttribute('spellcheck') && this.getAttribute('spellcheck') !== 'false',
|
|
264
265
|
onChange: this._handleChange,
|
|
265
266
|
onKeydown: this._handleKeydown
|
|
266
267
|
};
|
|
@@ -324,8 +325,14 @@ class OverTypeEditor extends HTMLElement {
|
|
|
324
325
|
break;
|
|
325
326
|
|
|
326
327
|
case 'placeholder':
|
|
327
|
-
if (this._editor
|
|
328
|
-
this._editor.
|
|
328
|
+
if (this._editor) {
|
|
329
|
+
this._editor.options.placeholder = value || '';
|
|
330
|
+
if (this._editor.textarea) {
|
|
331
|
+
this._editor.textarea.placeholder = value || '';
|
|
332
|
+
}
|
|
333
|
+
if (this._editor.placeholderEl) {
|
|
334
|
+
this._editor.placeholderEl.textContent = value || '';
|
|
335
|
+
}
|
|
329
336
|
}
|
|
330
337
|
break;
|
|
331
338
|
|
|
@@ -382,6 +389,16 @@ class OverTypeEditor extends HTMLElement {
|
|
|
382
389
|
this._reinitializeEditor();
|
|
383
390
|
break;
|
|
384
391
|
}
|
|
392
|
+
|
|
393
|
+
case 'spellcheck':
|
|
394
|
+
if (this._editor) {
|
|
395
|
+
const enabled = this.hasAttribute('spellcheck') && this.getAttribute('spellcheck') !== 'false';
|
|
396
|
+
this._editor.options.spellcheck = enabled;
|
|
397
|
+
if (this._editor.textarea) {
|
|
398
|
+
this._editor.textarea.setAttribute('spellcheck', String(enabled));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
385
402
|
}
|
|
386
403
|
}
|
|
387
404
|
|
|
@@ -670,6 +687,18 @@ class OverTypeEditor extends HTMLElement {
|
|
|
670
687
|
getEditor() {
|
|
671
688
|
return this._editor;
|
|
672
689
|
}
|
|
690
|
+
|
|
691
|
+
showToolbar() {
|
|
692
|
+
if (this._editor) {
|
|
693
|
+
this._editor.showToolbar();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
hideToolbar() {
|
|
698
|
+
if (this._editor) {
|
|
699
|
+
this._editor.hideToolbar();
|
|
700
|
+
}
|
|
701
|
+
}
|
|
673
702
|
}
|
|
674
703
|
|
|
675
704
|
// Register the custom element
|
package/src/overtype.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface Theme {
|
|
|
22
22
|
hr?: string;
|
|
23
23
|
link?: string;
|
|
24
24
|
listMarker?: string;
|
|
25
|
+
placeholder?: string;
|
|
25
26
|
primary?: string;
|
|
26
27
|
rawLine?: string;
|
|
27
28
|
selection?: string;
|
|
@@ -102,6 +103,7 @@ export interface Options {
|
|
|
102
103
|
toolbar?: boolean;
|
|
103
104
|
toolbarButtons?: ToolbarButton[]; // Custom toolbar button configuration
|
|
104
105
|
smartLists?: boolean; // v1.2.3+ Smart list continuation
|
|
106
|
+
spellcheck?: boolean; // Browser spellcheck (default: false)
|
|
105
107
|
statsFormatter?: (stats: Stats) => string;
|
|
106
108
|
codeHighlighter?: ((code: string, language: string) => string) | null; // Per-instance code highlighter
|
|
107
109
|
|
|
@@ -109,6 +111,15 @@ export interface Options {
|
|
|
109
111
|
theme?: string | Theme;
|
|
110
112
|
colors?: Partial<Theme['colors']>;
|
|
111
113
|
|
|
114
|
+
// File upload
|
|
115
|
+
fileUpload?: {
|
|
116
|
+
enabled: boolean;
|
|
117
|
+
maxSize?: number;
|
|
118
|
+
mimeTypes?: string[];
|
|
119
|
+
batch?: boolean;
|
|
120
|
+
onInsertFile: (file: File | File[]) => Promise<string | string[]>;
|
|
121
|
+
};
|
|
122
|
+
|
|
112
123
|
// Callbacks
|
|
113
124
|
onChange?: (value: string, instance: OverTypeInstance) => void;
|
|
114
125
|
onKeydown?: (event: KeyboardEvent, instance: OverTypeInstance) => void;
|
|
@@ -172,6 +183,10 @@ export interface OverTypeInstance {
|
|
|
172
183
|
setTheme(theme: string | Theme): this;
|
|
173
184
|
setCodeHighlighter(highlighter: ((code: string, language: string) => string) | null): void;
|
|
174
185
|
updatePreview(): void;
|
|
186
|
+
performAction(actionId: string, event?: Event | null): Promise<boolean>;
|
|
187
|
+
showToolbar(): void;
|
|
188
|
+
hideToolbar(): void;
|
|
189
|
+
insertAtCursor(text: string): void;
|
|
175
190
|
|
|
176
191
|
// HTML output methods
|
|
177
192
|
getRenderedHTML(options?: RenderOptions): string;
|
|
@@ -209,6 +224,7 @@ export const toolbarButtons: {
|
|
|
209
224
|
orderedList: ToolbarButton;
|
|
210
225
|
taskList: ToolbarButton;
|
|
211
226
|
quote: ToolbarButton;
|
|
227
|
+
upload: ToolbarButton;
|
|
212
228
|
viewMode: ToolbarButton;
|
|
213
229
|
};
|
|
214
230
|
|