mirror of
https://github.com/urbit/shrub.git
synced 2024-12-01 06:35:32 +03:00
publish: introduce ProseMirror for markdown editing
This commit is contained in:
parent
ce97d35d02
commit
a3545c5cb3
@ -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",
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
14
pkg/interface/src/views/apps/publish/css/ProseMirror.css
Normal file
14
pkg/interface/src/views/apps/publish/css/ProseMirror.css
Normal 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;
|
||||
}
|
||||
|
50
pkg/interface/src/views/components/MarkdownEditor.tsx
Normal file
50
pkg/interface/src/views/components/MarkdownEditor.tsx
Normal 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} />
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user