Skip to content

Refactor to use prosemirror-adapter-react for attribute menu #1147

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
"unified": "^11.0.4",
"unist-util-filter": "^5.0.1",
"unist-util-visit": "^5.0.0",
"use-debounce": "^10.0.0",
"use-debounce": "catalog:",
"utils": "workspace:*",
"uuid": "^9.0.0",
"zod": "catalog:"
Expand Down
5 changes: 5 additions & 0 deletions packages/context-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@codemirror/search": "^6.5.10",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.4",
"@hookform/resolvers": "catalog:",
"@lezer/cpp": "^1.1.2",
"@lezer/css": "^1.1.10",
"@lezer/html": "^1.3.10",
Expand All @@ -88,7 +89,9 @@
"@lezer/rust": "^1.0.2",
"@lezer/xml": "^1.0.6",
"@nytimes/react-prosemirror": "^1.0.0",
"@prosemirror-adapter/core": "^0.4.0",
"@prosemirror-adapter/react": "^0.4.0",
"@sinclair/typebox": "catalog:",
"deepmerge": "^4.3.1",
"fuzzy": "^0.1.3",
"install": "^0.13.0",
Expand All @@ -111,7 +114,9 @@
"react": "catalog:react19",
"react-csv-to-table": "^0.0.4",
"react-dom": "catalog:react19",
"react-hook-form": "catalog:",
"ui": "workspace:*",
"use-debounce": "catalog:",
"utils": "workspace:*",
"uuid": "^11.0.4"
},
Expand Down
52 changes: 35 additions & 17 deletions packages/context-editor/src/ContextEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
ProsemirrorAdapterProvider,
useNodeViewFactory,
usePluginViewFactory,
useWidgetViewFactory,
} from "@prosemirror-adapter/react";
import { Node } from "prosemirror-model";
import { EditorState, Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";

import { AttributePanel } from "./components/AttributePanel";
import { MenuBar } from "./components/MenuBar";
import { basePlugins } from "./plugins";
import { attributePanelKey } from "./plugins/attributePanel";
Expand All @@ -25,6 +25,7 @@ import "katex/dist/katex.min.css";

import { cn } from "utils";

import { AttributePanelToggleWidget } from "./components/AttributePanelToggleWidget";
import SuggestPanel from "./components/SuggestPanel";

const MENU_BAR_ID = "context-editor-menu-container";
Expand Down Expand Up @@ -53,19 +54,23 @@ export interface ContextEditorProps {
export interface PanelProps {
top: number;
left: number;
right: number | string;
right: number;
bottom: number;
pos: number;
// isLink: boolean;
isOpen: boolean;
node?: Partial<Node>;
}

const initPanelProps: PanelProps = {
top: 0,
left: 0,
right: "100%",
right: 0,
bottom: 0,
pos: 0,
node: undefined,
isOpen: false,
// isLink: false,
};

export interface SuggestProps {
Expand Down Expand Up @@ -96,8 +101,11 @@ function UnwrappedEditor(props: ContextEditorProps) {
return <AtomRenderingComponent nodeProp={undefined} />;
};
}, [props.atomRenderingComponent]);

const ToggleWidget = useMemo(() => AttributePanelToggleWidget, []);
const nodeViewFactory = useNodeViewFactory();
const pluginViewFactory = usePluginViewFactory();
const widgetViewFactory = useWidgetViewFactory();
const viewHost = useRef<HTMLDivElement | null>(null);
const view = useRef<EditorView | null>(null);
const [panelPosition, setPanelPosition] = useState<PanelProps>(initPanelProps);
Expand All @@ -107,18 +115,24 @@ function UnwrappedEditor(props: ContextEditorProps) {
/* plugins from: https://discuss.prosemirror.net/t/lightweight-react-integration-example/2680 */
useEffect(() => {
/* Initial Render */
const getToggleWidget = widgetViewFactory({
component: ToggleWidget,
as: "span",
});
const state = EditorState.create({
doc: props.initialDoc ? baseSchema.nodeFromJSON(props.initialDoc) : undefined,
schema: baseSchema,
plugins: [
...basePlugins(
baseSchema,
...basePlugins({
schema: baseSchema,
props,
panelPosition,
setPanelPosition,
suggestData,
setSuggestData
),
setSuggestData,
getToggleWidget,
pluginViewFactory,
}),
...(props.hideMenu
? []
: [
Expand All @@ -144,6 +158,7 @@ function UnwrappedEditor(props: ContextEditorProps) {
handleDOMEvents: {
focus: () => {
/* Reset the panelProps when the editor is focused */
const { pos, ...props } = initPanelProps;
setPanelPosition(initPanelProps);
},
},
Expand All @@ -155,15 +170,19 @@ function UnwrappedEditor(props: ContextEditorProps) {

useEffect(() => {
/* Every Render */
if (view.current) {
view.current.setProps({
editable: () => !props.disabled,
});
const tr = view.current.state.tr
.setMeta(reactPropsKey, { ...props, suggestData, setSuggestData })
.setMeta(attributePanelKey, { panelPosition, setPanelPosition });
view.current?.dispatch(tr);
}

setTimeout(() => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding this fixes a flushSync error. i don't really know why, and avoiding that kind of nonsense does seem like a strong pro of using the other view library

if (view.current) {
view.current.setProps({
editable: () => !props.disabled,
});
const tr = view.current.state.tr
.setMeta(reactPropsKey, { ...props, suggestData, setSuggestData })
.setMeta(attributePanelKey, { panelPosition, setPanelPosition });
view.current?.dispatch(tr);
}
}, 0);

/* It's not clear to me that any of the props need to trigger this to re-render. */
/* Doing so in some cases (onChange for the EditorDash) cause an infinite re-render loop */
/* Figure out what I actually need to render on, and then clean up any useMemo calls if necessary */
Expand All @@ -176,7 +195,6 @@ function UnwrappedEditor(props: ContextEditorProps) {
>
<div id={MENU_BAR_ID} className="sticky top-0 z-10"></div>
<div ref={viewHost} className={cn("font-serif", props.className)} />
<AttributePanel panelPosition={panelPosition} viewRef={view} />
<SuggestPanel {...suggestData} />
</div>
);
Expand Down
Loading
Loading