Le runtime SDK expose désormais react/react-dom résolus contre l'instance hébergée par IdeA plutôt qu'une copie embarquée, pour que les layouts plugin en JSX/hooks partagent le même arbre React que l'host. hello-plugin migre son layout d'exemple en .tsx pour illustrer le contrat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
import type { PluginLayoutProps } from "@idea/plugin-sdk";
|
|
import type { ReactElement } from "react";
|
|
import { useMemo, useState } from "react";
|
|
|
|
let hasLoggedFirstLayoutRender = false;
|
|
|
|
export function HelloWorldLayout(props: PluginLayoutProps): ReactElement {
|
|
const [localClicks, setLocalClicks] = useState(0);
|
|
const hostState = useMemo(() => {
|
|
return typeof props.state === "object" && props.state !== null && !Array.isArray(props.state)
|
|
? (props.state as Record<string, unknown>)
|
|
: {};
|
|
}, [props.state]);
|
|
const persistedClicks =
|
|
typeof hostState.clicks === "number" && Number.isFinite(hostState.clicks)
|
|
? hostState.clicks
|
|
: 0;
|
|
|
|
if (!hasLoggedFirstLayoutRender) {
|
|
hasLoggedFirstLayoutRender = true;
|
|
console.info("[hello-plugin] layout first render", {
|
|
projectId: props.projectId,
|
|
nodeId: props.nodeId,
|
|
layoutType: props.layoutType,
|
|
hasState: props.state !== undefined
|
|
});
|
|
}
|
|
|
|
return (
|
|
<section style={{ display: "grid", gap: 12, fontFamily: "system-ui, sans-serif" }}>
|
|
<header>
|
|
<h2 style={{ margin: 0, fontSize: 16 }}>Hello Plugin</h2>
|
|
<p style={{ margin: "4px 0 0", color: "#667085", fontSize: 13 }}>
|
|
React layout rendered by IdeA host React.
|
|
</p>
|
|
</header>
|
|
<dl style={{ display: "grid", gap: 4, margin: 0, fontSize: 13 }}>
|
|
<div>
|
|
<dt style={{ color: "#667085" }}>Project</dt>
|
|
<dd style={{ margin: 0 }}>{props.projectId}</dd>
|
|
</div>
|
|
<div>
|
|
<dt style={{ color: "#667085" }}>Layout</dt>
|
|
<dd style={{ margin: 0 }}>{props.layoutType}</dd>
|
|
</div>
|
|
</dl>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setLocalClicks((current) => current + 1);
|
|
props.setState({ ...hostState, clicks: persistedClicks + 1 });
|
|
}}
|
|
>
|
|
Persist click {persistedClicks} / local click {localClicks}
|
|
</button>
|
|
</section>
|
|
);
|
|
}
|