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:
- First choice: Avoid using JS Fields to call internal Markdown components; use Markdown fields or Markdown blocks directly.
- 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) => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
}[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));