import React, { ReactNode } from "react" import { withStreamlitConnection, StreamlitComponentBase, Streamlit, } from "./streamlit" import { Runtime, Inspector } from "@observablehq/runtime"; class Observable extends StreamlitComponentBase<{}> { public observeValue = {}; private notebookRef = React.createRef(); private runtime: any = null; private main: any = null; componentWillUnmount() { this.runtime?.dispose(); } // @ts-ignore public componentDidUpdate(prevProps: any) { const { args: prevArgs } = prevProps; if (prevArgs.notebook !== this.props.args.notebook) { // TODO handle new notebook } console.log('this.props.args.redefine: ', this.props.args.redefine); if (this.main !== null) { this.redefineCells(this.main, this.props.args.redefine); } } async embedNotebook(notebook: string, targets: string[], observe: string[], hide:string[]) { if (this.runtime) { this.runtime.dispose(); } console.log('Console says hi!'); const targetSet = new Set(targets); const observeSet = new Set(observe); const hideSet = new Set(hide); this.runtime = new Runtime(); const { default: define } = await eval(`import("https://api.observablehq.com/${notebook}.js?v=3")`); this.main = this.runtime.module(define, (name: string) => { console.log('name: ', name); console.log('observeSet.has(name: ', observeSet.has(name)); console.log('targetSet.has(name): ', targetSet.has(name)); if (observeSet.has(name) && !targetSet.has(name)) { const observeValue = this.observeValue; console.log('observeValue: ', observeValue); return { fulfilled: (value: any) => { //@ts-ignore observeValue[name] = value; //@ts-ignore Streamlit.setComponentValue(observeValue); } } } if (targetSet.size > 0 && !targetSet.has(name)) return; if(hideSet.has(name)) return true; const el = document.createElement('div'); this.notebookRef.current?.appendChild(el); const i = new Inspector(el); el.addEventListener('input', e => { Streamlit.setFrameHeight(); }) return { pending() { i.pending(); Streamlit.setFrameHeight(); }, fulfilled(value: any) { i.fulfilled(value); Streamlit.setFrameHeight(); }, rejected(error: any) { i.rejected(error); Streamlit.setFrameHeight(); }, }; }); if (observeSet.size > 0) { Promise.all(Array.from(observeSet).map(async name => [name, await this.main.value(name)])).then(initial => { for (const [name, value] of initial) { // @ts-ignore this.observeValue[name] = value }; Streamlit.setComponentValue(this.observeValue); }) } } redefineCells(main: any, redefine = {}) { console.log('Console says hi 2 !'); for (let cell in redefine) { //@ts-ignore main.redefine(cell, redefine[cell]); } } componentDidMount() { const { notebook, targets = [], observe = [], redefine = {} , hide=[]} = this.props.args; Streamlit.setComponentValue(this.observeValue); this.embedNotebook(notebook, targets, observe, hide).then(() => { this.redefineCells(this.main, redefine); }); } public render = (): ReactNode => { console.log('this.props.args.render_empty: ', this.props.args.render_empty); if (this.props.args.render_empty) { return (
{this.props.args.name}
) } return (
{this.props.args.name}
) } } export default withStreamlitConnection(Observable)