1- import { create } from 'zustand' ;
2- import { temporal } from 'zundo' ;
3- import { Node , Edge , applyNodeChanges , applyEdgeChanges , addEdge , NodeChange , EdgeChange , Connection } from '@xyflow/react' ;
4- import { NodeData , RoadmapData , Settings , ImageNodeData , TextNodeData } from './types' ;
1+ import { create } from "zustand" ;
2+ import { temporal } from "zundo" ;
3+ import {
4+ Node ,
5+ Edge ,
6+ applyNodeChanges ,
7+ applyEdgeChanges ,
8+ addEdge ,
9+ NodeChange ,
10+ EdgeChange ,
11+ Connection ,
12+ } from "@xyflow/react" ;
13+ import {
14+ NodeData ,
15+ RoadmapData ,
16+ Settings ,
17+ ImageNodeData ,
18+ TextNodeData ,
19+ } from "./types" ;
520
621// Note: This is a global store for the editor. Typically only one editor instance is active at a time.
722// If you need multiple independent editor instances, consider creating store instances per component or using context.
@@ -10,9 +25,8 @@ export interface EditorState {
1025 nodes : Node < NodeData > [ ] ;
1126 edges : Edge [ ] ;
1227 settings : Settings ;
13-
28+
1429 // UI state
15- saved : boolean ;
1630 previewMode : boolean ;
1731 debugMode : boolean ;
1832 showGrid : boolean ;
@@ -22,24 +36,24 @@ export interface EditorState {
2236 edgeDrawerOpen : boolean ;
2337 shareDialogOpen : boolean ;
2438 loadExternalDialogOpen : boolean ;
25-
39+
2640 // Selected items
2741 selectedNodeId : string | null ;
2842 selectedNodeIds : string [ ] ;
2943 selectedEdge : Edge | null ;
30-
44+
3145 // Other state
3246 nextNodeId : number ;
3347 clipboard : { nodes : Node < NodeData > [ ] ; edges : Edge [ ] } | null ;
3448 lastMousePosition : { x : number ; y : number } | null ;
3549 shareLink : string ;
3650 pendingExternalId : string | null ;
37-
51+
3852 // Debug settings
3953 showCompletionNeeds : boolean ;
4054 showCompletionOptional : boolean ;
4155 showUnlockAfter : boolean ;
42-
56+
4357 // Actions
4458 onNodesChange : ( changes : NodeChange < Node < NodeData > > [ ] ) => void ;
4559 onEdgesChange : ( changes : EdgeChange < Edge > [ ] ) => void ;
@@ -54,9 +68,8 @@ export interface EditorState {
5468 deleteNode : ( nodeId : string ) => void ;
5569 deleteEdge : ( edgeId : string ) => void ;
5670 addNode : ( node : Node < NodeData > ) => void ;
57-
71+
5872 // UI state setters
59- setSaved : ( saved : boolean ) => void ;
6073 setPreviewMode : ( previewMode : boolean ) => void ;
6174 setDebugMode : ( debugMode : boolean ) => void ;
6275 setShowGrid : ( showGrid : boolean ) => void ;
@@ -70,14 +83,16 @@ export interface EditorState {
7083 setSelectedNodeIds : ( nodeIds : string [ ] ) => void ;
7184 setSelectedEdge : ( edge : Edge | null ) => void ;
7285 setNextNodeId : ( nextNodeId : number ) => void ;
73- setClipboard : ( clipboard : { nodes : Node < NodeData > [ ] ; edges : Edge [ ] } | null ) => void ;
86+ setClipboard : (
87+ clipboard : { nodes : Node < NodeData > [ ] ; edges : Edge [ ] } | null ,
88+ ) => void ;
7489 setLastMousePosition : ( position : { x : number ; y : number } | null ) => void ;
7590 setShareLink : ( shareLink : string ) => void ;
7691 setPendingExternalId : ( pendingExternalId : string | null ) => void ;
7792 setShowCompletionNeeds : ( showCompletionNeeds : boolean ) => void ;
7893 setShowCompletionOptional : ( showCompletionOptional : boolean ) => void ;
7994 setShowUnlockAfter : ( showUnlockAfter : boolean ) => void ;
80-
95+
8196 // Bulk operations
8297 loadRoadmapData : ( roadmapData : RoadmapData ) => void ;
8398 getRoadmapData : ( ) => RoadmapData ;
@@ -89,7 +104,6 @@ const initialState = {
89104 nodes : [ ] ,
90105 edges : [ ] ,
91106 settings : { background : { color : "#ffffff" } } ,
92- saved : true ,
93107 previewMode : false ,
94108 debugMode : false ,
95109 showGrid : false ,
@@ -121,52 +135,47 @@ export const useEditorStore = create<EditorState>()(
121135 onNodesChange : ( changes ) => {
122136 set ( {
123137 nodes : applyNodeChanges ( changes , get ( ) . nodes ) ,
124- saved : false ,
125138 } ) ;
126139 } ,
127140
128141 onEdgesChange : ( changes ) => {
129142 set ( {
130143 edges : applyEdgeChanges ( changes , get ( ) . edges ) ,
131- saved : false ,
132144 } ) ;
133145 } ,
134146
135147 onConnect : ( connection ) => {
136148 set ( {
137149 edges : addEdge ( connection , get ( ) . edges ) ,
138- saved : false ,
139150 } ) ;
140151 } ,
141152
142153 // Node operations
143154 setNodes : ( nodes ) => {
144- set ( { nodes, saved : false } ) ;
155+ set ( { nodes } ) ;
145156 } ,
146157
147158 setEdges : ( edges ) => {
148- set ( { edges, saved : false } ) ;
159+ set ( { edges } ) ;
149160 } ,
150161
151162 setSettings : ( settings ) => {
152- set ( { settings, saved : false } ) ;
163+ set ( { settings } ) ;
153164 } ,
154165
155166 updateNode : ( nodeId , updates ) => {
156167 set ( {
157168 nodes : get ( ) . nodes . map ( ( n ) =>
158- n . id === nodeId ? { ...n , ...updates } : n
169+ n . id === nodeId ? { ...n , ...updates } : n ,
159170 ) ,
160- saved : false ,
161171 } ) ;
162172 } ,
163173
164174 updateNodeData : ( nodeId , dataUpdates ) => {
165175 set ( {
166176 nodes : get ( ) . nodes . map ( ( n ) =>
167- n . id === nodeId ? { ...n , data : { ...n . data , ...dataUpdates } } : n
177+ n . id === nodeId ? { ...n , data : { ...n . data , ...dataUpdates } } : n ,
168178 ) ,
169- saved : false ,
170179 } ) ;
171180 } ,
172181
@@ -176,16 +185,14 @@ export const useEditorStore = create<EditorState>()(
176185 const updated = updates . find ( ( un ) => un . id === n . id ) ;
177186 return updated ? updated : n ;
178187 } ) ,
179- saved : false ,
180188 } ) ;
181189 } ,
182190
183191 updateEdge : ( edgeId , updates ) => {
184192 set ( {
185193 edges : get ( ) . edges . map ( ( e ) =>
186- e . id === edgeId ? { ...e , ...updates } : e
194+ e . id === edgeId ? { ...e , ...updates } : e ,
187195 ) ,
188- saved : false ,
189196 } ) ;
190197 // Update selected edge if it's the one being updated
191198 const selectedEdge = get ( ) . selectedEdge ;
@@ -197,36 +204,36 @@ export const useEditorStore = create<EditorState>()(
197204 deleteNode : ( nodeId ) => {
198205 set ( {
199206 nodes : get ( ) . nodes . filter ( ( n ) => n . id !== nodeId ) ,
200- edges : get ( ) . edges . filter ( ( e ) => e . source !== nodeId && e . target !== nodeId ) ,
201- saved : false ,
207+ edges : get ( ) . edges . filter (
208+ ( e ) => e . source !== nodeId && e . target !== nodeId ,
209+ ) ,
202210 } ) ;
203211 } ,
204212
205213 deleteEdge : ( edgeId ) => {
206214 set ( {
207215 edges : get ( ) . edges . filter ( ( e ) => e . id !== edgeId ) ,
208- saved : false ,
209216 } ) ;
210217 } ,
211218
212219 addNode : ( node ) => {
213220 set ( {
214221 nodes : [ ...get ( ) . nodes , node ] ,
215- saved : false ,
216222 } ) ;
217223 } ,
218224
219225 // UI state setters
220- setSaved : ( saved ) => set ( { saved } ) ,
221226 setPreviewMode : ( previewMode ) => set ( { previewMode } ) ,
222227 setDebugMode : ( debugMode ) => set ( { debugMode } ) ,
223228 setShowGrid : ( showGrid ) => set ( { showGrid } ) ,
224229 setHelpOpen : ( helpOpen ) => set ( { helpOpen } ) ,
225230 setDrawerOpen : ( drawerOpen ) => set ( { drawerOpen } ) ,
226- setSettingsDrawerOpen : ( settingsDrawerOpen ) => set ( { settingsDrawerOpen } ) ,
231+ setSettingsDrawerOpen : ( settingsDrawerOpen ) =>
232+ set ( { settingsDrawerOpen } ) ,
227233 setEdgeDrawerOpen : ( edgeDrawerOpen ) => set ( { edgeDrawerOpen } ) ,
228234 setShareDialogOpen : ( shareDialogOpen ) => set ( { shareDialogOpen } ) ,
229- setLoadExternalDialogOpen : ( loadExternalDialogOpen ) => set ( { loadExternalDialogOpen } ) ,
235+ setLoadExternalDialogOpen : ( loadExternalDialogOpen ) =>
236+ set ( { loadExternalDialogOpen } ) ,
230237 setSelectedNodeId : ( selectedNodeId ) => set ( { selectedNodeId } ) ,
231238 setSelectedNodeIds : ( selectedNodeIds ) => set ( { selectedNodeIds } ) ,
232239 setSelectedEdge : ( selectedEdge ) => set ( { selectedEdge } ) ,
@@ -235,14 +242,20 @@ export const useEditorStore = create<EditorState>()(
235242 setLastMousePosition : ( lastMousePosition ) => set ( { lastMousePosition } ) ,
236243 setShareLink : ( shareLink ) => set ( { shareLink } ) ,
237244 setPendingExternalId : ( pendingExternalId ) => set ( { pendingExternalId } ) ,
238- setShowCompletionNeeds : ( showCompletionNeeds ) => set ( { showCompletionNeeds } ) ,
239- setShowCompletionOptional : ( showCompletionOptional ) => set ( { showCompletionOptional } ) ,
245+ setShowCompletionNeeds : ( showCompletionNeeds ) =>
246+ set ( { showCompletionNeeds } ) ,
247+ setShowCompletionOptional : ( showCompletionOptional ) =>
248+ set ( { showCompletionOptional } ) ,
240249 setShowUnlockAfter : ( showUnlockAfter ) => set ( { showUnlockAfter } ) ,
241250
242251 // Bulk operations
243252 loadRoadmapData : ( roadmapData ) => {
244- const nodesArr = Array . isArray ( roadmapData ?. nodes ) ? roadmapData . nodes : [ ] ;
245- const edgesArr = Array . isArray ( roadmapData ?. edges ) ? roadmapData . edges : [ ] ;
253+ const nodesArr = Array . isArray ( roadmapData ?. nodes )
254+ ? roadmapData . nodes
255+ : [ ] ;
256+ const edgesArr = Array . isArray ( roadmapData ?. edges )
257+ ? roadmapData . edges
258+ : [ ] ;
246259
247260 const rawNodes = nodesArr . map ( ( n ) => ( {
248261 ...n ,
@@ -257,15 +270,17 @@ export const useEditorStore = create<EditorState>()(
257270 const maxId = Math . max (
258271 ...nodesArr
259272 . map ( ( n ) => parseInt ( n . id . replace ( / \D / g, "" ) , 10 ) )
260- . filter ( ( id ) => ! isNaN ( id ) )
273+ . filter ( ( id ) => ! isNaN ( id ) ) ,
261274 ) ;
262275 nextNodeId = maxId + 1 ;
263276 }
264277
265278 set ( {
266279 nodes : rawNodes ,
267280 edges : edgesArr ,
268- settings : roadmapData ?. settings || { background : { color : "#ffffff" } } ,
281+ settings : roadmapData ?. settings || {
282+ background : { color : "#ffffff" } ,
283+ } ,
269284 nextNodeId,
270285 } ) ;
271286 } ,
@@ -317,19 +332,25 @@ export const useEditorStore = create<EditorState>()(
317332 // Zundo options
318333 limit : 100 ,
319334 equality : ( a , b ) => a === b ,
320- }
321- )
335+ } ,
336+ ) ,
322337) ;
323338
324339// Hook for accessing temporal store (undo/redo)
325- import { useStore } from ' zustand' ;
340+ import { useStore } from " zustand" ;
326341
327342export const useTemporalStore = ( ) => {
328343 const undo = useEditorStore . temporal . getState ( ) . undo ;
329344 const redo = useEditorStore . temporal . getState ( ) . redo ;
330- const pastStates = useStore ( useEditorStore . temporal , ( state ) => state . pastStates ) ;
331- const futureStates = useStore ( useEditorStore . temporal , ( state ) => state . futureStates ) ;
332-
345+ const pastStates = useStore (
346+ useEditorStore . temporal ,
347+ ( state ) => state . pastStates ,
348+ ) ;
349+ const futureStates = useStore (
350+ useEditorStore . temporal ,
351+ ( state ) => state . futureStates ,
352+ ) ;
353+
333354 return {
334355 undo,
335356 redo,
0 commit comments