Skip to content
This repository was archived by the owner on Jan 30, 2026. It is now read-only.
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
7 changes: 0 additions & 7 deletions demo/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
plugins: [react()],
base: '/',
resolve: {
alias: {
'superdoc/dist/style.css': path.resolve(__dirname, '../node_modules/superdoc/dist/style.css')
},
dedupe: ['react', 'react-dom', 'react/jsx-runtime']
}
});
Comment on lines 4 to 7

Choose a reason for hiding this comment

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

P1 Badge Restore React dedupe in demo Vite config

Removing the resolve.dedupe entry here means the demo now loads separate React copies: the linked library pulls React 19 from the repo root while the demo itself installs React 18 (see demo/pnpm-lock.yaml). Without Vite deduping, the library’s hooks run against a different React instance than the app, which will throw the “Invalid hook call” runtime error as soon as the demo renders the linked component. Please reintroduce deduping for react/react-dom in this config so both sides share one React build.

Useful? React with 👍 / 👎.

30 changes: 21 additions & 9 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@
const startTimeRef = useRef(Date.now());
const fieldsRef = useRef(fields);
const auditTrailRef = useRef<Types.AuditEvent[]>([]);
const onFieldsDiscoveredRef = useRef(onFieldsDiscovered);
fieldsRef.current = fields;
onFieldsDiscoveredRef.current = onFieldsDiscovered;

useEffect(() => {
auditTrailRef.current = auditTrail;
Expand Down Expand Up @@ -143,7 +145,7 @@
});

const discovered: Types.FieldInfo[] = tags
.map(({ node }: any) => ({

Check warning on line 148 in src/index.tsx

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
id: node.attrs.id,
label: node.attrs.label,
value: configValues.get(node.attrs.id) ?? node.textContent ?? "",
Expand All @@ -151,7 +153,7 @@
.filter((f: Types.FieldInfo) => f.id);

if (discovered.length > 0) {
onFieldsDiscovered?.(discovered);
onFieldsDiscoveredRef.current?.(discovered);

const allFields = [
...(fieldsRef.current.document || []),
Expand All @@ -168,7 +170,7 @@
);
}
},
[onFieldsDiscovered, updateFieldInDocument],
[updateFieldInDocument],
);

const addAuditEvent = (
Expand All @@ -178,7 +180,7 @@
...event,
timestamp: new Date().toISOString(),
};
const auditMock = (globalThis as any)?.__SUPERDOC_AUDIT_MOCK__;

Check warning on line 183 in src/index.tsx

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
if (auditMock) {
auditMock(auditEvent);
}
Expand All @@ -188,19 +190,28 @@
return nextTrail;
};

// Initialize SuperDoc - ONLY ONCE per document
// Initialize SuperDoc - uses abort pattern to handle React 18 Strict Mode
// which intentionally double-invokes effects to help identify cleanup issues
useEffect(() => {
if (!containerRef.current) return;

let aborted = false;
let instance: SuperDoc | null = null;

const initSuperDoc = async () => {
const { SuperDoc } = await import("superdoc");

const instance = new SuperDoc({
// If cleanup ran while we were importing, abort
if (aborted) return;

instance = new SuperDoc({
selector: containerRef.current!,
document: document.source,
documentMode: "viewing",
onReady: () => {
if (instance.activeEditor) {
// Guard callback execution if cleanup already ran
if (aborted) return;
if (instance?.activeEditor) {
discoverAndApplyFields(instance.activeEditor);
}
addAuditEvent({ type: "ready" });
Expand All @@ -214,12 +225,13 @@
initSuperDoc();

return () => {
if (superdocRef.current) {
if (typeof superdocRef.current.destroy === "function") {
superdocRef.current.destroy();
aborted = true;
if (instance) {
if (typeof instance.destroy === "function") {
instance.destroy();
}
superdocRef.current = null;
}
superdocRef.current = null;
};
}, [document.source, document.mode, discoverAndApplyFields]);

Expand Down
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig({
fileName: (format) => (format === 'es' ? 'index.mjs' : 'index.js'),
},
rollupOptions: {
external: ['react', 'react-dom', 'react/jsx-runtime', 'superdoc'],
external: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'superdoc'],
},
},
plugins: [
Expand Down
Loading