@@ -545,23 +545,65 @@ class EditorDocumentStore
545545 }
546546
547547 // #region IDocumentEditorActions implementation
548+ /**
549+ * Reset the entire document state
550+ *
551+ * This is a special operation that bypasses the reducer and directly replaces
552+ * the entire state. Unlike `dispatch()`, it does not generate patches.
553+ *
554+ * **Characteristics:**
555+ * - Completely replaces the state (no Immer produce)
556+ * - Preserves ONLY the current camera transform (everything else is replaced)
557+ * - Clears undo/redo history
558+ * - Resets transaction ID to 0
559+ * - Emits a "document/reset" action so subscribers can detect the reset
560+ *
561+ * **Use cases:**
562+ * - Loading a document from a file
563+ * - Importing content from external sources
564+ * - Resetting to a completely new state
565+ *
566+ * @param state - The new complete editor state to set
567+ * @param key - Optional unique identifier for this reset operation.
568+ * If not provided, a timestamp is auto-generated.
569+ * @param force - If true, bypass the locked check. Use with caution.
570+ *
571+ * @returns The new transaction ID (always 0 after reset)
572+ *
573+ * @example
574+ * ```ts
575+ * // Load a document from file
576+ * const fileData = await fetch('/example.grida').then(r => r.json());
577+ * editor.commands.reset(
578+ * editor.state.init({
579+ * editable: true,
580+ * document: fileData.document
581+ * }),
582+ * '/example.grida'
583+ * );
584+ * ```
585+ */
548586 public reset (
549587 state : editor . state . IEditorState ,
550588 key : string | undefined = undefined ,
551589 force : boolean = false
552590 ) : number {
553591 if ( this . _locked && ! force ) return this . _tid ;
554592
555- const __prev_state = this . mstate ;
556- const __prev_transform = __prev_state . transform ;
557- this . mstate = produce ( state , ( draft ) => {
558- if ( key ) draft . document_key = key ;
559- // preserve the transform state
560- draft . transform = __prev_transform ;
561- } ) ;
593+ const document_key = key ?? Date . now ( ) . toString ( ) ;
594+ const prev_transform = this . mstate . transform ;
595+
596+ // Explicit full reset: Use the provided state (typically from editor.state.init())
597+ // and only preserve the current camera transform
598+ this . mstate = {
599+ ...state ,
600+ document_key, // Set reset identifier
601+ transform : prev_transform , // Preserve camera transform
602+ } ;
603+
562604 this . historyManager . clear ( ) ;
563605 this . _tid = 0 ;
564- this . emit ( undefined , [ ] ) ;
606+ this . emit ( { type : "document/reset" , document_key } , [ ] ) ;
565607 return this . _tid ;
566608 }
567609
@@ -2383,12 +2425,26 @@ export class Editor
23832425 // subscribe
23842426 this . doc . subscribeWithSelector (
23852427 ( state ) => state . document ,
2386- ( _ , document , _prev , _action , patches ) => {
2428+ ( _ , document , _prev , action , patches ) => {
23872429 // FIXME: Unstable
23882430 // the current patch based sync is not stable, it WILL fail to direct sync when deleting a node, etc.
23892431 // this is not fully tested, and the direct sync fallback should kept as-is until we fully investicate this.
23902432
23912433 if ( ! this . _m_wasm_canvas_scene ) return ;
2434+
2435+ // Full sync on document reset
2436+ if ( action ?. type === "document/reset" ) {
2437+ syncDocument (
2438+ this . _m_wasm_canvas_scene ,
2439+ document ,
2440+ this . doc . state . scene_id
2441+ ) ;
2442+ // Perform initial actions after reset
2443+ this . camera . fit ( "*" ) ;
2444+ return ;
2445+ }
2446+
2447+ // Patch-based sync for normal changes
23922448 if ( ! patches || patches . length === 0 ) return ;
23932449
23942450 const documentPatches = patches . filter (
0 commit comments