|
import hoistNonReactStatics from "hoist-non-react-statics" |
|
import React, { ReactNode } from "react" |
|
import { RenderData, Streamlit } from "./streamlit" |
|
|
|
|
|
|
|
|
|
export interface ComponentProps { |
|
|
|
args: any |
|
|
|
|
|
width: number |
|
|
|
|
|
|
|
|
|
|
|
|
|
disabled: boolean |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class StreamlitComponentBase<S = {}> extends React.PureComponent< |
|
ComponentProps, |
|
S |
|
> { |
|
public componentDidMount(): void { |
|
|
|
|
|
Streamlit.setFrameHeight() |
|
} |
|
|
|
public componentDidUpdate(): void { |
|
|
|
Streamlit.setFrameHeight() |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
export function withStreamlitConnection( |
|
WrappedComponent: React.ComponentType<ComponentProps> |
|
): React.ComponentType { |
|
interface WrapperProps { } |
|
|
|
interface WrapperState { |
|
renderData?: RenderData |
|
componentError?: Error |
|
} |
|
|
|
class ComponentWrapper extends React.PureComponent< |
|
WrapperProps, |
|
WrapperState |
|
> { |
|
public constructor(props: WrapperProps) { |
|
super(props) |
|
this.state = { |
|
renderData: undefined, |
|
componentError: undefined, |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
public static getDerivedStateFromError = ( |
|
error: Error |
|
): Partial<WrapperState> => { |
|
return { componentError: error } |
|
} |
|
|
|
public componentDidMount = (): void => { |
|
|
|
|
|
Streamlit.events.addEventListener( |
|
Streamlit.RENDER_EVENT, |
|
this.onRenderEvent |
|
) |
|
Streamlit.setComponentReady() |
|
} |
|
|
|
public componentDidUpdate = (prevProps: any): void => { |
|
|
|
|
|
|
|
|
|
if (this.state.componentError != null) { |
|
Streamlit.setFrameHeight() |
|
} |
|
} |
|
|
|
public componentWillUnmount = (): void => { |
|
Streamlit.events.removeEventListener( |
|
Streamlit.RENDER_EVENT, |
|
this.onRenderEvent |
|
) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
private onRenderEvent = (event: Event): void => { |
|
|
|
const renderEvent = event as CustomEvent<RenderData> |
|
this.setState({ renderData: renderEvent.detail }) |
|
} |
|
|
|
public render = (): ReactNode => { |
|
|
|
if (this.state.componentError != null) { |
|
return ( |
|
<div> |
|
<h1>Component Error</h1> |
|
<span>{this.state.componentError.message}</span> |
|
</div> |
|
) |
|
} |
|
|
|
|
|
if (this.state.renderData == null) { |
|
return null |
|
} |
|
|
|
return ( |
|
<WrappedComponent |
|
width={window.innerWidth} |
|
disabled={this.state.renderData.disabled} |
|
args={this.state.renderData.args} |
|
/> |
|
) |
|
} |
|
} |
|
|
|
return hoistNonReactStatics(ComponentWrapper, WrappedComponent) |
|
} |
|
|