A small inspect function to log events to the browser console, when you expand a group you see a log of the full event object.
const [state, send, actor] = useActor(myMachine, {
inspect: logInspectionEvent,
});I know right 🤮, mainly this is down to the API for applying colours to browser console logs and this is about 30 minutes' work.
If you do any clean up on this, please comment and let me know. You'll notice there is a ts: Property 'id' does not exist on type 'ActorRefLike' – but they can have an ID.
import type { InspectionEvent, StateValue } from 'xstate';
export function logInspectionEvent(event: InspectionEvent): void {
const internalEvent = event.type;
const style = {
action: 'color:#F48FB1',
actor: 'color:inherit',
eventType: 'color:#81D4FA',
internalEvent: 'color:#999',
} as const;
switch (event.type) {
case '@xstate.snapshot': {
const actor = event.actorRef?.id;
console.groupCollapsed(`%c${internalEvent} %c${actor}`, style.internalEvent, style.actor);
break;
}
case '@xstate.event': {
const eventType = event.event?.type;
const sourceId = event.sourceRef?.id;
const actorId = event.actorRef?.id;
if (sourceId && actorId) {
console.groupCollapsed(`%c${internalEvent} %c${eventType} %c${sourceId} ➤ ${actorId}`, style.internalEvent, style.eventType, style.actor);
} else {
console.groupCollapsed(`%c${internalEvent} %c${eventType} %c${actorId}`, style.internalEvent, style.eventType, style.actor);
}
break;
}
case '@xstate.actor': {
const actorId = event.actorRef?.id;
console.groupCollapsed(`%c${internalEvent} %c${actorId}`, style.internalEvent, style.actor);
break;
}
case '@xstate.microstep': {
const actorId = event.actorRef?.id;
const eventType = event.event?.type;
const stateValue = getStateValueStrings(event.snapshot.value).sort().join('\n ');
console.groupCollapsed(`%c${internalEvent} %c${eventType} %c${actorId}\n %c${stateValue}`, style.internalEvent, style.eventType, style.actor, style.internalEvent);
break;
}
case '@xstate.action': {
const actorId = event.actorRef?.id;
const actionType = event.action?.type;
if (actionType === 'xstate.emit') {
const eventType = event.action.params?.event?.type;
console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${actorId} %c${eventType}`, style.internalEvent, style.action, style.actor, style.eventType);
} else if (actionType === 'xstate.stopChild' || actionType === 'xstate.spawnChild') {
const childSrc = event.action.params?.src;
console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${actorId} ➤ %c${childSrc}`, style.internalEvent, style.action, style.actor, style.actor);
} else if (actionType === 'xstate.sendTo') {
const targetId = event.action.params?.to?.id;
const eventType = event.action.params?.event?.type;
console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${eventType} %c${actorId} ➤ %c${targetId}`, style.internalEvent, style.action, style.eventType, style.actor, style.actor);
}
// console.groupCollapsed(`%c${internalEvent} %c${actionType} %c${actorId}`, style.internalEvent, style.action, style.actor);
break;
}
}
console.log(event);
console.groupEnd();
}
function getStateValueStrings(stateValue: StateValue): string[] {
if (typeof stateValue === 'string') {
return [stateValue];
}
const valueKeys = Object.keys(stateValue);
return valueKeys.concat(...valueKeys.map(key => getStateValueStrings(stateValue[key]!).map(s => key + '.' + s)));
}