@sigma-studio/editor
v0.306.1
Published
Embeddable React editor for SigmaDoc teaching materials.
Maintainers
Readme
@sigma-studio/editor
SigmaDoc教材のWeb編集をReactサイトへ組み込むEditorパッケージです。閲覧専用のサイトには、より軽量な@sigma-studio/viewerを使用してください。
パッケージの選び方
| 用途 | パッケージ |
| --- | --- |
| 教材を表示する | @sigma-studio/viewer |
| 教材をWeb上で編集する | @sigma-studio/editor |
含まれるもの
SigmaDocViewer: 問題・解答・コメントの出し分け、問題番号上書き、高さ制限を持つRead専用表示SigmaDocEditor: デスクトップ版と同じ編集UIを組み込み、onChange/onSaveへ完全なSigmaDocumentを返すcontrolled editorparseSigmaDocument: 外部JSONを正規スキーマで検証
教材一覧、認証、データ取得、永続化、AI/MCP、Electron API、デスクトップ専用の教材import機能は含みません。これらは組み込み先のアプリが担当します。
インストール
npm install @sigma-studio/editorentry pointでCSSを一度読み込みます。
import "@sigma-studio/editor/styles.css";SigmaDocEditorはブラウザ専用です。Viteなどのclient-side Reactアプリでは通常のimportを使用できます。SSRを行うフレームワークでは、Editor componentをSSR対象から外してください。
Next.js App Routerでは、global CSSをroot layoutで読み込み、Editorをclient componentからdynamic importします。
// app/layout.tsx
import "@sigma-studio/editor/styles.css";// components/SigmaEditorClient.tsx
"use client";
import dynamic from "next/dynamic";
import type { SigmaDocEditorProps } from "@sigma-studio/editor";
const SigmaDocEditor = dynamic<SigmaDocEditorProps>(
() => import("@sigma-studio/editor").then((module) => module.SigmaDocEditor),
{ ssr: false },
);
export function SigmaEditorClient(props: SigmaDocEditorProps) {
return <SigmaDocEditor {...props} />;
}Viewerを使う
import { SigmaDocViewer, type SigmaDocument } from "@sigma-studio/editor";
export function AnswerPage({ document }: { document: SigmaDocument }) {
return (
<SigmaDocViewer
document={document}
visibleParts={["problem", "solution"]}
hideProblemNumbers={false}
maxHeightPx={760}
/>
);
}visiblePartsはproblem、solution、commentsを自由に組み合わせられます。未指定なら完全版です。maxHeightPxを超えた場合だけFadeと「すべて表示」を出します。
Editorを使う
import { useState } from "react";
import {
SigmaDocEditor,
type SigmaDocument,
} from "@sigma-studio/editor";
export function MaterialEditor({ initialDocument }: { initialDocument: SigmaDocument }) {
const [document, setDocument] = useState(initialDocument);
return (
<SigmaDocEditor
document={document}
onChange={(nextDocument, change) => {
setDocument(nextDocument);
console.log(change.path);
}}
onSave={async (nextDocument) => {
await fetch(`/api/materials/${nextDocument.docId}`, {
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify(nextDocument),
});
}}
/>
);
}SigmaDocEditorは、デスクトップ版のEditorShellと汎用editor componentを再利用します。本文・数式・問題・ページ・overlay図形・グラフ・表・画像の編集操作、ツールバー、選択UIはデスクトップ版と共通です。編集のたびにchange.path === "$"、change.source === "desktop-editor"として完全なSigmaDocを返します。
AI編集と独自教材形式のimportはデスクトップ専用拡張です。公開Editorのbuildでは、それらへの依存を無効なadapterへ差し替え、実装moduleを公開bundleへ含めません。build時にはesbuildの入力一覧と出力bundleも検査し、デスクトップ専用moduleや識別文字列が混入した場合は失敗します。このためAIメニュー、AI選択アクション、AI設定、デスクトップ版への誘導placeholder、デスクトップ専用のimport形式は表示しません。
Electronのworkspace/library、AI/MCP、認証は接続しません。教材一覧・新規作成・複製・削除は組み込み先が担当し、編集結果の永続化はonSaveで受け取ります。onSaveを指定した場合は編集停止から450ms後に呼ばれ、保存中表示はonSaveの実行中だけ表示します。PDFプレビューからの保存はデスクトップ用routeやローカルfileIdを使わず、ブラウザの印刷画面を開きます。
document stateはonChangeだけが更新します。onSaveは永続化専用のフックであり、その中でsetDocumentしないでください(サーバーレスポンスを書き戻す場合も同様)。保存の完了を待つ間にユーザーが入力を続けていると、古いスナップショットで最新の入力を上書きしてしまい、それが再びdirtyとして次の自動保存を呼び、保存表示が止まらなくなる自走ループになります。documentへ新しい値を渡すのは、別の教材を開いた場合など、エディタの外で本当に文書が切り替わったときだけです。
実際の数学解答共有サイト、表示パラメータ操作、編集route、保存後の再表示はexamples/editor-react18にあります。
AIコーディングエージェントに導入させる
AIエージェントは次の順序で導入してください。
- ホストがReact
>=18.2.0 <20を使用していることを確認する npm install @sigma-studio/editorを実行する@sigma-studio/editor/styles.cssをアプリ全体で一度だけ読み込む- SSR環境では
SigmaDocEditorをclient-onlyのdynamic importにする - 外部の
unknown値をparseSigmaDocumentで検証する documentをホスト側のstateで所有し、onChangeでだけ編集結果をstateへ反映するonSaveでは永続化だけを行い、保存レスポンスで編集中のstateを上書きしない- ホスト側のtypecheckとproduction buildを実行する
SigmaDoc JSONを正本にし、Editor内部のTiptap JSON、HTML、DOM、CSS class、canvas状態を保存形式や連携APIにしないでください。教材一覧、認証、API通信、保存先はホスト側に実装し、公開packageの内部moduleはimportしません。
次の指示をそのままAIエージェントへ渡せます。
このReactプロジェクトへ @sigma-studio/editor を導入してください。
要件:
- 既存のpackage manager、React version、SSRの有無を最初に確認する
- @sigma-studio/editorを追加し、styles.cssをアプリ全体で一度だけ読み込む
- SSR環境ではSigmaDocEditorをssr:falseのclient-only dynamic importにする
- 外部から取得した教材JSONはparseSigmaDocumentで検証する
- SigmaDocumentはホスト側のcontrolled stateとして保持する
- onChangeで受け取った最新documentだけをstateへ反映する
- onSaveはAPIやstorageへの永続化だけを行い、setDocumentを呼ばない
- 教材の切り替え時だけ外部から新しいdocumentを渡す
- SigmaDoc JSONを正本とし、Tiptap JSON、HTML、DOM、canvas状態を永続化しない
- AI/MCP、認証、教材一覧、Electron APIをpackage内部に求めず、必要ならホスト側で実装する
- @sigma-studio/editorの内部moduleや内部CSS classをimportしない
- 実装後にtypecheckとproduction buildを実行し、変更ファイルと検証結果を報告するEditor API
interface SigmaDocEditorProps {
document: SigmaDocument;
onChange: (
document: SigmaDocument,
change: {
document: SigmaDocument;
path: "$";
source: "desktop-editor" | "reset";
},
) => void;
onSave?: (document: SigmaDocument) => void | Promise<void>;
className?: string;
style?: React.CSSProperties;
editorRef?: { current: SigmaDocEditorHandle | null };
}
interface SigmaDocEditorHandle {
getDocument(): SigmaDocument;
reset(document?: SigmaDocument): void;
focus(): void;
}互換性
- React / React DOM:
>=18.2.0 <20 - SigmaDoc:
version: "2.0" - CSS:
@sigma-studio/editor/styles.css
パッケージのバージョンはSigma Studio本体と揃えて公開します。
ライセンス
MIT
