publish: introduce ProseMirror for markdown editing

This commit is contained in:
Liam Fitzgerald 2020-09-22 16:49:39 +10:00
parent ce97d35d02
commit a3545c5cb3
4 changed files with 103 additions and 20 deletions

View File

@ -22,6 +22,11 @@
"mousetrap-global-bind": "^1.1.0",
"oembed-parser": "^1.4.1",
"prop-types": "^15.7.2",
"prosemirror": "^0.11.1",
"prosemirror-example-setup": "^1.1.2",
"prosemirror-markdown": "^1.5.0",
"prosemirror-state": "^1.3.3",
"prosemirror-view": "^1.15.7",
"react": "^16.5.2",
"react-codemirror2": "^6.0.1",
"react-dnd-html5-backend": "^11.1.3",
@ -40,6 +45,7 @@
"suncalc": "^1.8.0",
"urbit-ob": "^5.0.0",
"urbit-sigil-js": "^1.3.2",
"use-prosemirror": "^1.2.0",
"yup": "^0.29.3",
"normalize-wheel": "1.0.1"
},
@ -53,6 +59,8 @@
"@babel/preset-react": "^7.9.4",
"@babel/preset-typescript": "^7.10.1",
"@types/lodash": "^4.14.155",
"@types/prosemirror-model": "^1.7.2",
"@types/prosemirror-view": "^1.15.1",
"@types/react": "^16.9.38",
"@types/react-router-dom": "^5.1.5",
"@types/styled-components": "^5.1.2",

View File

@ -1,27 +1,38 @@
import React from 'react';
import styled from 'styled-components';
import { MarkdownEditor as _MarkdownEditor, Box, ErrorMessage } from '@tlon/indigo-react';
import { useField } from 'formik';
import React, { useCallback } from "react";
import styled from "styled-components";
import { Box, ErrorLabel } from "@tlon/indigo-react";
import { useField } from "formik";
import { MarkdownEditor } from "~/views/components/MarkdownEditor";
const MarkdownEditor = styled(_MarkdownEditor)`
border: 1px solid ${(p) => p.theme.colors.lightGray};
border-radius: ${(p) => p.theme.radii[2]}px;
`;
export const MarkdownField = ({
id,
...rest
}: { id: string } & Parameters<typeof Box>[0]) => {
const [{ value }, { error, touched }, { setValue, setTouched }] = useField(
id
);
export const MarkdownField = ({ id, ...rest }: { id: string; } & Parameters<typeof Box>[0]) => {
const [{ value }, { error, touched }, { setValue, setTouched }] = useField(id);
const onChange = useCallback(
(s: string) => {
setValue(s);
setTouched(true);
},
[setValue, setTouched]
);
return (
<Box overflowY="hidden" width="100%" display="flex" flexDirection="column" {...rest}>
<MarkdownEditor
onFocus={() => setTouched(true)}
onBlur={() => setTouched(false)}
value={value}
onBeforeChange={(e, d, v) => setValue(v)}
/>
<ErrorMessage>{touched && error}</ErrorMessage>
<Box
border={1}
borderRadius={1}
borderColor="washedGray"
overflowY="hidden"
width="100%"
display="flex"
flexDirection="column"
{...rest}
>
<MarkdownEditor content={value} onChange={onChange} />
<ErrorLabel>{touched && error}</ErrorLabel>
</Box>
);
};

View File

@ -0,0 +1,14 @@
.ProseMirror-menubar {
padding: 4px !important;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.ProseMirror-example-setup-style {
padding: 4px !important;
}
.ProseMirror > *, .ProseMirror-menubar > * {
font-family: "Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif;
}

View File

@ -0,0 +1,50 @@
import React, { useMemo, useCallback } from "react";
import {
schema,
defaultMarkdownParser,
defaultMarkdownSerializer,
} from "prosemirror-markdown";
import { exampleSetup } from "prosemirror-example-setup";
import "prosemirror-view/style/prosemirror.css";
import "prosemirror-menu/style/menu.css";
import { EditorState } from "prosemirror-state";
import { useProseMirror, ProseMirror } from "use-prosemirror";
import _ from "lodash";
import "~/views/apps/publish/css/ProseMirror.css"
interface MarkdownEditorProps {
content: string;
onChange: (s: string) => void;
}
export function MarkdownEditor(props: MarkdownEditorProps) {
const [state, setState] = useProseMirror({
schema,
doc: defaultMarkdownParser.parse(props.content),
plugins: exampleSetup({ schema, menuBar: true }),
});
const reportChange = _.debounce(
useCallback(
(doc: any) => {
const content = defaultMarkdownSerializer.serialize(doc);
props.onChange(content);
},
[props.onChange]
),
500
);
const onChange = useCallback(
(state: EditorState) => {
reportChange(state.doc);
setState(state);
},
[reportChange, setState]
);
return (
<ProseMirror className="h-100 w-100" onChange={onChange} state={state} />
);
}