Skip to content
Draft
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
212 changes: 209 additions & 3 deletions packages/super-editor/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,20 @@ export type Command = (props: CommandProps) => boolean;
* Chainable command object returned by editor.chain()
*/
export interface ChainableCommandObject {
run: () => boolean;
/** Execute the chained commands */
run(): boolean;
/** Chain any command - returns self for further chaining */
toggleBold(): ChainableCommandObject;
toggleItalic(): ChainableCommandObject;
toggleUnderline(): ChainableCommandObject;
toggleStrike(): ChainableCommandObject;
setFontSize(size: string | number): ChainableCommandObject;
setFontFamily(family: string): ChainableCommandObject;
setTextColor(color: string): ChainableCommandObject;
setTextAlign(alignment: 'left' | 'center' | 'right' | 'justify'): ChainableCommandObject;
insertContent(content: any): ChainableCommandObject;
focus(position?: 'start' | 'end' | 'all' | number | boolean | null): ChainableCommandObject;
/** Allow any other command */
[commandName: string]: ((...args: any[]) => ChainableCommandObject) | (() => boolean);
}

Expand Down Expand Up @@ -199,6 +212,67 @@ export interface OpenOptions {
fonts?: Record<string, unknown>;
}

// ============================================
// COMMENT TYPES
// ============================================

/** A comment element (paragraph, text run, etc.) */
export interface CommentElement {
type: string;
content?: CommentElement[];
text?: string;
}

/** A comment in the document */
export interface Comment {
/** Unique comment identifier */
commentId: string;
/** Timestamp when comment was created */
createdTime: number;
/** Email of the comment author */
creatorEmail: string;
/** Display name of the comment author */
creatorName: string;
/** Comment content elements */
elements: CommentElement[];
/** Original ID from imported document */
importedId?: string;
/** Whether the comment is resolved */
isDone: boolean;
/** Parent comment ID for replies */
parentCommentId?: string;
/** Raw JSON representation */
commentJSON?: unknown;
}

/** Event data for comments loaded event */
export interface CommentsLoadedEventData {
comments: Comment[];
}

/** Event data for content error event */
export interface ContentErrorEventData {
error: Error;
}

/** Font configuration */
export interface FontConfig {
key: string;
label: string;
fontWeight?: number;
props?: {
style?: {
fontFamily?: string;
};
};
}

/** Font support information */
export interface FontSupportInfo {
documentFonts: string[];
unsupportedFonts: string[];
}

// ============================================
// PRESENTATION EDITOR TYPES
// ============================================
Expand Down Expand Up @@ -586,6 +660,131 @@ export declare class Editor {
*/
isEmpty: boolean;

// ============================================
// EVENT METHODS
// ============================================

/**
* Register an event listener.
* @param event - Event name ('update', 'create', 'transaction', etc.)
* @param handler - Event handler function
*/
on(event: string, handler: (...args: any[]) => void): void;

/**
* Remove an event listener.
* @param event - Event name
* @param handler - Event handler function to remove
*/
off(event: string, handler: (...args: any[]) => void): void;

/**
* Emit an event.
* @param event - Event name
* @param args - Arguments to pass to handlers
*/
emit(event: string, ...args: any[]): void;

// ============================================
// DOCUMENT EXPORT METHODS
// ============================================

/**
* Export the document to DOCX format.
* @param options - Export options
* @returns Promise resolving to Blob (browser) or Buffer (Node.js)
*/
exportDocx(options?: {
isFinalDoc?: boolean;
commentsType?: string;
comments?: Comment[];
fieldsHighlightColor?: string | null;
compression?: 'DEFLATE' | 'STORE';
}): Promise<Blob | ArrayBuffer>;

/**
* Export the document (alias for exportDocx).
*/
exportDocument(options?: {
isFinalDoc?: boolean;
commentsType?: string;
comments?: Comment[];
}): Promise<Blob | ArrayBuffer>;
Comment on lines +676 to +680

Choose a reason for hiding this comment

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

P2 Badge Preserve Node Buffer in export return types

For headless/Node consumers, Editor.exportDocument() still resolves to a Buffer (Editor.ts returns Promise<Blob | Buffer>, and the Node export tests assert Buffer.isBuffer(exported)). Narrowing the declaration to Blob | ArrayBuffer breaks the common fs.writeFile(await editor.exportDocument()) flow at compile time even though runtime behavior is unchanged; exportDocx() immediately above has the same regression.

Useful? React with 👍 / 👎.


/**
* Save the document to the original source path (Node.js only).
*/
save(options?: { isFinalDoc?: boolean; commentsType?: string; comments?: Comment[] }): Promise<void>;

Choose a reason for hiding this comment

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

P2 Badge Keep save/export options aligned with SaveOptions

Editor.ts's SaveOptions already includes fieldsHighlightColor and compression, and save(), saveTo(), and exportDocument() all forward those flags into exportDocx(). After this narrowing, any TypeScript consumer using custom field highlighting or compression: 'STORE' will start failing to compile even though the feature still works at runtime.

Useful? React with 👍 / 👎.


/**
* Save the document to a specific path (Node.js only).
*/
saveTo(
path: string,
options?: {
isFinalDoc?: boolean;
commentsType?: string;
comments?: Comment[];
},
): Promise<void>;

// ============================================
// TOOLBAR & UI METHODS
// ============================================

/**
* Set the toolbar for this editor.
*/
setToolbar(toolbar: any): void;

/**
* Set whether the editor is editable.
*/
setEditable(editable: boolean, emitUpdate?: boolean): void;

/**
* Set the document mode.
*/
setDocumentMode(mode: 'editing' | 'viewing' | 'suggesting'): void;

/**
* Focus the editor.
*/
focus(): void;

/**
* Blur the editor.
*/
blur(): void;

// ============================================
// DOCUMENT METHODS
// ============================================

/**
* Open a document.
*/
open(source?: string | File | Blob | BinaryData, options?: OpenOptions): Promise<void>;

/**
* Close the current document.
*/
close(): void;

/**
* Replace the current file.
*/
replaceFile(newFile: File | Blob | BinaryData): Promise<void>;

/**
* Get the document as Markdown.
*/
getMarkdown(): Promise<string>;

/**
* Check if the editor is currently active/focused.
*/
isFocused: boolean;
// --- Tracked selection handle API ---

/** Capture the live PM selection as a tracked handle. Local-only. */
Expand Down Expand Up @@ -997,8 +1196,15 @@ export declare class PresentationEditor {
*/
emit(event: string, ...args: any[]): void;

/** Allow additional properties */
[key: string]: any;
/**
* Replace the current file.
*/
replaceFile(newFile: File | Blob | BinaryData): Promise<void>;

Comment on lines +1112 to +1113

Choose a reason for hiding this comment

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

P1 Badge Remove unsupported PresentationEditor methods

The public PresentationEditor class in packages/super-editor/src/core/presentation-editor/PresentationEditor.ts does not implement replaceFile() or setToolbar() at all (a repo-wide search only finds those members on Editor), so this declaration will make TypeScript consumers compile successfully and then crash with TypeError when they call the newly advertised API.

Useful? React with 👍 / 👎.

/**
* Set the toolbar for the editor.
*/
setToolbar(toolbar: any): void;
}

// ============================================
Expand Down
35 changes: 35 additions & 0 deletions packages/superdoc/src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
SuperConverter,
Editor,
PresentationEditor,
getStarterExtensions,
getRichTextExtensions,
createZip,
Extensions,
Expand All @@ -15,13 +17,46 @@ import { DOCX, PDF, HTML, getFileObject, compareVersions } from '@superdoc/commo
import BlankDOCX from '@superdoc/common/data/blank.docx?url';
import { getSchemaIntrospection } from './helpers/schema-introspection.js';

// ============================================
// TYPE RE-EXPORTS
// These types are defined in @superdoc/super-editor and re-exported for consumers
// ============================================

/**
* @typedef {import('@superdoc/super-editor').EditorState} EditorState
* @typedef {import('@superdoc/super-editor').Transaction} Transaction
* @typedef {import('@superdoc/super-editor').Schema} Schema
* @typedef {import('@superdoc/super-editor').EditorView} EditorView
* @typedef {import('@superdoc/super-editor').EditorCommands} EditorCommands
* @typedef {import('@superdoc/super-editor').ChainedCommand} ChainedCommand
* @typedef {import('@superdoc/super-editor').ChainableCommandObject} ChainableCommandObject
* @typedef {import('@superdoc/super-editor').PresentationEditorOptions} PresentationEditorOptions
* @typedef {import('@superdoc/super-editor').LayoutEngineOptions} LayoutEngineOptions
* @typedef {import('@superdoc/super-editor').PageSize} PageSize
* @typedef {import('@superdoc/super-editor').PageMargins} PageMargins
* @typedef {import('@superdoc/super-editor').Layout} Layout
* @typedef {import('@superdoc/super-editor').LayoutPage} LayoutPage
* @typedef {import('@superdoc/super-editor').LayoutFragment} LayoutFragment
* @typedef {import('@superdoc/super-editor').RangeRect} RangeRect
* @typedef {import('@superdoc/super-editor').BoundingRect} BoundingRect
* @typedef {import('@superdoc/super-editor').OpenOptions} OpenOptions
* @typedef {import('@superdoc/super-editor').DocxFileEntry} DocxFileEntry
* @typedef {import('@superdoc/super-editor').Comment} Comment
* @typedef {import('@superdoc/super-editor').CommentElement} CommentElement
* @typedef {import('@superdoc/super-editor').CommentsLoadedEventData} CommentsLoadedEventData
* @typedef {import('@superdoc/super-editor').FontConfig} FontConfig
* @typedef {import('@superdoc/super-editor').FontSupportInfo} FontSupportInfo
*/

// Public exports
export { SuperDoc } from './core/SuperDoc.js';
export {
BlankDOCX,
getFileObject,
compareVersions,
Editor,
PresentationEditor,
getStarterExtensions,
getRichTextExtensions,
getSchemaIntrospection,

Expand Down
14 changes: 14 additions & 0 deletions tests/consumer-typecheck/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "consumer-typecheck",
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
},
"dependencies": {
"superdoc": "file:../../packages/superdoc/superdoc.tgz"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
Loading
Loading