// TODO The purpose of importing this source file https://github.com/nteract/nteract/blob/main/packages/stateful-components/src/cells/markdown-cell.tsx // into our source is to be able to overwrite the version of react-markdown which has this fix ("escape html to false") // https://github.com/nteract/markdown/commit/e19c7cc590a4379fc507f67a7b4228363b9d8631 without having to upgrade // @nteract/stateful-component which causes runtime issues. import { ImmutableCell } from "@nteract/commutable/src"; import { actions, AppState, ContentRef, selectors } from "@nteract/core"; import { MarkdownPreviewer } from "@nteract/markdown"; import { defineConfigOption } from "@nteract/mythic-configuration"; import { Source as BareSource } from "@nteract/presentational-components"; import Editor, { EditorSlots } from "@nteract/stateful-components/lib/inputs/editor"; import React from "react"; import { ReactMarkdownProps } from "react-markdown"; import { connect } from "react-redux"; import { Dispatch } from "redux"; import styled from "styled-components"; 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; } // Add missing style to make the editor show https://github.com/nteract/nteract/commit/7fa580011578350e56deac81359f6294fdfcad20#diff-07829a1908e4bf98d4420f868a1c6f890b95d77297b9805c9590d2dba11e80ce export const Source = styled(BareSource)` width: 100%; width: -webkit-fill-available; width: -moz-available; `; export class PureMarkdownCell extends React.Component { 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;