usrnk1 2 месяцев назад
Родитель
Сommit
d46c02ba73

+ 3 - 1
packages/app/src/components/prompt-input.tsx

@@ -218,6 +218,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
   let scrollRef!: HTMLDivElement
   let slashPopoverRef!: HTMLDivElement
   let restoreEndOnFocus = true
+  let savedCursor: number | null = null
 
   const mirror = { input: false }
   const inset = 56
@@ -590,7 +591,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
 
   const restoreFocus = () => {
     requestAnimationFrame(() => {
-      const cursor = prompt.cursor() ?? promptLength(prompt.current())
+      const cursor = savedCursor ?? prompt.cursor() ?? promptLength(prompt.current())
       editorRef.focus()
       setCursorPosition(editorRef, cursor)
       queueScroll()
@@ -627,6 +628,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
   const isImeComposing = (event: KeyboardEvent) => event.isComposing || composing() || event.keyCode === 229
 
   const handleBlur = () => {
+    savedCursor = currentCursor()
     closePopover()
     setComposing(false)
   }

+ 1 - 1
packages/app/src/components/settings-v2/settings-v2.css

@@ -399,7 +399,7 @@
   overflow: hidden;
   font-size: 13px;
   font-weight: 440;
-  line-height: 1;
+  line-height: 16px;
   text-overflow: ellipsis;
   white-space: nowrap;
 }

+ 1 - 1
packages/app/src/components/titlebar-tab-popover.tsx

@@ -3,7 +3,7 @@ import { createSignal, Show, type JSXElement } from "solid-js"
 import "./titlebar-tab-popover.css"
 
 // Initial hover delay before the preview appears, per design.
-const OPEN_DELAY = 200
+const OPEN_DELAY = 400
 // Mouse-out delay: begin closing immediately (a brief exit animation plays).
 const CLOSE_DELAY = 0
 // After a preview closes, hovering a neighbouring tab within this window skips

+ 2 - 2
packages/app/src/pages/session/timeline/message-timeline.tsx

@@ -1393,14 +1393,14 @@ export function MessageTimeline(props: {
                     <button
                       type="button"
                       data-slot="session-title-parent"
-                      class="min-w-0 max-w-[40%] truncate px-2 text-[13px] font-[530] leading-4 tracking-[-0.04px] text-v2-text-text-faint transition-colors hover:text-v2-text-text-muted"
+                      class="min-w-0 max-w-[40%] truncate pl-2 text-[13px] font-[530] leading-4 tracking-[-0.04px] text-v2-text-text-faint transition-colors hover:text-v2-text-text-muted"
                       onClick={navigateParent}
                     >
                       {parentTitle()}
                     </button>
                     <span
                       data-slot="session-title-separator"
-                      class="-translate-y-[0.5px] px-1 text-[11px] font-medium text-v2-text-text-faint"
+                      class="-translate-y-[0.5px] pl-2 pr-1 text-[11px] font-medium text-v2-text-text-faint"
                       aria-hidden="true"
                     >
                       /

+ 16 - 1
packages/app/src/pages/session/use-composer-commands.tsx

@@ -3,6 +3,7 @@ import { useLanguage } from "@/context/language"
 import { useLocal } from "@/context/local"
 import { useSettings } from "@/context/settings"
 import { useDialog } from "@opencode-ai/ui/context/dialog"
+import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
 import { useSessionLayout } from "./session-layout"
 import { createSessionOwnership } from "./session-ownership"
 
@@ -26,9 +27,23 @@ export const useComposerCommands = () => {
 
   const chooseModel = async () => {
     const owner = sessionOwnership.capture()
+    const editor = document.querySelector<HTMLElement>('[data-component="prompt-input"]')
+    const selection = window.getSelection()
+    const cursor =
+      editor && selection?.rangeCount && editor.contains(selection.anchorNode) ? getCursorPosition(editor) : null
+    const restoreComposer = () => {
+      // Kobalte restores focus during its teardown effect; defer past it so the
+      // composer keeps focus and the caret returns to where the user left it.
+      requestAnimationFrame(() => {
+        const editor = document.querySelector<HTMLElement>('[data-component="prompt-input"]')
+        if (!editor) return
+        editor.focus()
+        if (cursor !== null) setCursorPosition(editor, cursor)
+      })
+    }
     const { DialogSelectModel } = await import("@/components/dialog-select-model")
     owner.run(() => {
-      void dialog.show(() => <DialogSelectModel model={local.model} />)
+      void dialog.show(() => <DialogSelectModel model={local.model} />, restoreComposer)
     })
   }