@helping-ai-workflow/md2doc 3.17.1 → 3.17.3

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/lib/md2doc.js CHANGED
@@ -379,6 +379,9 @@ function renderEditModeList(listToken, blocks, biRef, out) {
379
379
  const check = b.task
380
380
  ? `<span class="ed-li-check" data-checked="${b.checked ? 1 : 0}" role="checkbox" aria-checked="${!!b.checked}"></span>`
381
381
  : '';
382
+ // v3.17.3 C10: an svg in the item's own text gets the same white plate
383
+ // in dark as a top-level svg block (the attribute is read by the dark CSS).
384
+ const svgPlate = ownTokens.some((tk) => /<svg[\s>]/i.test(String(tk.raw || ''))) ? ' data-svg-plate="1"' : '';
382
385
  const runStart = liRunStartsHere(biRef, b) ? ' data-run-start="1"' : '';
383
386
  const listStartAttr = listStart ? ' data-list-start="1"' : '';
384
387
  listStart = false;
@@ -389,7 +392,7 @@ function renderEditModeList(listToken, blocks, biRef, out) {
389
392
  parts.push(
390
393
  `<div class="ed-block" data-block-id="${b.id}" data-block-type="li"` +
391
394
  ` data-list-type="${b.listType}" data-task="${b.task ? 1 : 0}" data-indent="${b.indent}"` +
392
- runStart + listStartAttr + looseAttr + ` style="--ed-indent:${b.indent}">` +
395
+ runStart + listStartAttr + looseAttr + svgPlate + ` style="--ed-indent:${b.indent}">` +
393
396
  `<span class="ed-li-marker" aria-hidden="true"></span>` + check +
394
397
  `<div class="ed-li-text">${inner}</div>` +
395
398
  `</div>`
@@ -2767,6 +2770,7 @@ const html = `<!DOCTYPE html>
2767
2770
  border-radius: 3px;
2768
2771
  }
2769
2772
  mark.search-hit-block { display: block; }
2773
+ svg .svg-hit { stroke: var(--md-svg-hit); stroke-width: 6px; stroke-linejoin: round; paint-order: stroke; }
2770
2774
  .toc {
2771
2775
  display: flex;
2772
2776
  flex-direction: column;
@@ -4799,6 +4803,15 @@ ${mermaidInitTag}`)
4799
4803
  }
4800
4804
 
4801
4805
  const SKIP_SELECTOR = 'svg, .mermaid, .graphviz, script, style';
4806
+ // v3.17.3 C11: a Markdown-native inline svg is read (its text is in the
4807
+ // search index); a diagram's own svg (mermaid, graphviz, draw.io, WaveDrom,
4808
+ // a formula) is not. Inside a native svg every text node is walked, the
4809
+ // ones in its title and desc elements too: the index holds those as well
4810
+ // (the paragraph's text tokens between the html tags), so a query that
4811
+ // finds the section can find them here.
4812
+ function isNativeSvg(el) {
4813
+ return el.matches('svg') && !el.closest('.mermaid, .graphviz, .drawio, .katex, .code-block, [class*="wave"], [id^="WaveDrom"]');
4814
+ }
4802
4815
 
4803
4816
  function buildSnippet(section, query) {
4804
4817
  const haystack = section.searchText || section.title || '';
@@ -4845,6 +4858,7 @@ ${mermaidInitTag}`)
4845
4858
  ? readerState.activeHighlights
4846
4859
  : (readerState.activeHighlight ? [readerState.activeHighlight] : []);
4847
4860
  marks.forEach((mark) => {
4861
+ if (mark.namespaceURI === 'http://www.w3.org/2000/svg') { mark.classList.remove('svg-hit'); if (!mark.getAttribute('class')) mark.removeAttribute('class'); return; }
4848
4862
  const parent = mark.parentNode;
4849
4863
  if (!parent) return;
4850
4864
  while (mark.firstChild) parent.insertBefore(mark.firstChild, mark);
@@ -4975,7 +4989,8 @@ ${mermaidInitTag}`)
4975
4989
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {
4976
4990
  acceptNode(node) {
4977
4991
  if (node.nodeType === Node.ELEMENT_NODE) {
4978
- if (node.matches(SKIP_SELECTOR) || node.matches('.reader-sidebar, .heading-anchor, button')) return NodeFilter.FILTER_REJECT;
4992
+ if (node.matches(SKIP_SELECTOR) && !isNativeSvg(node)) return NodeFilter.FILTER_REJECT;
4993
+ if (node.matches('.reader-sidebar, .heading-anchor, button')) return NodeFilter.FILTER_REJECT;
4979
4994
  return node.matches('br, .katex') ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
4980
4995
  }
4981
4996
  if (!node.nodeValue) return NodeFilter.FILTER_REJECT;
@@ -5065,6 +5080,14 @@ ${mermaidInitTag}`)
5065
5080
  const marks = [];
5066
5081
  Array.from(spans.keys()).sort((a, b) => b - a).forEach((ni) => {
5067
5082
  const node = nodes[ni];
5083
+ // v3.17.3 C11: svg cannot hold a mark element; the text node's parent
5084
+ // (text or tspan) is flagged instead and painted by .svg-hit.
5085
+ if (node.nodeType === Node.TEXT_NODE && node.parentElement && node.parentElement.closest('svg')) {
5086
+ // Two text nodes can share one parent (a tspan or a comment splits it).
5087
+ node.parentElement.classList.add('svg-hit');
5088
+ if (marks.indexOf(node.parentElement) === -1) marks.unshift(node.parentElement);
5089
+ return;
5090
+ }
5068
5091
  const mark = document.createElement('mark');
5069
5092
  mark.className = 'search-hit is-selected';
5070
5093
  if (node.nodeType === Node.ELEMENT_NODE) {
@@ -34,6 +34,9 @@ const THEME_TOKENS = [
34
34
  { name: 'active-bg', light: ['#dbe6f3'], dark: '#24364f' },
35
35
  { name: 'hit-bg', light: ['#fff5c2'], dark: '#4d4417' },
36
36
  { name: 'mark-bg', light: ['#fde68a'], dark: '#6e5e14' },
37
+ // A search hit inside an inline svg is painted on the svg plate, which is white in both themes,
38
+ // so its halo is the same yellow in both (the dark mark-bg would read worse than no hit at all).
39
+ { name: 'svg-hit', light: ['#fde68a'], dark: '#fde68a', direct: true },
37
40
  { name: 'code', light: ['#b93a0c'], dark: '#ff9f70' },
38
41
  { name: 'accent-soft', light: ['#93c5fd'], dark: '#6ea8f5' },
39
42
  { name: 'error', light: ['#b91c1c'], dark: '#ff8a8a' },
@@ -165,7 +168,7 @@ function themeCss() {
165
168
  ' ' + D + ' .content .drawio { background: #ffffff; border-radius: 6px; box-shadow: 0 0 0 10px #ffffff; }',
166
169
  // R7 甲: a Markdown-native inline svg (wrapped in .inline-svg by the renderer) gets the
167
170
  // same white plate; its ink stays the light text colour because the plate is always white.
168
- ' ' + D + ' .content .inline-svg > svg, ' + D + ' .content .ed-block[data-svg-plate="1"] > svg, ' + D + ' .content .ed-block[data-svg-plate="1"] > p > svg { background: #ffffff; color: #1f2328; border-radius: 4px; box-shadow: 0 0 0 10px #ffffff; }',
171
+ ' ' + D + ' .content .inline-svg > svg, ' + D + ' .content .ed-block[data-svg-plate="1"] > svg, ' + D + ' .content .ed-block[data-svg-plate="1"] > p > svg, ' + D + ' .content .ed-block[data-svg-plate="1"] .ed-li-text > svg, ' + D + ' .content .ed-block[data-svg-plate="1"] .ed-li-text > p > svg { background: #ffffff; color: #1f2328; border-radius: 4px; box-shadow: 0 0 0 10px #ffffff; }',
169
172
  ' ' + D + ' .lightbox-canvas > svg[data-md2doc-recoloured] { background: var(--md-bg); }',
170
173
  ' }',
171
174
  ' .md2doc-theme-toggle { position: fixed; right: 20px; bottom: 20px; z-index: 60; width: 40px; height: 40px;',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helping-ai-workflow/md2doc",
3
- "version": "3.17.1",
3
+ "version": "3.17.3",
4
4
  "description": "Markdown → HTML / PDF renderer with WaveDrom, Mermaid, Graphviz, and draw.io support",
5
5
  "keywords": [
6
6
  "markdown",