/* Copyright 2026 Marimo. All rights reserved. */ import { useAtomValue } from "jotai"; import { EditIcon, LayoutTemplateIcon, PlayIcon, SquareIcon, Undo2Icon, } from "lucide-react"; import type { JSX } from "react"; import { KeyboardShortcuts } from "@/components/editor/controls/keyboard-shortcuts"; import { NotebookMenuDropdown } from "@/components/editor/controls/notebook-menu-dropdown"; import { ShutdownButton } from "@/components/editor/controls/shutdown-button"; import { Button } from "@/components/editor/inputs/Inputs"; import { FindReplace } from "@/components/find-replace/find-replace"; import type { AppConfig } from "@/core/config/config-schema"; import { canInteractWithAppAtom } from "@/core/network/connection"; import { SaveComponent } from "@/core/saving/save-component"; import { getConnectionTooltip, isAppInteractionDisabled, } from "@/core/websocket/connection-utils"; import { WebSocketState } from "@/core/websocket/types"; import { cn } from "@/utils/cn"; import { Functions } from "@/utils/functions"; import { canUndoDeletesAtom, needsRunAtom, useCellActions, } from "../../../core/cells/cells"; import { ConfigButton } from "../../app-config/app-config-button"; import { renderShortcut } from "../../shortcuts/renderShortcut"; import { Tooltip } from "../../ui/tooltip"; import { useShouldShowInterrupt } from "../cell/useShouldShowInterrupt"; import { HideInKioskMode } from "../kiosk-mode"; import { LayoutSelect } from "../renderers/layout-select"; import { CommandPaletteButton } from "./command-palette-button"; interface ControlsProps { presenting: boolean; onTogglePresenting: () => void; onInterrupt: () => void; onRun: () => void; connectionState: WebSocketState; running: boolean; appConfig: AppConfig; } export const Controls = ({ presenting, onTogglePresenting, onInterrupt, onRun, connectionState, running, }: ControlsProps): JSX.Element => { const undoAvailable = useAtomValue(canUndoDeletesAtom); const needsRun = useAtomValue(needsRunAtom); const { undoDeleteCell } = useCellActions(); const closed = connectionState === WebSocketState.CLOSED; let undoControl: JSX.Element | null = null; if (!closed && undoAvailable) { undoControl = ( ); } const disabled = isAppInteractionDisabled(connectionState); const connectionTooltip = disabled ? getConnectionTooltip(connectionState) : undefined; return ( <> {!presenting && } {!closed && (
{presenting && }
)}
{undoControl} {!closed && ( )} {!closed && }
); }; const RunControlButton = ({ needsRun, onRun, }: { needsRun: boolean; onRun: () => void; }) => { const canInteractWithApp = useAtomValue(canInteractWithAppAtom); if (needsRun) { return ( ); } return ( ); }; const StopControlButton = ({ running, onInterrupt, }: { running: boolean; onInterrupt: () => void; }) => { // Show the interrupt button after 200ms to avoid flickering. const showInterrupt = useShouldShowInterrupt(running); return ( ); }; const topRightControls = "absolute top-3 right-5 m-0 flex items-center gap-2 min-h-[28px] print:hidden pointer-events-auto z-30"; const bottomRightControls = "absolute bottom-5 right-5 flex flex-col gap-2 items-center print:hidden pointer-events-auto z-30";