From 8c0bca32ca3e6ebc97967674ac34126b3cf2365d Mon Sep 17 00:00:00 2001 From: Dara Adedeji Date: Mon, 12 Oct 2026 23:29:18 -0400 Subject: [PATCH 1/2] fix(web): Enter creates the new project after clicking an option Clicking the GitHub repository option left the mouse on its row, and Enter ran the highlighted row, so it unticked the box instead of creating the project. In New project only a keyboard highlight now takes over Enter. Co-Authored-By: Claude Opus 5.5 --- apps/web/src/components/CommandPalette.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/CommandPalette.tsx b/apps/web/src/components/CommandPalette.tsx index 7280f7457baa..2c1fb8232dc8 100644 --- a/apps/web/src/components/CommandPalette.tsx +++ b/apps/web/src/components/CommandPalette.tsx @@ -607,6 +607,8 @@ function OpenCommandPaletteDialog(props: { const deferredQuery = useDeferredValue(query); const isActionsOnly = deferredQuery.startsWith(">"); const [highlightedItemValue, setHighlightedItemValue] = useState(null); + // Whether the mouse, rather than the keyboard, put the highlight where it is. + const [isPointerHighlight, setIsPointerHighlight] = useState(false); const resultListRef = useRef(null); // Typing or entering a submenu clears the highlight. Base UI keeps its own on the // first row, but the palette shows none until the user navigates, and the first @@ -2838,6 +2840,10 @@ function OpenCommandPaletteDialog(props: { const newProjectPathPreview = newProjectsRoot === null ? null : getNewProjectPathPreview(newProjectsRoot, newProjectName); const newProjectPublishToggleValue = "new-project:publish"; + // The rows under the name are options for the project, so Enter creates it. + // Only a row reached with the arrow keys takes Enter over; one under the + // mouse, such as the option just clicked, does not. + const newProjectEnterItemValue = isPointerHighlight ? null : highlightedItemValue; // The name step's way out to folders and clones, for the selected machine. // It replaces the name step (and a sources view for another machine under // it), so Back returns to wherever New project was opened from. @@ -3164,16 +3170,16 @@ function OpenCommandPaletteDialog(props: { return; } - // Enter creates the project unless an item below the name is - // highlighted, in which case it runs that item. if ( newProjectFlow !== null && event.key === "Enter" && - highlightedItemValue === null && + newProjectEnterItemValue === null && // Enter that confirms an IME composition is part of typing the name. !event.nativeEvent.isComposing && event.keyCode !== 229 ) { + // Base UI would otherwise click the row under the mouse. + (event as typeof event & { preventBaseUIHandler?: () => void }).preventBaseUIHandler?.(); event.preventDefault(); void submitNewProject(); return; @@ -3214,6 +3220,7 @@ function OpenCommandPaletteDialog(props: { event.preventDefault(); highlightClearedRef.current = false; setHighlightedItemValue(firstItemValue); + setIsPointerHighlight(false); scrollCommandPaletteRowIntoView( resultListRef.current, resultRows.rowIndexByItemIndex[0] ?? 0, @@ -3479,9 +3486,9 @@ function OpenCommandPaletteDialog(props: { const footerActionLabel = newProjectFlow !== null - ? highlightedItemValue === null + ? newProjectEnterItemValue === null ? "Create" - : highlightedItemValue === newProjectPublishToggleValue + : newProjectEnterItemValue === newProjectPublishToggleValue ? "Toggle" : "Select" : addProjectCloneFlow?.step === "repository" @@ -3547,6 +3554,7 @@ function OpenCommandPaletteDialog(props: { if (eventDetails.reason === "none" && highlightClearedRef.current) return; highlightClearedRef.current = false; setHighlightedItemValue(typeof value === "string" ? value : null); + setIsPointerHighlight(eventDetails.reason === "pointer"); const rowIndex = resultRows.rowIndexByItemIndex[eventDetails.index]; if (eventDetails.reason === "keyboard" && rowIndex !== undefined) { scrollCommandPaletteRowIntoView(resultListRef.current, rowIndex); From 9736e5949279417d980c81625aae0f0ff49578f6 Mon Sep 17 00:00:00 2001 From: Dara Adedeji Date: Mon, 12 Oct 2026 23:59:54 -0400 Subject: [PATCH 2/2] fix(web): Cmd+Enter creates the new project while an option is highlighted Match the folder browser: Enter runs the highlighted row, Mod+Enter always submits, and the Create button shows the modifier while a row is highlighted. Replaces the mouse-versus-keyboard highlight rule. Co-Authored-By: Claude Opus 5.5 --- apps/web/src/components/CommandPalette.tsx | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/web/src/components/CommandPalette.tsx b/apps/web/src/components/CommandPalette.tsx index 2c1fb8232dc8..6596e451e3fc 100644 --- a/apps/web/src/components/CommandPalette.tsx +++ b/apps/web/src/components/CommandPalette.tsx @@ -607,8 +607,6 @@ function OpenCommandPaletteDialog(props: { const deferredQuery = useDeferredValue(query); const isActionsOnly = deferredQuery.startsWith(">"); const [highlightedItemValue, setHighlightedItemValue] = useState(null); - // Whether the mouse, rather than the keyboard, put the highlight where it is. - const [isPointerHighlight, setIsPointerHighlight] = useState(false); const resultListRef = useRef(null); // Typing or entering a submenu clears the highlight. Base UI keeps its own on the // first row, but the palette shows none until the user navigates, and the first @@ -2840,10 +2838,6 @@ function OpenCommandPaletteDialog(props: { const newProjectPathPreview = newProjectsRoot === null ? null : getNewProjectPathPreview(newProjectsRoot, newProjectName); const newProjectPublishToggleValue = "new-project:publish"; - // The rows under the name are options for the project, so Enter creates it. - // Only a row reached with the arrow keys takes Enter over; one under the - // mouse, such as the option just clicked, does not. - const newProjectEnterItemValue = isPointerHighlight ? null : highlightedItemValue; // The name step's way out to folders and clones, for the selected machine. // It replaces the name step (and a sources view for another machine under // it), so Back returns to wherever New project was opened from. @@ -3078,6 +3072,10 @@ function OpenCommandPaletteDialog(props: { ? "Create & Add" : "Add"; const addShortcutLabel = hasHighlightedBrowseItem ? `${submitModifierLabel} Enter` : "Enter"; + const hasHighlightedNewProjectItem = newProjectFlow !== null && highlightedItemValue !== null; + const createShortcutLabel = hasHighlightedNewProjectItem + ? `${submitModifierLabel} Enter` + : "Enter"; const remoteProjectButtonLabel = addProjectCloneFlow ? addProjectCloneFlow.source === "url" ? "Continue" @@ -3170,15 +3168,17 @@ function OpenCommandPaletteDialog(props: { return; } + // Enter creates the project unless an item below the name is + // highlighted, in which case it runs that item. Mod+Enter always creates. if ( newProjectFlow !== null && event.key === "Enter" && - newProjectEnterItemValue === null && + (!hasHighlightedNewProjectItem || isPrimaryModifierPressed(event)) && // Enter that confirms an IME composition is part of typing the name. !event.nativeEvent.isComposing && event.keyCode !== 229 ) { - // Base UI would otherwise click the row under the mouse. + // Base UI would otherwise also click the highlighted row. (event as typeof event & { preventBaseUIHandler?: () => void }).preventBaseUIHandler?.(); event.preventDefault(); void submitNewProject(); @@ -3220,7 +3220,6 @@ function OpenCommandPaletteDialog(props: { event.preventDefault(); highlightClearedRef.current = false; setHighlightedItemValue(firstItemValue); - setIsPointerHighlight(false); scrollCommandPaletteRowIntoView( resultListRef.current, resultRows.rowIndexByItemIndex[0] ?? 0, @@ -3390,7 +3389,7 @@ function OpenCommandPaletteDialog(props: { size="xs" tabIndex={-1} className="absolute inset-e-2.5 top-1/2 -translate-y-1/2" - aria-label="Create (Enter)" + aria-label={`Create (${createShortcutLabel})`} disabled={!canSubmitNewProject} onMouseDown={(event) => { event.preventDefault(); @@ -3403,10 +3402,10 @@ function OpenCommandPaletteDialog(props: { > {isCreatingNewProject ? "Creating" : "Create"} - Enter + {createShortcutLabel} - Create (Enter) + {`Create (${createShortcutLabel})`} ) : addProjectCloneFlow?.step === "repository" ? ( @@ -3486,9 +3485,9 @@ function OpenCommandPaletteDialog(props: { const footerActionLabel = newProjectFlow !== null - ? newProjectEnterItemValue === null + ? highlightedItemValue === null ? "Create" - : newProjectEnterItemValue === newProjectPublishToggleValue + : highlightedItemValue === newProjectPublishToggleValue ? "Toggle" : "Select" : addProjectCloneFlow?.step === "repository" @@ -3519,8 +3518,9 @@ function OpenCommandPaletteDialog(props: { inputProps={{ // The submit button is absolutely positioned over the field, so the // inner input must reserve enough room for the full action label. - className: - addProjectCloneFlow?.step === "repository" || newProjectFlow !== null + className: hasHighlightedNewProjectItem + ? "*:data-[slot=autocomplete-input]:pe-38!" + : addProjectCloneFlow?.step === "repository" || newProjectFlow !== null ? "*:data-[slot=autocomplete-input]:pe-32!" : isBrowsing ? browseInputEndPaddingClass({ @@ -3554,7 +3554,6 @@ function OpenCommandPaletteDialog(props: { if (eventDetails.reason === "none" && highlightClearedRef.current) return; highlightClearedRef.current = false; setHighlightedItemValue(typeof value === "string" ? value : null); - setIsPointerHighlight(eventDetails.reason === "pointer"); const rowIndex = resultRows.rowIndexByItemIndex[eventDetails.index]; if (eventDetails.reason === "keyboard" && rowIndex !== undefined) { scrollCommandPaletteRowIntoView(resultListRef.current, rowIndex);