diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b0933fcc..74d90639 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,6 +2,9 @@ ## [Unreleased] +### Refactored +* Split `MarkdownParser.fs` (1500 lines) into `MarkdownInlineParser.fs` (inline formatting) and `MarkdownParser.fs` (block-level parsing) for better maintainability. [#1022](https://github.com/fsprojects/FSharp.Formatting/issues/1022) + ### Added * Add `dotnet fsdocs convert` command to convert a single `.md`, `.fsx`, or `.ipynb` file to HTML (or another output format) without building a full documentation site. [#811](https://github.com/fsprojects/FSharp.Formatting/issues/811) * `fsdocs convert` now accepts the input file as a positional argument (e.g. `fsdocs convert notebook.ipynb -o notebook.html`). [#1019](https://github.com/fsprojects/FSharp.Formatting/pull/1019) @@ -9,7 +12,9 @@ * `fsdocs convert` now accepts `-o` as a shorthand for `--output`. [#1019](https://github.com/fsprojects/FSharp.Formatting/pull/1019) ### Changed +* Tooltip elements (`div.fsdocs-tip`) now use the [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) when available (Baseline 2024). This places tooltips in the browser's top layer, ensuring they always render above overlapping content without relying on `z-index`. Also fixes a positioning bug where tooltips would appear offset when the page was scrolled. Falls back to the previous `display` toggle approach in browsers without Popover API support. [#422](https://github.com/fsprojects/FSharp.Formatting/issues/422) * When no template is provided (e.g. `fsdocs convert` without `--template`), `fsdocs-tip` tooltip divs are no longer included in the output. Tooltips require JavaScript/CSS from a template to function, so omitting them produces cleaner raw output. [#1019](https://github.com/fsprojects/FSharp.Formatting/pull/1019) + ## 22.0.0-alpha.1 - 2026-03-03 ### Added diff --git a/docs/content/fsdocs-default.css b/docs/content/fsdocs-default.css index 6a91c57e..6d79e466 100644 --- a/docs/content/fsdocs-default.css +++ b/docs/content/fsdocs-default.css @@ -993,12 +993,18 @@ div.fsdocs-tip { font-variant-ligatures: none; color: var(--code-color); box-shadow: 0 1px 1px var(--shadow-color); + margin: 0; & code { color: var(--code-color); } } +/* When using the Popover API, the browser adds :popover-open when shown */ +div.fsdocs-tip:popover-open { + display: block; +} + span[onmouseout] { cursor: pointer; } diff --git a/docs/content/fsdocs-tips.js b/docs/content/fsdocs-tips.js index 87388253..1803f8c7 100644 --- a/docs/content/fsdocs-tips.js +++ b/docs/content/fsdocs-tips.js @@ -3,17 +3,35 @@ let currentTipElement = null; function hideTip(evt, name, unique) { const el = document.getElementById(name); - el.style.display = "none"; + if (el) { + if (el.hidePopover) { + try { el.hidePopover(); } catch (_) { } + } else { + el.style.display = "none"; + } + } currentTip = null; + currentTipElement = null; } function hideUsingEsc(e) { - hideTip(e, currentTipElement, currentTip); + if (currentTipElement) { + hideTip(e, currentTipElement, currentTip); + } } function showTip(evt, name, unique, owner) { document.onkeydown = hideUsingEsc; if (currentTip === unique) return; + + // Hide the previously shown tooltip (for non-auto-popover fallback path) + if (currentTipElement !== null) { + const prev = document.getElementById(currentTipElement); + if (prev && !prev.showPopover) { + prev.style.display = "none"; + } + } + currentTip = unique; currentTipElement = name; @@ -22,25 +40,31 @@ function showTip(evt, name, unique, owner) { let y = evt.clientY + offset; const el = document.getElementById(name); - el.style.position = "absolute"; - el.style.display = "block"; - el.style.left = `${x}px`; - el.style.top = `${y}px`; const maxWidth = document.documentElement.clientWidth - x - 16; el.style.maxWidth = `${maxWidth}px`; + el.style.left = `${x}px`; + el.style.top = `${y}px`; + + if (el.showPopover) { + // Popover API path: element is placed in the top layer with fixed positioning + el.style.position = "fixed"; + el.showPopover(); + } else { + // Fallback for browsers without Popover API support + el.style.position = "absolute"; + el.style.display = "block"; + } - const rect = el.getBoundingClientRect(); - // Move tooltip if it is out of sight - if(rect.bottom > window.innerHeight) { + const rect = el.getBoundingClientRect(); + // Move tooltip if it would appear outside the viewport + if (rect.bottom > window.innerHeight) { y = y - el.clientHeight - offset; el.style.top = `${y}px`; } - if (rect.right > window.innerWidth) { - x = y - el.clientWidth - offset; + x = x - el.clientWidth - offset; el.style.left = `${x}px`; - const maxWidth = document.documentElement.clientWidth - x - 16; - el.style.maxWidth = `${maxWidth}px`; + el.style.maxWidth = `${document.documentElement.clientWidth - x - 16}px`; } } @@ -60,4 +84,4 @@ function Clipboard_CopyTo(value) { window.showTip = showTip; window.hideTip = hideTip; // Used by API documentation -window.Clipboard_CopyTo = Clipboard_CopyTo; \ No newline at end of file +window.Clipboard_CopyTo = Clipboard_CopyTo; diff --git a/src/FSharp.Formatting.CodeFormat/HtmlFormatting.fs b/src/FSharp.Formatting.CodeFormat/HtmlFormatting.fs index 307406ab..fb94745a 100644 --- a/src/FSharp.Formatting.CodeFormat/HtmlFormatting.fs +++ b/src/FSharp.Formatting.CodeFormat/HtmlFormatting.fs @@ -59,7 +59,7 @@ type ToolTipFormatter(prefix) = /// Returns all generated tool tip elements member x.WriteTipElements(writer: TextWriter) = for (KeyValue(_, (index, html))) in tips do - writer.WriteLine(sprintf "