Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Chinese input method in Remirror editor #396

Merged
merged 2 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ui/src/components/nodes/Code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import ReactFlow, {
NodeProps,
useStore as useReactFlowStore,
} from "reactflow";
import "reactflow/dist/style.css";

import Box from "@mui/material/Box";
import InputBase from "@mui/material/InputBase";
Expand Down
50 changes: 21 additions & 29 deletions ui/src/components/nodes/Rich.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
useContext,
useEffect,
memo,
useMemo,
} from "react";
import * as React from "react";

Expand All @@ -30,7 +31,6 @@ import ReactFlow, {
Node,
useStore as useReactFlowStore,
} from "reactflow";
import "reactflow/dist/style.css";
import Ansi from "ansi-to-react";

import Box from "@mui/material/Box";
Expand Down Expand Up @@ -114,7 +114,6 @@ import { markInputRule } from "@remirror/core-utils";
import { TableExtension } from "@remirror/extension-react-tables";
import { GenIcon, IconBase } from "@remirror/react-components";
import "remirror/styles/all.css";
import "./remirror-size.css";
import { styled } from "@mui/material";

import { MyYjsExtension } from "./extensions/YjsRemirror";
Expand All @@ -128,11 +127,15 @@ import {
TaskListExtension,
} from "./extensions/list";

import { CodePodSyncExtension } from "./extensions/codepodSync";

import { LinkExtension, LinkToolbar } from "./extensions/link";

import { NewPodButtons, level2fontsize } from "./utils";
import { RepoContext } from "../../lib/store";

import "./remirror-size.css";

/**
* This is the toolbar when user select some text. It allows user to change the
* markups of the text, e.g. bold, italic, underline, highlight, etc.
Expand Down Expand Up @@ -303,6 +306,11 @@ const MyEditor = ({
autoLinkAllowedTLDs: ["dev", ...TOP_50_TLDS],
}),
new UnderlineExtension(),
new CodePodSyncExtension({
id: id,
setPodContent: setPodContent,
setPodRichContent: setPodRichContent,
}),
],
onError: ({ json, invalidContent, transformers }) => {
// Automatically remove all invalid nodes and marks.
Expand All @@ -329,8 +337,6 @@ const MyEditor = ({
stringHandler: "markdown",
});

let index_onChange = 0;

return (
<Box
className="remirror-theme"
Expand Down Expand Up @@ -362,32 +368,18 @@ const MyEditor = ({
<MyStyledWrapper>
<Remirror
manager={manager}
// initialContent={state}
state={state}
// Must set initialContent, otherwise the Reactflow will fire two
// dimension change events at the beginning. This should be caused
// by initialContent being empty, then the actual content. Setting
// it to the actual content at the beginning will prevent this.
initialContent={state}
// Should not set state and onChange (the controlled Remirror editor
// [1]), otherwise Chinsee (or CJK) input methods will not be
// supported [2].
// - [1] https://remirror.io/docs/controlled-editor
// - [2] demo that Chinese input method is not working:
// https://remirror.vercel.app/?path=/story/editors-controlled--editable
editable={!isGuest}
// FIXME: onFocus is not working
onChange={(parameter) => {
let nextState = parameter.state;
setState(nextState);
// TODO sync with DB and yjs
if (parameter.tr?.docChanged) {
setPodRichContent({
id,
richContent: parameter.helpers.getMarkdown(),
});
index_onChange += 1;
if (index_onChange == 1) {
if (
JSON.stringify(pod.content) ===
JSON.stringify(nextState.doc.toJSON())
) {
// This is the first onChange trigger, and the content is the same. Skip it.
return;
}
}
setPodContent({ id, content: nextState.doc.toJSON() });
}
}}
>
{/* <WysiwygToolbar /> */}
<EditorComponent />
Expand Down
1 change: 0 additions & 1 deletion ui/src/components/nodes/Scope.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import ReactFlow, {
NodeProps,
useStore as useReactFlowStore,
} from "reactflow";
import "reactflow/dist/style.css";

import Box from "@mui/material/Box";
import InputBase from "@mui/material/InputBase";
Expand Down
53 changes: 53 additions & 0 deletions ui/src/components/nodes/extensions/codepodSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import TurndownService from "turndown";

import { PlainExtension, StateUpdateLifecycleProps, extension } from "remirror";

interface CodePodSyncOptions {
// Options are `Dynamic` by default.
id: string;
setPodContent: any;
setPodRichContent: any;
}

@extension<CodePodSyncOptions>({
defaultOptions: {
id: "defaultId",
setPodContent: () => {},
setPodRichContent: () => {},
},
staticKeys: [],
handlerKeys: [],
customHandlerKeys: [],
})
/**
* This extension is used to sync the content of the editor with the pod.
*/
export class CodePodSyncExtension extends PlainExtension<CodePodSyncOptions> {
firstUpdate = true;
turndownService = new TurndownService();
get name(): string {
return "codepod-sync";
}
onStateUpdate({ state, tr }: StateUpdateLifecycleProps) {
if (tr?.docChanged) {
this.options.setPodContent(
{
id: this.options.id,
content: state.doc.toJSON(),
},
// The first onChange event is triggered wehn the content is the same.
// Skip it.
this.firstUpdate
);
this.firstUpdate = false;
}

var markdown = this.turndownService.turndown(
this.store.helpers.getHTML(state)
);
this.options.setPodRichContent({
id: this.options.id,
richContent: markdown,
});
}
}
14 changes: 12 additions & 2 deletions ui/src/lib/store/podSlice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ export interface PodSlice {
dirty?: boolean
) => void;
setPodName: ({ id, name }: { id: string; name: string }) => void;
setPodContent: ({ id, content }: { id: string; content: string }) => void;
setPodContent: (
{ id, content }: { id: string; content: string },
// Whether to perform additional verification of whether content ==
// pod.content before setting the dirty flag..
verify?: boolean
) => void;
setPodRichContent: ({
id,
richContent,
Expand Down Expand Up @@ -87,10 +92,15 @@ export const createPodSlice: StateCreator<MyState, [], [], PodSlice> = (
// @ts-ignore
"setPodName"
),
setPodContent: ({ id, content }) =>
setPodContent: ({ id, content }, verify = false) =>
set(
produce((state) => {
let pod = state.pods[id];
if (verify) {
if (JSON.stringify(pod.content) === JSON.stringify(content)) {
return;
}
}
pod.content = content;
pod.dirty = true;
}),
Expand Down