Add sketch tools back to the command bar (#3008)

* Make machine command type names more explicit

* Prepare "change tool" event for command bar

* Make it so that state machine events can each map to multiple command configs

* Make commands with all skippable args possible

* Add back the tools to the command bar

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Update to use new `groupId` property name

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Oops didn't save this other instance of `ownerMachine`

* Add a playwright test

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2024-07-12 16:16:26 -04:00
committed by GitHub
parent 0710f6e5f2
commit 5a5fe3bb95
25 changed files with 180 additions and 70 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -3691,6 +3691,46 @@ const extrude001 = extrude(distance001, sketch001)`.replace(
) // remove newlines ) // remove newlines
) )
}) })
test('Can switch between sketch tools via command bar', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
const cmdBarButton = page.getByRole('button', { name: 'Commands' })
const rectangleToolCommand = page.getByRole('option', {
name: 'Rectangle',
})
const rectangleToolButton = page.getByRole('button', { name: 'Rectangle' })
const lineToolCommand = page.getByRole('option', { name: 'Line' })
const lineToolButton = page.getByRole('button', { name: 'Line' })
const arcToolCommand = page.getByRole('option', { name: 'Tangential Arc' })
const arcToolButton = page.getByRole('button', { name: 'Tangential Arc' })
// Start a sketch
await sketchButton.click()
await page.mouse.click(700, 200)
// Switch between sketch tools via the command bar
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
await cmdBarButton.click()
await rectangleToolCommand.click()
await expect(rectangleToolButton).toHaveAttribute('aria-pressed', 'true')
await cmdBarButton.click()
await lineToolCommand.click()
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
// Click in the scene a couple times to draw a line
// so tangential arc is valid
await page.mouse.click(700, 200)
await page.mouse.click(700, 300)
// switch to tangential arc via command bar
await cmdBarButton.click()
await arcToolCommand.click()
await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
})
}) })
test.describe('Regression tests', () => { test.describe('Regression tests', () => {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -60,7 +60,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: 'line', data: { tool: 'line' },
}), }),
{ enabled: !disableLineButton, scopes: ['sketch'] } { enabled: !disableLineButton, scopes: ['sketch'] }
) )
@ -75,7 +75,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: 'tangentialArc', data: { tool: 'tangentialArc' },
}), }),
{ enabled: !disableTangentialArc, scopes: ['sketch'] } { enabled: !disableTangentialArc, scopes: ['sketch'] }
) )
@ -89,7 +89,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: 'rectangle', data: { tool: 'rectangle' },
}), }),
{ enabled: !disableRectangle, scopes: ['sketch'] } { enabled: !disableRectangle, scopes: ['sketch'] }
) )
@ -263,7 +263,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: 'line', data: { tool: 'line' },
}) })
} }
aria-pressed={state?.matches('Sketch.Line tool')} aria-pressed={state?.matches('Sketch.Line tool')}
@ -293,7 +293,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: 'tangentialArc', data: { tool: 'tangentialArc' },
}) })
} }
aria-pressed={state.matches('Sketch.Tangential arc to')} aria-pressed={state.matches('Sketch.Tangential arc to')}
@ -323,7 +323,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: 'rectangle', data: { tool: 'rectangle' },
}) })
} }
aria-pressed={state.matches('Sketch.Rectangle tool')} aria-pressed={state.matches('Sketch.Rectangle tool')}

View File

@ -28,6 +28,11 @@ export const CommandBarProvider = ({
Object.keys(context.selectedCommand?.args).length === 0 Object.keys(context.selectedCommand?.args).length === 0
) )
}, },
'All arguments are skippable': (context, _event) => {
return Object.values(context.selectedCommand!.args!).every(
(argConfig) => argConfig.skip
)
},
}, },
}) })

View File

@ -70,7 +70,7 @@ function CommandComboBox({
> >
{filteredOptions?.map((option) => ( {filteredOptions?.map((option) => (
<Combobox.Option <Combobox.Option
key={option.name} key={option.groupId + option.name + (option.displayName || '')}
value={option} value={option}
className="flex items-center gap-2 px-4 py-1 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90" className="flex items-center gap-2 px-4 py-1 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90"
> >

View File

@ -42,7 +42,7 @@ import {
import { applyConstraintIntersect } from './Toolbar/Intersect' import { applyConstraintIntersect } from './Toolbar/Intersect'
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance' import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
import useStateMachineCommands from 'hooks/useStateMachineCommands' import useStateMachineCommands from 'hooks/useStateMachineCommands'
import { modelingMachineConfig } from 'lib/commandBarConfigs/modelingCommandConfig' import { modelingMachineCommandConfig } from 'lib/commandBarConfigs/modelingCommandConfig'
import { import {
STRAIGHT_SEGMENT, STRAIGHT_SEGMENT,
TANGENTIAL_ARC_TO_SEGMENT, TANGENTIAL_ARC_TO_SEGMENT,
@ -920,7 +920,7 @@ export const ModelingMachineProvider = ({
state: modelingState, state: modelingState,
send: modelingSend, send: modelingSend,
actor: modelingActor, actor: modelingActor,
commandBarConfig: modelingMachineConfig, commandBarConfig: modelingMachineCommandConfig,
allCommandsRequireNetwork: true, allCommandsRequireNetwork: true,
// TODO for when sketch tools are in the toolbar: This was added when we used one "Cancel" event, // TODO for when sketch tools are in the toolbar: This was added when we used one "Cancel" event,
// but we need to support "SketchCancel" and basically // but we need to support "SketchCancel" and basically

View File

@ -6,7 +6,11 @@ import { modelingMachine } from 'machines/modelingMachine'
import { authMachine } from 'machines/authMachine' import { authMachine } from 'machines/authMachine'
import { settingsMachine } from 'machines/settingsMachine' import { settingsMachine } from 'machines/settingsMachine'
import { homeMachine } from 'machines/homeMachine' import { homeMachine } from 'machines/homeMachine'
import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes' import {
Command,
StateMachineCommandSetConfig,
StateMachineCommandSetSchema,
} from 'lib/commandTypes'
import { useKclContext } from 'lang/KclProvider' import { useKclContext } from 'lang/KclProvider'
import { useNetworkContext } from 'hooks/useNetworkContext' import { useNetworkContext } from 'hooks/useNetworkContext'
import { NetworkHealthState } from 'hooks/useNetworkStatus' import { NetworkHealthState } from 'hooks/useNetworkStatus'
@ -21,20 +25,20 @@ export type AllMachines =
interface UseStateMachineCommandsArgs< interface UseStateMachineCommandsArgs<
T extends AllMachines, T extends AllMachines,
S extends CommandSetSchema<T> S extends StateMachineCommandSetSchema<T>
> { > {
machineId: T['id'] machineId: T['id']
state: StateFrom<T> state: StateFrom<T>
send: Function send: Function
actor: InterpreterFrom<T> actor: InterpreterFrom<T>
commandBarConfig?: CommandSetConfig<T, S> commandBarConfig?: StateMachineCommandSetConfig<T, S>
allCommandsRequireNetwork?: boolean allCommandsRequireNetwork?: boolean
onCancel?: () => void onCancel?: () => void
} }
export default function useStateMachineCommands< export default function useStateMachineCommands<
T extends AnyStateMachine, T extends AnyStateMachine,
S extends CommandSetSchema<T> S extends StateMachineCommandSetSchema<T>
>({ >({
machineId, machineId,
state, state,
@ -58,7 +62,7 @@ export default function useStateMachineCommands<
const newCommands = state.nextEvents const newCommands = state.nextEvents
.filter((_) => !allCommandsRequireNetwork || !disableAllButtons) .filter((_) => !allCommandsRequireNetwork || !disableAllButtons)
.filter((e) => !['done.', 'error.'].some((n) => e.includes(n))) .filter((e) => !['done.', 'error.'].some((n) => e.includes(n)))
.map((type) => .flatMap((type) =>
createMachineCommand<T, S>({ createMachineCommand<T, S>({
// The group is the owner machine's ID. // The group is the owner machine's ID.
groupId: machineId, groupId: machineId,

View File

@ -1,9 +1,9 @@
import { CommandSetConfig } from 'lib/commandTypes' import { StateMachineCommandSetConfig } from 'lib/commandTypes'
import { authMachine } from 'machines/authMachine' import { authMachine } from 'machines/authMachine'
type AuthCommandSchema = {} type AuthCommandSchema = {}
export const authCommandBarConfig: CommandSetConfig< export const authCommandBarConfig: StateMachineCommandSetConfig<
typeof authMachine, typeof authMachine,
AuthCommandSchema AuthCommandSchema
> = { > = {

View File

@ -1,4 +1,4 @@
import { CommandSetConfig } from 'lib/commandTypes' import { StateMachineCommandSetConfig } from 'lib/commandTypes'
import { homeMachine } from 'machines/homeMachine' import { homeMachine } from 'machines/homeMachine'
export type HomeCommandSchema = { export type HomeCommandSchema = {
@ -17,7 +17,7 @@ export type HomeCommandSchema = {
} }
} }
export const homeCommandBarConfig: CommandSetConfig< export const homeCommandBarConfig: StateMachineCommandSetConfig<
typeof homeMachine, typeof homeMachine,
HomeCommandSchema HomeCommandSchema
> = { > = {

View File

@ -1,8 +1,8 @@
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { CommandSetConfig, KclCommandValue } from 'lib/commandTypes' import { StateMachineCommandSetConfig, KclCommandValue } from 'lib/commandTypes'
import { KCL_DEFAULT_LENGTH } from 'lib/constants' import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import { Selections } from 'lib/selections' import { Selections } from 'lib/selections'
import { modelingMachine } from 'machines/modelingMachine' import { modelingMachine, SketchTool } from 'machines/modelingMachine'
type OutputFormat = Models['OutputFormat_type'] type OutputFormat = Models['OutputFormat_type']
type OutputTypeKey = OutputFormat['type'] type OutputTypeKey = OutputFormat['type']
@ -27,9 +27,12 @@ export type ModelingCommandSchema = {
// result: (typeof EXTRUSION_RESULTS)[number] // result: (typeof EXTRUSION_RESULTS)[number]
distance: KclCommandValue distance: KclCommandValue
} }
'change tool': {
tool: SketchTool
}
} }
export const modelingMachineConfig: CommandSetConfig< export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
typeof modelingMachine, typeof modelingMachine,
ModelingCommandSchema ModelingCommandSchema
> = { > = {
@ -37,22 +40,47 @@ export const modelingMachineConfig: CommandSetConfig<
description: 'Enter sketch mode.', description: 'Enter sketch mode.',
icon: 'sketch', icon: 'sketch',
}, },
// TODO the event is no 'change tool' with data: 'line', 'rectangle' etc 'change tool': [
// 'Equip Line tool': { {
// description: 'Start drawing straight lines.', description: 'Start drawing straight lines.',
// icon: 'line', icon: 'line',
// displayName: 'Line', displayName: 'Line',
// }, args: {
// 'Equip tangential arc to': { tool: {
// description: 'Start drawing an arc tangent to the current segment.', defaultValue: 'line',
// icon: 'arc', required: true,
// displayName: 'Tangential Arc', skip: true,
// }, inputType: 'string',
// 'Equip rectangle tool': { },
// description: 'Start drawing a rectangle.', },
// icon: 'rectangle', },
// displayName: 'Rectangle', {
// }, description: 'Start drawing an arc tangent to the current segment.',
icon: 'arc',
displayName: 'Tangential Arc',
args: {
tool: {
defaultValue: 'tangentialArc',
required: true,
skip: true,
inputType: 'string',
},
},
},
{
description: 'Start drawing a rectangle.',
icon: 'rectangle',
displayName: 'Rectangle',
args: {
tool: {
defaultValue: 'rectangle',
required: true,
skip: true,
inputType: 'string',
},
},
},
],
Export: { Export: {
description: 'Export the current model.', description: 'Export the current model.',
icon: 'exportFile', icon: 'exportFile',

View File

@ -33,13 +33,13 @@ export interface KclExpressionWithVariable extends KclExpression {
export type KclCommandValue = KclExpression | KclExpressionWithVariable export type KclCommandValue = KclExpression | KclExpressionWithVariable
export type CommandInputType = (typeof INPUT_TYPES)[number] export type CommandInputType = (typeof INPUT_TYPES)[number]
export type CommandSetSchema<T extends AnyStateMachine> = Partial<{ export type StateMachineCommandSetSchema<T extends AnyStateMachine> = Partial<{
[EventType in EventFrom<T>['type']]: Record<string, any> [EventType in EventFrom<T>['type']]: Record<string, any>
}> }>
export type CommandSet< export type StateMachineCommandSet<
T extends AllMachines, T extends AllMachines,
Schema extends CommandSetSchema<T> Schema extends StateMachineCommandSetSchema<T>
> = Partial<{ > = Partial<{
[EventType in EventFrom<T>['type']]: Command< [EventType in EventFrom<T>['type']]: Command<
T, T,
@ -48,21 +48,25 @@ export type CommandSet<
> >
}> }>
export type CommandSetConfig< /**
* 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, T extends AllMachines,
Schema extends CommandSetSchema<T> Schema extends StateMachineCommandSetSchema<T>
> = Partial<{ > = Partial<{
[EventType in EventFrom<T>['type']]: CommandConfig< [EventType in EventFrom<T>['type']]:
T, | CommandConfig<T, EventFrom<T>['type'], Schema[EventType]>
EventFrom<T>['type'], | CommandConfig<T, EventFrom<T>['type'], Schema[EventType]>[]
Schema[EventType]
>
}> }>
export type Command< export type Command<
T extends AnyStateMachine = AnyStateMachine, T extends AnyStateMachine = AnyStateMachine,
CommandName extends EventFrom<T>['type'] = EventFrom<T>['type'], CommandName extends EventFrom<T>['type'] = EventFrom<T>['type'],
CommandSchema extends CommandSetSchema<T>[CommandName] = CommandSetSchema<T>[CommandName] CommandSchema extends StateMachineCommandSetSchema<T>[CommandName] = StateMachineCommandSetSchema<T>[CommandName]
> = { > = {
name: CommandName name: CommandName
groupId: T['id'] groupId: T['id']
@ -81,7 +85,7 @@ export type Command<
export type CommandConfig< export type CommandConfig<
T extends AnyStateMachine = AnyStateMachine, T extends AnyStateMachine = AnyStateMachine,
CommandName extends EventFrom<T>['type'] = EventFrom<T>['type'], CommandName extends EventFrom<T>['type'] = EventFrom<T>['type'],
CommandSchema extends CommandSetSchema<T>[CommandName] = CommandSetSchema<T>[CommandName] CommandSchema extends StateMachineCommandSetSchema<T>[CommandName] = StateMachineCommandSetSchema<T>[CommandName]
> = Omit< > = Omit<
Command<T, CommandName, CommandSchema>, Command<T, CommandName, CommandSchema>,
'name' | 'groupId' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview' 'name' | 'groupId' | 'onSubmit' | 'onCancel' | 'args' | 'needsReview'

View File

@ -11,20 +11,20 @@ import {
CommandArgument, CommandArgument,
CommandArgumentConfig, CommandArgumentConfig,
CommandConfig, CommandConfig,
CommandSetConfig, StateMachineCommandSetConfig,
CommandSetSchema, StateMachineCommandSetSchema,
} from './commandTypes' } from './commandTypes'
interface CreateMachineCommandProps< interface CreateMachineCommandProps<
T extends AnyStateMachine, T extends AnyStateMachine,
S extends CommandSetSchema<T> S extends StateMachineCommandSetSchema<T>
> { > {
type: EventFrom<T>['type'] type: EventFrom<T>['type']
groupId: T['id'] groupId: T['id']
state: StateFrom<T> state: StateFrom<T>
send: Function send: Function
actor: InterpreterFrom<T> actor: InterpreterFrom<T>
commandBarConfig?: CommandSetConfig<T, S> commandBarConfig?: StateMachineCommandSetConfig<T, S>
onCancel?: () => void onCancel?: () => void
} }
@ -32,7 +32,7 @@ interface CreateMachineCommandProps<
// from a more terse Command Bar Meta definition. // from a more terse Command Bar Meta definition.
export function createMachineCommand< export function createMachineCommand<
T extends AnyStateMachine, T extends AnyStateMachine,
S extends CommandSetSchema<T> S extends StateMachineCommandSetSchema<T>
>({ >({
groupId, groupId,
type, type,
@ -41,13 +41,30 @@ export function createMachineCommand<
actor, actor,
commandBarConfig, commandBarConfig,
onCancel, onCancel,
}: CreateMachineCommandProps<T, S>): Command< }: CreateMachineCommandProps<T, S>):
T, | Command<T, typeof type, S[typeof type]>
typeof type, | Command<T, typeof type, S[typeof type]>[]
S[typeof type] | null {
> | null {
const commandConfig = commandBarConfig && commandBarConfig[type] const commandConfig = commandBarConfig && commandBarConfig[type]
if (!commandConfig) return null // There may be no command config for this event type,
// or there may be multiple commands to create.
if (!commandConfig) {
return null
} else if (commandConfig instanceof Array) {
return commandConfig
.map((config) =>
createMachineCommand({
groupId,
type,
state,
send,
actor,
commandBarConfig: { [type]: config },
onCancel,
})
)
.filter((c) => c !== null) as Command<T, typeof type, S[typeof type]>[]
}
// Hide commands based on platform by returning `null` // Hide commands based on platform by returning `null`
// so the consumer can filter them out // so the consumer can filter them out
@ -84,6 +101,10 @@ export function createMachineCommand<
command.onCancel = onCancel command.onCancel = onCancel
} }
if ('displayName' in commandConfig) {
command.displayName = commandConfig.displayName
}
return command return command
} }
@ -92,7 +113,7 @@ export function createMachineCommand<
// bundled together into the args for a Command. // bundled together into the args for a Command.
function buildCommandArguments< function buildCommandArguments<
T extends AnyStateMachine, T extends AnyStateMachine,
S extends CommandSetSchema<T>, S extends StateMachineCommandSetSchema<T>,
CommandName extends EventFrom<T>['type'] = EventFrom<T>['type'] CommandName extends EventFrom<T>['type'] = EventFrom<T>['type']
>( >(
state: StateFrom<T>, state: StateFrom<T>,
@ -112,7 +133,7 @@ function buildCommandArguments<
export function buildCommandArgument< export function buildCommandArgument<
T extends AnyStateMachine, T extends AnyStateMachine,
O extends CommandSetSchema<T> = CommandSetSchema<T> O extends StateMachineCommandSetSchema<T> = StateMachineCommandSetSchema<T>
>( >(
arg: CommandArgumentConfig<O, T>, arg: CommandArgumentConfig<O, T>,
context: ContextFrom<T>, context: ContextFrom<T>,

View File

@ -66,7 +66,7 @@ export type CommandBarMachineEvent =
export const commandBarMachine = createMachine( export const commandBarMachine = createMachine(
{ {
/** @xstate-layout N4IgpgJg5mDOIC5QGED2BbdBDAdhABAEJYBOAxMgDaqxgDaADALqKgAONAlgC6eo6sQAD0QBaAJwA6AGwAmAKwBmBoukAWafIAcDcSoA0IAJ6JZDaZIDs8hgzV6AjA61a1DWQF8PhtJlwFiciowUkYWJBAOWB4+AQiRBFF5CwdpcVkHS1lpVyU5QxNEh1lFGTUsrUUtOQd5SwZLLx8MbDwiUkkqGkgyAHk2MBwwwSiY-kEEswZJbPltM0U3eXLZAsRFeQcrerUHRbTFvfkmkF9WgI6u2ggyADFONv98WkowAGNufDeW-2GI0d443iiHESkktUUilkskqdiUWjWCAcDC0kjUqnElkc6lkoK0JzOT0CnWo1zIAEEIARvn48LA-uwuIC4qAEqIHJjJPJcYtxFoYdJFFjVsZEG5pqCquJxJoGvJxOUCT82sSrj0AEpgdCoABuYC+yog9OYIyZsQmYmhWzMmTqLnU0kyikRGVRbj5lg2SmUam5StpFxIkgAymBXh8HlADQGyKHw58aecGZEzUDWYgchY7CisWoSlpQQ5EVDLJJxKkdIpyypUop-ed2kHCW0Xu9uD1kwDzcCEJCtlUNgWhZZ1OlnaKEBpZJItHVzDZ5xlpPWiZdDc8w22Ow5wozosyLUiVNMSg5ytVKmfrIipzO564z2otPVpI1vKd18SAOJYbgACzAEhI3wUgoAAV3QQZuFgCg-1wGAvjAkgSCgkCSHAyCcG4TtUxZYRED2TQZGSOw80qaQ7ARCc9mmZYSksextGkNJBRXFUOh-f9AOA0CIKgmCABE4E3D5oyTE1-lww8clKBjZF2Bh5SFZwXUUyRVDzJwNE2LQzzYwNJE4gCgJwKNeMw6DJHJAB3LAYlM-AHjYMDuFjMCACN0B4NCMKgnD927dMkWSUs8yY8RISfWQshvcsrDlapshULJPHfZsDKM7iHPM-jJAANSwShOAgX9IzICB+DASQHh1VAAGsqp1Qrit-MByXQvisP8sY8ISZwbCsDllBLSwz1qRFBQsRZ5WRIVkui-TG0M39jJ4jqLNgfLmpK3hTLIQCSFQIM2EoX8ADMjvQSQmqKna2vWvyJL3HrD1SEoyzSdJUkUm9dnUtQn10aK6hkxbiU1HVODAay3M87zE1+J6UwCtN8IQUauR0OZ0ksFwUUqRFPWmUdouPXR3TBjoIahmHKQIHKuqRrtUYSaVShhLF+TkeTzBFQosVKDRM2RVInEdSmg2p6GyE1bU9R8zrsKZqSexFqQHWlHNXHzCbFhnX1+UydFkVxiXJClmGAFEIG8hmld3ZGXp7TR5C5RSCxdjlQV1tR9bqaVdhsSFxDN5AALeOrgPa3ysJgiqcCqmr6sa7bWujxXjQd5nesQZYthsblIQYJx6hUic9AsdEFT2HQzByVLmgDJaw-eSOHPTjbysq6qcFqhrrtT9sO-4ugd1NFGc4QXEPo5eVLGsFxlnKREXGnZI9HcT1mOikO0s-S5w7bqNh9j-bkKOyQTvOy6B9utOHtj7qD1V8pSyrHJZ3STY4QmjQ0R2Ww0oSjuF3u+HAqAIBwEEOlRs48nZBVENkKQNprC42qBoJ0LothaXMJ9aElRXDLj3k3VUpJIBwOfgg4oMx8y41SPUOY8p5DFk2GiKoxsoRVmhGoM2cY2zAQRngChgU0a7HZtFH0ilRp1D5usVh6JXCKD2CUdI8lQ7rlbB8chkkJ6HkxFsBeulbQZAUCwrYCiqzIhyE+fqZtMomTMg-aCwiWYEV2NOBUCghQ6EFGzYsvpwQUT5MxawFECx2JWllRxMdLI2TsrtKMTkXIuMnmeCiZYwrePMFWCKv1XZKVGroWwmxNARK4g4hWG0tp3wSSk16lQpC41ULjV8uxUjSBvFCNEDTdCOkWCY44xCGzgzAJDaGdTnaZHBADYcqg5DpCovzeRno5izA0BeUOh8o5OPgDo+BaNvqV0xNFaE7gdYTnnvkmUChdKEMyF4LwQA */ /** @xstate-layout N4IgpgJg5mDOIC5QGED2BbdBDAdhABAEJYBOAxMgDaqxgDaADALqKgAONAlgC6eo6sQAD0QBaAJwA6AGwAmAKwBmBoukAWafIAcDcSoA0IAJ6JZDaZIDs8hgzV6AjA61a1DWQF8PhtJlwFiciowUkYWJBAOWB4+AQiRBFF5CwdpcVkHS1lpVyU5QxNEh1lFGTUsrUUtOQd5SwZLLx8MbDwiUkkqGkgyAHk2MBwwwSiY-kEEswZJbPltM0U3eXLZAsRFeQcrerUHRbTFvfkmkF9WgI6u2ggyADFONv98WkowAGNufDeW-2GI0d443iiHESkktUUilkskqdiUWjWCAcDC0kjUqnElkc6lkoK0JzOT0CnWo1zIAEEIARvn48LA-uwuIC4qAEqIHJjJPJcYtxFoYdJFFjVsZEG5pqCquJxJoGvJxOUCT82sSrj0AEpgdCoABuYC+yog9OYIyZsQmYmhWzMmTqLnU0kyikRGVRbj5lg2SmUam5StpFxIkgAymBXh8HlADQGyKHw58aecGZEzUDWYgchY7CisWoSlpQQ5EVDLJJxKkdIpyypUop-ed2kHCW0Xu9uD1kwDzcCEJCtlUNgWhZZ1OlnaKEBpZJItHVzDZ5xlpPWiZdDc8w22O7JwozosyLUj3KiZZY85YtMUNgx5Ii81JuS5xBtPVCCyuVR0AOJYbgACzAEhI3wUgoAAV3QQZuFgCg-1wGAvjAkgSCgkCSHAyCcG4TtUxZYRED2TQZGSOw80qaQ7ARCc9mmZYSjPPFpDSQUP0DSQf3-QDgNAiCoJggAROBNw+aMkxNf5cMPHJSjPWRdhvZ9LGcF0b0kVQ8ycDRNkvNRWMbdjfwAoCcCjHjMOgyRyQAdywGITPwB42DA7hYzAgAjdAeDQjCoJw-du3TJE6mnWwoT0NIUTUAs71sMtdGsRYCyUtI9OJDijO49DeKw2BJAANSwShOAgX9IzICB+DASQHh1VAAGsqp1Qrit-MBySy8y-LGPCElSeoy2lZJcwcNRfXHQpBWmWQsRsPYdDPZJUu-QyuPssy+Py5qSt4EyyEAkhUCDNhKF-AAzQ70EkJqiu2tqOt88S926w9UhhLlykWXFHXcTJixsd60hHGxNj2Jag01HVODAKzXI8rzE1+R6U38tN8IQJSuR0OZ0gvHQXHGxBPWmUdppUWwFV0MHJAhqGYcpAh1qwrqDx7ZFajUmVpulEbqlqREsfBTQ0jcPM5P5KmaehshNW1PVvOy7Cka7VHeoYDkyjSPQtAvPMqkRQU1BnX1+UydFkQvCWwEhqWAFEIC8xnFd3ZHntZuTDZG4ob1nGxPTUfXrBnS8nDmEpT2ObxTnXVUALeOrgPanycvKyrqpwWqGqurbWsThXjWd5WesQZYtmBkplCceplIncK0SrXYqnccxxcj5s2OQWP4-s3PzJgiqcCqmr6sa7P2x7vi6AcAvJJ7XEy0dUFMWsFxlnKfn+S5CL3E9Jiuapjv3i7qNx+T-bDskY6zourObpz+6cuZgK0Y5Ua0TqEvXDkJR-YnR0s1xjkIMnDln3uuVsHwOxT1NCjIuR5nCSBUExJi1huRqyooUTYpYnzeyUFkKsy4Tg4FQBAOAgg26Nmga7QKohshSBtNYXGDonQumtPYaQfsSjLBHDefepJICUJZtQ4oMx8wXj6jebGt4JwbC2OiVwig9hh2hLpVu0cOhxjbMBBGeABFPwSA3ERRMlhKWCn9WRVQzZQirMo0BAYNzxn4RJGBh5MRbGXsHawGQFBmLrpUasOQorOAjs0OxaUVrGVMvfaCuiVYEV2KWTYg1yxyA0i6ZYaIPSL3lOkS8wSo6hOWpxCJ8te6WRsnZKMjlnIxNgSNIiiTF6vVSdI9JM1taXlxLzTwqiClBnSqtSJScLIFVvjtKANSXquENqoJwtgyZzRFIUQ4MhqgNACdNTQCpLbWyshMnsjpSwjXRJYHecgcmImsLIz0odNAaGqPiHpDYY6HwTlE+ATiqHPwohYewWQshmGhHrCcJz5Bck5toZwGhMheC8EAA */
predictableActionArguments: true, predictableActionArguments: true,
tsTypes: {} as import('./commandBarMachine.typegen').Typegen0, tsTypes: {} as import('./commandBarMachine.typegen').Typegen0,
context: { context: {
@ -147,6 +147,10 @@ export const commandBarMachine = createMachine(
cond: 'Command has no arguments', cond: 'Command has no arguments',
actions: ['Execute command'], actions: ['Execute command'],
}, },
{
target: 'Checking Arguments',
cond: 'All arguments are skippable',
},
{ {
target: 'Gathering arguments', target: 'Gathering arguments',
actions: ['Set current argument to first non-skippable'], actions: ['Set current argument to first non-skippable'],

File diff suppressed because one or more lines are too long