2020-08-27 16:43:39 +02:00

198 lines
6.8 KiB
TypeScript

import * as React from "react";
import "./base.css";
import "./default.css";
import { RawCell, Cells, CodeCell, MarkdownCell } from "@nteract/stateful-components";
import CodeMirrorEditor from "@nteract/stateful-components/lib/inputs/connected-editors/codemirror";
import Prompt from "./Prompt";
import { promptContent } from "./PromptContent";
import { AzureTheme } from "./AzureTheme";
import { DndProvider } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import { connect } from "react-redux";
import { Dispatch } from "redux";
import { actions, ContentRef } from "@nteract/core";
import { CellId } from "@nteract/commutable";
import loadTransform from "../NotebookComponent/loadTransform";
import DraggableCell from "./decorators/draggable";
import CellCreator from "./decorators/CellCreator";
import KeyboardShortcuts from "./decorators/kbd-shortcuts";
import CellToolbar from "./Toolbar";
import StatusBar from "./StatusBar";
import HijackScroll from "./decorators/hijack-scroll";
import { CellType } from "@nteract/commutable/src";
import "./NotebookRenderer.less";
import HoverableCell from "./decorators/HoverableCell";
import CellLabeler from "./decorators/CellLabeler";
import MonacoEditor from "../MonacoEditor/MonacoEditor";
import * as cdbActions from "../NotebookComponent/actions";
export interface NotebookRendererBaseProps {
contentRef: any;
}
interface NotebookRendererDispatchProps {
updateNotebookParentDomElt: (contentRef: ContentRef, parentElt: HTMLElement) => void;
}
type NotebookRendererProps = NotebookRendererBaseProps & NotebookRendererDispatchProps;
interface PassedEditorProps {
id: string;
contentRef: ContentRef;
editorFocused: boolean;
value: string;
channels: any;
kernelStatus: string;
theme: string;
onChange: (text: string) => void;
onFocusChange: (focused: boolean) => void;
className: string;
}
const decorate = (id: string, contentRef: ContentRef, cell_type: CellType, children: React.ReactNode) => {
const Cell = () => (
<DraggableCell id={id} contentRef={contentRef}>
<HijackScroll id={id} contentRef={contentRef}>
<CellCreator id={id} contentRef={contentRef}>
<CellLabeler id={id} contentRef={contentRef}>
<HoverableCell id={id} contentRef={contentRef}>
{children}
</HoverableCell>
</CellLabeler>
</CellCreator>
</HijackScroll>
</DraggableCell>
);
Cell.defaultProps = { cell_type };
return <Cell />;
};
class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
private notebookRendererRef = React.createRef<HTMLDivElement>();
constructor(props: NotebookRendererProps) {
super(props);
this.state = {
hoveredCellId: undefined
};
}
componentDidMount() {
loadTransform(this.props as any);
this.props.updateNotebookParentDomElt(this.props.contentRef, this.notebookRendererRef.current);
}
componentDidUpdate() {
this.props.updateNotebookParentDomElt(this.props.contentRef, this.notebookRendererRef.current);
}
componentWillUnmount() {
this.props.updateNotebookParentDomElt(this.props.contentRef, undefined);
}
render(): JSX.Element {
return (
<>
<div className="NotebookRendererContainer">
<div className="NotebookRenderer" ref={this.notebookRendererRef}>
<DndProvider backend={HTML5Backend}>
<KeyboardShortcuts contentRef={this.props.contentRef}>
<Cells contentRef={this.props.contentRef}>
{{
code: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) =>
decorate(
id,
contentRef,
"code",
<CodeCell id={id} contentRef={contentRef} cell_type="code">
{{
editor: {
codemirror: (props: PassedEditorProps) => (
<MonacoEditor
{...props}
lineNumbers={true}
enableCompletion={true}
shouldRegisterDefaultCompletion={true}
/>
)
},
prompt: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) => (
<Prompt id={id} contentRef={contentRef} isHovered={false}>
{promptContent}
</Prompt>
),
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />
}}
</CodeCell>
),
markdown: ({ id, contentRef }: { id: any; contentRef: ContentRef }) =>
decorate(
id,
contentRef,
"markdown",
<MarkdownCell id={id} contentRef={contentRef} cell_type="markdown">
{{
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />
}}
</MarkdownCell>
),
raw: ({ id, contentRef }: { id: any; contentRef: ContentRef }) =>
decorate(
id,
contentRef,
"raw",
<RawCell id={id} contentRef={contentRef} cell_type="raw">
{{
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />
}}
</RawCell>
)
}}
</Cells>
</KeyboardShortcuts>
<AzureTheme />
</DndProvider>
</div>
<StatusBar contentRef={this.props.contentRef} />
</div>
</>
);
}
}
const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: NotebookRendererBaseProps) => {
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => {
return dispatch(
actions.addTransform({
mediaType: transform.MIMETYPE,
component: transform
})
);
},
updateNotebookParentDomElt: (contentRef: ContentRef, parentElt: HTMLElement) => {
return dispatch(
cdbActions.UpdateNotebookParentDomElt({
contentRef,
parentElt
})
);
}
};
};
return mapDispatchToProps;
};
export default connect(null, makeMapDispatchToProps)(BaseNotebookRenderer);