From 6eea92e31df7516fa16fe45e8d993ae967cd943b Mon Sep 17 00:00:00 2001 From: Steve Purves Date: Wed, 31 May 2023 16:38:33 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=B4external=20rendermime=20management?= =?UTF-8?q?=20(#632)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🪴external rendermime means users explititly set their rendermime boundary 👏 * 📄changeset --- .changeset/tasty-ducks-scream.md | 9 ++++++ _build/templates/site/myst/book-theme | 1 + apps/demo-core/src/app.ts | 6 +++- apps/demo-core/static/index.html | 2 +- apps/demo-react/src/NotebookPage.tsx | 10 +++--- packages/core/src/cell.ts | 2 -- packages/core/src/manager.ts | 30 +++++------------ packages/core/src/notebook.ts | 11 +++---- packages/core/src/passive.ts | 4 +-- packages/core/src/rendermime.ts | 2 +- packages/core/src/server.ts | 20 +++++++----- packages/core/src/session.ts | 9 ++++-- packages/core/src/thebe/api.ts | 23 ++++++++++--- packages/core/src/thebe/entrypoint.ts | 14 ++++++-- packages/core/src/types.ts | 1 + .../src/ThebeRenderMimeRegistryProvider.tsx | 32 +++++++++++++++++++ packages/react/src/ThebeSessionProvider.tsx | 4 ++- packages/react/src/hooks/notebook.ts | 10 +++++- packages/react/src/index.ts | 1 + packages/thebe/src/thebe.ts | 12 +++++-- turbo.json | 4 +-- 21 files changed, 143 insertions(+), 64 deletions(-) create mode 100644 .changeset/tasty-ducks-scream.md create mode 160000 _build/templates/site/myst/book-theme create mode 100644 packages/react/src/ThebeRenderMimeRegistryProvider.tsx diff --git a/.changeset/tasty-ducks-scream.md b/.changeset/tasty-ducks-scream.md new file mode 100644 index 00000000..e2bc3c85 --- /dev/null +++ b/.changeset/tasty-ducks-scream.md @@ -0,0 +1,9 @@ +--- +'demo-react': minor +'demo-core': minor +'thebe-react': minor +'thebe-core': minor +'thebe': patch +--- + +Made changes to the `thebe-core` APIs to make rendermime registries external, the caller now has to manage how registries are used across the other session nd notebook object. Updates the demos, `thebe` and `thebe-react` to reflect this base change. `thebe-react` now has a new provider making it easy to add a rendermine registry in the component tree. diff --git a/_build/templates/site/myst/book-theme b/_build/templates/site/myst/book-theme new file mode 160000 index 00000000..df9cbcd1 --- /dev/null +++ b/_build/templates/site/myst/book-theme @@ -0,0 +1 @@ +Subproject commit df9cbcd11841914648d7608aca94475ad246bc8a diff --git a/apps/demo-core/src/app.ts b/apps/demo-core/src/app.ts index e6725262..dd44c7c3 100644 --- a/apps/demo-core/src/app.ts +++ b/apps/demo-core/src/app.ts @@ -1,5 +1,6 @@ import type { ThebeSession } from 'thebe-core'; import { + makeRenderMimeRegistry, ThebeEvents, ThebeEventType, shortId, @@ -216,7 +217,9 @@ class App { await this.server?.connectToJupyterServer(); } - this.session = await this.server.startNewSession(); + const rendermime = makeRenderMimeRegistry(this.server.config.mathjax); + + this.session = await this.server.startNewSession(rendermime); this.notebook = ThebeNotebook.fromCodeBlocks( code[this.exampleType].map((source) => ({ @@ -224,6 +227,7 @@ class App { source, })), this.server.config, + rendermime, ); if (this.session == null) console.error('could not start session'); diff --git a/apps/demo-core/static/index.html b/apps/demo-core/static/index.html index 53facfcb..552fbeb5 100644 --- a/apps/demo-core/static/index.html +++ b/apps/demo-core/static/index.html @@ -20,7 +20,7 @@ src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-MML-AM_CHTML" > - + ) { const { ready } = useThebeServer(); if (!ready) return null; return ( - - {children} - + + + {children} + + ); } diff --git a/packages/core/src/cell.ts b/packages/core/src/cell.ts index 11772be8..14b5aff7 100644 --- a/packages/core/src/cell.ts +++ b/packages/core/src/cell.ts @@ -71,7 +71,6 @@ class ThebeCell extends PassiveCellRenderer implements IThebeCell { * @param session */ attachSession(session: ThebeSession) { - session.manager.addWidgetFactories(this.rendermime); this.session = session; this.events.triggerStatus({ status: CellStatusEvent.attached, @@ -85,7 +84,6 @@ class ThebeCell extends PassiveCellRenderer implements IThebeCell { * */ detachSession() { - this.session?.manager.removeWidgetFactories(this.rendermime); this.session = undefined; this.events.triggerStatus({ status: CellStatusEvent.detached, diff --git a/packages/core/src/manager.ts b/packages/core/src/manager.ts index b5b6897b..d9a52bc2 100644 --- a/packages/core/src/manager.ts +++ b/packages/core/src/manager.ts @@ -1,5 +1,4 @@ import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { RenderMimeRegistry, standardRendererFactories } from '@jupyterlab/rendermime'; import type { IKernelConnection } from '@jupyterlab/services/lib/kernel/kernel'; import type { Widget } from '@lumino/widgets'; @@ -26,34 +25,21 @@ export class ThebeManager extends KernelWidgetManager { id: string; _loader: RequireJsLoader; - constructor(kernel: IKernelConnection, rendermime?: IRenderMimeRegistry) { - const rm = - rendermime ?? - new RenderMimeRegistry({ - initialFactories: standardRendererFactories, - }); + constructor(kernel: IKernelConnection, rendermime: IRenderMimeRegistry) { + super(kernel, rendermime); + this.id = shortId(); /** ensure this registry always gets the widget renderer. * This is essential for cases where widgets are rendered heirarchically */ - rm.addFactory( - { - safe: false, - mimeTypes: [WIDGET_MIMETYPE], - createRenderer: (options) => new WidgetRenderer(options, this as any), - }, - 1, - ); + this.addWidgetFactories(); - super(kernel, rm); - - this.id = shortId(); this._registerWidgets(); this._loader = new RequireJsLoader(); } - addWidgetFactories(rendermime: IRenderMimeRegistry) { - rendermime.addFactory( + addWidgetFactories() { + this.rendermime.addFactory( { safe: false, mimeTypes: [WIDGET_MIMETYPE], @@ -63,8 +49,8 @@ export class ThebeManager extends KernelWidgetManager { ); } - removeWidgetFactories(rendermime: IRenderMimeRegistry) { - rendermime.removeMimeType(WIDGET_MIMETYPE); + removeWidgetFactories() { + this.rendermime.removeMimeType(WIDGET_MIMETYPE); } /** diff --git a/packages/core/src/notebook.ts b/packages/core/src/notebook.ts index 66103212..432d0c43 100644 --- a/packages/core/src/notebook.ts +++ b/packages/core/src/notebook.ts @@ -3,7 +3,6 @@ import type ThebeSession from './session'; import type { IThebeCell, IThebeCellExecuteReturn } from './types'; import { shortId } from './utils'; import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; -import { getRenderMimeRegistry } from './rendermime'; import type { Config } from './config'; import { EventSubject, NotebookStatusEvent } from './events'; import { EventEmitter } from './emitter'; @@ -24,16 +23,16 @@ class ThebeNotebook { session?: ThebeSession; protected events: EventEmitter; - constructor(id: string, config: Config, rendermime?: IRenderMimeRegistry) { + constructor(id: string, config: Config, rendermime: IRenderMimeRegistry) { this.id = id; this.events = new EventEmitter(id, config, EventSubject.notebook, this); this.cells = []; this.metadata = {}; - this.rendermime = rendermime ?? getRenderMimeRegistry(config.mathjax); + this.rendermime = rendermime; console.debug('thebe:notebook constructor', this); } - static fromCodeBlocks(blocks: CodeBlock[], config: Config, rendermime?: IRenderMimeRegistry) { + static fromCodeBlocks(blocks: CodeBlock[], config: Config, rendermime: IRenderMimeRegistry) { const id = shortId(); const notebook = new ThebeNotebook(id, config, rendermime); notebook.cells = blocks.map((c) => { @@ -46,7 +45,7 @@ class ThebeNotebook { return notebook; } - static fromIpynb(ipynb: INotebookContent, config: Config, rendermime?: IRenderMimeRegistry) { + static fromIpynb(ipynb: INotebookContent, config: Config, rendermime: IRenderMimeRegistry) { const notebook = new ThebeNotebook(shortId(), config, rendermime); Object.assign(notebook.metadata, ipynb.metadata); @@ -119,7 +118,6 @@ class ThebeNotebook { // note all cells in a notebook share the rendermime registry // we only need to add the widgets factory once this.session = session; - session.manager.addWidgetFactories(this.rendermime); this.cells?.forEach((cell) => (cell.session = session)); this.events.triggerStatus({ status: NotebookStatusEvent.attached, @@ -128,7 +126,6 @@ class ThebeNotebook { } detachSession() { - this.session?.manager.removeWidgetFactories(this.rendermime); this.cells?.map((cell) => (cell.session = undefined)); this.session = undefined; this.events.triggerStatus({ diff --git a/packages/core/src/passive.ts b/packages/core/src/passive.ts index 75932c51..fba9db44 100644 --- a/packages/core/src/passive.ts +++ b/packages/core/src/passive.ts @@ -1,5 +1,5 @@ import type * as nbformat from '@jupyterlab/nbformat'; -import { getRenderMimeRegistry } from './rendermime'; +import { makeRenderMimeRegistry } from './rendermime'; import { OutputArea, OutputAreaModel } from '@jupyterlab/outputarea'; import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import type { IPassiveCell, MathjaxOptions } from './types'; @@ -49,7 +49,7 @@ class PassiveCellRenderer implements IPassiveCell { constructor(id: string, rendermime?: IRenderMimeRegistry, mathjax?: MathjaxOptions) { this.id = id; - this.rendermime = rendermime ?? getRenderMimeRegistry(mathjax ?? makeMathjaxOptions()); + this.rendermime = rendermime ?? makeRenderMimeRegistry(mathjax ?? makeMathjaxOptions()); this.model = new OutputAreaModel({ trusted: true }); this.area = new OutputArea({ model: this.model, diff --git a/packages/core/src/rendermime.ts b/packages/core/src/rendermime.ts index 3e69145c..21a1cfee 100644 --- a/packages/core/src/rendermime.ts +++ b/packages/core/src/rendermime.ts @@ -55,7 +55,7 @@ export function getRenderers(mathjax: MathjaxOptions) { }; } -export function getRenderMimeRegistry(mathjax?: MathjaxOptions) { +export function makeRenderMimeRegistry(mathjax?: MathjaxOptions) { const rendermime = new RenderMimeRegistry(getRenderers(mathjax ?? makeMathjaxOptions())); rendermime.addFactory(jsonRendererFactory, 10); return rendermime; diff --git a/packages/core/src/server.ts b/packages/core/src/server.ts index 6dbeefc8..21e53d3c 100644 --- a/packages/core/src/server.ts +++ b/packages/core/src/server.ts @@ -6,10 +6,14 @@ import type { ServerSettings, SessionIModel, } from './types'; +import type { Config } from './config'; +import type { ServiceManager } from '@jupyterlab/services'; +import type { LiteServerConfig } from 'thebe-lite'; +import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; +import type { StatusEvent } from './events'; import { RepoProvider } from './types'; import { makeGitHubUrl, makeGitLabUrl, makeGitUrl } from './url'; import { getExistingServer, makeStorageKey, saveServerInfo } from './sessions'; -import type { ServiceManager } from '@jupyterlab/services'; import { KernelManager, KernelSpecAPI, @@ -17,12 +21,9 @@ import { SessionManager, } from '@jupyterlab/services'; import ThebeSession from './session'; -import type { Config } from './config'; import { shortId } from './utils'; -import type { StatusEvent } from './events'; import { ServerStatusEvent, EventSubject, ErrorStatusEvent } from './events'; import { EventEmitter } from './emitter'; -import { LiteServerConfig } from 'thebe-lite'; async function responseToJson(res: Response) { if (!res.ok) throw Error(`${res.status} - ${res.statusText}`); @@ -79,7 +80,10 @@ class ThebeServer implements ServerRuntime, ServerRestAPI { this._isDisposed = true; } - async startNewSession(kernelOptions?: KernelOptions): Promise { + async startNewSession( + rendermime: IRenderMimeRegistry, + kernelOptions?: KernelOptions, + ): Promise { await this.ready; if (!this.sessionManager?.isReady) { @@ -96,7 +100,7 @@ class ThebeServer implements ServerRuntime, ServerRestAPI { }, }); - return new ThebeSession(this, connection); + return new ThebeSession(this, connection, rendermime); } async listRunningSessions(): Promise { @@ -116,7 +120,7 @@ class ThebeServer implements ServerRuntime, ServerRestAPI { return this.listRunningSessions(); } - async connectToExistingSession(model: SessionIModel) { + async connectToExistingSession(model: SessionIModel, rendermime: IRenderMimeRegistry) { await this.ready; if (!this.sessionManager?.isReady) { throw Error('Requesting session from a server, with no SessionManager available'); @@ -124,7 +128,7 @@ class ThebeServer implements ServerRuntime, ServerRestAPI { const connection = this.sessionManager?.connectTo({ model }); - return new ThebeSession(this, connection); + return new ThebeSession(this, connection, rendermime); } async clearSavedBinderSessions() { diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index 5f489aca..6d760406 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -3,6 +3,7 @@ import { EventSubject, SessionStatusEvent } from './events'; import { ThebeManager } from './manager'; import type ThebeServer from './server'; import { EventEmitter } from './emitter'; +import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; class ThebeSession { readonly server: ThebeServer; @@ -11,13 +12,17 @@ class ThebeSession { private connection: ISessionConnection; private events: EventEmitter; - constructor(server: ThebeServer, connection: ISessionConnection) { + constructor( + server: ThebeServer, + connection: ISessionConnection, + rendermime: IRenderMimeRegistry, + ) { this.server = server; this.connection = connection; this.events = new EventEmitter(this.connection.id, server.config, EventSubject.session, this); if (this.connection.kernel == null) throw Error('ThebeSession - kernel is null'); - this.manager = new ThebeManager(this.connection.kernel); + this.manager = new ThebeManager(this.connection.kernel, rendermime); this.events.triggerStatus({ status: SessionStatusEvent.ready, diff --git a/packages/core/src/thebe/api.ts b/packages/core/src/thebe/api.ts index 1f516a76..2140ccbb 100644 --- a/packages/core/src/thebe/api.ts +++ b/packages/core/src/thebe/api.ts @@ -3,8 +3,11 @@ import type { CodeBlock } from '../notebook'; import ThebeNotebook from '../notebook'; import type { INotebookContent } from '@jupyterlab/nbformat'; import type { Config } from '..'; -import { makeConfiguration, ThebeEvents } from '..'; +import { ThebeEvents } from '../events'; +import { makeConfiguration } from '../options'; +import { makeRenderMimeRegistry } from '../rendermime'; import * as coreModule from '../index'; +import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; export function connectToBinder(config: Config): ThebeServer { const server: ThebeServer = new ThebeServer(config); @@ -35,21 +38,31 @@ export function makeServer(config: Config) { return new ThebeServer(config); } -export function setupNotebookFromBlocks(blocks: CodeBlock[], config: Config) { - return ThebeNotebook.fromCodeBlocks(blocks, config); +export function setupNotebookFromBlocks( + blocks: CodeBlock[], + config: Config, + rendermime: IRenderMimeRegistry, +) { + return ThebeNotebook.fromCodeBlocks(blocks, config, rendermime); } -export function setupNotebookFromIpynb(ipynb: INotebookContent, config: Config) { - return ThebeNotebook.fromIpynb(ipynb, config); +export function setupNotebookFromIpynb( + ipynb: INotebookContent, + config: Config, + rendermime: IRenderMimeRegistry, +) { + return ThebeNotebook.fromIpynb(ipynb, config, rendermime); } export function setupThebeCore() { + console.log(`thebe:api:setupThebeCore`, { coreModule }); window.thebeCore = Object.assign(window.thebeCore ?? {}, { module: coreModule, api: { makeConfiguration, makeEvents, makeServer, + makeRenderMimeRegistry, connectToBinder, connectToJupyter, connectToJupyterLite, diff --git a/packages/core/src/thebe/entrypoint.ts b/packages/core/src/thebe/entrypoint.ts index 5ac3f522..33d77891 100644 --- a/packages/core/src/thebe/entrypoint.ts +++ b/packages/core/src/thebe/entrypoint.ts @@ -13,6 +13,7 @@ import type { ThebeEvents } from '../events'; import type { ThebeLiteGlobal } from 'thebe-lite'; import type * as coreModule from '../index'; import type { INotebookContent } from '@jupyterlab/nbformat'; +import type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { setupThebeCore } from './api'; /** @@ -24,11 +25,20 @@ export interface JsApi { makeEvents: () => ThebeEvents; makeConfiguration: (options: Partial, events?: ThebeEvents) => Config; makeServer: (config: Config) => ThebeServer; + makeRenderMimeRegistry: (mathjax?: coreModule.MathjaxOptions | undefined) => IRenderMimeRegistry; connectToBinder: (config: Config) => ThebeServer; connectToJupyter: (config: Config) => ThebeServer; connectToJupyterLite: (config: Config) => ThebeServer; - setupNotebookFromBlocks: (blocks: CodeBlock[], config: Config) => ThebeNotebook; - setupNotebookFromIpynb: (ipynb: INotebookContent, config: Config) => ThebeNotebook; + setupNotebookFromBlocks: ( + blocks: CodeBlock[], + config: Config, + rendermime: IRenderMimeRegistry, + ) => ThebeNotebook; + setupNotebookFromIpynb: ( + ipynb: INotebookContent, + config: Config, + rendermime: IRenderMimeRegistry, + ) => ThebeNotebook; } export type ThebeCore = typeof coreModule; diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index c8d82307..2d2a4dc6 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -9,6 +9,7 @@ export type JsonObject = Record; export type SessionIModel = Session.IModel; export type KernelISpecModels = KernelSpecAPI.ISpecModels; export type KernelISpecModel = KernelSpecAPI.ISpecModel; +export type { IRenderMimeRegistry } from '@jupyterlab/rendermime'; export interface ServerInfo { id: string; diff --git a/packages/react/src/ThebeRenderMimeRegistryProvider.tsx b/packages/react/src/ThebeRenderMimeRegistryProvider.tsx new file mode 100644 index 00000000..e8f972e1 --- /dev/null +++ b/packages/react/src/ThebeRenderMimeRegistryProvider.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import type { IRenderMimeRegistry } from 'thebe-core'; +import { useThebeCore } from './ThebeCoreProvider'; +import { useThebeConfig } from './ThebeServerProvider'; + +const RenderMimeRegistryContext = React.createContext< + { rendermime: IRenderMimeRegistry } | undefined +>(undefined); + +/* future: could allow for renderer configuration here */ +export function ThebeRenderMimeRegistryProvider({ children }: React.PropsWithChildren) { + const { core } = useThebeCore(); + const { config } = useThebeConfig(); + const rendermime = React.useMemo( + () => core?.makeRenderMimeRegistry(config?.mathjax) as IRenderMimeRegistry, + [core, config], + ); + + return ( + + {children} + + ); +} + +export function useRenderMimeRegistry() { + const context = React.useContext(RenderMimeRegistryContext); + if (context === undefined) { + throw new Error('useRenderMimeRegistry must be used within a ThebeRenderMimeRegistry'); + } + return context.rendermime; +} diff --git a/packages/react/src/ThebeSessionProvider.tsx b/packages/react/src/ThebeSessionProvider.tsx index f4e6b09a..a1e9a2f8 100644 --- a/packages/react/src/ThebeSessionProvider.tsx +++ b/packages/react/src/ThebeSessionProvider.tsx @@ -1,6 +1,7 @@ import React, { useContext, useEffect, useState } from 'react'; import type { ThebeSession } from 'thebe-core'; import { useThebeServer } from './ThebeServerProvider'; +import { useRenderMimeRegistry } from './ThebeRenderMimeRegistryProvider'; interface ThebeSessionContextData { name: string; @@ -27,6 +28,7 @@ export function ThebeSessionProvider({ shutdownOnUnmount?: boolean; }>) { const { config, server, ready: serverReady } = useThebeServer(); + const rendermime = useRenderMimeRegistry(); const [starting, setStarting] = useState(false); const [session, setSession] = useState(); @@ -36,7 +38,7 @@ export function ThebeSessionProvider({ const startSession = () => { setStarting(true); server - ?.startNewSession({ ...config?.kernels, name, path: name }) + ?.startNewSession(rendermime, { ...config?.kernels, name, path: name }) .then((sesh: ThebeSession | null) => { setStarting(false); if (sesh == null) { diff --git a/packages/react/src/hooks/notebook.ts b/packages/react/src/hooks/notebook.ts index 6409ade4..e9b7a76e 100644 --- a/packages/react/src/hooks/notebook.ts +++ b/packages/react/src/hooks/notebook.ts @@ -4,6 +4,8 @@ import { useThebeConfig } from '../ThebeServerProvider'; import { useThebeCore } from '../ThebeCoreProvider'; import type { INotebookContent } from '@jupyterlab/nbformat'; import { useThebeSession } from '../ThebeSessionProvider'; +import { useRenderMimeRegistry } from '../ThebeRenderMimeRegistryProvider'; +import { render } from 'react-dom'; export interface NotebookExecuteOptions { stopOnError?: boolean; @@ -42,6 +44,7 @@ export function useNotebookBase() { */ useEffect(() => { if (!notebook || !session || !sessionReady) return; + console.debug(`thebe-react: attaching notebook to session`, { notebook, session }); notebook.attachSession(session); setSessionAttached(true); }, [notebook, session, sessionReady]); @@ -118,6 +121,7 @@ export function useNotebook( ) { const { core } = useThebeCore(); const { config } = useThebeConfig(); + const rendermime = useRenderMimeRegistry(); const [loading, setLoading] = useState(false); const { @@ -148,7 +152,7 @@ export function useNotebook( setLoading(true); fetchNotebook(name) .then((ipynb) => { - return core?.ThebeNotebook.fromIpynb(ipynb, config); + return core?.ThebeNotebook.fromIpynb(ipynb, config, rendermime); }) .then((nb: ThebeNotebook) => { const cells = opts?.refsForWidgetsOnly ? nb?.widgets ?? [] : nb?.cells ?? []; @@ -193,6 +197,7 @@ export function useNotebook( export function useNotebookFromSource(sourceCode: string[], opts = { refsForWidgetsOnly: true }) { const { core } = useThebeCore(); const { config } = useThebeConfig(); + const rendermime = useRenderMimeRegistry(); const [loading, setLoading] = useState(false); const { ready, @@ -216,6 +221,7 @@ export function useNotebookFromSource(sourceCode: string[], opts = { refsForWidg const nb = core.ThebeNotebook.fromCodeBlocks( sourceCode.map((source) => ({ id: core?.shortId(), source })), config, + rendermime, ); const cells = opts?.refsForWidgetsOnly ? nb?.widgets ?? [] : nb?.cells ?? []; setRefs( @@ -255,6 +261,7 @@ export function useNotebookFromSource(sourceCode: string[], opts = { refsForWidg export function useNotebookfromSourceLegacy(sourceCode: string[]) { const { core } = useThebeCore(); const { config } = useThebeConfig(); + const rendermime = useRenderMimeRegistry(); const [busy, setBusy] = useState(false); const [notebook, setNotebook] = useState(); @@ -271,6 +278,7 @@ export function useNotebookfromSourceLegacy(sourceCode: string[]) { core.ThebeNotebook.fromCodeBlocks( sourceCode.map((source) => ({ id: core?.shortId(), source })), config, + rendermime, ), ); }, [core, notebook]); diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 7500e074..f9f89d0a 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -2,4 +2,5 @@ export * from './OutputAreaByRef'; export * from './ThebeCoreProvider'; export * from './ThebeServerProvider'; export * from './ThebeSessionProvider'; +export * from './ThebeRenderMimeRegistryProvider'; export * from './hooks'; diff --git a/packages/thebe/src/thebe.ts b/packages/thebe/src/thebe.ts index 2ba296a7..14f08df3 100644 --- a/packages/thebe/src/thebe.ts +++ b/packages/thebe/src/thebe.ts @@ -11,7 +11,12 @@ import * as base from '@jupyter-widgets/base'; import * as controls from '@jupyter-widgets/controls'; import { output } from '@jupyter-widgets/jupyterlab-manager'; import type { Options } from './options'; -import { makeConfiguration, setupNotebookFromBlocks, ThebeServer } from 'thebe-core'; +import { + makeConfiguration, + makeRenderMimeRegistry, + setupNotebookFromBlocks, + ThebeServer, +} from 'thebe-core'; import type { CellDOMPlaceholder } from './types'; if (typeof window !== 'undefined' && typeof window.define !== 'undefined') { @@ -70,8 +75,9 @@ export async function bootstrap(opts: Partial = {}) { }); const config = makeConfiguration(options, window.thebe.events); + const rendermime = makeRenderMimeRegistry(config.mathjax); - const notebook = setupNotebookFromBlocks(codeWithIds, config); + const notebook = setupNotebookFromBlocks(codeWithIds, config, rendermime); window.thebe.notebook = notebook; renderAllCells(options, notebook, items); @@ -100,7 +106,7 @@ export async function bootstrap(opts: Partial = {}) { await server.ready; - const session = await server.startNewSession(); + const session = await server.startNewSession(rendermime); if (session != null) notebook.attachSession(session); window.thebe.session = session ?? undefined; diff --git a/turbo.json b/turbo.json index 8a8d022a..64893de6 100644 --- a/turbo.json +++ b/turbo.json @@ -26,11 +26,11 @@ "outputs": ["dist/**"] }, "demo-core#build": { - "dependsOn": ["thebe-core#build", "thebe-lite#build", "thebe#build"], + "dependsOn": ["thebe-core#build", "thebe-lite#build"], "outputs": ["dist/**"] }, "demo-react#build": { - "dependsOn": ["thebe-core#build", "thebe-lite#build", "thebe#build"], + "dependsOn": ["thebe-core#build", "thebe-lite#build", "thebe-react#build"], "outputs": ["build/**"] }, "demo": {