import type { HierarchyNode } from 'd3-hierarchy'; import type { ActorRef } from 'xstate'; import { createMachine, assign, spawn, send, sendParent } from 'xstate'; import type { IFieldBase } from '$lib/Models'; import { validationMachine } from './util/validationMachine'; export type StepContext = { node: HierarchyNode; specialistMachineScaffold: any; specialistMachine: ActorRef; validationMachine: any; }; export type StepState = { value: 'initializing' | 'idle' | { active: { interaction: 'pristine' | 'touched' | 'dirty', focus: 'blurred' | 'focused' } | 'submitted' }; context: StepContext }; export const stepMachine = createMachine( { context: { node: null, specialistMachineScaffold: null, specialistMachine: null, validationMachine: null }, tsTypes: {} as import("./stepMachine.typegen").Typegen0, schema: { context: {} as StepContext, events: {} as { type: 'ACTIVATE_STEP' } | { type: 'DEACTIVATE_STEP' } | { type: 'SUBMIT_NODE' } | { type: 'VALIDATED', value: any } | { type: 'INVALIDATED', value: any } | { type: 'FOCUS', value: any } | { type: 'BLUR', value: any } | { type: 'CHANGE', value: any } | // routing { type: 'REFRESH_FIELDS', fieldMap: any } | { type: 'SOURCE_DYNAMIC_VALUE', dataKeySourceId: string, returnAction: string, returnKey: string } | { type: 'SOURCE_DYNAMIC_VALUE_RESPONSE', dataKeySourceId: string, returnAction: string, returnKey: string, value: any } }, id: '', initial: 'initializing', states: { initializing: { entry: [ 'assignMachines' ], always: 'idle' }, idle: { entry: [ 'deactivateSpecialistMachine' ], on: { ACTIVATE_STEP: 'active', SUBMIT_NODE: 'submitted' } }, active: { type: 'parallel', entry: [ 'activateSpecialistMachine' ], states: { interaction: { initial: 'pristine', states:{ pristine: { on: { FOCUS: 'touched', CHANGE: { target: 'dirty', actions: [ 'assignChanges', 'startValidation', ] } } }, touched: { on: { CHANGE: { target: 'dirty', actions: [ 'assignChanges', 'startValidation', ] } } }, dirty: { type: 'final' } } }, focus: { initial: 'blurred', states:{ blurred: { on: { FOCUS: 'focused' } }, focused: { on: { BLUR: 'blurred' } } } } }, on: { CHANGE: { internal: false, actions: [ 'assignChanges', 'startValidation', 'resetQueue' ] }, VALIDATED: { actions: [ 'addProgressToLeaf', 'queue' ] }, INVALIDATED: { actions: [ 'unqueue' ] }, DEACTIVATE_STEP: 'idle', SUBMIT_NODE: 'submitted' } }, submitted: { type: 'final' } }, on: { SOURCE_DYNAMIC_VALUE: { actions: [ 'forwardDynamicRequestToParent' ] }, SOURCE_DYNAMIC_VALUE_RESPONSE: { actions: [ 'forwardDynamicValueSpecialistMachine' ] }, REFRESH_FIELDS: { actions: [ 'broadcastFields' ] } } }, { actions: { activateSpecialistMachine: send({ type: 'ACTIVATE_MACHINE' }, { to: (context, event) => context.specialistMachine }), deactivateSpecialistMachine: send({ type: 'DEACTIVATE_MACHINE' }, { to: (context, event) => context.specialistMachine }), assignMachines: assign((context) => { return { ...context, specialistMachine: spawn( context.specialistMachineScaffold.withContext({ ...context.specialistMachineScaffold.context, field: context.node.data }) ), validationMachine: spawn( validationMachine, { name: 'validationMachine' } ) } }), assignChanges: assign({ node: (context, event) => { (c,e) => console.log("second hit in assignChanges: ", c, e) context.node.data = event.value || context.node.data; return context.node; } }), startValidation: send( (context) => ({ type: 'VALIDATE', field: context.node.data }), { to: (context) => context.validationMachine } ), addProgressToLeaf: assign({ node: (context, event) => { const leaf = context.node; leaf.data.progress = 100; return leaf; } }), queue: sendParent((context, event) => ({ type: 'QUEUE', delay: context.node.data.waitForHowManyMSBeforeSubmit })), resetQueue: sendParent((context, event) => ({ type: 'RESET_QUEUE' })), unqueue: sendParent((context, event) => ({ type: 'UNQUEUE' })), forwardDynamicRequestToParent: sendParent((context, event) => { console.log("recieved dynamic request in step machine:", event); return event; }), forwardDynamicValueSpecialistMachine: send((context, event) => { return { type: event.returnAction, [ event.returnKey ]: event.value }; }, { to: (context, event) => context.specialistMachine }), broadcastFields: send((context, event) => event, { to: (context, event) => context.specialistMachine }) } } )