Compare commits
	
		
			1 Commits
		
	
	
		
			nicboone8-
			...
			franknoiro
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7ca51be5bc | 
| @ -18,7 +18,7 @@ import { markOnce } from '@src/lib/performance' | ||||
| import { loadAndValidateSettings } from '@src/lib/settings/settingsUtils' | ||||
| import { trap } from '@src/lib/trap' | ||||
| import type { IndexLoaderData } from '@src/lib/types' | ||||
| import { settingsActor, useSettings } from '@src/machines/appMachine' | ||||
| import { appActor, settingsActor, useSettings } from '@src/machines/appMachine' | ||||
|  | ||||
| export const RouteProviderContext = createContext({}) | ||||
|  | ||||
| @ -34,6 +34,38 @@ export function RouteProvider({ children }: { children: ReactNode }) { | ||||
|   const location = useLocation() | ||||
|   const settings = useSettings() | ||||
|  | ||||
|   /** | ||||
|    * Spawn a router machine that we can interact with outside of React, | ||||
|    * but providing the react-router-dom methods and information we need. | ||||
|    */ | ||||
|   useEffect(() => { | ||||
|     appActor.send({ | ||||
|       type: 'event:router_set_up', | ||||
|       data: { | ||||
|         location, | ||||
|         navigation, | ||||
|         navigate, | ||||
|       }, | ||||
|     }) | ||||
|   }, []) | ||||
|   /** | ||||
|    * "Subscribe" to the location and navigation from react-router-dom | ||||
|    * to keep the router actor up-to-date from here on out | ||||
|    */ | ||||
|   useEffect(() => { | ||||
|     appActor.getSnapshot().children.router?.send({ | ||||
|       type: 'event:set_location', | ||||
|       data: location, | ||||
|     }) | ||||
|   }, [location]) | ||||
|  | ||||
|   useEffect(() => { | ||||
|     appActor.getSnapshot().children.router?.send({ | ||||
|       type: 'event:set_navigation', | ||||
|       data: navigation, | ||||
|     }) | ||||
|   }, [navigation]) | ||||
|  | ||||
|   useEffect(() => { | ||||
|     // On initialization, the react-router-dom does not send a 'loading' state event. | ||||
|     // it sends an idle event first. | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { useSelector } from '@xstate/react' | ||||
| import { createActor, setup, spawnChild } from 'xstate' | ||||
| import { createActor, InputFrom, setup, spawnChild } from 'xstate' | ||||
|  | ||||
| import { createSettings } from '@src/lib/settings/initialSettings' | ||||
| import { authMachine } from '@src/machines/authMachine' | ||||
| @ -9,13 +9,15 @@ import { | ||||
|   engineStreamMachine, | ||||
| } from '@src/machines/engineStreamMachine' | ||||
| import { ACTOR_IDS } from '@src/machines/machineConstants' | ||||
| import { routerMachine } from '@src/machines/routerMachine' | ||||
| import { settingsMachine } from '@src/machines/settingsMachine' | ||||
|  | ||||
| const { AUTH, SETTINGS, ENGINE_STREAM } = ACTOR_IDS | ||||
| const { AUTH, SETTINGS, ENGINE_STREAM, ROUTER } = ACTOR_IDS | ||||
| const appMachineActors = { | ||||
|   [AUTH]: authMachine, | ||||
|   [SETTINGS]: settingsMachine, | ||||
|   [ENGINE_STREAM]: engineStreamMachine, | ||||
|   [ROUTER]: routerMachine, | ||||
| } as const | ||||
|  | ||||
| const appMachine = setup({ | ||||
| @ -23,6 +25,12 @@ const appMachine = setup({ | ||||
|     children: { | ||||
|       auth: typeof AUTH | ||||
|       settings: typeof SETTINGS | ||||
|       engine_stream: typeof ENGINE_STREAM | ||||
|       router?: typeof ROUTER | ||||
|     } | ||||
|     events: { | ||||
|       type: 'event:router_set_up' | ||||
|       data: InputFrom<typeof routerMachine> | ||||
|     } | ||||
|   }, | ||||
|   actors: appMachineActors, | ||||
| @ -41,9 +49,30 @@ const appMachine = setup({ | ||||
|       input: engineStreamContextCreate(), | ||||
|     }), | ||||
|   ], | ||||
|   on: { | ||||
|     'event:router_set_up': { | ||||
|       actions: spawnChild(ROUTER, { | ||||
|         id: ROUTER, | ||||
|         systemId: ROUTER, | ||||
|         input: ({ event, context }) => { | ||||
|           if (event.type !== 'event:router_set_up') | ||||
|             return { | ||||
|               location: {} as InputFrom<typeof routerMachine>['location'], | ||||
|               navigation: {} as InputFrom<typeof routerMachine>['navigation'], | ||||
|               navigate: (() => {}) as InputFrom< | ||||
|                 typeof routerMachine | ||||
|               >['navigate'], | ||||
|             } | ||||
|           return event.data | ||||
|         }, | ||||
|       }), | ||||
|     }, | ||||
|   }, | ||||
| }) | ||||
|  | ||||
| export const appActor = createActor(appMachine) | ||||
| // REMOVE THIS BEFORE MERGING | ||||
| window.appActor = appActor | ||||
| /** | ||||
|  * GOTCHA: the type coercion of this actor works because it is spawned for | ||||
|  * the lifetime of {appActor}, but would not work if it were invoked | ||||
|  | ||||
| @ -2,4 +2,5 @@ export const ACTOR_IDS = { | ||||
|   AUTH: 'auth', | ||||
|   SETTINGS: 'settings', | ||||
|   ENGINE_STREAM: 'engine_stream', | ||||
|   ROUTER: 'router', | ||||
| } as const | ||||
|  | ||||
							
								
								
									
										81
									
								
								src/machines/routerMachine.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/machines/routerMachine.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| import { useLocation, useNavigate, useNavigation } from 'react-router-dom' | ||||
| import { assign, setup } from 'xstate' | ||||
|  | ||||
| export const routerMachine = setup({ | ||||
|   types: {} as { | ||||
|     context: { | ||||
|       location: ReturnType<typeof useLocation> | ||||
|       navigation: ReturnType<typeof useNavigation> | ||||
|       navigate: ReturnType<typeof useNavigate> | ||||
|     } | ||||
|     input: { | ||||
|       location: ReturnType<typeof useLocation> | ||||
|       navigation: ReturnType<typeof useNavigation> | ||||
|       navigate: ReturnType<typeof useNavigate> | ||||
|     } | ||||
|     events: | ||||
|       | { | ||||
|           type: 'event:navigate' | ||||
|           data: Parameters<ReturnType<typeof useNavigate>> | ||||
|         } | ||||
|       | { type: 'event:set_location'; data: ReturnType<typeof useLocation> } | ||||
|       | { type: 'event:set_navigation'; data: ReturnType<typeof useNavigation> } | ||||
|   }, | ||||
|   actions: { | ||||
|     navigate: ( | ||||
|       _, | ||||
|       params: { | ||||
|         navigate: ReturnType<typeof useNavigate> | ||||
|         args: Parameters<ReturnType<typeof useNavigate>> | ||||
|       } | ||||
|     ) => { | ||||
|       console.log("FRANK let's try and navigate", { | ||||
|         params, | ||||
|       }) | ||||
|       params.navigate(...params.args) | ||||
|     }, | ||||
|   }, | ||||
| }).createMachine({ | ||||
|   id: 'router', | ||||
|   context: ({ input }) => ({ | ||||
|     ...input, | ||||
|   }), | ||||
|   on: { | ||||
|     'event:navigate': { | ||||
|       actions: { | ||||
|         type: 'navigate', | ||||
|         params: ({ event, context }) => ({ | ||||
|           navigate: context.navigate, | ||||
|           args: event.data, | ||||
|         }), | ||||
|       }, | ||||
|     }, | ||||
|     'event:set_location': { | ||||
|       actions: assign({ | ||||
|         location: ({ event }) => event.data, | ||||
|       }), | ||||
|     }, | ||||
|     'event:set_navigation': { | ||||
|       actions: assign({ | ||||
|         navigation: ({ event }) => event.data, | ||||
|       }), | ||||
|     }, | ||||
|   }, | ||||
|   // states: { | ||||
|   //   idle: { | ||||
|   //     on: { | ||||
|   //       'event:navigate:start': { | ||||
|   //         target: 'navigating', | ||||
|   //         actions: ['navigate'], | ||||
|   //       }, | ||||
|   //     }, | ||||
|   //   }, | ||||
|   //   navigating: { | ||||
|   //     on: { | ||||
|   //       'event:navigate:end': { | ||||
|   //         target: 'idle', | ||||
|   //       }, | ||||
|   //     }, | ||||
|   //   }, | ||||
|   // }, | ||||
| }) | ||||
		Reference in New Issue
	
	Block a user
	