import { CustomIconName } from 'components/CustomIcon' import { AllMachines } from 'hooks/useStateMachineCommands' import { Actor, AnyStateMachine, ContextFrom, EventFrom } from 'xstate' import { Selection } from './selections' import { Identifier, Expr, VariableDeclaration } from 'lang/wasm' import { commandBarMachine } from 'machines/commandBarMachine' import { ReactNode } from 'react' type Icon = CustomIconName const PLATFORMS = ['both', 'web', 'desktop'] as const const INPUT_TYPES = [ 'options', 'string', 'text', 'kcl', 'selection', 'boolean', ] as const export interface KclExpression { valueAst: Expr valueText: string valueCalculated: string } export interface KclExpressionWithVariable extends KclExpression { variableName: string variableDeclarationAst: VariableDeclaration variableIdentifierAst: Identifier insertIndex: number } export type KclCommandValue = KclExpression | KclExpressionWithVariable export type CommandInputType = (typeof INPUT_TYPES)[number] export type StateMachineCommandSetSchema = Partial<{ [EventType in EventFrom['type']]: Record }> export type StateMachineCommandSet< T extends AllMachines, Schema extends StateMachineCommandSetSchema > = Partial<{ [EventType in EventFrom['type']]: Command< T, EventFrom['type'], Schema[EventType] > }> /** * A configuration object for a set of commands tied to a state machine. * Each event type can have one or more commands associated with it. * @param T The state machine type. * @param Schema The schema for the command set, defined by the developer. */ export type StateMachineCommandSetConfig< T extends AllMachines, Schema extends StateMachineCommandSetSchema > = Partial<{ [EventType in EventFrom['type']]: | CommandConfig['type'], Schema[EventType]> | CommandConfig['type'], Schema[EventType]>[] }> export type Command< T extends AnyStateMachine = AnyStateMachine, CommandName extends EventFrom['type'] = EventFrom['type'], CommandSchema extends StateMachineCommandSetSchema[CommandName] = StateMachineCommandSetSchema[CommandName] > = { name: CommandName groupId: T['id'] needsReview: boolean reviewMessage?: | string | ReactNode | (( commandBarContext: { argumentsToSubmit: Record } // Should be the commandbarMachine's context, but it creates a circular dependency ) => string | ReactNode) onSubmit: (data?: CommandSchema) => void onCancel?: () => void args?: { [ArgName in keyof CommandSchema]: CommandArgument } displayName?: string description?: string icon?: Icon hide?: (typeof PLATFORMS)[number] } export type CommandConfig< T extends AnyStateMachine = AnyStateMachine, CommandName extends EventFrom['type'] = EventFrom['type'], CommandSchema extends StateMachineCommandSetSchema[CommandName] = StateMachineCommandSetSchema[CommandName] > = Omit< Command, 'name' | 'groupId' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview' > & { needsReview?: true args?: { [ArgName in keyof CommandSchema]: CommandArgumentConfig< CommandSchema[ArgName], ContextFrom > } } export type CommandArgumentConfig< OutputType, C = ContextFrom > = { description?: string required: | boolean | (( commandBarContext: { argumentsToSubmit: Record }, // Should be the commandbarMachine's context, but it creates a circular dependency machineContext?: C ) => boolean) warningMessage?: string skip?: boolean /** For showing a summary display of the current value, such as in * the command bar's header */ valueSummary?: (value: OutputType) => string } & ( | { inputType: 'options' options: | CommandArgumentOption[] | (( commandBarContext: { argumentsToSubmit: Record }, // Should be the commandbarMachine's context, but it creates a circular dependency machineContext?: C ) => CommandArgumentOption[]) optionsFromContext?: (context: C) => CommandArgumentOption[] defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: C ) => OutputType) defaultValueFromContext?: (context: C) => OutputType } | { inputType: 'selection' selectionTypes: Selection['type'][] multiple: boolean } | { inputType: 'kcl'; defaultValue?: string } // KCL expression inputs have simple strings as default values | { inputType: 'string' defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: C ) => OutputType) defaultValueFromContext?: (context: C) => OutputType } | { inputType: 'text' defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: C ) => OutputType) defaultValueFromContext?: (context: C) => OutputType } | { inputType: 'boolean' defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: C ) => OutputType) defaultValueFromContext?: (context: C) => OutputType } ) export type CommandArgument< OutputType, T extends AnyStateMachine = AnyStateMachine > = { description?: string required: | boolean | (( commandBarContext: { argumentsToSubmit: Record }, // Should be the commandbarMachine's context, but it creates a circular dependency machineContext?: ContextFrom ) => boolean) skip?: boolean machineActor?: Actor warningMessage?: string /** For showing a summary display of the current value, such as in * the command bar's header */ valueSummary?: (value: OutputType) => string } & ( | { inputType: Extract options: | CommandArgumentOption[] | (( commandBarContext: { argumentsToSubmit: Record }, // Should be the commandbarMachine's context, but it creates a circular dependency machineContext?: ContextFrom ) => CommandArgumentOption[]) defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: ContextFrom ) => OutputType) } | { inputType: 'selection' selectionTypes: Selection['type'][] multiple: boolean } | { inputType: 'kcl'; defaultValue?: string } // KCL expression inputs have simple strings as default value | { inputType: 'string' defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: ContextFrom ) => OutputType) } | { inputType: 'text' defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: ContextFrom ) => OutputType) } | { inputType: 'boolean' defaultValue?: | OutputType | (( commandBarContext: ContextFrom, machineContext?: ContextFrom ) => OutputType) } ) export type CommandArgumentWithName< OutputType, T extends AnyStateMachine = AnyStateMachine > = CommandArgument & { name: string } export type CommandArgumentOption = { name: string isCurrent?: boolean value: A }