import { defineConfigOption } from "@nteract/mythic-configuration";
import React from "react";
import { connect } from "react-redux";
import { Dispatch } from "redux";
import { actions, AppState, ContentRef, selectors } from "@nteract/core";
import { MarkdownPreviewer } from "@nteract/markdown";
import { Source } from "@nteract/presentational-components";
import Editor, { EditorSlots } from "../inputs/editor";
import { ImmutableCell } from "@nteract/commutable/src";
import { ReactMarkdownProps } from "react-markdown";
const {
selector: markdownConfig,
} = defineConfigOption({
key: "markdownOptions",
label: "Markdown Editor Options",
defaultValue: {},
});
interface NamedMDCellSlots {
editor?: EditorSlots;
toolbar?: () => JSX.Element;
}
interface ComponentProps {
id: string;
contentRef: ContentRef;
cell_type?: "markdown";
children?: NamedMDCellSlots;
}
interface StateProps {
isCellFocused: boolean;
isEditorFocused: boolean;
cell?: ImmutableCell;
markdownOptions: ReactMarkdownProps;
}
interface DispatchProps {
focusAboveCell: () => void;
focusBelowCell: () => void;
focusEditor: () => void;
unfocusEditor: () => void;
}
export class PureMarkdownCell extends React.Component<
ComponentProps & DispatchProps & StateProps
> {
render() {
const { contentRef, id, cell, children } = this.props;
const { isEditorFocused, isCellFocused, markdownOptions } = this.props;
const {
focusAboveCell,
focusBelowCell,
focusEditor,
unfocusEditor,
} = this.props;
/**
* We don't set the editor slots as defaults to support dynamic imports
* Users can continue to add the editorSlots as children
*/
const editor = children?.editor
const toolbar = children?.toolbar;
const source = cell ? cell.get("source", "") : "";
return (
{toolbar && toolbar()}
{editor}
);
}
}
export const makeMapStateToProps = (
initialState: AppState,
ownProps: ComponentProps
): ((state: AppState) => StateProps) => {
const { id, contentRef } = ownProps;
const mapStateToProps = (state: AppState): StateProps => {
const model = selectors.model(state, { contentRef });
let isCellFocused = false;
let isEditorFocused = false;
let cell;
if (model && model.type === "notebook") {
cell = selectors.notebook.cellById(model, { id });
isCellFocused = model.cellFocused === id;
isEditorFocused = model.editorFocused === id;
}
const markdownOptionsDefaults = {
linkTarget: "_blank",
};
const currentMarkdownOptions = markdownConfig(state);
const markdownOptions = Object.assign(
{},
markdownOptionsDefaults,
currentMarkdownOptions
);
return {
cell,
isCellFocused,
isEditorFocused,
markdownOptions,
};
};
return mapStateToProps;
};
const makeMapDispatchToProps = (
initialDispatch: Dispatch,
ownProps: ComponentProps
): ((dispatch: Dispatch) => DispatchProps) => {
const { id, contentRef } = ownProps;
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
focusAboveCell: () => {
dispatch(actions.focusPreviousCell({ id, contentRef }));
dispatch(actions.focusPreviousCellEditor({ id, contentRef }));
},
focusBelowCell: () => {
dispatch(
actions.focusNextCell({ id, createCellIfUndefined: true, contentRef })
);
dispatch(actions.focusNextCellEditor({ id, contentRef }));
},
focusEditor: () => dispatch(actions.focusCellEditor({ id, contentRef })),
unfocusEditor: () =>
dispatch(actions.focusCellEditor({ id: undefined, contentRef })),
});
return mapDispatchToProps;
};
const MarkdownCell = connect(
makeMapStateToProps,
makeMapDispatchToProps
)(PureMarkdownCell);
export default MarkdownCell;