@helping-ai-workflow/md2doc 2.4.1 → 2.4.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.
Files changed (2) hide show
  1. package/lib/md2doc.js +77 -0
  2. package/package.json +2 -2
package/lib/md2doc.js CHANGED
@@ -1868,6 +1868,83 @@ ${mermaidInitTag}` : ''}
1868
1868
  setSidebarOpen(false);
1869
1869
  }
1870
1870
  });
1871
+
1872
+ // ── Zoom / resize scroll anchoring ────────────────────────────────────────
1873
+ // Browser zoom (and any window resize) reflows the column but leaves the
1874
+ // pixel scroll offset untouched, so the passage being read slides out of
1875
+ // view. Remember what sat at the top of the reading column and put it back.
1876
+ var ANCHOR_LINE = 80;
1877
+ var contentEl = document.querySelector('main.content');
1878
+ var anchorNode = null;
1879
+ var anchorTop = 0;
1880
+ var anchorFrame = 0;
1881
+ var suppressAnchorCapture = false;
1882
+ var lastLayoutWidth = document.documentElement.clientWidth;
1883
+ var lastPixelRatio = window.devicePixelRatio;
1884
+
1885
+ function captureScrollAnchor() {
1886
+ if (suppressAnchorCapture || !contentEl) return;
1887
+ var rect = contentEl.getBoundingClientRect();
1888
+ var hit = document.elementFromPoint(rect.left + rect.width / 2, ANCHOR_LINE);
1889
+ var node = (hit && hit.closest) ? hit.closest('main.content > *') : null;
1890
+ if (!node) {
1891
+ // Between blocks, or over a gap: fall back to the last heading above the
1892
+ // anchor line. Heading offsets are monotonic in document order, so this
1893
+ // is a binary search rather than a scan of every heading each frame.
1894
+ var lo = 0;
1895
+ var hi = headingNodes.length - 1;
1896
+ while (lo <= hi) {
1897
+ var mid = (lo + hi) >> 1;
1898
+ if (headingNodes[mid].getBoundingClientRect().top <= ANCHOR_LINE) {
1899
+ node = headingNodes[mid];
1900
+ lo = mid + 1;
1901
+ } else {
1902
+ hi = mid - 1;
1903
+ }
1904
+ }
1905
+ }
1906
+ if (!node) return;
1907
+ anchorNode = node;
1908
+ anchorTop = node.getBoundingClientRect().top;
1909
+ }
1910
+
1911
+ function restoreScrollAnchor() {
1912
+ if (!anchorNode || !anchorNode.isConnected) return;
1913
+ var delta = anchorNode.getBoundingClientRect().top - anchorTop;
1914
+ if (!delta) return;
1915
+ window.scrollTo(window.scrollX, window.scrollY + delta);
1916
+ }
1917
+
1918
+ window.addEventListener('scroll', function () {
1919
+ if (anchorFrame) return;
1920
+ anchorFrame = window.requestAnimationFrame(function () {
1921
+ anchorFrame = 0;
1922
+ captureScrollAnchor();
1923
+ });
1924
+ }, { passive: true });
1925
+
1926
+ window.addEventListener('resize', function () {
1927
+ var width = document.documentElement.clientWidth;
1928
+ var ratio = window.devicePixelRatio;
1929
+ // A height-only change (a mobile browser hiding its toolbar, a devtools
1930
+ // dock) reflows nothing, so correcting the scroll would only jerk the page.
1931
+ if (width === lastLayoutWidth && ratio === lastPixelRatio) return;
1932
+ lastLayoutWidth = width;
1933
+ lastPixelRatio = ratio;
1934
+ // Hold the anchor across the whole reflow: the scrollTo below fires scroll
1935
+ // events that would otherwise re-capture a mid-reflow position.
1936
+ suppressAnchorCapture = true;
1937
+ restoreScrollAnchor();
1938
+ window.requestAnimationFrame(function () {
1939
+ restoreScrollAnchor();
1940
+ window.requestAnimationFrame(function () {
1941
+ suppressAnchorCapture = false;
1942
+ captureScrollAnchor();
1943
+ });
1944
+ });
1945
+ });
1946
+
1947
+ captureScrollAnchor();
1871
1948
  })();
1872
1949
  </script>
1873
1950
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helping-ai-workflow/md2doc",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "Markdown → HTML / PDF renderer with WaveDrom, Mermaid, and Graphviz support",
5
5
  "keywords": [
6
6
  "markdown",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "scripts": {
38
38
  "preinstall": "node scripts/preinstall.js",
39
- "test": "node test/md2doc.test.js && node test/images.test.js && node test/cli.test.js && node test/code-operator.test.js"
39
+ "test": "node test/md2doc.test.js && node test/images.test.js && node test/scroll-anchor.test.js && node test/cli.test.js && node test/code-operator.test.js"
40
40
  },
41
41
  "repository": {
42
42
  "type": "git",