npm install @harbour-enterprises/superdoc
import { useEffect, useRef } from 'react';
import { SuperDoc } from '@harbour-enterprises/superdoc';
import '@harbour-enterprises/superdoc/style.css';
function DocEditor({ document }) {
const containerRef = useRef(null);
const superdocRef = useRef(null);
useEffect(() => {
if (!containerRef.current) return;
superdocRef.current = new SuperDoc({
selector: containerRef.current,
document
});
return () => {
superdocRef.current = null;
};
}, [document]);
return <div ref={containerRef} style={{ height: '700px' }} />;
}
import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
import { SuperDoc } from '@harbour-enterprises/superdoc';
import '@harbour-enterprises/superdoc/style.css';
const DocEditor = forwardRef(({ document, user, onReady }, ref) => {
const containerRef = useRef(null);
const superdocRef = useRef(null);
useImperativeHandle(ref, () => ({
export: (options) => superdocRef.current?.export(options),
setMode: (mode) => superdocRef.current?.setDocumentMode(mode),
getHTML: () => superdocRef.current?.getHTML()
}));
useEffect(() => {
if (!containerRef.current) return;
superdocRef.current = new SuperDoc({
selector: containerRef.current,
document,
user,
onReady: () => onReady?.(superdocRef.current)
});
return () => {
superdocRef.current = null;
};
}, [document, user, onReady]);
return <div ref={containerRef} style={{ height: '700px' }} />;
});
// Usage
function App() {
const editorRef = useRef();
const handleExport = async () => {
await editorRef.current.export({ isFinalDoc: true });
};
return (
<>
<button onClick={handleExport}>Export Final</button>
<button onClick={() => editorRef.current.setMode('suggesting')}>
Review Mode
</button>
<DocEditor
ref={editorRef}
document="contract.docx"
user={{ name: 'John', email: 'john@company.com' }}
onReady={(editor) => console.log('Ready', editor)}
/>
</>
);
}
function FileEditor() {
const [file, setFile] = useState(null);
const editorRef = useRef();
const handleFile = (e) => {
setFile(e.target.files[0]);
};
const handleExport = async () => {
const blob = await editorRef.current?.export({
isFinalDoc: true
});
// Download blob...
};
return (
<>
<input type="file" accept=".docx" onChange={handleFile} />
{file && (
<>
<button onClick={handleExport}>Export</button>
<DocEditor
ref={editorRef}
document={file}
user={{ name: 'User', email: 'user@company.com' }}
/>
</>
)}
</>
);
}
import { useEffect, useRef, forwardRef } from 'react';
import { SuperDoc } from '@harbour-enterprises/superdoc';
import type { SuperDocConfig } from '@harbour-enterprises/superdoc';
interface EditorProps {
document: string | File | Blob;
userId: string;
onReady?: (editor: SuperDoc) => void;
}
interface EditorRef {
export: (options?: ExportOptions) => Promise<Blob>;
setMode: (mode: 'editing' | 'viewing' | 'suggesting') => void;
getHTML: () => string[];
}
const DocEditor = forwardRef<EditorRef, EditorProps>(
({ document, userId, onReady }, ref) => {
const containerRef = useRef<HTMLDivElement>(null);
const superdocRef = useRef<SuperDoc | null>(null);
useImperativeHandle(ref, () => ({
export: async (options) => {
if (!superdocRef.current) throw new Error('Editor not ready');
return await superdocRef.current.export(options);
},
setMode: (mode) => {
superdocRef.current?.setDocumentMode(mode);
},
getHTML: () => {
return superdocRef.current?.getHTML() || [];
}
}));
useEffect(() => {
if (!containerRef.current) return;
const config: SuperDocConfig = {
selector: containerRef.current,
document,
user: {
name: userId,
email: `${userId}@company.com`
},
onReady: () => onReady?.(superdocRef.current!)
};
superdocRef.current = new SuperDoc(config);
return () => {
superdocRef.current = null;
};
}, [document, userId, onReady]);
return <div ref={containerRef} style={{ height: '700px' }} />;
}
);
import dynamic from 'next/dynamic';
const DocEditor = dynamic(
() => import('./DocEditor'),
{
ssr: false,
loading: () => <div>Loading editor...</div>
}
);
// Or manually check for client-side
function SafeEditor(props) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return <div>Loading...</div>;
return <DocEditor {...props} />;
}
function useSuperDoc(config) {
const [ready, setReady] = useState(false);
const superdocRef = useRef(null);
useEffect(() => {
if (!config.selector) return;
superdocRef.current = new SuperDoc({
...config,
onReady: () => {
setReady(true);
config.onReady?.();
}
});
return () => {
superdocRef.current = null;
setReady(false);
};
}, [config.selector, config.document]);
return {
editor: superdocRef.current,
ready,
export: (options) => superdocRef.current?.export(options),
setMode: (mode) => superdocRef.current?.setDocumentMode(mode)
};
}
Was this page helpful?