overtype 2.0.0 → 2.0.2
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 +6 -5
- package/dist/overtype-webcomponent.esm.js +111 -53
- package/dist/overtype-webcomponent.esm.js.map +2 -2
- package/dist/overtype-webcomponent.js +111 -53
- package/dist/overtype-webcomponent.js.map +2 -2
- package/dist/overtype-webcomponent.min.js +55 -54
- package/dist/overtype.cjs +111 -53
- package/dist/overtype.cjs.map +2 -2
- package/dist/overtype.esm.js +111 -53
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +111 -53
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +51 -50
- package/package.json +9 -5
- package/src/link-tooltip.js +100 -9
- package/src/overtype.js +2 -15
- package/src/parser.js +1 -1
- package/src/styles.js +35 -34
- package/src/toolbar.js +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OverType
|
|
2
2
|
|
|
3
|
-
A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~
|
|
3
|
+
A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~92KB minified with all features.
|
|
4
4
|
|
|
5
5
|
## Live Examples
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ A lightweight markdown editor library with perfect WYSIWYG alignment using an in
|
|
|
19
19
|
- ⌨️ **Keyboard shortcuts** - Common markdown shortcuts (Cmd/Ctrl+B for bold, etc.)
|
|
20
20
|
- 📱 **Mobile optimized** - Responsive design with mobile-specific styles
|
|
21
21
|
- 🔄 **DOM persistence aware** - Recovers from existing DOM (perfect for HyperClay and similar platforms)
|
|
22
|
-
- 🚀 **Lightweight** - ~
|
|
22
|
+
- 🚀 **Lightweight** - ~92KB minified
|
|
23
23
|
- 🎯 **Optional toolbar** - Clean, minimal toolbar with all essential formatting
|
|
24
24
|
- ✨ **Smart shortcuts** - Keyboard shortcuts with selection preservation
|
|
25
25
|
- 📝 **Smart list continuation** - GitHub-style automatic list continuation on Enter
|
|
@@ -35,7 +35,7 @@ We overlap an invisible textarea on top of styled output, giving the illusion of
|
|
|
35
35
|
|
|
36
36
|
| Feature | OverType | HyperMD | Milkdown | TUI Editor | EasyMDE |
|
|
37
37
|
|---------|----------|---------|----------|------------|---------|
|
|
38
|
-
| **Size** | ~
|
|
38
|
+
| **Size** | ~92KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |
|
|
39
39
|
| **Dependencies** | Bundled | CodeMirror | ProseMirror + plugins | Multiple libs | CodeMirror |
|
|
40
40
|
| **Setup** | Single file | Complex config | Build step required | Complex config | Moderate |
|
|
41
41
|
| **Approach** | Invisible textarea | ContentEditable | ContentEditable | ContentEditable | CodeMirror |
|
|
@@ -740,6 +740,7 @@ Special thanks to:
|
|
|
740
740
|
- [kbhomes](https://github.com/kbhomes) - Fixed text selection desynchronization during overscroll ([#17](https://github.com/panphora/overtype/pull/17))
|
|
741
741
|
- [Kristián Kostecký](https://github.com/kristiankostecky) - Fixed toolbar option being ignored in reinit() ([#62](https://github.com/panphora/overtype/pull/62))
|
|
742
742
|
- [Lyric Wai](https://github.com/lyricat) - Fixed double-escaping of links ([#64](https://github.com/panphora/overtype/pull/64)), reported code block alignment issues ([#65](https://github.com/panphora/overtype/issues/65))
|
|
743
|
+
- [kozi](https://github.com/kozi) - Reported link tooltip issues in Firefox ([#68](https://github.com/panphora/overtype/issues/68)) and toolbar positioning ([#69](https://github.com/panphora/overtype/issues/69))
|
|
743
744
|
|
|
744
745
|
### TypeScript & Framework Support
|
|
745
746
|
- [merlinz01](https://github.com/merlinz01) - Initial TypeScript definitions implementation ([#20](https://github.com/panphora/overtype/pull/20))
|
|
@@ -766,12 +767,12 @@ MIT
|
|
|
766
767
|
|
|
767
768
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
768
769
|
|
|
770
|
+
<p> </p>
|
|
771
|
+
|
|
769
772
|
---
|
|
770
773
|
|
|
771
774
|
Built with the radical idea that sometimes dumb ideas work.
|
|
772
775
|
|
|
773
|
-
---
|
|
774
|
-
|
|
775
776
|
**Ready for another radical idea?**
|
|
776
777
|
Let's remove every layer of the web application stack.
|
|
777
778
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OverType v2.0.
|
|
2
|
+
* OverType v2.0.2
|
|
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
|
return html.replace(/^((?: )*)-\s+\[([ xX])\]\s+(.+)$/, (match, indent, checked, content) => {
|
|
106
106
|
if (isPreviewMode) {
|
|
107
107
|
const isChecked = checked.toLowerCase() === "x";
|
|
108
|
-
return `${indent}<li class="task-list"><input type="checkbox"
|
|
108
|
+
return `${indent}<li class="task-list"><input type="checkbox" ${isChecked ? "checked" : ""}> ${content}</li>`;
|
|
109
109
|
} else {
|
|
110
110
|
return `${indent}<li class="task-list"><span class="syntax-marker">- [${checked}] </span>${content}</li>`;
|
|
111
111
|
}
|
|
@@ -1839,8 +1839,8 @@ function generateStyles(options = {}) {
|
|
|
1839
1839
|
|
|
1840
1840
|
/* Container base styles after reset */
|
|
1841
1841
|
.overtype-container {
|
|
1842
|
-
display:
|
|
1843
|
-
|
|
1842
|
+
display: flex !important;
|
|
1843
|
+
flex-direction: column !important;
|
|
1844
1844
|
width: 100% !important;
|
|
1845
1845
|
height: 100% !important;
|
|
1846
1846
|
position: relative !important; /* Override reset - needed for absolute children */
|
|
@@ -1860,10 +1860,10 @@ function generateStyles(options = {}) {
|
|
|
1860
1860
|
/* Auto-resize mode styles */
|
|
1861
1861
|
.overtype-container.overtype-auto-resize {
|
|
1862
1862
|
height: auto !important;
|
|
1863
|
-
grid-template-rows: auto auto auto !important;
|
|
1864
1863
|
}
|
|
1865
|
-
|
|
1864
|
+
|
|
1866
1865
|
.overtype-container.overtype-auto-resize .overtype-wrapper {
|
|
1866
|
+
flex: 0 0 auto !important; /* Don't grow/shrink, use explicit height */
|
|
1867
1867
|
height: auto !important;
|
|
1868
1868
|
min-height: 60px !important;
|
|
1869
1869
|
overflow: visible !important;
|
|
@@ -1872,11 +1872,10 @@ function generateStyles(options = {}) {
|
|
|
1872
1872
|
.overtype-wrapper {
|
|
1873
1873
|
position: relative !important; /* Override reset - needed for absolute children */
|
|
1874
1874
|
width: 100% !important;
|
|
1875
|
-
|
|
1875
|
+
flex: 1 1 0 !important; /* Grow to fill remaining space, with flex-basis: 0 */
|
|
1876
1876
|
min-height: 60px !important; /* Minimum usable height */
|
|
1877
1877
|
overflow: hidden !important;
|
|
1878
1878
|
background: var(--bg-secondary, #ffffff) !important;
|
|
1879
|
-
grid-row: 2 !important; /* Always second row in grid */
|
|
1880
1879
|
z-index: 1; /* Below toolbar and dropdown */
|
|
1881
1880
|
}
|
|
1882
1881
|
|
|
@@ -2211,7 +2210,7 @@ function generateStyles(options = {}) {
|
|
|
2211
2210
|
|
|
2212
2211
|
/* Stats bar */
|
|
2213
2212
|
|
|
2214
|
-
/* Stats bar - positioned by
|
|
2213
|
+
/* Stats bar - positioned by flexbox */
|
|
2215
2214
|
.overtype-stats {
|
|
2216
2215
|
height: 40px !important;
|
|
2217
2216
|
padding: 0 20px !important;
|
|
@@ -2223,7 +2222,7 @@ function generateStyles(options = {}) {
|
|
|
2223
2222
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
|
2224
2223
|
font-size: 0.85rem !important;
|
|
2225
2224
|
color: #666 !important;
|
|
2226
|
-
|
|
2225
|
+
flex-shrink: 0 !important; /* Don't shrink */
|
|
2227
2226
|
}
|
|
2228
2227
|
|
|
2229
2228
|
/* Dark theme stats bar */
|
|
@@ -2266,7 +2265,6 @@ function generateStyles(options = {}) {
|
|
|
2266
2265
|
-webkit-overflow-scrolling: touch !important;
|
|
2267
2266
|
flex-shrink: 0 !important;
|
|
2268
2267
|
height: auto !important;
|
|
2269
|
-
grid-row: 1 !important; /* Always first row in grid */
|
|
2270
2268
|
position: relative !important; /* Override reset */
|
|
2271
2269
|
z-index: 100 !important; /* Ensure toolbar is above wrapper */
|
|
2272
2270
|
scrollbar-width: thin; /* Thin scrollbar on Firefox */
|
|
@@ -2336,9 +2334,6 @@ function generateStyles(options = {}) {
|
|
|
2336
2334
|
}
|
|
2337
2335
|
|
|
2338
2336
|
/* Adjust wrapper when toolbar is present */
|
|
2339
|
-
.overtype-container .overtype-toolbar + .overtype-wrapper {
|
|
2340
|
-
}
|
|
2341
|
-
|
|
2342
2337
|
/* Mobile toolbar adjustments */
|
|
2343
2338
|
@media (max-width: 640px) {
|
|
2344
2339
|
.overtype-toolbar {
|
|
@@ -2609,36 +2604,42 @@ function generateStyles(options = {}) {
|
|
|
2609
2604
|
height: 2px !important;
|
|
2610
2605
|
}
|
|
2611
2606
|
|
|
2612
|
-
/* Link Tooltip -
|
|
2607
|
+
/* Link Tooltip - Base styles (all browsers) */
|
|
2608
|
+
.overtype-link-tooltip {
|
|
2609
|
+
/* Visual styles that work for both positioning methods */
|
|
2610
|
+
background: #333 !important;
|
|
2611
|
+
color: white !important;
|
|
2612
|
+
padding: 6px 10px !important;
|
|
2613
|
+
border-radius: 16px !important;
|
|
2614
|
+
font-size: 12px !important;
|
|
2615
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
2616
|
+
display: none !important;
|
|
2617
|
+
z-index: 10000 !important;
|
|
2618
|
+
cursor: pointer !important;
|
|
2619
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
2620
|
+
max-width: 300px !important;
|
|
2621
|
+
white-space: nowrap !important;
|
|
2622
|
+
overflow: hidden !important;
|
|
2623
|
+
text-overflow: ellipsis !important;
|
|
2624
|
+
|
|
2625
|
+
/* Base positioning for Floating UI fallback */
|
|
2626
|
+
position: absolute;
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
.overtype-link-tooltip.visible {
|
|
2630
|
+
display: flex !important;
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
/* CSS Anchor Positioning (modern browsers only) */
|
|
2613
2634
|
@supports (position-anchor: --x) and (position-area: center) {
|
|
2614
2635
|
.overtype-link-tooltip {
|
|
2615
|
-
|
|
2636
|
+
/* Only anchor positioning specific properties */
|
|
2616
2637
|
position-anchor: var(--target-anchor, --link-0);
|
|
2617
2638
|
position-area: block-end center;
|
|
2618
2639
|
margin-top: 8px !important;
|
|
2619
|
-
|
|
2620
|
-
background: #333 !important;
|
|
2621
|
-
color: white !important;
|
|
2622
|
-
padding: 6px 10px !important;
|
|
2623
|
-
border-radius: 16px !important;
|
|
2624
|
-
font-size: 12px !important;
|
|
2625
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
2626
|
-
display: none !important;
|
|
2627
|
-
z-index: 10000 !important;
|
|
2628
|
-
cursor: pointer !important;
|
|
2629
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
2630
|
-
max-width: 300px !important;
|
|
2631
|
-
white-space: nowrap !important;
|
|
2632
|
-
overflow: hidden !important;
|
|
2633
|
-
text-overflow: ellipsis !important;
|
|
2634
|
-
|
|
2635
2640
|
position-try: most-width block-end inline-end, flip-inline, block-start center;
|
|
2636
2641
|
position-visibility: anchors-visible;
|
|
2637
2642
|
}
|
|
2638
|
-
|
|
2639
|
-
.overtype-link-tooltip.visible {
|
|
2640
|
-
display: flex !important;
|
|
2641
|
-
}
|
|
2642
2643
|
}
|
|
2643
2644
|
|
|
2644
2645
|
${mobileStyles}
|
|
@@ -2671,7 +2672,7 @@ var Toolbar = class {
|
|
|
2671
2672
|
this.container.appendChild(button);
|
|
2672
2673
|
}
|
|
2673
2674
|
});
|
|
2674
|
-
this.editor.
|
|
2675
|
+
this.editor.container.insertBefore(this.container, this.editor.wrapper);
|
|
2675
2676
|
}
|
|
2676
2677
|
/**
|
|
2677
2678
|
* Create a toolbar separator
|
|
@@ -2896,9 +2897,26 @@ var LinkTooltip = class {
|
|
|
2896
2897
|
this.currentLink = null;
|
|
2897
2898
|
this.hideTimeout = null;
|
|
2898
2899
|
this.visibilityChangeHandler = null;
|
|
2900
|
+
this.useFloatingUI = false;
|
|
2901
|
+
this.floatingUI = null;
|
|
2899
2902
|
this.init();
|
|
2900
2903
|
}
|
|
2901
|
-
init() {
|
|
2904
|
+
async init() {
|
|
2905
|
+
const supportsAnchorPositioning = CSS.supports("position-anchor: --x") && CSS.supports("position-area: center");
|
|
2906
|
+
if (!supportsAnchorPositioning) {
|
|
2907
|
+
try {
|
|
2908
|
+
const importFn = new Function("url", "return import(url)");
|
|
2909
|
+
const { computePosition, offset, shift, flip } = await importFn(
|
|
2910
|
+
"https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.7.4/+esm"
|
|
2911
|
+
);
|
|
2912
|
+
this.floatingUI = { computePosition, offset, shift, flip };
|
|
2913
|
+
this.useFloatingUI = true;
|
|
2914
|
+
} catch (error) {
|
|
2915
|
+
console.warn("Failed to load Floating UI fallback:", error);
|
|
2916
|
+
this.floatingUI = null;
|
|
2917
|
+
this.useFloatingUI = false;
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2902
2920
|
this.createTooltip();
|
|
2903
2921
|
this.editor.textarea.addEventListener("selectionchange", () => this.checkCursorPosition());
|
|
2904
2922
|
this.editor.textarea.addEventListener("keyup", (e) => {
|
|
@@ -2907,7 +2925,13 @@ var LinkTooltip = class {
|
|
|
2907
2925
|
}
|
|
2908
2926
|
});
|
|
2909
2927
|
this.editor.textarea.addEventListener("input", () => this.hide());
|
|
2910
|
-
this.editor.textarea.addEventListener("scroll", () =>
|
|
2928
|
+
this.editor.textarea.addEventListener("scroll", () => {
|
|
2929
|
+
if (this.useFloatingUI && this.currentLink) {
|
|
2930
|
+
this.showWithFloatingUI(this.currentLink);
|
|
2931
|
+
} else {
|
|
2932
|
+
this.hide();
|
|
2933
|
+
}
|
|
2934
|
+
});
|
|
2911
2935
|
this.editor.textarea.addEventListener("blur", () => this.hide());
|
|
2912
2936
|
this.visibilityChangeHandler = () => {
|
|
2913
2937
|
if (document.hidden) {
|
|
@@ -2916,7 +2940,6 @@ var LinkTooltip = class {
|
|
|
2916
2940
|
};
|
|
2917
2941
|
document.addEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
2918
2942
|
this.tooltip.addEventListener("mouseenter", () => this.cancelHide());
|
|
2919
|
-
this.tooltip.addEventListener("mouseleave", () => this.scheduleHide());
|
|
2920
2943
|
}
|
|
2921
2944
|
createTooltip() {
|
|
2922
2945
|
this.tooltip = document.createElement("div");
|
|
@@ -2977,9 +3000,52 @@ var LinkTooltip = class {
|
|
|
2977
3000
|
this.cancelHide();
|
|
2978
3001
|
const urlSpan = this.tooltip.querySelector(".overtype-link-tooltip-url");
|
|
2979
3002
|
urlSpan.textContent = linkInfo.url;
|
|
2980
|
-
this.
|
|
3003
|
+
if (this.useFloatingUI) {
|
|
3004
|
+
this.showWithFloatingUI(linkInfo);
|
|
3005
|
+
} else {
|
|
3006
|
+
this.showWithAnchorPositioning(linkInfo);
|
|
3007
|
+
}
|
|
2981
3008
|
this.tooltip.classList.add("visible");
|
|
2982
3009
|
}
|
|
3010
|
+
showWithAnchorPositioning(linkInfo) {
|
|
3011
|
+
this.tooltip.style.setProperty("--target-anchor", `--link-${linkInfo.index}`);
|
|
3012
|
+
}
|
|
3013
|
+
async showWithFloatingUI(linkInfo) {
|
|
3014
|
+
const anchorElement = this.findAnchorElement(linkInfo.index);
|
|
3015
|
+
if (!anchorElement) {
|
|
3016
|
+
return;
|
|
3017
|
+
}
|
|
3018
|
+
const rect = anchorElement.getBoundingClientRect();
|
|
3019
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
3020
|
+
return;
|
|
3021
|
+
}
|
|
3022
|
+
try {
|
|
3023
|
+
const { x, y } = await this.floatingUI.computePosition(
|
|
3024
|
+
anchorElement,
|
|
3025
|
+
this.tooltip,
|
|
3026
|
+
{
|
|
3027
|
+
placement: "bottom",
|
|
3028
|
+
middleware: [
|
|
3029
|
+
this.floatingUI.offset(8),
|
|
3030
|
+
this.floatingUI.shift({ padding: 8 }),
|
|
3031
|
+
this.floatingUI.flip()
|
|
3032
|
+
]
|
|
3033
|
+
}
|
|
3034
|
+
);
|
|
3035
|
+
Object.assign(this.tooltip.style, {
|
|
3036
|
+
left: `${x}px`,
|
|
3037
|
+
top: `${y}px`,
|
|
3038
|
+
position: "absolute"
|
|
3039
|
+
});
|
|
3040
|
+
} catch (error) {
|
|
3041
|
+
console.warn("Floating UI positioning failed:", error);
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
findAnchorElement(linkIndex) {
|
|
3046
|
+
const preview = this.editor.preview;
|
|
3047
|
+
return preview.querySelector(`a[style*="--link-${linkIndex}"]`);
|
|
3048
|
+
}
|
|
2983
3049
|
hide() {
|
|
2984
3050
|
this.tooltip.classList.remove("visible");
|
|
2985
3051
|
this.currentLink = null;
|
|
@@ -3005,6 +3071,8 @@ var LinkTooltip = class {
|
|
|
3005
3071
|
}
|
|
3006
3072
|
this.tooltip = null;
|
|
3007
3073
|
this.currentLink = null;
|
|
3074
|
+
this.floatingUI = null;
|
|
3075
|
+
this.useFloatingUI = false;
|
|
3008
3076
|
}
|
|
3009
3077
|
};
|
|
3010
3078
|
|
|
@@ -3459,22 +3527,10 @@ var _OverType = class _OverType {
|
|
|
3459
3527
|
this._updateStats();
|
|
3460
3528
|
}
|
|
3461
3529
|
this.element.appendChild(this.container);
|
|
3462
|
-
if (window.location.pathname.includes("demo.html")) {
|
|
3463
|
-
console.log("_createDOM completed:", {
|
|
3464
|
-
elementId: this.element.id,
|
|
3465
|
-
autoResize: this.options.autoResize,
|
|
3466
|
-
containerClasses: this.container.className,
|
|
3467
|
-
hasStats: !!this.statsBar,
|
|
3468
|
-
hasToolbar: this.options.toolbar
|
|
3469
|
-
});
|
|
3470
|
-
}
|
|
3471
3530
|
if (this.options.autoResize) {
|
|
3472
3531
|
this._setupAutoResize();
|
|
3473
3532
|
} else {
|
|
3474
3533
|
this.container.classList.remove("overtype-auto-resize");
|
|
3475
|
-
if (window.location.pathname.includes("demo.html")) {
|
|
3476
|
-
console.log("Removed auto-resize class from:", this.element.id);
|
|
3477
|
-
}
|
|
3478
3534
|
}
|
|
3479
3535
|
}
|
|
3480
3536
|
/**
|
|
@@ -3977,6 +4033,7 @@ var _OverType = class _OverType {
|
|
|
3977
4033
|
*/
|
|
3978
4034
|
showNormalEditMode() {
|
|
3979
4035
|
this.container.dataset.mode = "normal";
|
|
4036
|
+
this.updatePreview();
|
|
3980
4037
|
requestAnimationFrame(() => {
|
|
3981
4038
|
this.textarea.scrollTop = this.preview.scrollTop;
|
|
3982
4039
|
this.textarea.scrollLeft = this.preview.scrollLeft;
|
|
@@ -4004,6 +4061,7 @@ var _OverType = class _OverType {
|
|
|
4004
4061
|
*/
|
|
4005
4062
|
showPreviewMode() {
|
|
4006
4063
|
this.container.dataset.mode = "preview";
|
|
4064
|
+
this.updatePreview();
|
|
4007
4065
|
return this;
|
|
4008
4066
|
}
|
|
4009
4067
|
/**
|