@codemirror/tooltip
Advanced tools
Comparing version 0.19.4 to 0.19.5
@@ -0,1 +1,15 @@ | ||
## 0.19.5 (2021-11-06) | ||
### Bug fixes | ||
Fix breakage of hover tooltips inside shadow roots. | ||
### New features | ||
Adds a `hasHoverTooltips` predicate that tells you if an editor state has any open hover tooltips. | ||
Adds a `closeHoverTooltips` state effect that closes all hover tooltips. | ||
Tooltip views can now provide an `offset` property to change the tooltip position. | ||
## 0.19.4 (2021-10-13) | ||
@@ -2,0 +16,0 @@ |
import { EditorView, ViewUpdate } from '@codemirror/view'; | ||
import { Extension, Facet } from '@codemirror/state'; | ||
import { Extension, Facet, EditorState, StateEffect } from '@codemirror/state'; | ||
@@ -78,2 +78,14 @@ /** | ||
/** | ||
Adjust the position of the tooltip relative to its anchor | ||
position. A positive `x` value will move the tooltip | ||
horizontally along with the text direction (so right in | ||
left-to-right context, left in right-to-left). A positive `y` | ||
will move the tooltip up when it is above its anchor, and down | ||
otherwise. | ||
*/ | ||
offset?: { | ||
x: number; | ||
y: number; | ||
}; | ||
/** | ||
Called after the tooltip is added to the DOM for the first time. | ||
@@ -111,3 +123,11 @@ */ | ||
}): Extension; | ||
/** | ||
Returns true if any hover tooltips are currently active. | ||
*/ | ||
declare function hasHoverTooltips(state: EditorState): boolean; | ||
/** | ||
Transaction effect that closes all hover tooltips. | ||
*/ | ||
declare const closeHoverTooltips: StateEffect<null>; | ||
export { Tooltip, TooltipView, hoverTooltip, showTooltip, tooltips }; | ||
export { Tooltip, TooltipView, closeHoverTooltips, hasHoverTooltips, hoverTooltip, showTooltip, tooltips }; |
import { ViewPlugin, Direction, EditorView, logException } from '@codemirror/view'; | ||
import { Facet, StateEffect, StateField, MapMode } from '@codemirror/state'; | ||
var _a; | ||
const ios = typeof navigator != "undefined" && | ||
@@ -120,4 +119,7 @@ !/*@__PURE__*//Edge\/(\d+)/.exec(navigator.userAgent) && /*@__PURE__*//Apple Computer/.test(navigator.vendor) && | ||
tooltipView.dom.classList.add("cm-tooltip"); | ||
if (tooltip.arrow) | ||
tooltipView.dom.classList.add("cm-tooltip-arrow"); | ||
if (tooltip.arrow && !tooltipView.dom.querySelector("cm-tooltip > cm-tooltip-arrow")) { | ||
let arrow = document.createElement("div"); | ||
arrow.className = "cm-tooltip-arrow"; | ||
tooltipView.dom.appendChild(arrow); | ||
} | ||
tooltipView.dom.style.position = this.position; | ||
@@ -156,14 +158,19 @@ tooltipView.dom.style.top = Outside; | ||
} | ||
let arrow = !!tooltip.arrow, above = !!tooltip.above; | ||
let width = size.right - size.left, height = size.bottom - size.top + (arrow ? 7 /* Size */ : 0); | ||
let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null; | ||
let arrowHeight = arrow ? 7 /* Size */ : 0; | ||
let width = size.right - size.left, height = size.bottom - size.top; | ||
let offset = tView.offset || noOffset; | ||
let left = this.view.textDirection == Direction.LTR | ||
? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0), measured.innerWidth - width) | ||
: Math.max(0, pos.left - width + (arrow ? 14 /* Offset */ : 0)); | ||
if (!tooltip.strictSide && | ||
(above ? pos.top - (size.bottom - size.top) < 0 : pos.bottom + (size.bottom - size.top) > measured.innerHeight)) | ||
? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, measured.innerWidth - width) | ||
: Math.max(0, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x); | ||
let above = !!tooltip.above; | ||
if (!tooltip.strictSide && (above | ||
? pos.top - (size.bottom - size.top) - offset.y < 0 | ||
: pos.bottom + (size.bottom - size.top) + offset.y > measured.innerHeight)) | ||
above = !above; | ||
let top = above ? pos.top - height : pos.bottom + (arrow ? 7 /* Size */ : 0), right = left + width; | ||
let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y; | ||
let right = left + width; | ||
for (let r of others) | ||
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top) | ||
top = above ? r.top - height : r.bottom; | ||
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2; | ||
if (this.position == "absolute") { | ||
@@ -177,2 +184,4 @@ dom.style.top = (top - measured.parent.top) + "px"; | ||
} | ||
if (arrow) | ||
arrow.style.left = `${pos.left - (left + 14 /* Offset */ - 7 /* Size */)}px`; | ||
others.push({ left, top, right, bottom: top + height }); | ||
@@ -202,4 +211,2 @@ dom.classList.toggle("cm-tooltip-above", above); | ||
}); | ||
const insetInlineStart = typeof document == 'undefined' || ((_a = document.body) === null || _a === void 0 ? void 0 : _a.style.insetInlineStart) != null | ||
? 'insetInlineStart' : 'left'; | ||
const baseTheme = /*@__PURE__*/EditorView.baseTheme({ | ||
@@ -220,39 +227,49 @@ ".cm-tooltip": { | ||
}, | ||
".cm-tooltip.cm-tooltip-arrow:before, .cm-tooltip.cm-tooltip-arrow:after": { | ||
".cm-tooltip-arrow": { | ||
height: `${7 /* Size */}px`, | ||
width: `${7 /* Size */ * 2}px`, | ||
position: "absolute", | ||
content: "''", | ||
[insetInlineStart]: `${14 /* Offset */ - 7 /* Size */}px`, | ||
width: 0, | ||
height: 0, | ||
borderLeft: `${7 /* Size */}px solid transparent`, | ||
borderRight: `${7 /* Size */}px solid transparent`, | ||
zIndex: -1 | ||
zIndex: -1, | ||
overflow: "hidden", | ||
"&:before, &:after": { | ||
content: "''", | ||
position: "absolute", | ||
width: 0, | ||
height: 0, | ||
borderLeft: `${7 /* Size */}px solid transparent`, | ||
borderRight: `${7 /* Size */}px solid transparent`, | ||
}, | ||
".cm-tooltip-above &": { | ||
bottom: `-${7 /* Size */}px`, | ||
"&:before": { | ||
borderTop: `${7 /* Size */}px solid #bbb`, | ||
}, | ||
"&:after": { | ||
borderTop: `${7 /* Size */}px solid #f5f5f5`, | ||
bottom: "1px" | ||
} | ||
}, | ||
".cm-tooltip-below &": { | ||
top: `-${7 /* Size */}px`, | ||
"&:before": { | ||
borderBottom: `${7 /* Size */}px solid #bbb`, | ||
}, | ||
"&:after": { | ||
borderBottom: `${7 /* Size */}px solid #f5f5f5`, | ||
top: "1px" | ||
} | ||
}, | ||
}, | ||
".cm-tooltip-above.cm-tooltip-arrow:before": { | ||
borderTop: `${7 /* Size */}px solid #f5f5f5`, | ||
bottom: `-${7 /* Size */ - 1}px` | ||
}, | ||
".cm-tooltip-below.cm-tooltip-arrow:before": { | ||
borderBottom: `${7 /* Size */}px solid #f5f5f5`, | ||
top: `-${7 /* Size */ - 1}px` | ||
}, | ||
".cm-tooltip-above.cm-tooltip-arrow:after": { | ||
borderTop: `${7 /* Size */}px solid #bbb`, | ||
bottom: `-${7 /* Size */}px`, | ||
zIndex: -2 | ||
}, | ||
".cm-tooltip-below.cm-tooltip-arrow:after": { | ||
borderBottom: `${7 /* Size */}px solid #bbb`, | ||
top: `-${7 /* Size */}px`, | ||
zIndex: -2 | ||
}, | ||
"&dark .cm-tooltip.cm-tooltip-arrow:before": { | ||
borderTopColor: "#333338", | ||
borderBottomColor: "#333338" | ||
}, | ||
"&dark .cm-tooltip.cm-tooltip-arrow:after": { | ||
borderTopColor: "transparent", | ||
borderBottomColor: "transparent" | ||
"&dark .cm-tooltip .cm-tooltip-arrow": { | ||
"&:before": { | ||
borderTopColor: "#333338", | ||
borderBottomColor: "#333338" | ||
}, | ||
"&:after": { | ||
borderTopColor: "transparent", | ||
borderBottomColor: "transparent" | ||
} | ||
} | ||
}); | ||
const noOffset = { x: 0, y: 0 }; | ||
/** | ||
@@ -321,7 +338,6 @@ Behavior by which an extension can provide a tooltip to be shown. | ||
this.hoverTime = hoverTime; | ||
this.lastMouseMove = null; | ||
this.lastMoveTime = 0; | ||
this.hoverTimeout = -1; | ||
this.restartTimeout = -1; | ||
this.pending = null; | ||
this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 }; | ||
this.checkHover = this.checkHover.bind(this); | ||
@@ -345,3 +361,3 @@ view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this)); | ||
return; | ||
let hovered = Date.now() - this.lastMoveTime; | ||
let hovered = Date.now() - this.lastMove.time; | ||
if (hovered < this.hoverTime) | ||
@@ -355,16 +371,14 @@ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered); | ||
clearTimeout(this.restartTimeout); | ||
let lastMove = this.lastMouseMove; | ||
let coords = { x: lastMove.clientX, y: lastMove.clientY }; | ||
let pos = this.view.contentDOM.contains(lastMove.target) | ||
? this.view.posAtCoords(coords) : null; | ||
let { lastMove } = this; | ||
let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null; | ||
if (pos == null) | ||
return; | ||
let posCoords = this.view.coordsAtPos(pos); | ||
if (posCoords == null || coords.y < posCoords.top || coords.y > posCoords.bottom || | ||
coords.x < posCoords.left - this.view.defaultCharacterWidth || | ||
coords.x > posCoords.right + this.view.defaultCharacterWidth) | ||
if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom || | ||
lastMove.x < posCoords.left - this.view.defaultCharacterWidth || | ||
lastMove.x > posCoords.right + this.view.defaultCharacterWidth) | ||
return; | ||
let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos); | ||
let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1; | ||
let open = this.source(this.view, pos, (coords.x < posCoords.left ? -rtl : rtl)); | ||
let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl)); | ||
if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) { | ||
@@ -386,10 +400,9 @@ let pending = this.pending = { pos }; | ||
var _a; | ||
this.lastMouseMove = event; | ||
this.lastMoveTime = Date.now(); | ||
this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() }; | ||
if (this.hoverTimeout < 0) | ||
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime); | ||
let tooltip = this.active; | ||
if (tooltip && !isInTooltip(event.target) || this.pending) { | ||
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) { | ||
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos; | ||
if ((pos == end ? this.view.posAtCoords({ x: event.clientX, y: event.clientY }) != pos | ||
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos | ||
: !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) { | ||
@@ -454,5 +467,8 @@ this.view.dispatch({ effects: this.setHover.of(null) }); | ||
return null; | ||
for (let effect of tr.effects) | ||
for (let effect of tr.effects) { | ||
if (effect.is(setHover)) | ||
return effect.value; | ||
if (effect.is(closeHoverTooltipEffect)) | ||
return null; | ||
} | ||
if (value && tr.docChanged) { | ||
@@ -472,3 +488,3 @@ let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel); | ||
}); | ||
let hoverTime = options.hoverTime || 750 /* Time */; | ||
let hoverTime = options.hoverTime || 600 /* Time */; | ||
return [ | ||
@@ -480,3 +496,14 @@ hoverState, | ||
} | ||
/** | ||
Returns true if any hover tooltips are currently active. | ||
*/ | ||
function hasHoverTooltips(state) { | ||
return state.facet(showHoverTooltip).some(x => x); | ||
} | ||
const closeHoverTooltipEffect = /*@__PURE__*/StateEffect.define(); | ||
/** | ||
Transaction effect that closes all hover tooltips. | ||
*/ | ||
const closeHoverTooltips = /*@__PURE__*/closeHoverTooltipEffect.of(null); | ||
export { hoverTooltip, showTooltip, tooltips }; | ||
export { closeHoverTooltips, hasHoverTooltips, hoverTooltip, showTooltip, tooltips }; |
{ | ||
"name": "@codemirror/tooltip", | ||
"version": "0.19.4", | ||
"version": "0.19.5", | ||
"description": "Tooltip support for the CodeMirror code editor", | ||
@@ -5,0 +5,0 @@ "scripts": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
49775
1121