@superdoc-dev/react 1.0.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # @superdoc/react
2
+
3
+ Official React wrapper for [SuperDoc](https://www.superdoc.dev).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @superdoc/react
9
+ ```
10
+
11
+ > `superdoc` is included as a dependency - no need to install it separately.
12
+
13
+ ## Quick Start
14
+
15
+ ```tsx
16
+ import { SuperDocEditor } from '@superdoc/react';
17
+ import '@superdoc/react/style.css';
18
+
19
+ function App() {
20
+ return <SuperDocEditor document={file} />;
21
+ }
22
+ ```
23
+
24
+ ## Changing Mode
25
+
26
+ Just update the `documentMode` prop - the component handles it efficiently (no rebuild):
27
+
28
+ ```tsx
29
+ function App() {
30
+ const [mode, setMode] = useState<DocumentMode>('editing');
31
+
32
+ return (
33
+ <>
34
+ <button onClick={() => setMode('viewing')}>View</button>
35
+ <button onClick={() => setMode('editing')}>Edit</button>
36
+ <SuperDocEditor document={file} documentMode={mode} />
37
+ </>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ## Using the Ref
43
+
44
+ Access SuperDoc methods via `getInstance()`:
45
+
46
+ ```tsx
47
+ import { useRef } from 'react';
48
+ import { SuperDocEditor, SuperDocRef } from '@superdoc/react';
49
+
50
+ function App() {
51
+ const ref = useRef<SuperDocRef>(null);
52
+
53
+ const handleExport = async () => {
54
+ await ref.current?.getInstance()?.export({ triggerDownload: true });
55
+ };
56
+
57
+ return (
58
+ <>
59
+ <SuperDocEditor ref={ref} document={file} />
60
+ <button onClick={handleExport}>Export</button>
61
+ </>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ## Props
67
+
68
+ All [SuperDoc config options](https://docs.superdoc.dev) are available as props, plus:
69
+
70
+ | Prop | Type | Description |
71
+ |------|------|-------------|
72
+ | `id` | `string` | Custom container ID (auto-generated if not provided) |
73
+ | `renderLoading` | `() => ReactNode` | Loading UI |
74
+ | `hideToolbar` | `boolean` | Hide toolbar (default: false) |
75
+ | `className` | `string` | Wrapper CSS class |
76
+ | `style` | `CSSProperties` | Wrapper inline styles |
77
+
78
+ ### Common Props
79
+
80
+ ```tsx
81
+ <SuperDocEditor
82
+ document={file} // File, Blob, URL, or config object
83
+ documentMode="editing" // 'editing' | 'viewing' | 'suggesting'
84
+ role="editor" // 'editor' | 'viewer' | 'suggester'
85
+ user={{ name: 'John', email: 'john@example.com' }}
86
+ onReady={({ superdoc }) => console.log('Ready!')}
87
+ onEditorCreate={({ editor }) => console.log('Editor created')}
88
+ />
89
+ ```
90
+
91
+ ## Examples
92
+
93
+ ### View-Only Mode
94
+
95
+ ```tsx
96
+ <SuperDocEditor
97
+ document={file}
98
+ documentMode="viewing"
99
+ hideToolbar
100
+ />
101
+ ```
102
+
103
+ ### File Upload
104
+
105
+ ```tsx
106
+ function Editor() {
107
+ const [file, setFile] = useState<File | null>(null);
108
+
109
+ return (
110
+ <>
111
+ <input type="file" accept=".docx" onChange={(e) => setFile(e.target.files?.[0] || null)} />
112
+ {file && <SuperDocEditor document={file} />}
113
+ </>
114
+ );
115
+ }
116
+ ```
117
+
118
+ ### With Collaboration
119
+
120
+ ```tsx
121
+ <SuperDocEditor
122
+ document={file}
123
+ modules={{
124
+ collaboration: { ydoc, provider },
125
+ }}
126
+ />
127
+ ```
128
+
129
+ ## Next.js
130
+
131
+ ```tsx
132
+ 'use client';
133
+
134
+ import dynamic from 'next/dynamic';
135
+
136
+ const SuperDocEditor = dynamic(
137
+ () => import('@superdoc/react').then((m) => m.SuperDocEditor),
138
+ { ssr: false }
139
+ );
140
+ ```
141
+
142
+ ## TypeScript
143
+
144
+ ```tsx
145
+ import type {
146
+ SuperDocEditorProps,
147
+ SuperDocRef,
148
+ DocumentMode,
149
+ UserRole,
150
+ SuperDocUser,
151
+ } from '@superdoc/react';
152
+ ```
153
+
154
+ Types are extracted from the `superdoc` package, ensuring they stay in sync.
155
+
156
+ ## License
157
+
158
+ AGPL-3.0
159
+
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("react/jsx-runtime"),e=require("react");function O(){return`superdoc-${Date.now()}-${Math.random().toString(36).slice(2,9)}`}function A(l,q){const[f,z]=e.useState(!1);e.useEffect(()=>{z(!0)},[]);const{id:T,renderLoading:d,hideToolbar:p=!1,className:_,style:j,onReady:E,onEditorCreate:m,onEditorDestroy:R,onEditorUpdate:S,onContentError:D,onException:g,document:y,user:C,users:I,modules:b,...k}=l,n=l.documentMode??"editing",v=l.role??"editor",s=e.useRef(null),N=e.useRef(null),M=e.useRef(null);if(M.current===null){const r=T??O();M.current={containerId:r,toolbarId:`${r}-toolbar`}}const{containerId:w,toolbarId:P}=M.current,[B,$]=e.useState(!0),o=e.useRef({onReady:E,onEditorCreate:m,onEditorDestroy:R,onEditorUpdate:S,onContentError:D,onException:g});e.useEffect(()=>{o.current={onReady:E,onEditorCreate:m,onEditorDestroy:R,onEditorUpdate:S,onContentError:D,onException:g}},[E,m,R,S,D,g]);const c=e.useRef(null),u=e.useRef(!1),L=e.useRef(n);e.useEffect(()=>{L.current!==n&&(s.current?s.current.setDocumentMode(n):u.current&&(c.current=n)),L.current=n},[n]),e.useImperativeHandle(q,()=>({getInstance:()=>s.current}),[]),e.useEffect(()=>{if(!f)return;$(!0),u.current=!0;let r=!1,a=null;return(async()=>{try{const F=(await import("superdoc")).SuperDoc;if(r)return;const H={...k,selector:`#${CSS.escape(w)}`,...!p&&N.current?{toolbar:`#${CSS.escape(P)}`}:{},documentMode:n,role:v,...y!=null?{document:y}:{},...C?{user:C}:{},...I?{users:I}:{},...b?{modules:b}:{},onReady:t=>{r||($(!1),u.current=!1,c.current&&c.current!==n&&(t.superdoc.setDocumentMode(c.current),c.current=null),o.current.onReady?.(t))},onEditorCreate:t=>{r||o.current.onEditorCreate?.(t)},onEditorDestroy:()=>{r||o.current.onEditorDestroy?.()},onEditorUpdate:t=>{r||o.current.onEditorUpdate?.(t)},onContentError:t=>{r||o.current.onContentError?.(t)},onException:t=>{r||o.current.onException?.(t)}};a=new F(H),s.current=a}catch(x){r||(u.current=!1,console.error("[SuperDocEditor] Failed to initialize SuperDoc:",x),o.current.onException?.({error:x}))}})(),()=>{r=!0,u.current=!1,c.current=null,a&&(a.destroy(),s.current=null)}},[f,y,C,I,b,v,p]);const U=["superdoc-wrapper",_].filter(Boolean).join(" ");return f?i.jsxs("div",{className:U,style:j,children:[!p&&i.jsx("div",{ref:N,id:P,className:"superdoc-toolbar-container"}),i.jsx("div",{id:w,className:"superdoc-editor-container"}),B&&d&&i.jsx("div",{className:"superdoc-loading-container",children:d()})]}):d?i.jsx("div",{className:U,style:j,children:d()}):null}const h=e.forwardRef(A);h.displayName="SuperDocEditor";exports.SuperDocEditor=h;exports.default=h;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @superdoc-dev/react - Official React wrapper for SuperDoc
3
+ * @packageDocumentation
4
+ */
5
+
6
+ import { CSSProperties } from 'react';
7
+ import { ForwardRefExoticComponent } from 'react';
8
+ import { ReactNode } from 'react';
9
+ import { RefAttributes } from 'react';
10
+ import { SuperDoc } from 'superdoc';
11
+
12
+ /** Document mode - extracted from Config.documentMode */
13
+ export declare type DocumentMode = NonNullable<SuperDocConstructorConfig['documentMode']>;
14
+
15
+ /**
16
+ * Props managed internally by the React component (not exposed to users).
17
+ * - selector: managed by component (creates internal container)
18
+ */
19
+ declare type InternalProps = 'selector';
20
+
21
+ /**
22
+ * Props that are required in core but should be optional in React.
23
+ * - documentMode: defaults to 'editing' if not provided
24
+ */
25
+ declare type OptionalInReact = 'documentMode';
26
+
27
+ /**
28
+ * React-specific props added on top of SuperDocConfig.
29
+ */
30
+ declare interface ReactProps {
31
+ /** Optional ID for the editor container. Auto-generated if not provided. */
32
+ id?: string;
33
+ /** Render function for loading state */
34
+ renderLoading?: () => ReactNode;
35
+ /** Hide the toolbar container. When true, no toolbar is rendered. @default false */
36
+ hideToolbar?: boolean;
37
+ /** Additional CSS class name for the wrapper element */
38
+ className?: string;
39
+ /** Additional inline styles for the wrapper element */
40
+ style?: CSSProperties;
41
+ }
42
+
43
+ /** Full SuperDoc config - extracted from constructor */
44
+ export declare type SuperDocConfig = SuperDocConstructorConfig;
45
+
46
+ /**
47
+ * Types for @superdoc/react
48
+ *
49
+ * Core types are extracted from the SuperDoc constructor parameter type,
50
+ * ensuring they stay in sync with the superdoc package.
51
+ */
52
+ /** SuperDoc constructor config - extracted from superdoc package */
53
+ declare type SuperDocConstructorConfig = ConstructorParameters<typeof SuperDoc>[0];
54
+
55
+ /**
56
+ * SuperDocEditor component with forwardRef - Initializes SuperDoc instance and handles cleanup.
57
+ */
58
+ declare const SuperDocEditor: ForwardRefExoticComponent<SuperDocEditorProps & RefAttributes<SuperDocRef>>;
59
+ export { SuperDocEditor }
60
+ export default SuperDocEditor;
61
+
62
+ /**
63
+ * Props for SuperDocEditor component.
64
+ *
65
+ * Extends SuperDocConfig (minus internal props) with React-specific additions.
66
+ * When new props are added to SuperDoc core, they're automatically available here.
67
+ *
68
+ * Note: All callback types (onReady, onEditorCreate, etc.) come directly from
69
+ * SuperDocConfig, ensuring type compatibility with the core package.
70
+ */
71
+ export declare interface SuperDocEditorProps extends Omit<SuperDocConfig, InternalProps | OptionalInReact>, Partial<Pick<SuperDocConfig, OptionalInReact>>, ReactProps {
72
+ }
73
+
74
+ /** SuperDoc instance type - from superdoc package */
75
+ export declare type SuperDocInstance = InstanceType<typeof SuperDoc>;
76
+
77
+ /** Modules configuration - extracted from Config.modules */
78
+ export declare type SuperDocModules = NonNullable<SuperDocConstructorConfig['modules']>;
79
+
80
+ /**
81
+ * Ref interface for SuperDocEditor component
82
+ */
83
+ export declare interface SuperDocRef {
84
+ /** Get the underlying SuperDoc instance. Returns null if not yet initialized. */
85
+ getInstance(): SuperDocInstance | null;
86
+ }
87
+
88
+ /** User object - extracted from Config.user */
89
+ export declare type SuperDocUser = NonNullable<SuperDocConstructorConfig['user']>;
90
+
91
+ /** User role - extracted from Config.role */
92
+ export declare type UserRole = NonNullable<SuperDocConstructorConfig['role']>;
93
+
94
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,126 @@
1
+ import { jsx as a, jsxs as J } from "react/jsx-runtime";
2
+ import { forwardRef as K, useState as z, useEffect as l, useRef as o, useImperativeHandle as O } from "react";
3
+ function Q() {
4
+ return `superdoc-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5
+ }
6
+ function V(f, k) {
7
+ const [p, B] = z(!1);
8
+ l(() => {
9
+ B(!0);
10
+ }, []);
11
+ const {
12
+ // React-specific
13
+ id: F,
14
+ renderLoading: u,
15
+ hideToolbar: m = !1,
16
+ className: H,
17
+ style: x,
18
+ // Callbacks (stored in ref to avoid triggering rebuilds)
19
+ onReady: E,
20
+ onEditorCreate: D,
21
+ onEditorDestroy: S,
22
+ onEditorUpdate: C,
23
+ onContentError: y,
24
+ onException: I,
25
+ // Key props that trigger rebuild when changed
26
+ document: R,
27
+ user: g,
28
+ users: b,
29
+ modules: M,
30
+ // All other props passed through
31
+ ...T
32
+ } = f, t = f.documentMode ?? "editing", v = f.role ?? "editor", i = o(null), w = o(null), h = o(null);
33
+ if (h.current === null) {
34
+ const e = F ?? Q();
35
+ h.current = { containerId: e, toolbarId: `${e}-toolbar` };
36
+ }
37
+ const { containerId: $, toolbarId: P } = h.current, [q, j] = z(!0), n = o({
38
+ onReady: E,
39
+ onEditorCreate: D,
40
+ onEditorDestroy: S,
41
+ onEditorUpdate: C,
42
+ onContentError: y,
43
+ onException: I
44
+ });
45
+ l(() => {
46
+ n.current = {
47
+ onReady: E,
48
+ onEditorCreate: D,
49
+ onEditorDestroy: S,
50
+ onEditorUpdate: C,
51
+ onContentError: y,
52
+ onException: I
53
+ };
54
+ }, [E, D, S, C, y, I]);
55
+ const c = o(null), s = o(!1), L = o(t);
56
+ l(() => {
57
+ L.current !== t && (i.current ? i.current.setDocumentMode(t) : s.current && (c.current = t)), L.current = t;
58
+ }, [t]), O(
59
+ k,
60
+ () => ({
61
+ getInstance: () => i.current
62
+ }),
63
+ []
64
+ ), l(() => {
65
+ if (!p) return;
66
+ j(!0), s.current = !0;
67
+ let e = !1, d = null;
68
+ return (async () => {
69
+ try {
70
+ const A = (await import("superdoc")).SuperDoc;
71
+ if (e) return;
72
+ const G = {
73
+ ...T,
74
+ selector: `#${CSS.escape($)}`,
75
+ // Use internal toolbar container unless hideToolbar is true
76
+ ...!m && w.current ? { toolbar: `#${CSS.escape(P)}` } : {},
77
+ documentMode: t,
78
+ role: v,
79
+ ...R != null ? { document: R } : {},
80
+ ...g ? { user: g } : {},
81
+ ...b ? { users: b } : {},
82
+ ...M ? { modules: M } : {},
83
+ // Wire up callbacks with lifecycle guards
84
+ onReady: (r) => {
85
+ e || (j(!1), s.current = !1, c.current && c.current !== t && (r.superdoc.setDocumentMode(c.current), c.current = null), n.current.onReady?.(r));
86
+ },
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
+ onEditorCreate: (r) => {
89
+ e || n.current.onEditorCreate?.(r);
90
+ },
91
+ onEditorDestroy: () => {
92
+ e || n.current.onEditorDestroy?.();
93
+ },
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
+ onEditorUpdate: (r) => {
96
+ e || n.current.onEditorUpdate?.(r);
97
+ },
98
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
+ onContentError: (r) => {
100
+ e || n.current.onContentError?.(r);
101
+ },
102
+ onException: (r) => {
103
+ e || n.current.onException?.(r);
104
+ }
105
+ };
106
+ d = new A(G), i.current = d;
107
+ } catch (N) {
108
+ e || (s.current = !1, console.error("[SuperDocEditor] Failed to initialize SuperDoc:", N), n.current.onException?.({ error: N }));
109
+ }
110
+ })(), () => {
111
+ e = !0, s.current = !1, c.current = null, d && (d.destroy(), i.current = null);
112
+ };
113
+ }, [p, R, g, b, M, v, m]);
114
+ const U = ["superdoc-wrapper", H].filter(Boolean).join(" ");
115
+ return p ? /* @__PURE__ */ J("div", { className: U, style: x, children: [
116
+ !m && /* @__PURE__ */ a("div", { ref: w, id: P, className: "superdoc-toolbar-container" }),
117
+ /* @__PURE__ */ a("div", { id: $, className: "superdoc-editor-container" }),
118
+ q && u && /* @__PURE__ */ a("div", { className: "superdoc-loading-container", children: u() })
119
+ ] }) : u ? /* @__PURE__ */ a("div", { className: U, style: x, children: u() }) : null;
120
+ }
121
+ const W = K(V);
122
+ W.displayName = "SuperDocEditor";
123
+ export {
124
+ W as SuperDocEditor,
125
+ W as default
126
+ };
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@superdoc-dev/react",
3
+ "version": "1.0.0-canary.2",
4
+ "description": "Official React wrapper for SuperDoc document editor",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "require": "./dist/index.cjs",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./style.css": {
16
+ "import": "./style.css",
17
+ "require": "./style.css"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "vite build",
22
+ "dev": "vite build --watch",
23
+ "test": "vitest run",
24
+ "type-check": "tsc --noEmit",
25
+ "lint": "eslint src --ext .ts,.tsx",
26
+ "prepublishOnly": "pnpm run build"
27
+ },
28
+ "keywords": [
29
+ "superdoc",
30
+ "react",
31
+ "document",
32
+ "editor",
33
+ "docx",
34
+ "word"
35
+ ],
36
+ "license": "AGPL-3.0",
37
+ "dependencies": {
38
+ "superdoc": "workspace:*"
39
+ },
40
+ "peerDependencies": {
41
+ "react": ">=16.8.0",
42
+ "react-dom": ">=16.8.0"
43
+ },
44
+ "devDependencies": {
45
+ "@testing-library/react": "catalog:",
46
+ "@types/node": "catalog:",
47
+ "@types/react": "catalog:",
48
+ "@types/react-dom": "catalog:",
49
+ "@typescript-eslint/eslint-plugin": "catalog:",
50
+ "@typescript-eslint/parser": "catalog:",
51
+ "eslint": "catalog:",
52
+ "happy-dom": "catalog:",
53
+ "react": "catalog:",
54
+ "react-dom": "catalog:",
55
+ "typescript": "catalog:",
56
+ "vite": "catalog:",
57
+ "vite-plugin-dts": "catalog:",
58
+ "@vitejs/plugin-react": "catalog:",
59
+ "vitest": "catalog:"
60
+ },
61
+ "files": [
62
+ "dist",
63
+ "style.css",
64
+ "README.md"
65
+ ],
66
+ "publishConfig": {
67
+ "access": "public"
68
+ },
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git+https://github.com/superdoc-dev/superdoc.git",
72
+ "directory": "packages/react"
73
+ },
74
+ "bugs": {
75
+ "url": "https://github.com/superdoc-dev/superdoc/issues"
76
+ },
77
+ "homepage": "https://github.com/superdoc-dev/superdoc/tree/main/packages/react#readme"
78
+ }
package/style.css ADDED
@@ -0,0 +1,2 @@
1
+ /* @superdoc/react styles - re-exports superdoc styles */
2
+ @import 'superdoc/style.css';