SaulLu's picture
fix bubbles viz
c3a14f0
raw
history blame
4.99 kB
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<HTMLDivElement>();
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 (
<div >
<div style={{ padding: '9px 12px' }}>
<div ref={this.notebookRef}></div>
</div>
<div style={{ marginTop: '4px' }}>
<div >
<div style={{textAlign:"left"}}>{this.props.args.name}</div>
<div style={{textAlign:"right"}}>
<a href={`https://observablehq.com/${this.props.args.notebook}`} style={{ color: '#666', }}></a>
</div>
</div>
</div>
</div >
)
}
return (
<div style={{ border: '1px solid gray', borderRadius: '4px' }}>
<div style={{ padding: '9px 12px' }}>
<div ref={this.notebookRef}></div>
</div>
<div style={{ marginTop: '4px' }}>
<div style={{
backgroundColor: '#ddd',
fontWeight: 700,
padding: ".25rem .5rem",
borderRadius: '0 0 4px 4px',
gridTemplateColumns: "auto auto",
display:"grid"
}}>
<div style={{textAlign:"left"}}>{this.props.args.name}</div>
<div style={{textAlign:"right"}}>
<a href={`https://observablehq.com/${this.props.args.notebook}`} style={{ color: '#666', }}></a>
</div>
</div>
</div>
</div >
)
}
}
export default withStreamlitConnection(Observable)