Render markdown in JS Field (v2.1.10)

RunJS render error
ctx.useComponent is not a function. (In ‘ctx.useComponent(‘Markdown’)’, ‘ctx.useComponent’ is undefined)

…is the result when I try to render markdown in a JS Field using this:
function JsReadonlyField() {
const React = ctx.React;
const { prefix, suffix, overflowMode } = ctx.model?.props || {};

// Internal NocoBase markdown component???
const Markdown = ctx.useComponent(‘Markdown’);

if (Markdown) {
return {ctx.value};
}

// Fallback: Plain Text
const text = String(ctx.value ?? ‘’);
const whiteSpace = overflowMode === ‘wrap’ ? ‘pre-line’ : ‘nowrap’;
return (
<span style={{ whiteSpace }}>
{prefix}
{text}
{suffix}

);
}

ctx.render();

Any idea how I can make this work?

Solutions:

  1. First choice: Avoid using JS Fields to call internal Markdown components; use Markdown fields or Markdown blocks directly.
  2. If you must render Markdown within a JS Field, use the publicly supported ctx.render(...) to generate the HTML yourself. ctx.render(string) will use the cleanup logic of ElementProxy.innerHTML.
function escapeHtml(value) {
  return String(value ?? '').replace(/[&<>"']/g, (ch) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
  }[ch]));
}

function renderInline(value) {
  return escapeHtml(value)
    .replace(/`([^`]+)`/g, '<code>$1</code>')
    .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
    .replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
}

function renderMarkdown(value) {
  const html = [];
  for (const line of String(value ?? '').split(/\r?\n/)) {
    if (!line.trim()) continue;
    const heading = line.match(/^(#{1,6})\s+(.+)$/);
    if (heading) {
      const level = heading[1].length;
      html.push(`<h${level}>${renderInline(heading[2])}</h${level}>`);
    } else {
      html.push(`<p>${renderInline(line)}</p>`);
    }
  }
  return `<div class="nb-markdown">${html.join('')}</div>`;
}

ctx.render(renderMarkdown(ctx.value));