TypeScript interfaces for implementing MIME renderer extensions in JupyterLab
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Core rendering interfaces for creating MIME renderers and factories that integrate with JupyterLab's rendering pipeline.
A widget that displays the contents of a MIME model. Must extend the Lumino Widget class and implement the renderModel method.
/**
* A widget which displays the contents of a mime model
*/
interface IRenderer extends Widget {
/**
* Render a mime model.
* This method may be called multiple times during the lifetime
* of the widget to update it if and when new data is available.
* @param model - The mime model to render
* @returns A promise which resolves when rendering is complete
*/
renderModel(model: IMimeModel): Promise<void>;
}Usage Example:
import { IRenderMime } from "@jupyterlab/rendermime-interfaces";
import { Widget } from "@lumino/widgets";
class CustomRenderer extends Widget implements IRenderMime.IRenderer {
async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
// Clear previous content
this.node.innerHTML = '';
// Extract data from the model
const data = model.data['application/my-custom-type'] as string;
// Create and append content
const content = document.createElement('div');
content.className = 'custom-content';
content.textContent = data;
// Apply trust-based styling
if (!model.trusted) {
content.style.border = '2px solid orange';
content.title = 'Untrusted content';
}
this.node.appendChild(content);
}
}Factory for creating renderer instances. Defines which MIME types can be handled and creates renderers with the appropriate options.
/**
* The interface for a renderer factory
*/
interface IRendererFactory {
/**
* Whether the factory is a "safe" factory.
* A "safe" factory produces renderer widgets which can render
* untrusted model data in a usable way. All renderers must
* handle untrusted data safely, but some may simply failover
* with a "Run cell to view output" message. A "safe" renderer
* is an indication that its sanitized output will be useful.
*/
readonly safe: boolean;
/** The mime types handled by this factory */
readonly mimeTypes: ReadonlyArray<string>;
/** The default rank of the factory. If not given, defaults to 100. */
readonly defaultRank?: number;
/**
* Create a renderer which displays the mime data
* @param options - The options used to render the data
*/
createRenderer(options: IRendererOptions): IRenderer;
}Usage Example:
import { IRenderMime } from "@jupyterlab/rendermime-interfaces";
class CustomRendererFactory implements IRenderMime.IRendererFactory {
readonly safe = true;
readonly mimeTypes = ['application/my-custom-type', 'text/my-format'];
readonly defaultRank = 50;
createRenderer(options: IRenderMime.IRendererOptions): IRenderMime.IRenderer {
return new CustomRenderer(options);
}
}
// Register with RenderMime
const factory = new CustomRendererFactory();
renderMime.addFactory(factory, factory.defaultRank);Options passed to renderer factories when creating new renderer instances. Contains all the services needed for rendering.
/**
* The options used to create a renderer
*/
interface IRendererOptions {
/** The preferred mimeType to render */
mimeType: string;
/** The html sanitizer */
sanitizer: ISanitizer;
/** An optional url resolver */
resolver: IResolver | null;
/** An optional link handler */
linkHandler: ILinkHandler | null;
/** The LaTeX typesetter */
latexTypesetter: ILatexTypesetter | null;
/** The Markdown parser */
markdownParser?: IMarkdownParser | null;
/** The application language translator */
translator?: ITranslator;
}Usage Example:
import { IRenderMime } from "@jupyterlab/rendermime-interfaces";
import { Widget } from "@lumino/widgets";
class AdvancedRenderer extends Widget implements IRenderMime.IRenderer {
constructor(private options: IRenderMime.IRendererOptions) {
super();
this.addClass('advanced-renderer');
}
async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
const data = model.data[this.options.mimeType] as string;
// Use sanitizer for HTML content
if (this.options.mimeType === 'text/html') {
const sanitized = this.options.sanitizer.sanitize(data);
this.node.innerHTML = sanitized;
}
// Use markdown parser if available
if (this.options.markdownParser && this.options.mimeType === 'text/markdown') {
const html = await this.options.markdownParser.render(data);
const sanitized = this.options.sanitizer.sanitize(html);
this.node.innerHTML = sanitized;
}
// Use LaTeX typesetter for math content
if (this.options.latexTypesetter) {
this.options.latexTypesetter.typeset(this.node);
}
// Handle links if link handler is available
if (this.options.linkHandler) {
const links = this.node.querySelectorAll('a');
links.forEach(link => {
const href = link.getAttribute('href');
if (href) {
this.options.linkHandler!.handleLink(link as HTMLElement, href);
}
});
}
// Use translator for internationalization
if (this.options.translator) {
const bundle = this.options.translator.load('my-renderer');
const title = bundle.__('Rendered Content');
this.node.title = title;
}
}
}All interfaces in this capability depend on several external types and interfaces:
// From @lumino/widgets
class Widget {
// Widget implementation from Lumino
}
// From other capabilities in this package
interface IMimeModel {
readonly trusted: boolean;
readonly data: ReadonlyPartialJSONObject;
readonly metadata: ReadonlyPartialJSONObject;
setData(options: IMimeModel.ISetDataOptions): void;
}
interface ISanitizer {
sanitize(dirty: string, options?: ISanitizerOptions): string;
getAutolink?(): boolean;
readonly allowNamedProperties?: boolean;
}
interface IResolver {
resolveUrl(url: string): Promise<string>;
getDownloadUrl(url: string): Promise<string>;
isLocal?(url: string, allowRoot?: boolean): boolean;
resolvePath?(path: string): Promise<IResolvedLocation | null>;
}
interface ILinkHandler {
handleLink(node: HTMLElement, path: string, id?: string): void;
handlePath?(node: HTMLElement, path: string, scope: 'kernel' | 'server', id?: string): void;
}
interface ILatexTypesetter {
typeset(element: HTMLElement): void;
}
interface IMarkdownParser {
render(source: string): Promise<string>;
}
interface ITranslator {
readonly languageCode: string;
load(domain: string): TranslationBundle;
}