From 728e87a62752dc1d73479ba3ce472c58c0b5397b Mon Sep 17 00:00:00 2001 From: Frank Noirot Date: Thu, 12 Sep 2024 22:06:50 -0400 Subject: [PATCH] Remove most of modelingMachine.context.store (#3867) --- .../testing-camera-movement.spec.ts | 13 +++- e2e/playwright/testing-selections.spec.ts | 26 +++++-- src/App.tsx | 60 +--------------- src/clientSideScene/CameraControls.ts | 26 ++++++- src/clientSideScene/sceneInfra.ts | 4 -- .../ModelingSidebar/ModelingPane.tsx | 4 +- .../ModelingSidebar/ModelingSidebar.tsx | 1 - src/components/Stream.tsx | 72 ++----------------- src/hooks/useSetupEngineManager.ts | 31 ++------ src/lib/selections.ts | 6 +- src/machines/modelingMachine.ts | 31 +++++--- src/routes/Onboarding/Camera.tsx | 5 +- src/routes/Onboarding/CmdK.tsx | 5 +- src/routes/Onboarding/CodeEditor.tsx | 5 +- src/routes/Onboarding/Export.tsx | 5 +- src/routes/Onboarding/InteractiveNumbers.tsx | 5 +- src/routes/Onboarding/ParametricModeling.tsx | 5 +- src/routes/Onboarding/ProjectMenu.tsx | 5 +- src/routes/Onboarding/Sketching.tsx | 5 +- src/routes/Onboarding/Streaming.tsx | 5 +- src/routes/Onboarding/UserMenu.tsx | 5 +- 21 files changed, 97 insertions(+), 227 deletions(-) diff --git a/e2e/playwright/testing-camera-movement.spec.ts b/e2e/playwright/testing-camera-movement.spec.ts index a84453c99..a43d8dad2 100644 --- a/e2e/playwright/testing-camera-movement.spec.ts +++ b/e2e/playwright/testing-camera-movement.spec.ts @@ -12,8 +12,8 @@ test.afterEach(async ({ page }, testInfo) => { }) test.describe('Testing Camera Movement', () => { - test('Can moving camera', async ({ page, context }) => { - test.skip(process.platform === 'darwin', 'Can moving camera') + test('Can move camera reliably', async ({ page, context }) => { + test.skip(process.platform === 'darwin', 'Can move camera reliably') const u = await getUtils(page) await page.setViewportSize({ width: 1200, height: 500 }) @@ -102,6 +102,13 @@ test.describe('Testing Camera Movement', () => { await bakeInRetries(async () => { await page.mouse.move(700, 200) await page.mouse.down({ button: 'right' }) + const appLogoBBox = await page.getByTestId('app-logo').boundingBox() + expect(appLogoBBox).not.toBeNull() + if (!appLogoBBox) throw new Error('app logo not found') + await page.mouse.move( + appLogoBBox.x + appLogoBBox.width / 2, + appLogoBBox.y + appLogoBBox.height / 2 + ) await page.mouse.move(600, 303) await page.mouse.up({ button: 'right' }) }, [4, -10.5, -120]) @@ -295,11 +302,11 @@ test.describe('Testing Camera Movement', () => { await expect( page.getByRole('button', { name: 'Edit Sketch' }) ).toBeVisible() + await hoverOverNothing() await page.getByRole('button', { name: 'Edit Sketch' }).click() await page.waitForTimeout(400) - await hoverOverNothing() x = 975 y = 468 diff --git a/e2e/playwright/testing-selections.spec.ts b/e2e/playwright/testing-selections.spec.ts index 452992647..7d7b245b5 100644 --- a/e2e/playwright/testing-selections.spec.ts +++ b/e2e/playwright/testing-selections.spec.ts @@ -31,8 +31,18 @@ test.describe('Testing selections', () => { const xAxisClick = () => page.mouse.click(700, 253).then(() => page.waitForTimeout(100)) + const emptySpaceHover = () => + test.step('Hover over empty space', async () => { + await page.mouse.move(700, 143, { steps: 5 }) + await expect(page.locator('.hover-highlight')).not.toBeVisible() + }) const emptySpaceClick = () => - page.mouse.click(700, 343).then(() => page.waitForTimeout(100)) + test.step(`Click in empty space`, async () => { + await page.mouse.click(700, 143) + await expect(page.locator('.cm-line').last()).toHaveClass( + /cm-activeLine/ + ) + }) const topHorzSegmentClick = () => page.mouse.click(709, 290).then(() => page.waitForTimeout(100)) const bottomHorzSegmentClick = () => @@ -171,7 +181,9 @@ test.describe('Testing selections', () => { await emptySpaceClick() } - await selectionSequence() + await test.step(`Test hovering and selecting on fresh sketch`, async () => { + await selectionSequence() + }) // hovering in fresh sketch worked, lets try exiting and re-entering await u.openAndClearDebugPanel() @@ -184,16 +196,15 @@ test.describe('Testing selections', () => { // select a line, this verifies that sketches in the scene can be selected outside of sketch mode await topHorzSegmentClick() - await page.waitForTimeout(100) + await emptySpaceHover() // enter sketch again await u.doAndWaitForCmd( () => page.getByRole('button', { name: 'Edit Sketch' }).click(), 'default_camera_get_settings' ) - await page.waitForTimeout(150) - await page.waitForTimeout(300) // wait for animation + await page.waitForTimeout(450) // wait for animation await u.openAndClearDebugPanel() await u.sendCustomCmd({ @@ -220,8 +231,9 @@ test.describe('Testing selections', () => { await u.closeDebugPanel() - // hover again and check it works - await selectionSequence() + await test.step(`Test hovering and selecting on edited sketch`, async () => { + await selectionSequence() + }) }) test('Solids should be select and deletable', async ({ page }) => { diff --git a/src/App.tsx b/src/App.tsx index 234f2e190..133fca2a8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,8 @@ -import { MouseEventHandler, useEffect, useMemo, useRef } from 'react' -import { uuidv4 } from 'lib/utils' +import { useEffect, useMemo, useRef } from 'react' import { useHotKeyListener } from './hooks/useHotKeyListener' import { Stream } from './components/Stream' -import { EngineCommand } from 'lang/std/artifactGraph' -import { throttle } from './lib/utils' import { AppHeader } from './components/AppHeader' import { useHotkeys } from 'react-hotkeys-hook' -import { getNormalisedCoordinates } from './lib/utils' import { useLoaderData, useNavigate } from 'react-router-dom' import { type IndexLoaderData } from 'lib/types' import { PATHS } from 'lib/paths' @@ -14,7 +10,6 @@ import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { onboardingPaths } from 'routes/Onboarding/paths' import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions' import { codeManager, engineCommandManager } from 'lib/singletons' -import { useModelingContext } from 'hooks/useModelingContext' import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath' import { isDesktop } from 'lib/isDesktop' import { useLspContext } from 'components/LspProvider' @@ -26,7 +21,6 @@ import useHotkeyWrapper from 'lib/hotkeyWrapper' import Gizmo from 'components/Gizmo' import { CoreDumpManager } from 'lib/coredump' import { UnitsMenu } from 'components/UnitsMenu' -import { reportRejection } from 'lib/trap' export function App() { const { project, file } = useLoaderData() as IndexLoaderData @@ -45,7 +39,6 @@ export function App() { }, [projectName, projectPath]) useHotKeyListener() - const { context, state } = useModelingContext() const { auth, settings } = useSettingsAuthContext() const token = auth?.context?.token @@ -74,61 +67,14 @@ export function App() { (p) => p === onboardingStatus.current ) ? 'opacity-20' - : context.store?.didDragInStream - ? 'opacity-40' : '' useEngineConnectionSubscriptions() - const debounceSocketSend = throttle((message) => { - engineCommandManager.sendSceneCommand(message).catch(reportRejection) - }, 1000 / 15) - const handleMouseMove: MouseEventHandler = (e) => { - if (state.matches('Sketch')) { - return - } - - const { x, y } = getNormalisedCoordinates({ - clientX: e.clientX, - clientY: e.clientY, - el: e.currentTarget, - ...context.store?.streamDimensions, - }) - - const newCmdId = uuidv4() - if (state.matches({ idle: 'showPlanes' })) return - if (context.store?.buttonDownInStream !== undefined) return - debounceSocketSend({ - type: 'modeling_cmd_req', - cmd: { - type: 'highlight_set_entity', - selected_at_window: { x, y }, - }, - cmd_id: newCmdId, - }) - } - return ( -
+
diff --git a/src/clientSideScene/CameraControls.ts b/src/clientSideScene/CameraControls.ts index 2e45fbdc8..fd14ae387 100644 --- a/src/clientSideScene/CameraControls.ts +++ b/src/clientSideScene/CameraControls.ts @@ -343,7 +343,8 @@ export class CameraControls { this.camera.updateProjectionMatrix() } - onMouseDown = (event: MouseEvent) => { + onMouseDown = (event: PointerEvent) => { + this.domElement.setPointerCapture(event.pointerId) this.isDragging = true this.mouseDownPosition.set(event.clientX, event.clientY) let interaction = this.getInteractionType(event) @@ -363,7 +364,7 @@ export class CameraControls { } } - onMouseMove = (event: MouseEvent) => { + onMouseMove = (event: PointerEvent) => { if (this.isDragging) { this.mouseNewPosition.set(event.clientX, event.clientY) const deltaMove = this.mouseNewPosition @@ -401,10 +402,29 @@ export class CameraControls { this.pendingPan.x += -deltaMove.x * panSpeed this.pendingPan.y += deltaMove.y * panSpeed } + } else { + /** + * If we're not in sketch mode and not dragging, we can highlight entities + * under the cursor. This recently moved from being handled in App.tsx. + * This might not be the right spot, but it is more consolidated. + */ + if (this.syncDirection === 'engineToClient') { + const newCmdId = uuidv4() + + this.throttledEngCmd({ + type: 'modeling_cmd_req', + cmd: { + type: 'highlight_set_entity', + selected_at_window: { x: event.clientX, y: event.clientY }, + }, + cmd_id: newCmdId, + }) + } } } - onMouseUp = (event: MouseEvent) => { + onMouseUp = (event: PointerEvent) => { + this.domElement.releasePointerCapture(event.pointerId) this.isDragging = false this.handleEnd() if (this.syncDirection === 'engineToClient') { diff --git a/src/clientSideScene/sceneInfra.ts b/src/clientSideScene/sceneInfra.ts index ea75a0d02..dc4de6500 100644 --- a/src/clientSideScene/sceneInfra.ts +++ b/src/clientSideScene/sceneInfra.ts @@ -105,10 +105,6 @@ export class SceneInfra { _baseUnit: BaseUnit = 'mm' _baseUnitMultiplier = 1 _theme: Themes = Themes.System - _streamDimensions: { streamWidth: number; streamHeight: number } = { - streamWidth: 1280, - streamHeight: 720, - } extraSegmentTexture: Texture lastMouseState: MouseState = { type: 'idle' } onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {} diff --git a/src/components/ModelingSidebar/ModelingPane.tsx b/src/components/ModelingSidebar/ModelingPane.tsx index 314debcfc..068c63995 100644 --- a/src/components/ModelingSidebar/ModelingPane.tsx +++ b/src/components/ModelingSidebar/ModelingPane.tsx @@ -1,6 +1,5 @@ import styles from './ModelingPane.module.css' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' -import { useModelingContext } from 'hooks/useModelingContext' import { ActionButton } from 'components/ActionButton' import Tooltip from 'components/Tooltip' import { CustomIconName } from 'components/CustomIcon' @@ -69,9 +68,8 @@ export const ModelingPane = ({ }: ModelingPaneProps) => { const { settings } = useSettingsAuthContext() const onboardingStatus = settings.context.app.onboardingStatus - const { context } = useModelingContext() const pointerEventsCssClass = - context.store?.buttonDownInStream || onboardingStatus.current === 'camera' + onboardingStatus.current === 'camera' ? 'pointer-events-none ' : 'pointer-events-auto ' return ( diff --git a/src/components/ModelingSidebar/ModelingSidebar.tsx b/src/components/ModelingSidebar/ModelingSidebar.tsx index b8534a892..15bdd12a1 100644 --- a/src/components/ModelingSidebar/ModelingSidebar.tsx +++ b/src/components/ModelingSidebar/ModelingSidebar.tsx @@ -31,7 +31,6 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) { const onboardingStatus = settings.context.app.onboardingStatus const { send, context } = useModelingContext() const pointerEventsCssClass = - context.store?.buttonDownInStream || onboardingStatus.current === 'camera' || context.store?.openPanes.length === 0 ? 'pointer-events-none ' diff --git a/src/components/Stream.tsx b/src/components/Stream.tsx index 9fda3d488..3a90f83e5 100644 --- a/src/components/Stream.tsx +++ b/src/components/Stream.tsx @@ -1,5 +1,4 @@ import { MouseEventHandler, useEffect, useRef, useState } from 'react' -import { getNormalisedCoordinates } from '../lib/utils' import Loading from './Loading' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useModelingContext } from 'hooks/useModelingContext' @@ -28,10 +27,9 @@ enum StreamState { export const Stream = () => { const [isLoading, setIsLoading] = useState(true) - const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>() const videoRef = useRef(null) const { settings } = useSettingsAuthContext() - const { state, send, context } = useModelingContext() + const { state, send } = useModelingContext() const { mediaStream } = useAppStream() const { overallState, immediateState } = useNetworkContext() const [streamState, setStreamState] = useState(StreamState.Unset) @@ -256,75 +254,15 @@ export const Stream = () => { setIsLoading(false) }, [mediaStream]) - const handleMouseDown: MouseEventHandler = (e) => { - if (!isNetworkOkay) return - if (!videoRef.current) return - if (state.matches('Sketch')) return - if (state.matches('Sketch no face')) return - - const { x, y } = getNormalisedCoordinates({ - clientX: e.clientX, - clientY: e.clientY, - el: videoRef.current, - ...context.store?.streamDimensions, - }) - - send({ - type: 'Set context', - data: { - buttonDownInStream: e.button, - }, - }) - setClickCoords({ x, y }) - } - const handleMouseUp: MouseEventHandler = (e) => { if (!isNetworkOkay) return if (!videoRef.current) return - send({ - type: 'Set context', - data: { - buttonDownInStream: undefined, - }, - }) if (state.matches('Sketch')) return if (state.matches({ idle: 'showPlanes' })) return - if (!context.store?.didDragInStream && btnName(e).left) { + if (btnName(e).left) { // eslint-disable-next-line @typescript-eslint/no-floating-promises - sendSelectEventToEngine( - e, - videoRef.current, - context.store?.streamDimensions - ) - } - - send({ - type: 'Set context', - data: { - didDragInStream: false, - }, - }) - setClickCoords(undefined) - } - - const handleMouseMove: MouseEventHandler = (e) => { - if (!isNetworkOkay) return - if (state.matches('Sketch')) return - if (state.matches('Sketch no face')) return - if (!clickCoords) return - - const delta = - ((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) ** - 0.5 - - if (delta > 5 && !context.store?.didDragInStream) { - send({ - type: 'Set context', - data: { - didDragInStream: true, - }, - }) + sendSelectEventToEngine(e, videoRef.current) } } @@ -333,8 +271,7 @@ export const Stream = () => { className="absolute inset-0 z-0" id="stream" data-testid="stream" - onMouseUp={handleMouseUp} - onMouseDown={handleMouseDown} + onClick={handleMouseUp} onContextMenu={(e) => e.preventDefault()} onContextMenuCapture={(e) => e.preventDefault()} > @@ -344,7 +281,6 @@ export const Stream = () => { autoPlay controls={false} onPlay={() => setIsLoading(false)} - onMouseMoveCapture={handleMouseMove} className="w-full cursor-pointer h-full" disablePictureInPicture id="video-stream" diff --git a/src/hooks/useSetupEngineManager.ts b/src/hooks/useSetupEngineManager.ts index e9a6c3314..a870913c0 100644 --- a/src/hooks/useSetupEngineManager.ts +++ b/src/hooks/useSetupEngineManager.ts @@ -59,15 +59,6 @@ export function useSetupEngineManager( return modifyGrid(kclManager.engineCommandManager, hidden) }, }) - modelingSend({ - type: 'Set context', - data: { - streamDimensions: { - streamWidth: quadWidth, - streamHeight: quadHeight, - }, - }, - }) hasSetNonZeroDimensions.current = true } @@ -111,24 +102,10 @@ export function useSetupEngineManager( streamRef?.current?.offsetWidth ?? 0, streamRef?.current?.offsetHeight ?? 0 ) - if ( - modelingContext.store.streamDimensions.streamWidth !== width || - modelingContext.store.streamDimensions.streamHeight !== height - ) { - engineCommandManager.handleResize({ - streamWidth: width, - streamHeight: height, - }) - modelingSend({ - type: 'Set context', - data: { - streamDimensions: { - streamWidth: width, - streamHeight: height, - }, - }, - }) - } + engineCommandManager.handleResize({ + streamWidth: width, + streamHeight: height, + }) }, 500) const onOnline = () => { diff --git a/src/lib/selections.ts b/src/lib/selections.ts index c85f36c0b..8bb0c381c 100644 --- a/src/lib/selections.ts +++ b/src/lib/selections.ts @@ -617,14 +617,14 @@ function codeToIdSelections( export async function sendSelectEventToEngine( e: MouseEvent | React.MouseEvent, - el: HTMLVideoElement, - streamDimensions: { streamWidth: number; streamHeight: number } + el: HTMLVideoElement ) { const { x, y } = getNormalisedCoordinates({ clientX: e.clientX, clientY: e.clientY, el, - ...streamDimensions, + streamWidth: el.clientWidth, + streamHeight: el.clientHeight, }) const res = await engineCommandManager.sendSceneCommand({ type: 'modeling_cmd_req', diff --git a/src/machines/modelingMachine.ts b/src/machines/modelingMachine.ts index b712f771e..fd6eb57fe 100644 --- a/src/machines/modelingMachine.ts +++ b/src/machines/modelingMachine.ts @@ -153,9 +153,6 @@ export type SegmentOverlayPayload = export interface Store { videoElement?: HTMLVideoElement - buttonDownInStream: number | undefined - didDragInStream: boolean - streamDimensions: { streamWidth: number; streamHeight: number } openPanes: SidebarType[] } @@ -300,9 +297,6 @@ export const modelingMachineDefaultContext: ModelingMachineContext = { segmentOverlays: {}, segmentHoverMap: {}, store: { - buttonDownInStream: undefined, - didDragInStream: false, - streamDimensions: { streamWidth: 1280, streamHeight: 720 }, openPanes: getPersistedContext().openPanes || ['code'], }, } @@ -613,6 +607,18 @@ export const modelingMachine = setup({ ) if (err(applyFilletToSelectionResult)) return applyFilletToSelectionResult }, + 'set selection filter to curves only': () => { + ;(async () => { + await engineCommandManager.sendSceneCommand({ + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'set_selection_filter', + filter: ['curve'], + }, + }) + })().catch(reportRejection) + }, 'conditionally equip line tool': ({ event: { type } }) => { if (type === 'xstate.done.actor.animate-to-face') { sceneInfra.modelingSend({ @@ -777,9 +783,6 @@ export const modelingMachine = setup({ store: ({ context: { store }, event }) => { if (event.type !== 'Set context') return store if (!event.data) return store - if (event.data.streamDimensions) { - sceneInfra._streamDimensions = event.data.streamDimensions - } const result = { ...store, @@ -1209,7 +1212,7 @@ export const modelingMachine = setup({ }, // end services }).createMachine({ - /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogC0ANhoBWAHQAOAMwB2KQEY5AFgCcGqWqkAaEAE9Ew0RLEqa64TIBMKmTUXCAvk71oMOfAQDKYdgAJYLDByTm5aBiQQFjYwniiBBEEpYSkJOUUaOWsxeylrWzk9QwQClQkrVOsZNWExFItnVxB3LDxCXwCAW1QAVyDA9hJ2MAjeGI4ueNBE5KkaCWspZfMM+XE1YsQZMQWxNQtxao0ZeRc3dDavTv9ybhG+djGoibjeRJothBpzlsvPDp+fy+KBdMC4AIAeQAbmAAE6YEj6WDPZisSbcd6IT4GbG-VoAiTYCCYMAEACiEPhgQA1n5yAALVHRdFvBJCJYLHZKawHczVBxfeySRTmOpqMRyNSZapNC4edpEklkykjOG0+lMxSRNGxKZYpK2BbmWrqcQ0URiJZCkxyGgyYTKfZSK28sT4-6K4mkimPOG9DDM1769lJSUyCQSlTKGQqXKKF3CL6KaoRjKpORieM1RQehX4JU+gBi2EwpKe9HGrJDMyEWYjdhdYkcdsl1iKuIQiljwgkMakchsMmUDjzVyghZVfBYcIrOpZesxocEYjq6XbohoKVFUsUyZUjokNUzSmE1gT57HhO9ZOQJDpQerS9rCBU1gqWjfakH0ay+y+wgKOk3IqComZmLGUhXl6yoEAAIsEIyBMEoRTI+i7TPwQiOuU2hmCOCbRooYjJpK5Q1GevKKI41FStBBY3gQAAqYCPII7CoIIRAAIJwehGKYbMzbvmYKRZhK4YHsmqi9lY2Q5No1jCNGcj0RON4SAyxJgAACoiuBwAQ3GztgABmJChP4UBwiQTAMv4LBML0iIjBA-Fsi+ggHmoEjiDG35aIFDpfN+EYOKJA7dtRUgqGpk4SLADKoAA7npZCGcZnDmZZ1m2fZYBdEwnCQO5NZYUkYFyOkLqZkpgExWBJGdtRBR9lo1H2BaObWHF3h0uwjLEGQlCYH1mqlc+5Upqcix2G+dSOkptjJooBy+cpVhZnIUr2r1-WDQh5ZgMhoLgnOVYYQa22SGobpLOodrLDIXxxlVGjmPWuzKRae2agQdwYP4kAcP4EC9HC7QagNTKVi8T6CYg3a3aYYEBVoylmB2JRqDUvmrsstRZNRaixc0BKKmN0MSJTjIAJKwXedInWCEL+LCJnkCQmATQjXanGkw7LEpjgqOj+6tbY9TqPMQuyL9VM0wy9M+ozx1BKdrNJRDABe9xczzBrdue6SgfUOw45UKjJjYxrSla+xEzQo5k56BaK9T+1K7BRDcLA7A2Xg-ha9gusQlzoPYH7w2jLDuoCYb9iKH2ChLLIxEKLonZGpITtG2BOzp3Kfz5hO7uK8rZI+7gfsB7gbPwpwnOYBHUcUDH87BpNiRRb2W5PQ454SrGXwFPkEhgU7NAHLkw7y4yHuahXxC+-7JCB9xABC3j+AAGgbobdjYpg-jj0bno6TUlLyViRjQSkWPY1gOFBLslwvCue0vVc12vdeb9vABNfeL5D7vnkEoE0tR7ZW07PYb8FQ1gnhihnIu5M3ae3fnTb2K9a7+DIFAUkwCpo1D2KteYrY+T5BHs2XsT9QJ33tPdUCc8GSYK9j6b+q9A6knwOwGGHd4YJxiqYcKA5HSCzsCPM8VUMhWjfAUPuxEWFsK-jg3+Dl4RMHBBAbA5BnIkHVDo1ulAiHd3bJITavI+7tl5JnK++QIzGDbE-J26geqv3HGwlR2Dq5cLrsHUOQwyz6DwTgKAuBTGIzgZGEmB4ZD5GkVmUiORZothcQ6LcMhlHlx8T-QO7NG5c0wCErm2BwmRL5kpUwqQaoaGyMpZ6zUrDlFyKuAoEoDhDmyZ-XJfjAi4Fsv4Diu8KndhMDUAKqh9iZCoVnPyydRQHGWKtZQ3TF69NwbAAZTAhmoH8EA2OC544HwyYsFM19zxSkHI0q+xFezqDjLsVaOwp5rOhqo3xuCwAAEdejhx4VAPhozYwLDqH+JQ252nSVxvIRadgbA4TeVgjhajA5MAMUU6ghzO6827KoPsZ59iAUyKKbsyYJS9izFLBwyluyk3lJ4suPSUWfPUXCAqqBYS3FRRCFE2LBEHzdCbGKsY5BgvMcmWQPlajtlAnaaUw5cweMJEy9ZPoABKYBBCsRCL0EYozHRpG0NGcUhNvzJnNOPWQoEKXCBOO4hlKqME5J9ADY6wMAhgwhvgKGjJgXI0dNKZQA4H6rQtfaXyYrNqrhxlmJVjqKbOuZZXbgBTdlswMdgEgAAjQh-LLonI0NILICSSarSsNYIU58jyrhwk-fY9Li6MqTWqskjJ8HHQ4qgbm+bjkvhyHfaQVjboO1CpW5qxF3xZE3O02QVgX4JvQZqCQ3FkprwCAEvWzcjFDDbv4PAplUAEAgNwMARJcDQlQHSCQMB2CCE3WHTAggD2oAqdUZspgHFCyfjFOoI83xpClCkMCptE6NrQaXDBq711B1QDrLdLdd2UH3bgQ9BB4RwjgxIJgLlD1wi6Devw964Mhy3c+1Dr7e0eXKu+98A74mKQvpsLOJDIzAdsGeZY4hVLKsTcu6DIMCm6PDju6OKG0MnoMuey917b2CCE03cjh633m0WIODOMV5hnhHryd8+RMhipNJc5RAmAgKZE5HJDx0X3obhJhuE2HcNwYI3J8zT6X0qf2JGFSsLVzypgVfHISdqKijqg004Jm10g3-rvcTR7JNnrwDJs9cmc2wEEHwJTlGBEFv7Q6CMWggNZFjDake34k5bjPKsSr2RIswZizvOLtn7OOeGHhlzRG0sZayyp5S1TtBniJipMrKT7BysHOQnGPHF2Qf41FgIMWAFNYS9Jq9KXOvZvS-oHrVGyqJFlA2aUP5fy2HkEKad49xui1HQOOr0Wt77KaxhrDOG2vOcI3err22PO7a7ogWU5RHAOnTmBc8W4hQxl8sRUWdRZUtjuwEfBpJluntW7Jzr+BSQ7Zy32mjDpyh2AyHi8wsyr6rkkGImwEEVm2AR3gzH1mKPNZe05-DH3BBI61T9nH1H9sOgp+YTIxgHBir3FnK0vd9g1DjEpSUoo6cAr4SjqTSW1vs8VwybHF1cd87PNU2Q9SsxZHHVfO15QnbShNfITM02m1OrmzBjXT27Ms7e2zuTGutdw1y3jm+B2HTKVPqKKRH7RBp3kM2fIu1eNLqpqZjRcItG4B0XoxEhjLNiZsyt1X6O71aMT9o3R+i4SCFE23L3cdef-eHAsKedh7SZB2M2LG-3rVHmUFYgcW06f56Tyn4viHM9M+ew5177B2vs974X1PBjS8Z-L9z7XVfSg198iTewNem-KBHgoXsw5shLPArbiDXiAAyeBO2oG7f9BkHbdndrfaISlcYBwZBSDYEKSxTCy6nsL9szsZsz8L979MAJBaZcAOACA30lgIxvwbU6hMwUxZAAI1pCIxVThuwDcHU7c+MqZz8DIQCwCID2AoDtQl89t-sqJIwMh7plJCclIvgpRexvw7Ugdzx4kFBlF8DL9u0JAAA5PZHSVAPAdgWAIyCACAQYAxAIFgEQx-NaR+GoIcbQCUACbIceC+SUbaBSOiGPWbPA4ArtUAgQ-wIQkQsQ0gNuHtHnCgrsdGAlOdbjNsOxRADIY0N8EXeoLQLcZRcAyA0ZLqCoc+KPBoXfZMWwd8aMWMXYU4KwV5PQrxPwkgqgMg73HXRGKeHyO+GpRVJYO0JMZqTqYCWiQ4HIeJd0BI92JiDtCELNZuAxcgXZG-O-IwipdYPfOMcQO1J+MVLIRg+oCoCedArIJZCowA92XoZPPZKOWcRWSEXAY9VHHPM9bibwJiQQSYk9QQGY9gOYiJX7XFYHT9bQ0UeofYEmfo4LDGa7BQVGcDV2fQ+eTVUITnEA5o-AHg6w8gv7BAGvBYaHfIVQFMXfFvLsO+HyQ1QE3YJsVBB4rxZ43dAhT4ldebSGIIO4ZPblOEAyOEAgEsCAxKfwdlF4hnNo+RCoeMRoPyZsALRAAcMBWwEmYWTIEDZRBE14owlE9dSGEjKAPAcQyQ4kxE5HXkvAMkhwdIK0EmLMO1ewTMRgzISNI4JQDQC2bAk-d2dkhnQg-EyOBkSAfwLUpEqAg4w2O0BYN0C2Z0RwBgzsWoWAhMM1C0NxZRcgUkMgQIFyMkUZA8JOIE3Ic06oAoS+RGFMJOCUZ5MUJ2YHOnDEtNYZaETNHNH0bPC9NXOTOMhudiTiRMiGZMrnCjFTCWA8UHYWHGC0KtL-ULeFMVGhW6WM1NBudNXMrNXNMkEfVrcfd7DMxs2cbM+TJMtsivI5ZfVMKqcRQCBwKcis2BB0QDA-eaaKVae4t+d2ePDEvJOudlHoLlDcvxUQxYlXNM69LYvc2uQQbczlLVM83+c6NI0cmwJOKUk7bQDAgokoBMGaIndsaieoLcDIBs1lQOB9IJYpQ8xLY8s9U8nlYjeDR9YpFTUWYCXkcBGKJYZaQoxUwPA4KUGhU4wCzc+uDmIpfQcCtHKCziG8vAeTBuYTYJTze5dC9sLQWVWkrsEnI8DMbsXYZ+CLSoqDebblIC-xEjQJEi0JMpBY1M5LCQaC4S2C0jeC7bUpcpU00MVMCE5sXYEnOMNi4iZQaQPkQ1WwGqBdHA2PeedcnlIiwpYJCS8JMi5Y2SyimCtzYpDnMJfYmwn4oMp8g4aspQZsZMcRI8KeR0q0HYWMAivpLZQZYZHeRyyC5ywQKi3AbY7ZfsvgRCmRdMaUE4OtEeCwc3KoO1O2F5eNcyx41hKy4S-pOKvZABRKmSuSzc9K2yfs-QTzRxEtNxEVDfEebixYVIaiQCP86iaKr5X5f5cEQFBkJqtXFqvxbVKap9DXFTXGC0Y3OpLvEMrsbIHOU0K0HaU4aoCa9RdFGyMsLAeak8ly+Si6zFL4+82w99XuN8UXe0YwfOclMCNqR8xwO2ZpZRIgW-D4-wJiK-TAE07y3mOHKHU4B5OXO+G5DI6UYCVQb8XkDOWoYG0GmAcGyG0gmGg0KicoVQNxCwWwVaHIC1NG9TB6LGgmWE1cjBEGu-CG6-KgawYm0MYcdQPsLQp2U7UQHGWmv0+QBmtGEmXG9mwmqgGQHml8B0baCoCUF0X8CiHYMW9GyW7G5m5tTUfwXAPZbKMkXwUkSyDAcyZyGQ-Sdub43mQQJ+SIlC8tJsFU98owQcdIYwTGp2b9NQOKMgbALoYYSGYZV7AyG6s9YO0OkYfs02ipcMCoX-QoEWmpACQ8AdDTR0QcdUuE2OsOn1YZViSzNEz2aOiQQu+OjibYz2JOgys8ClY4ZQKZc7SQB0BVGhbIG0poZoY2jAeAKICDB2g0EQZYDQ7kW4vkZjD8qpX8eYJ+YNeYVcOKG8Ue5cb6Se+oaeiwWeuk3GUUF0dseQAuHINe5UTSbSNKAyIeyvWwlcZGOJHemKGei1FJJYYicEu0BQWrBIjSRKFKG+uADezyHYd8BQd6e0WQEY-esEj+wK7+ktP+8Yz2UBqacKIIxwEI0QMIrObsUwbQEtZ0HYbaJFdhMAdB7uTo8eBGrQuoUrZqJ+MKENMwA4OAuWfih3EGECizYxRnQ9KhxGO2Y+O1OXC2aXf9CUqiFMRG4cfW+3OPQStzQfPdF9IRrsW6HyS026EXRwO+HTAY78SeMiBSSUOnBrOLDR5ci0lZHqrGsrcwcebImUW6RvCxh7JbdR56n455CEugmUF0C0W6c7fFZQTAhMVQAcHYOnV47x++3xpkn20Qc8AcHGPCahAysVWoIDOdKoBXGapXeJkc2w55KqXIKMevZG+oKROMdGpQVaKlAAyqrxePKfZPIvNPVR5DYpnFQ2TpSMGwGHZYM2GmrOHaCoBaa1CRcQLgwwyGjR88XYRYKefLb8UKUEs4tTADYmc8H9OZggzkpIxZshFZiR9Z9TRgiUlqbBu2MK4-OE92bgwg42-DLmRZswcocROU1cYmMXEoNwy7JepBJZA55Ekwsw3lD5p2ceGnOoGKTIJJTsbaJOAoWUmSTu3kXw4g6xoXaqUUO+ZsW6J-FaNaZ06NbaTpZRaoj42o8OBo3ZDR+QWwXyToyqdYSrACXGYwM8R0dOClQOrhqmTY6YoYWYz2eY6xwcWSDIEskau0E3RAKlZx7aUWWQGAiwNkkIYUz4pli0JOSKMwHIZ2mckoSUWhe0WtBoU4aPVB5dI05HTk0zNEkIbgSQu4bE+EJlzIHyQ1t8K0BhT2hABp6Qd-Earo9QLJIVp47VjkyGrkyYH1UUzCPp3m0lCoUhv82Uv8BU2vVsT+1Uh0fOlm+12N7Uzk3UxKA0h1yhnx3mYcWMUwK0X8rMJacHO0i0aQO1RhbIQEuoV090uuWAL06x+hBBQrNsE1f5jI9Qg4ZpU+baGJ6N6qwSzM2cZswc0kaxgZi2OwYaiIgx2BdpRYOpbQ8+DGM6wOS83cnlUQ6x9qXyIcO+DcXIAoSVY2KbFIH8I4bsS9kSuC0CkoBJ3FB9xhR+F9oZ8I7QaQdA1UgG-J5dhNgIVKmyui4pe9tGsD592syD5qMUH2+0W6bIewDMP92DAD8SlSlNgVEBUDoccBTG+qUiTtkaiUcQKnI6sjtykpTyjDirejyB+pFwrsUQJ8nYZSQcJ2YwQcMj2KnZeK7diNNU5scBQloN5hujEmE8M8MbMYlptc1d6yuT9NABRT2AotlThQNTga+QNTKUEmU8HGKNu1pRmDFDn5P5ZuDXPjx9scwrJSBQaSTt2FZQQmUWFksjh6q6zARTujeYDAgcV-EJ5qWNZx41FeuoEjmWsGjmmLutkm+pFGHet-CtFaD9emzGqWhR3AxkI2k2iyWt4Dse41yZ0SVQBRGoW0koeaapMPRoU0M4BI6u8OvZSOxrkp3xm+RSUWdA8MAbACK0NjMFWMUhlBlp4b4uvZUuv2cuzUDR4wNTMomwXt1u4T+RgWh+aRGiHjFwIAA */ + /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogC0ANhoBWAHQAOAMwB2KQEY5AFgCcGqWqkAaEAE9Ew0RLEqa64TIBMKmTUXCAvk71oMOfAQDKYdgAJYLDByTm5aBiQQFjYwniiBBEEpYSkJOUUaOWsxeylrWzk9QwQClQkrVOsZNWExFItnVxB3LDxCXwCAW1QAVyDA9hJ2MAjeGI4ueNBE5KkaCWspZfMM+XE1YsQZMQWxNQtxao0ZeRc3dDavTv9ybhG+djGoibjeRJothBpzlsvPDp+fy+KBdMC4AIAeQAbmAAE6YEj6WDPZisSbcd6IT4GbG-VoAiTYCCYMAEACiEPhgQA1n5yAALVHRdFvBJCJYLHZKawHczVBxfeySRTmOpqMRyNSZapNC4edpEklkykjOG0+lMxSRNGxKZYpK2BbmWrqcQ0URiJZCkxyGgyYTKfZSK28sT4-6K4mkimPOG9DDM1769lJSUyCQSlTKGQqXKKF3CL6KaoRjKpORieM1RQehX4JU+gBi2EwpKe9HGrJDMyEWYjdhdYkcdsl1iKuIQiljwgkMakchsMmUDjzVyghZVfBYcIrOpZesxocEYjq6XbohoKVFUsUyZUjokNUzSmE1gT57HhO9ZOQJDpQerS9rCBU1gqWjfakH0ay+y+wgKOk3IqComZmLGUhXl6yoEAAIsEIyBMEoRTI+i7TPwQiOuU2hmCOCbRooYjJpK5Q1GevKKI41FStBBY3gQAAqYCPII7CoIIRAAIJwehGKYbMzbvmYKRZhK4YHsmqi9lY2Q5No1jCNGcj0RON4SAyxJgAACoiuBwAQ3GztgABmJChP4UBwiQTAMv4LBML0iIjBA-Fsi+ggHmoEjiDG35aIFDpfN+EYOKJA7dtRUgqGpk4SLADKoAA7npZCGcZnDmZZ1m2fZYBdEwnCQO5NZYUkYFyOkLqZkpgExWBJGdtRBR9lo1H2BaObWHF3h0uwjLEGQlCYH1mqlc+5Upqcix2G+dSOkptjJooBy+cpVhZnIUr2r1-WDQh5ZgMhoLgnOVYYQa22SGobpLOodrLDIXxxlVGjmPWuzKRae2agQdwYP4kAcP4EC9HC7QagNTKVi8T6CYg3a3aYYEBVoylmB2JRqDUvmrsstRZNRaixc0BKKmN0MSJTjIAJKwXedInWCEL+LCJnkCQmATQjXanGkw7LEpjgqOj+6tbY9TqPMQuyL9VM0wy9M+ozx1BKdrNJRDABe9xczzBrdue6SgfUOw45UKjJjYxrSla+xEzQo5k56BaK9T+1K7BRDcLA7A2Xg-ha9gusQlzoPYH7w2jLDuoCYb9iKH2ChLLIxEKLonZGpITtG2BOzp3Kfz5hO7uK8rZI+7gfsB7gbPwpwnOYBHUcUDH87BpNiRRb2W5PQ454SrGXwFPkEhgU7NAHLkw7y4yHuahXxC+-7JCB9xABC3j+AAGgbobdjYpg-jj0bno6TUlLyViRjQSkWPY1gOFBLslwvCue0vVc12vdeb9vABNfeL5D7vnkEoE0tR7ZW07PYb8FQ1gnhihnIu5M3ae3fnTb2K9a7+DIFAUkwCpo1D2KteYrY+T5BHs2XsT9QJ33tPdUCc8GSYK9j6b+q9A6knwOwGGHd4YJxiqYcKA5HSCzsCPM8VUMhWjfAUPuxEWFsK-jg3+Dl4RMHBBAbA5BnIkHVDo1ulAiHd3bJITavI+7tl5JnK++QIzGDbE-J26geqv3HGwlR2Dq5cLrsHUOQwyz6DwTgKAuBTGIzgZGEmB4ZD5GkVmUiORZothcQ6LcMhlHlx8T-QO7NG5c0wCErm2BwmRL5kpUwqQaoaGyMpZ6zUrDlFyKuAoEoDhDmyZ-XJfjAi4Fsv4Diu8KndhMDUAKqh9iZCoVnPyydRQHGWKtZQ3TF69NwbAAZTAhmoH8EA2OC544HwyYsFM19zxSkHI0q+xFezqDjLsVaOwp5rOhqo3xuCwAAEdejhx4VAPhozYwLDqH+JQ252nSVxvIRadgbA4TeVgjhajA5MAMUU6ghzO6827KoPsZ59iAUyKKbsyYJS9izFLBwyluyk3lJ4suPSUWfPUXCAqqBYS3FRRCFE2LBEHzdCbGKsY5BgvMcmWQPlajtlAnaaUw5cweMJEy9ZPoABKYBBCsRCL0EYozHRpG0NGcUhNvzJnNOPWQoEKXCBOO4hlKqME5J9ADY6wMAhgwhvgKGjJgXI0dNKZQA4H6rQtfaXyYrNqrhxlmJVjqKbOuZZXbgBTdlswMdgEgAAjQh-LLonI0NILICSSarSsNYIU58jyrhwk-fY9Li6MqTWqskjJ8HHQ4qgbm+bjkvhyHfaQVjboO1CpW5qxF3xZE3O02QVgX4JvQZqCQ3FkprwCAEvWzcjFDDbv4PAplUAEAgNwMARJcDQlQHSCQMB2CCE3WHTAggD2oAqdUZspgHFCyfjFOoI83xpClCkMCptE6NrQaXDBq711B1QDrLdLdd2UH3bgQ9BB4RwjgxIJgLlD1wi6Devw964Mhy3c+1Dr7e0eXKu+98A74mKQvpsLOJDIzAdsGeZY4hVLKsTcu6DIMCm6PDju6OKG0MnoMuey917b2CCE03cjh633m0WIODOMV5hnhHryd8+RMhipNJc5RAmAgKZE5HJDx0X3obhJhuE2HcNwYI3J8zT6X0qf2JGFSsLVzypgVfHISdqKijqg004Jm10g3-rvcTR7JNnrwDJs9cmc2wEEHwJTlGBEFv7Q6CMWggNZFjDake34k5bjPKsSr2RIswZizvOLtn7OOeGHhlzRG0sZayyp5S1TtBniJipMrKT7BysHOQnGPHF2Qf41FgIMWAFNYS9Jq9KXOvZvS-oHrVGyqJFlA2aUP5fy2HkEKad49xui1HQOOr0Wt77KaxhrDOG2vOcI3err22PO7a7ogWU5RHAOnTmBc8W4hQxl8sRUWdRZUtjuwEfBpJluntW7Jzr+BSQ7Zy32mjDpyh2AyHi8wsyr6rkkGImwEEVm2AR3gzH1mKPNZe05-DH3BBI61T9nH1H9sOgp+YTIxgHBir3FnK0vd9g1DjEpSUoo6cAr4SjqTSW1vs8VwybHF1cd87PNU2Q9SsxZHHVfO15QnbShNfITM02m1OrmzBjXT27Ms7e2zuTGutdw1y3jm+B2HTKVPqKKRH7RBp3kM2fIu1eNLqpqZjRcItG4B0XoxEhjLNiZsyt1X6O71aMT9o3R+i4SCFE23L3cdef-eHAsKedh7SZB2M2LG-3rVHmUFYgcW06f56Tyn4viHM9M+ew5177B2vs974X1PBjS8Z-L9z7XVfSg198iTewNem-KBHgoXsw5shLPArbiDXiAAyeBO2oG7f9BkHbdndrfaISlcYBwZBSDYEKSxTCy6nsL9szsZsz8L979MAJBaZcAOACA30lgIxvwbU6hMwUxZAAI1pCIxVThuwDcHU7c+MqZz8DIQCwCID2AoDtQl89t-sqJIwMh7plJCclIvgpRexvw7Ugdzx4kFBlF8DL9u0JAAA5PZHSVAPAdgWAIyCACAQYAxAIFgEQx-NaR+GoIcbQCUACbIceC+SUbaBSOiGPWbPA4ArtUAgQ-wIQkQsQ0gNuHtHnCgrsdGAlOdbjNsOxRADIY0N8EXeoLQLcZRcAyA0ZLqCoc+KPBoXfZMWwd8aMWMXYU4KwV5PQrxPwkgqgMg73HXRGKeHyO+GpRVJYO0JMZqTqYCWiQ4HIeJd0BI92JiDtCELNZuAxcgXZG-O-IwipdYPfOMcQO1J+MVLIRg+oCoCedArIJZCowA92XoZPPZKOWcRWSEXAY9VHHPM9bibwJiQQSYk9QQGY9gOYiJX7XFYHT9bQ0UeofYEmfo4LDGa7BQVGcDV2fQ+eTVUITnEA5o-AHg6w8gv7BAGvBYaHfIVQFMXfFvLsO+HyQ1QE3YJsVBB4rxZ43dAhT4ldebSGIIO4ZPblOEAyOEAgEsCAxKfwdlF4hnNo+RCoeMRoPyZsALRAAcMBWwEmYWTIEDZRBE14owlE9dSGEjKAPAcQyQ4kxE5HXkvAMkhwdIK0EmLMO1ewTMRgzISNI4JQDQC2bAk-d2dkhnQg-EyOBkSAfwLUpEqAg4w2O0BYN0C2Z0RwBgzsWoWAhMM1C0NxZRcgUkMgQIFyMkUZA8JOIE3Ic06oAoS+RGFMJOCUZ5MUJ2YHOnDEtNYZaETNHNH0bPC9NXOTOMhudiTiRMiGZMrnCjFTCWA8UHYWHGC0KtL-ULeFMVGhW6WM1NBudNXMrNXNMkEfVrcfd7DMxs2cbM+TJMtsivI5ZfVMKqcRQCBwKcis2BB0QDA-eaaKVae4t+d2ePDEvJOudlHoLlDcvxUQxYlXNM69LYvc2uQQbczlLVM83+c6NI0cmwJOKUk7bQDAgokoBMGaIndsaieoLcDIBs1lQOB9IJYpQ8xLY8s9U8nlYjeDR9YpFTUWYCXkcBGKJYZaQoxUwPA4KUGhU4wCzc+uDmIpfQcCtHKCziG8vAeTBuYTYJTze5dC9sLQWVWkrsEnI8DMbsXYZ+CLSoqDebblIC-xEjQJEi0JMpBY1M5LCQaC4S2C0jeC7bUpcpU00MVMCE5sXYEnOMNi4iZQaQPkQ1WwGqBdHA2PeedcnlIiwpYJCS8JMi5Y2SyimCtzYpDnMJfYmwn4oMp8g4aspQZsZMcRI8KeR0q0HYWMAivpLZQZYZHeRyyC5ywQKi3AbY7ZfsvgRCmRdMaUE4OtEeCwc3KoO1O2F5eNcyx41hKy4S-pOKvZABRKmSuSzc9K2yfs-QTzRxEtNxEVDfEebixYVIaiQCP86iaKr5X5f5cEQFBkJqtXFqvxbVKap9DXFTXGC0Y3OpLvEMrsbIHOU0K0HaU4aoCa9RdFGyMsLAeak8ly+Si6zFL4+82w99XuN8UXe0YwfOclMCNqR8xwO2ZpZRIgW-D4-wJiK-TAE07y3mOHKHU4B5OXO+G5DI6UYCVQb8XkDOWoYG0GmAcGyG0gmGg0KicoVQNxCwWwVaHIC1NG9TB6LGgmWE1cjBEGu-CG6-KgawYm0MYcdQPsLQp2U7UQHGWmv0+QBmtGEmXG9mwmqgGQHml8B0baCoCUF0X8CiHYMW9GyW7G5m5tTUfwXAPZbKMkXwUkSyDAcyZyGQ-Sdub43mQQJ+SIlC8tJsFU98owQcdIYwTGp2b9NQOKMgbALoYYSGYZV7AyG6s9YO0OkYfs02ipcMCoX-QoEWmpACQ8AdDTR0QcdUuE2OsOn1YZViSzNEz2aOiQQu+OjibYz2JOgys8ClY4ZQKZc7SQB0BVGhbIG0poZoY2jAeAKICDB2g0EQZYDQ7kW4vkZjD8qpX8KUbQTIDpPiwAm8Ue5cb6Se+oaeiwWeuk3GUUF0HIUQcbfW68ZUTSbSNKAyIeyvWwlcZGOJHemKGei1FJJYYicEu0BQWrBIjSRKFKG+uADezyHYd8BQd6e0WQEY-esEj+wK7+ktP+8Yz2UBqacKIIxwEI0QMIrObsUwbQY3cMYUVcJFdhMAdB7uTo8eBGrQuoUrZqJ+MKENMwA4OAuWfih3EGECizYxRnQ9KhxGO2Y+O1OXC2aXf9CUqiFMRG4cc+3AyywStzQfPdF9IRrsW6HyS026EXRwO+HTAY78SeMiBSSUOnBrOLDR5ci0lZHqrGsrcwcebImUW6RvCxh7JbdR56n455CEugmUF0C0W6c7fFZQTAhMVQAcHYOnV47x++3xpkn20Qc8AcHGPCahAysVWoIDOdKoBXGapXeJkc2w55KqXIKMevZG+oKROMdGpQVaKlAAyqrxePKfZPIvNPVR5DYpnFQ2TpSMGwGHZYM2GmrOHaCoBaa1CRcQLgwwyGjR88XYRYKefLb8UKUEs4tTADJ5O+GhOZggzkpIxZshFZiR9Z9TRgiUlqbBu2MK4-OE92bgwg42-DLmRZswcocROU1cYmMXEoNwy7J+J0AmHwrhgww5yG-gwQ4Q3lD5p2ceGnOoGKTIJJTsbaJOAoWUmSTu3kXw4g6xoXaqUUPZ6mp-FaNaZ06NbaTpZRaoj42o8OBo3ZDR+QWwXyToyqdYSrACXGYwM8R0dOClQO8F+eTY6YoYWYz2eY6xwcWSDIEskau0E3RAKlZx7aUWWQGAiwNkkIYUz41li0JOSKMwHIZ2mckoSUWhe0GUl0AKWZ0V1hI05HTk0zNEkIbgSQu4bE+EVl5e6QWRN8K0BhT2hABp6Qd-Earo9QLJR1iQZ15Et1n1UUzCPp3m0lCoHYE8YJn5hU2vVsT+1Uh0fOlm5dBNnUvAPUg0hNv12MUwK0X8rMJacHO0i0aQO1RhbIQEuoV090uuWAL06x+hBBQrNsE1f5jI9Qg4ZpU+baGJuNmq+MvZFs-M6xgZi2OwYaiIgx2BdpRYOpbQ8+DGM6wOS83cnlUQ6x9qXyIcO+DcXIAoSVY2KbFIH8I4bsE9kSuC0CkoBJ3Fa9xhR+e9oZ8I7QANqwVUgG-JhdwS1Kmyui4pK9tGwDu92skD5qMUH2+0W6bIewDMT92Db98SlS1NgVEBADoccBTG+qUiNtkaiUcQKnI6gjtykpTypDirSjyB+pFwrsUQJ8nYZSQcJ2YwQcAj2KnZeKtdiNNU5scBPZ0N5hujEmE8M8MbMYlptc2D6yiT9NABaT2A4tuThQBTga+QNTRe0WAG1ezTgSmDODn5P5ZuDXDjm9scwrJSBQaSNt2FZQQmKznVmD+z6yh6q6zAaTujeYDAgcV-EJ5qWNZx41eYcnPDmWsGjm8Lnx2G+pFGHet-CtFaD9emzGqWhRiy+yY2-wU2jRp2q0SZ0SVQBRGoW0koeaapMPRoU0M4BI6u8OvZSOyhrLw2G+RSUWdA8MAbACOrgbGIuwLQktzxXr4uvZUuv2cuzUDR4wNTMomwLt1u3j+RgWh+aRGiHjFwIAA */ id: 'Modeling', context: ({ input }) => ({ @@ -1286,7 +1289,13 @@ export const modelingMachine = setup({ 'Artifact graph emptied': 'hidePlanes', }, - entry: ['show default planes', 'reset camera position'], + entry: [ + 'show default planes', + 'reset camera position', + 'set selection filter to curves only', + ], + description: `We want to disable selections and hover highlights here, because users can't do anything with that information until they actually add something to the scene. The planes are just for orientation here.`, + exit: 'set selection filter to defaults', }, }, diff --git a/src/routes/Onboarding/Camera.tsx b/src/routes/Onboarding/Camera.tsx index 6cca1bfa4..b52b74d72 100644 --- a/src/routes/Onboarding/Camera.tsx +++ b/src/routes/Onboarding/Camera.tsx @@ -7,10 +7,8 @@ import { cameraSystems, } from 'lib/cameraControls' import { SettingsSection } from 'components/Settings/SettingsSection' -import { useModelingContext } from 'hooks/useModelingContext' export default function Units() { - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.STREAMING) const { @@ -28,8 +26,7 @@ export default function Units() {

Command Bar

diff --git a/src/routes/Onboarding/CodeEditor.tsx b/src/routes/Onboarding/CodeEditor.tsx index a4d140903..2ba82b3ed 100644 --- a/src/routes/Onboarding/CodeEditor.tsx +++ b/src/routes/Onboarding/CodeEditor.tsx @@ -1,4 +1,3 @@ -import { useModelingContext } from 'hooks/useModelingContext' import { kbdClasses, OnboardingButtons, @@ -10,7 +9,6 @@ import { onboardingPaths } from 'routes/Onboarding/paths' export default function OnboardingCodeEditor() { useDemoCode() - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING) @@ -18,8 +16,7 @@ export default function OnboardingCodeEditor() {
diff --git a/src/routes/Onboarding/Export.tsx b/src/routes/Onboarding/Export.tsx index 523d42e44..f09827769 100644 --- a/src/routes/Onboarding/Export.tsx +++ b/src/routes/Onboarding/Export.tsx @@ -1,10 +1,8 @@ import { APP_NAME } from 'lib/constants' import { OnboardingButtons, useDismiss, useNextClick } from '.' import { onboardingPaths } from 'routes/Onboarding/paths' -import { useModelingContext } from 'hooks/useModelingContext' export default function Export() { - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.SKETCHING) @@ -12,8 +10,7 @@ export default function Export() {
diff --git a/src/routes/Onboarding/InteractiveNumbers.tsx b/src/routes/Onboarding/InteractiveNumbers.tsx index 4dc72fbcc..3f5987dab 100644 --- a/src/routes/Onboarding/InteractiveNumbers.tsx +++ b/src/routes/Onboarding/InteractiveNumbers.tsx @@ -7,11 +7,9 @@ import { } from '.' import { onboardingPaths } from 'routes/Onboarding/paths' import { bracketWidthConstantLine } from 'lib/exampleKcl' -import { useModelingContext } from 'hooks/useModelingContext' export default function OnboardingInteractiveNumbers() { useDemoCode() - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.COMMAND_K) @@ -19,8 +17,7 @@ export default function OnboardingInteractiveNumbers() {
diff --git a/src/routes/Onboarding/ParametricModeling.tsx b/src/routes/Onboarding/ParametricModeling.tsx index d20b50747..edb8334b9 100644 --- a/src/routes/Onboarding/ParametricModeling.tsx +++ b/src/routes/Onboarding/ParametricModeling.tsx @@ -3,11 +3,9 @@ import { onboardingPaths } from 'routes/Onboarding/paths' import { Themes, getSystemTheme } from 'lib/theme' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { bracketThicknessCalculationLine } from 'lib/exampleKcl' -import { useModelingContext } from 'hooks/useModelingContext' export default function OnboardingParametricModeling() { useDemoCode() - const { context } = useModelingContext() const { settings: { context: { @@ -29,8 +27,7 @@ export default function OnboardingParametricModeling() {
diff --git a/src/routes/Onboarding/ProjectMenu.tsx b/src/routes/Onboarding/ProjectMenu.tsx index ad2c1882e..fc41b9958 100644 --- a/src/routes/Onboarding/ProjectMenu.tsx +++ b/src/routes/Onboarding/ProjectMenu.tsx @@ -1,10 +1,8 @@ import { OnboardingButtons, useDismiss, useNextClick } from '.' import { onboardingPaths } from 'routes/Onboarding/paths' import { isDesktop } from 'lib/isDesktop' -import { useModelingContext } from 'hooks/useModelingContext' export default function ProjectMenu() { - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.EXPORT) const onDesktop = isDesktop() @@ -13,8 +11,7 @@ export default function ProjectMenu() {
diff --git a/src/routes/Onboarding/Sketching.tsx b/src/routes/Onboarding/Sketching.tsx index 8244a9c7b..54f79fdc5 100644 --- a/src/routes/Onboarding/Sketching.tsx +++ b/src/routes/Onboarding/Sketching.tsx @@ -2,10 +2,8 @@ import { OnboardingButtons, useDismiss, useNextClick } from '.' import { onboardingPaths } from 'routes/Onboarding/paths' import { useEffect } from 'react' import { codeManager, kclManager } from 'lib/singletons' -import { useModelingContext } from 'hooks/useModelingContext' export default function Sketching() { - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.FUTURE_WORK) @@ -24,8 +22,7 @@ export default function Sketching() {

Sketching

diff --git a/src/routes/Onboarding/Streaming.tsx b/src/routes/Onboarding/Streaming.tsx index e4fd3705c..8e764840e 100644 --- a/src/routes/Onboarding/Streaming.tsx +++ b/src/routes/Onboarding/Streaming.tsx @@ -1,9 +1,7 @@ -import { useModelingContext } from 'hooks/useModelingContext' import { OnboardingButtons, useDismiss, useNextClick } from '.' import { onboardingPaths } from 'routes/Onboarding/paths' export default function Streaming() { - const { context } = useModelingContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.EDITOR) @@ -11,8 +9,7 @@ export default function Streaming() {
diff --git a/src/routes/Onboarding/UserMenu.tsx b/src/routes/Onboarding/UserMenu.tsx index 443602ee3..daec412bb 100644 --- a/src/routes/Onboarding/UserMenu.tsx +++ b/src/routes/Onboarding/UserMenu.tsx @@ -1,11 +1,9 @@ import { OnboardingButtons, useDismiss, useNextClick } from '.' import { onboardingPaths } from 'routes/Onboarding/paths' import { useEffect, useState } from 'react' -import { useModelingContext } from 'hooks/useModelingContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' export default function UserMenu() { - const { context } = useModelingContext() const { auth } = useSettingsAuthContext() const dismiss = useDismiss() const next = useNextClick(onboardingPaths.PROJECT_MENU) @@ -35,8 +33,7 @@ export default function UserMenu() {