overtype 2.0.1 → 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 +108 -52
- package/dist/overtype-webcomponent.esm.js.map +2 -2
- package/dist/overtype-webcomponent.js +108 -52
- package/dist/overtype-webcomponent.js.map +2 -2
- package/dist/overtype-webcomponent.min.js +50 -49
- package/dist/overtype.cjs +108 -52
- package/dist/overtype.cjs.map +2 -2
- package/dist/overtype.esm.js +108 -52
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +108 -52
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +51 -50
- package/package.json +1 -1
- package/src/link-tooltip.js +100 -9
- package/src/overtype.js +0 -15
- package/src/styles.js +35 -34
- package/src/toolbar.js +2 -1
package/src/link-tooltip.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Link Tooltip - CSS Anchor Positioning with
|
|
2
|
+
* Link Tooltip - CSS Anchor Positioning with Floating UI fallback
|
|
3
3
|
* Shows a clickable tooltip when cursor is within a link
|
|
4
|
-
* Uses CSS anchor positioning
|
|
4
|
+
* Uses CSS anchor positioning for modern browsers, Floating UI for older browsers
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export class LinkTooltip {
|
|
@@ -11,11 +11,35 @@ export class LinkTooltip {
|
|
|
11
11
|
this.currentLink = null;
|
|
12
12
|
this.hideTimeout = null;
|
|
13
13
|
this.visibilityChangeHandler = null;
|
|
14
|
+
this.useFloatingUI = false;
|
|
15
|
+
this.floatingUI = null;
|
|
14
16
|
|
|
15
17
|
this.init();
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
init() {
|
|
20
|
+
async init() {
|
|
21
|
+
// Detect CSS anchor positioning support
|
|
22
|
+
const supportsAnchorPositioning = CSS.supports('position-anchor: --x') &&
|
|
23
|
+
CSS.supports('position-area: center');
|
|
24
|
+
|
|
25
|
+
// Load Floating UI if needed
|
|
26
|
+
if (!supportsAnchorPositioning) {
|
|
27
|
+
try {
|
|
28
|
+
// Use indirect eval to prevent bundler from processing the import
|
|
29
|
+
const importFn = new Function('url', 'return import(url)');
|
|
30
|
+
const { computePosition, offset, shift, flip } = await importFn(
|
|
31
|
+
'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.7.4/+esm'
|
|
32
|
+
);
|
|
33
|
+
this.floatingUI = { computePosition, offset, shift, flip };
|
|
34
|
+
this.useFloatingUI = true;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
// If dynamic import fails, tooltips simply won't show
|
|
37
|
+
console.warn('Failed to load Floating UI fallback:', error);
|
|
38
|
+
this.floatingUI = null;
|
|
39
|
+
this.useFloatingUI = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
19
43
|
// Create tooltip element
|
|
20
44
|
// Note: Styles are now in the main stylesheet (styles.js) with @supports wrapper
|
|
21
45
|
this.createTooltip();
|
|
@@ -28,9 +52,19 @@ export class LinkTooltip {
|
|
|
28
52
|
}
|
|
29
53
|
});
|
|
30
54
|
|
|
31
|
-
// Hide tooltip when typing
|
|
55
|
+
// Hide tooltip when typing
|
|
32
56
|
this.editor.textarea.addEventListener('input', () => this.hide());
|
|
33
|
-
|
|
57
|
+
|
|
58
|
+
// Reposition or hide tooltip when scrolling
|
|
59
|
+
this.editor.textarea.addEventListener('scroll', () => {
|
|
60
|
+
if (this.useFloatingUI && this.currentLink) {
|
|
61
|
+
// Reposition the tooltip for Floating UI
|
|
62
|
+
this.showWithFloatingUI(this.currentLink);
|
|
63
|
+
} else {
|
|
64
|
+
// Hide for CSS anchor positioning (native browser behavior handles this)
|
|
65
|
+
this.hide();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
34
68
|
|
|
35
69
|
// Hide tooltip when textarea loses focus
|
|
36
70
|
this.editor.textarea.addEventListener('blur', () => this.hide());
|
|
@@ -43,9 +77,8 @@ export class LinkTooltip {
|
|
|
43
77
|
};
|
|
44
78
|
document.addEventListener('visibilitychange', this.visibilityChangeHandler);
|
|
45
79
|
|
|
46
|
-
// Keep tooltip visible on hover
|
|
80
|
+
// Keep tooltip visible on hover (only prevent hide, don't schedule hide on leave)
|
|
47
81
|
this.tooltip.addEventListener('mouseenter', () => this.cancelHide());
|
|
48
|
-
this.tooltip.addEventListener('mouseleave', () => this.scheduleHide());
|
|
49
82
|
}
|
|
50
83
|
|
|
51
84
|
createTooltip() {
|
|
@@ -128,11 +161,67 @@ export class LinkTooltip {
|
|
|
128
161
|
const urlSpan = this.tooltip.querySelector('.overtype-link-tooltip-url');
|
|
129
162
|
urlSpan.textContent = linkInfo.url;
|
|
130
163
|
|
|
164
|
+
if (this.useFloatingUI) {
|
|
165
|
+
this.showWithFloatingUI(linkInfo);
|
|
166
|
+
} else {
|
|
167
|
+
this.showWithAnchorPositioning(linkInfo);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.tooltip.classList.add('visible');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
showWithAnchorPositioning(linkInfo) {
|
|
131
174
|
// Set the CSS variable to point to the correct anchor
|
|
132
175
|
this.tooltip.style.setProperty('--target-anchor', `--link-${linkInfo.index}`);
|
|
176
|
+
}
|
|
133
177
|
|
|
134
|
-
|
|
135
|
-
this
|
|
178
|
+
async showWithFloatingUI(linkInfo) {
|
|
179
|
+
// Find the <a> element in preview that corresponds to this link
|
|
180
|
+
const anchorElement = this.findAnchorElement(linkInfo.index);
|
|
181
|
+
|
|
182
|
+
if (!anchorElement) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check if anchor element is visible and in viewport
|
|
187
|
+
const rect = anchorElement.getBoundingClientRect();
|
|
188
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
// Compute position using Floating UI
|
|
194
|
+
const { x, y } = await this.floatingUI.computePosition(
|
|
195
|
+
anchorElement,
|
|
196
|
+
this.tooltip,
|
|
197
|
+
{
|
|
198
|
+
placement: 'bottom',
|
|
199
|
+
middleware: [
|
|
200
|
+
this.floatingUI.offset(8),
|
|
201
|
+
this.floatingUI.shift({ padding: 8 }),
|
|
202
|
+
this.floatingUI.flip()
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Apply position
|
|
208
|
+
Object.assign(this.tooltip.style, {
|
|
209
|
+
left: `${x}px`,
|
|
210
|
+
top: `${y}px`,
|
|
211
|
+
position: 'absolute'
|
|
212
|
+
});
|
|
213
|
+
} catch (error) {
|
|
214
|
+
// If Floating UI computation fails, don't show tooltip
|
|
215
|
+
console.warn('Floating UI positioning failed:', error);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
findAnchorElement(linkIndex) {
|
|
221
|
+
// Find the <a> element with the matching anchor-name style
|
|
222
|
+
const preview = this.editor.preview;
|
|
223
|
+
// Direct query for the specific link - more efficient than iterating
|
|
224
|
+
return preview.querySelector(`a[style*="--link-${linkIndex}"]`);
|
|
136
225
|
}
|
|
137
226
|
|
|
138
227
|
hide() {
|
|
@@ -166,5 +255,7 @@ export class LinkTooltip {
|
|
|
166
255
|
}
|
|
167
256
|
this.tooltip = null;
|
|
168
257
|
this.currentLink = null;
|
|
258
|
+
this.floatingUI = null;
|
|
259
|
+
this.useFloatingUI = false;
|
|
169
260
|
}
|
|
170
261
|
}
|
package/src/overtype.js
CHANGED
|
@@ -362,27 +362,12 @@ class OverType {
|
|
|
362
362
|
// Add container to element
|
|
363
363
|
this.element.appendChild(this.container);
|
|
364
364
|
|
|
365
|
-
// Debug logging
|
|
366
|
-
if (window.location.pathname.includes('demo.html')) {
|
|
367
|
-
console.log('_createDOM completed:', {
|
|
368
|
-
elementId: this.element.id,
|
|
369
|
-
autoResize: this.options.autoResize,
|
|
370
|
-
containerClasses: this.container.className,
|
|
371
|
-
hasStats: !!this.statsBar,
|
|
372
|
-
hasToolbar: this.options.toolbar
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
|
|
376
365
|
// Setup auto-resize if enabled
|
|
377
366
|
if (this.options.autoResize) {
|
|
378
367
|
this._setupAutoResize();
|
|
379
368
|
} else {
|
|
380
369
|
// Ensure auto-resize class is removed if not using auto-resize
|
|
381
370
|
this.container.classList.remove('overtype-auto-resize');
|
|
382
|
-
|
|
383
|
-
if (window.location.pathname.includes('demo.html')) {
|
|
384
|
-
console.log('Removed auto-resize class from:', this.element.id);
|
|
385
|
-
}
|
|
386
371
|
}
|
|
387
372
|
}
|
|
388
373
|
|
package/src/styles.js
CHANGED
|
@@ -72,8 +72,8 @@ export function generateStyles(options = {}) {
|
|
|
72
72
|
|
|
73
73
|
/* Container base styles after reset */
|
|
74
74
|
.overtype-container {
|
|
75
|
-
display:
|
|
76
|
-
|
|
75
|
+
display: flex !important;
|
|
76
|
+
flex-direction: column !important;
|
|
77
77
|
width: 100% !important;
|
|
78
78
|
height: 100% !important;
|
|
79
79
|
position: relative !important; /* Override reset - needed for absolute children */
|
|
@@ -93,10 +93,10 @@ export function generateStyles(options = {}) {
|
|
|
93
93
|
/* Auto-resize mode styles */
|
|
94
94
|
.overtype-container.overtype-auto-resize {
|
|
95
95
|
height: auto !important;
|
|
96
|
-
grid-template-rows: auto auto auto !important;
|
|
97
96
|
}
|
|
98
|
-
|
|
97
|
+
|
|
99
98
|
.overtype-container.overtype-auto-resize .overtype-wrapper {
|
|
99
|
+
flex: 0 0 auto !important; /* Don't grow/shrink, use explicit height */
|
|
100
100
|
height: auto !important;
|
|
101
101
|
min-height: 60px !important;
|
|
102
102
|
overflow: visible !important;
|
|
@@ -105,11 +105,10 @@ export function generateStyles(options = {}) {
|
|
|
105
105
|
.overtype-wrapper {
|
|
106
106
|
position: relative !important; /* Override reset - needed for absolute children */
|
|
107
107
|
width: 100% !important;
|
|
108
|
-
|
|
108
|
+
flex: 1 1 0 !important; /* Grow to fill remaining space, with flex-basis: 0 */
|
|
109
109
|
min-height: 60px !important; /* Minimum usable height */
|
|
110
110
|
overflow: hidden !important;
|
|
111
111
|
background: var(--bg-secondary, #ffffff) !important;
|
|
112
|
-
grid-row: 2 !important; /* Always second row in grid */
|
|
113
112
|
z-index: 1; /* Below toolbar and dropdown */
|
|
114
113
|
}
|
|
115
114
|
|
|
@@ -444,7 +443,7 @@ export function generateStyles(options = {}) {
|
|
|
444
443
|
|
|
445
444
|
/* Stats bar */
|
|
446
445
|
|
|
447
|
-
/* Stats bar - positioned by
|
|
446
|
+
/* Stats bar - positioned by flexbox */
|
|
448
447
|
.overtype-stats {
|
|
449
448
|
height: 40px !important;
|
|
450
449
|
padding: 0 20px !important;
|
|
@@ -456,7 +455,7 @@ export function generateStyles(options = {}) {
|
|
|
456
455
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
|
457
456
|
font-size: 0.85rem !important;
|
|
458
457
|
color: #666 !important;
|
|
459
|
-
|
|
458
|
+
flex-shrink: 0 !important; /* Don't shrink */
|
|
460
459
|
}
|
|
461
460
|
|
|
462
461
|
/* Dark theme stats bar */
|
|
@@ -499,7 +498,6 @@ export function generateStyles(options = {}) {
|
|
|
499
498
|
-webkit-overflow-scrolling: touch !important;
|
|
500
499
|
flex-shrink: 0 !important;
|
|
501
500
|
height: auto !important;
|
|
502
|
-
grid-row: 1 !important; /* Always first row in grid */
|
|
503
501
|
position: relative !important; /* Override reset */
|
|
504
502
|
z-index: 100 !important; /* Ensure toolbar is above wrapper */
|
|
505
503
|
scrollbar-width: thin; /* Thin scrollbar on Firefox */
|
|
@@ -569,9 +567,6 @@ export function generateStyles(options = {}) {
|
|
|
569
567
|
}
|
|
570
568
|
|
|
571
569
|
/* Adjust wrapper when toolbar is present */
|
|
572
|
-
.overtype-container .overtype-toolbar + .overtype-wrapper {
|
|
573
|
-
}
|
|
574
|
-
|
|
575
570
|
/* Mobile toolbar adjustments */
|
|
576
571
|
@media (max-width: 640px) {
|
|
577
572
|
.overtype-toolbar {
|
|
@@ -842,36 +837,42 @@ export function generateStyles(options = {}) {
|
|
|
842
837
|
height: 2px !important;
|
|
843
838
|
}
|
|
844
839
|
|
|
845
|
-
/* Link Tooltip -
|
|
840
|
+
/* Link Tooltip - Base styles (all browsers) */
|
|
841
|
+
.overtype-link-tooltip {
|
|
842
|
+
/* Visual styles that work for both positioning methods */
|
|
843
|
+
background: #333 !important;
|
|
844
|
+
color: white !important;
|
|
845
|
+
padding: 6px 10px !important;
|
|
846
|
+
border-radius: 16px !important;
|
|
847
|
+
font-size: 12px !important;
|
|
848
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
849
|
+
display: none !important;
|
|
850
|
+
z-index: 10000 !important;
|
|
851
|
+
cursor: pointer !important;
|
|
852
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
853
|
+
max-width: 300px !important;
|
|
854
|
+
white-space: nowrap !important;
|
|
855
|
+
overflow: hidden !important;
|
|
856
|
+
text-overflow: ellipsis !important;
|
|
857
|
+
|
|
858
|
+
/* Base positioning for Floating UI fallback */
|
|
859
|
+
position: absolute;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
.overtype-link-tooltip.visible {
|
|
863
|
+
display: flex !important;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/* CSS Anchor Positioning (modern browsers only) */
|
|
846
867
|
@supports (position-anchor: --x) and (position-area: center) {
|
|
847
868
|
.overtype-link-tooltip {
|
|
848
|
-
|
|
869
|
+
/* Only anchor positioning specific properties */
|
|
849
870
|
position-anchor: var(--target-anchor, --link-0);
|
|
850
871
|
position-area: block-end center;
|
|
851
872
|
margin-top: 8px !important;
|
|
852
|
-
|
|
853
|
-
background: #333 !important;
|
|
854
|
-
color: white !important;
|
|
855
|
-
padding: 6px 10px !important;
|
|
856
|
-
border-radius: 16px !important;
|
|
857
|
-
font-size: 12px !important;
|
|
858
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
859
|
-
display: none !important;
|
|
860
|
-
z-index: 10000 !important;
|
|
861
|
-
cursor: pointer !important;
|
|
862
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
863
|
-
max-width: 300px !important;
|
|
864
|
-
white-space: nowrap !important;
|
|
865
|
-
overflow: hidden !important;
|
|
866
|
-
text-overflow: ellipsis !important;
|
|
867
|
-
|
|
868
873
|
position-try: most-width block-end inline-end, flip-inline, block-start center;
|
|
869
874
|
position-visibility: anchors-visible;
|
|
870
875
|
}
|
|
871
|
-
|
|
872
|
-
.overtype-link-tooltip.visible {
|
|
873
|
-
display: flex !important;
|
|
874
|
-
}
|
|
875
876
|
}
|
|
876
877
|
|
|
877
878
|
${mobileStyles}
|
package/src/toolbar.js
CHANGED
|
@@ -36,7 +36,8 @@ export class Toolbar {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
// Insert toolbar before the wrapper (as sibling, not child)
|
|
40
|
+
this.editor.container.insertBefore(this.container, this.editor.wrapper);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/**
|