Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## [22.0.0] - 2026-04-03

### Fixed
* Fix tooltip not being interactive: moving the mouse from a code token into its tooltip now keeps the tooltip open, allowing users to select and copy the tooltip text. [#949](https://github.com/fsprojects/FSharp.Formatting/issues/949)
* Fix spurious `'fsi' is not defined` error during literate script type-checking when scripts use `fsi.AddPrinter` or related APIs. The `FSharp.Compiler.Interactive.Settings.dll` reference is now explicitly added to the type-checker options. [#1139](https://github.com/fsprojects/FSharp.Formatting/issues/1139)
* Fix literate script comment parser prematurely closing `(**` blocks when the markdown text contained nested `(*** ... ***)` references (e.g. in backtick-quoted command examples), causing subsequent content to be silently dropped from HTML output.
* Add missing `[<Test>]` attribute on `Can include-output-and-it` test so it is executed by the test runner.
Expand Down
2 changes: 2 additions & 0 deletions docs/content/fsdocs-default.css
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,8 @@ div.fsdocs-tip:popover-open {
position: fixed;
inset: unset;
animation: fsdocs-tip-fade-in 120ms ease-out;
cursor: text;
user-select: text;
}

[data-fsdocs-tip] {
Expand Down
51 changes: 45 additions & 6 deletions docs/content/fsdocs-tips.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
let currentTip = null;
let currentTipElement = null;
let hideTimer = null;

function cancelHide() {
if (hideTimer !== null) {
clearTimeout(hideTimer);
hideTimer = null;
}
}

function hideTip(name) {
cancelHide();
const el = document.getElementById(name);
if (el) {
try { el.hidePopover(); } catch (_) { }
Expand All @@ -10,7 +19,16 @@ function hideTip(name) {
currentTipElement = null;
}

function scheduleHide(name) {
cancelHide();
hideTimer = setTimeout(() => {
hideTimer = null;
hideTip(name);
}, 150);
}

function showTip(evt, name, unique) {
cancelHide();
if (currentTip === unique) return;

// Hide the previously shown tooltip before showing the new one
Expand Down Expand Up @@ -52,10 +70,16 @@ function showTip(evt, name, unique) {
// Event delegation: trigger tooltips from data-fsdocs-tip attributes
document.addEventListener('mouseover', function (evt) {
const target = evt.target.closest('[data-fsdocs-tip]');
if (!target) return;
const name = target.dataset.fsdocsTip;
const unique = parseInt(target.dataset.fsdocsTipUnique, 10);
showTip(evt, name, unique);
if (target) {
const name = target.dataset.fsdocsTip;
const unique = parseInt(target.dataset.fsdocsTipUnique, 10);
showTip(evt, name, unique);
return;
}
// Cancel pending hide if mouse enters the tooltip itself
if (evt.target.closest('.fsdocs-tip[popover]')) {
cancelHide();
}
});

document.addEventListener('mouseout', function (evt) {
Expand All @@ -64,8 +88,23 @@ document.addEventListener('mouseout', function (evt) {
// Only hide when the mouse has left the trigger element entirely
if (target.contains(evt.relatedTarget)) return;
const name = target.dataset.fsdocsTip;
const unique = parseInt(target.dataset.fsdocsTipUnique, 10);
hideTip(name);
// Don't hide if the mouse is moving directly into the tooltip itself
const el = document.getElementById(name);
if (el && el.contains(evt.relatedTarget)) return;
// Use a short delay so the mouse has time to cross any gap between trigger and tooltip
scheduleHide(name);
});

// Hide the tooltip when the mouse leaves the tooltip element itself
document.addEventListener('mouseout', function (evt) {
const tip = evt.target.closest('.fsdocs-tip[popover]');
if (!tip) return;
// Stay open while the mouse remains inside the tooltip
if (tip.contains(evt.relatedTarget)) return;
// Stay open if the mouse returns to the trigger element
const trigger = document.querySelector(`[data-fsdocs-tip="${tip.id}"]`);
if (trigger && trigger.contains(evt.relatedTarget)) return;
scheduleHide(tip.id);
});

function Clipboard_CopyTo(value) {
Expand Down