Skip to content

Commit

Permalink
Fix CodeMirror-Portal integration to handle updates
Browse files Browse the repository at this point in the history
eq should check all props

updateDOM now re-renders the react component - it's called when eq
returns false. This maintains state and allows props to change.

We take care to cope with the transition to/from rendering the "inline"
case.
  • Loading branch information
wilsonkooi authored and microbit-matt-hillsdon committed Apr 30, 2024
1 parent f6795a8 commit 06826ad
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 24 deletions.
26 changes: 21 additions & 5 deletions src/editor/codemirror/CodeMirror.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,25 @@ const CodeMirror = ({

const [portals, setPortals] = useState<PortalContent[]>([]);
const portalFactory: PortalFactory = useCallback((dom, content) => {
const portal = { dom, content };
setPortals((portals) => [...portals, portal]);
return () => setPortals((portals) => portals.filter((p) => p !== portal));
setPortals((portals) => {
let found = false;
let updated = portals.map((p) => {
if (p.dom === dom) {
found = true;
return {
dom,
content,
};
}
return p;
});
if (!found) {
updated = [...portals, { dom, content }];
}
return updated;
});

return () => setPortals((portals) => portals.filter((p) => p.dom !== dom));
}, []);

useEffect(() => {
Expand All @@ -143,7 +159,7 @@ const CodeMirror = ({
logPastedLineCount(logging, update);
}
});

const state = EditorState.create({
doc: defaultValue,
extensions: [
Expand Down Expand Up @@ -331,4 +347,4 @@ const logPastedLineCount = (logging: Logging, update: ViewUpdate) => {
);
};

export default CodeMirror;
export default CodeMirror;
49 changes: 34 additions & 15 deletions src/editor/codemirror/helper-widgets/reactWidgetExtension.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { syntaxTree } from "@codemirror/language";
import { PortalFactory } from "../CodeMirror";
import React from "react";
import { createWidget } from "./widgetArgParser";
import { OpenReactComponent, openWidgetEffect } from "./openWidgets";
import { openWidgetEffect } from "./openWidgets";
import { ValidateComponentArgs } from "./widgetArgParser";

export interface WidgetProps {
Expand Down Expand Up @@ -43,25 +43,44 @@ class Widget extends WidgetType {

eq(other: WidgetType): boolean {
const them = other as Widget;
return them.component === this.component && them.props.to === this.props.to && them.inline === this.inline;
let args1 = this.props.args;
let args2 = them.props.args;
let eqArgs =
args1.length === args2.length &&
args1.every((element, index) => element === args2[index]);

return (
them.component === this.component &&
them.props.to === this.props.to &&
eqArgs &&
them.inline === this.inline
);
}

updateDOM(dom: HTMLElement, view: EditorView): boolean {
dom.style.display = this.inline ? "inline-block" : "unset";
this.portalCleanup = this.createPortal(dom, this.toComponent(view));
return true;
}

private toComponent(view: EditorView) {
if (this.inline) {
return <this.open loc={this.props.to} view={view} />;
}
return <this.component props={this.props} view={view} />;
}

toDOM(view: EditorView) {
const dom = document.createElement("div");

if (this.inline) {
if (ValidateComponentArgs(this.component, this.props.args, this.props.types)) {
dom.style.display = "inline-block"; // want it inline for the open-close widget
this.portalCleanup = this.createPortal(
dom,
<this.open loc={this.props.to} view={view} />
);
}
} else
this.portalCleanup = this.createPortal(
dom,
<this.component props={this.props} view={view} />
);
if (
this.inline &&
!ValidateComponentArgs(this.component, this.props.args, this.props.types)
) {
return dom;
}
dom.style.display = this.inline ? "inline-block" : "unset";
this.portalCleanup = this.createPortal(dom, this.toComponent(view));
return dom;
}

Expand Down
4 changes: 2 additions & 2 deletions src/editor/codemirror/helper-widgets/setPixelWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ const MicrobitSinglePixelGrid: React.FC<MicrobitSinglePixelGridProps> = ({
style={{ marginLeft: "15px", marginTop: "15px", marginBottom: "15px" }}
>
{[...Array(5)].map((_, gridY) => (
<Box key={y} display="flex">
<Box key={gridY} display="flex">
{[...Array(5)].map((_, gridX) => (
<Box key={x} display="flex" mr="0px">
<Box key={gridX} display="flex" mr="0px">
<Button
height="32px"
width="30px"
Expand Down
3 changes: 1 addition & 2 deletions src/editor/codemirror/helper-widgets/widgetArgParser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function createWidget(
break;
default:
// No widget implemented for this function
console.log("No widget implemented for this function: " + name);
// console.log("No widget implemented for this function: " + name);
return null;
}
if (component) {
Expand All @@ -60,7 +60,6 @@ function getChildNodes(node: SyntaxNode): SyntaxNode[] {
let child = node.firstChild?.nextSibling;
let children = [];
while (child && child.name !== ")") {
console.log(child.name);
if (child.name !== "," && child.name !== "Comment") children.push(child);
child = child.nextSibling;
}
Expand Down

0 comments on commit 06826ad

Please sign in to comment.