Skip to content

Commit

Permalink
add markdown editor
Browse files Browse the repository at this point in the history
  • Loading branch information
3mcd committed May 28, 2024
1 parent 04dd034 commit 1b778ae
Show file tree
Hide file tree
Showing 8 changed files with 370 additions and 10 deletions.
19 changes: 19 additions & 0 deletions core/actions/_lib/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { z } from "zod";

class Markdown extends z.ZodString {
static create = () =>
new Markdown({
typeName: "Markdown" as z.ZodFirstPartyTypeKind.ZodString,
checks: [],
coerce: false,
});

_parse(): z.ParseReturnType<string> {
return {
status: "valid",
value: "",
};
}
}

export const markdown = Markdown.create;
8 changes: 4 additions & 4 deletions core/actions/email/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as z from "zod";

import { Mail } from "ui/icon";

import { markdown } from "../_lib/types";
import * as corePubFields from "../corePubFields";
import { defineAction } from "../types";

Expand All @@ -10,7 +11,7 @@ export const action = defineAction({
config: z.object({
email: z.string().email().describe("Email address"),
subject: z.string().describe("Email subject"),
body: z.string().min(0).max(1_000).describe("Email body||textarea"),
body: markdown().min(0).max(1_000).describe("Email body"),
}),
description: "Send an email to one or more users",
runParameters: z
Expand All @@ -26,11 +27,10 @@ export const action = defineAction({
.string()
.describe("Email subject|Overrides the subject specified in the action config.")
.optional(),
body: z
.string()
body: markdown()
.min(0)
.max(1_000)
.describe("Email body|Overrides the body specified in the action config.|textarea")
.describe("Email body|Overrides the body specified in the action config.")
.optional(),
})
.optional(),
Expand Down
7 changes: 7 additions & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@
},
"dependencies": {
"@hookform/resolvers": "^3.3.1",
"@lexical/code": "^0.15.0",
"@lexical/link": "^0.15.0",
"@lexical/list": "^0.15.0",
"@lexical/markdown": "^0.15.0",
"@lexical/react": "^0.15.0",
"@lexical/rich-text": "^0.15.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-avatar": "^1.0.3",
Expand Down Expand Up @@ -279,6 +285,7 @@
"clsx": "^2.0.0",
"cmdk": "^1.0.0",
"date-fns": "^3.6.0",
"lexical": "^0.15.0",
"lucide-react": "^0.357.0",
"next": "14.2.1",
"react-day-picker": "^8.10.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/auto-form/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import AutoFormDate from "./fields/date";
import AutoFormEnum from "./fields/enum";
import AutoFormFile from "./fields/file";
import AutoFormInput from "./fields/input";
import MarkdownEditor from "./fields/markdown";
import AutoFormNumber from "./fields/number";
import AutoFormRadioGroup from "./fields/radio-group";
import AutoFormSwitch from "./fields/switch";
Expand All @@ -18,6 +19,7 @@ export const INPUT_COMPONENTS = {
number: AutoFormNumber,
file: AutoFormFile,
fallback: AutoFormInput,
markdown: MarkdownEditor,
};

/**
Expand All @@ -32,4 +34,5 @@ export const DEFAULT_ZOD_HANDLERS: {
ZodEnum: "select",
ZodNativeEnum: "select",
ZodNumber: "number",
Markdown: "markdown",
};
83 changes: 83 additions & 0 deletions packages/ui/src/auto-form/fields/markdown/MarkdownEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as React from "react";
import { CodeNode } from "@lexical/code";
import { LinkNode } from "@lexical/link";
import { ListItemNode, ListNode } from "@lexical/list";
import {
$convertFromMarkdownString,
$convertToMarkdownString,
TRANSFORMERS,
} from "@lexical/markdown";
import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode";
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
import { EditorState } from "lexical";

import { AutoFormInputComponentProps } from "../../types";

const theme = {};

function onError(error: unknown) {
console.error(error);
}

const NODES = [
HorizontalRuleNode,
CodeNode,
HeadingNode,
LinkNode,
ListNode,
ListItemNode,
QuoteNode,
];

const makeSyntheticChangeEvent = (value: string) => {
return {
target: {
value,
},
};
};

export const MarkdownEditor = (props: AutoFormInputComponentProps) => {
const initialValue = React.useMemo(() => props.field.value ?? "", []);
const initialConfig = React.useMemo(() => {
return {
namespace: "MarkdownEditor",
theme,
onError,
editorState: () => $convertFromMarkdownString(initialValue, TRANSFORMERS),
nodes: NODES,
};
}, [initialValue]);

const onChange = React.useCallback(
(editorState: EditorState) => {
editorState.read(() => {
const markdown = $convertToMarkdownString(TRANSFORMERS);
props.fieldProps.onChange(makeSyntheticChangeEvent(markdown));
});
},
[props.fieldProps.onChange]
);

return (
<LexicalComposer initialConfig={initialConfig}>
<RichTextPlugin
contentEditable={<ContentEditable />}
placeholder={<div>Enter some text...</div>}
ErrorBoundary={LexicalErrorBoundary}
/>
<OnChangePlugin onChange={onChange} />
<HistoryPlugin />
<AutoFocusPlugin />
<MarkdownShortcutPlugin transformers={TRANSFORMERS} />
</LexicalComposer>
);
};
1 change: 1 addition & 0 deletions packages/ui/src/auto-form/fields/markdown/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MarkdownEditor as default } from "./MarkdownEditor";
2 changes: 1 addition & 1 deletion packages/ui/src/auto-form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function AutoForm<SchemaType extends ZodObjectOrWrapped>({

const form = useForm<z.infer<typeof objectFormSchema>>({
resolver: zodResolver(formSchema),
defaultValues: defaultValues ?? undefined,
defaultValues: defaultValues ? { ...defaultValues, ...valuesProp } : undefined,
values: valuesProp,
});

Expand Down
Loading

0 comments on commit 1b778ae

Please sign in to comment.