diff --git a/packages/experimental/client-ui-forge/README.i18n.yaml b/packages/experimental/client-ui-forge/README.i18n.yaml index 7beff73f1b..61b61e6dc9 100644 --- a/packages/experimental/client-ui-forge/README.i18n.yaml +++ b/packages/experimental/client-ui-forge/README.i18n.yaml @@ -18,8 +18,8 @@ en: c3fa707a638717e4 zh: dfeba8a57c58a8aa /deepseek-ai-dsh-experimental-client-ui-forge/understand-the-implementation: - en: 34e9adf3a843f969 - zh: 7a04974cf01fa2e7 + en: c9541603ea971f46 + zh: 15c41326e3fb29e4 /deepseek-ai-dsh-experimental-client-ui-forge/further-exploration: en: fa4d8c579ffc49ff zh: 5856ed7469e4585b diff --git a/packages/experimental/client-ui-forge/README.md b/packages/experimental/client-ui-forge/README.md index 0cff619fbf..2d95507268 100644 --- a/packages/experimental/client-ui-forge/README.md +++ b/packages/experimental/client-ui-forge/README.md @@ -106,6 +106,7 @@ The browser entry mounts the Remote, then the UI. One stream per Session feeds t | [`src/client/thread-state.ts`](src/client/thread-state.ts) | Thread reads and their places in the shown changes | | [`src/review-cache.ts`](src/review-cache.ts) | Review threads kept in memory | | [`src/client/host-viewed.ts`](src/client/host-viewed.ts) | Viewed marks the code host keeps, with marks being saved | +| [`src/client/menu-search.ts`](src/client/menu-search.ts) | Keys of the search field at the top of a menu | | [`src/client/FileLabel.tsx`](src/client/FileLabel.tsx) | Changed file label: name, then directory | | [`src/client/WorktreeToggle.tsx`](src/client/WorktreeToggle.tsx) | New Session worktree option | | [`src/client/WorktreeProgress.tsx`](src/client/WorktreeProgress.tsx) | Worktree creation and removed-worktree card | diff --git a/packages/experimental/client-ui-forge/README.zh.md b/packages/experimental/client-ui-forge/README.zh.md index b5a53effd0..c7f9d4b994 100644 --- a/packages/experimental/client-ui-forge/README.zh.md +++ b/packages/experimental/client-ui-forge/README.zh.md @@ -106,6 +106,7 @@ Session 在所创建的 worktree 中工作时,`localDiff` 以它的 `baseCommi | [`src/client/thread-state.ts`](src/client/thread-state.ts) | 读取讨论并确定它们在所显示变更中的位置 | | [`src/review-cache.ts`](src/review-cache.ts) | 保存在内存中的评审讨论 | | [`src/client/host-viewed.ts`](src/client/host-viewed.ts) | 代码托管平台保存的已审阅标记,以及正在保存的标记 | +| [`src/client/menu-search.ts`](src/client/menu-search.ts) | 菜单顶部搜索框的按键处理 | | [`src/client/FileLabel.tsx`](src/client/FileLabel.tsx) | 变更文件的标签:文件名在前,目录在后 | | [`src/client/WorktreeToggle.tsx`](src/client/WorktreeToggle.tsx) | 新会话的工作树选项 | | [`src/client/WorktreeProgress.tsx`](src/client/WorktreeProgress.tsx) | worktree 创建卡片与 worktree 缺失卡片 | diff --git a/packages/experimental/client-ui-forge/src/client/BaseMenu.tsx b/packages/experimental/client-ui-forge/src/client/BaseMenu.tsx index 9125fef677..0bcabc3408 100644 --- a/packages/experimental/client-ui-forge/src/client/BaseMenu.tsx +++ b/packages/experimental/client-ui-forge/src/client/BaseMenu.tsx @@ -10,6 +10,7 @@ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots' import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol' import type { ForgeBaseBranch, ForgeBaseBranches } from '../types.ts' import type { NS } from './locales.ts' +import { searchFieldKeyDown } from './menu-search.ts' import css from './BaseMenu.module.css' /** Milliseconds between the last keystroke of a search and the listing it reads. */ @@ -169,12 +170,7 @@ export function BaseMenu({ chosen, label, missing, visible, list, choose, t }: B } value={query} aria-label={t('diff.base.search')} placeholder={t('diff.base.search')} onChange={(event) => { setQuery(event.target.value) }} - onKeyDown={(event) => { - if (['Home', 'End', 'ArrowLeft', 'ArrowRight'].includes(event.key)) event.stopPropagation() - if (event.key !== 'Enter' || event.nativeEvent.isComposing || first === undefined) return - event.preventDefault() - pick(first.base) - }} /> + onKeyDown={(event) => { searchFieldKeyDown(event, first === undefined ? undefined : () => { pick(first.base) }) }} />
{body}
{t('diff.base.note')}
diff --git a/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.module.css b/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.module.css index 71e602700a..3f0cc3ba36 100644 --- a/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.module.css +++ b/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.module.css @@ -35,6 +35,7 @@ justify-content: center; box-sizing: border-box; border-radius: 50%; + corner-shape: round; background: var(--dsw-alias-interactive-bg-active); color: var(--dsw-alias-label-secondary); font-size: 10px; diff --git a/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.tsx b/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.tsx index dd44612e4f..4fb047f74d 100644 --- a/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.tsx +++ b/packages/experimental/client-ui-forge/src/client/ChangeRequestOverview.tsx @@ -22,6 +22,7 @@ import { formatDuration } from './format.ts' import { CheckGlyph } from './glyphs.tsx' import type { ForgePanelKey, NS } from './locales.ts' import { checkCounts, checkDuration } from './status.ts' +import { searchFieldKeyDown } from './menu-search.ts' import css from './ForgeTab.module.css' import overview from './ChangeRequestOverview.module.css' @@ -470,12 +471,7 @@ function ReviewerSearch({ url, list, choose, t }: {
} value={query} aria-label={t('reviewers.search')} placeholder={t('reviewers.search')} onChange={(event) => { setQuery(event.target.value) }} - onKeyDown={(event) => { - if (['Home', 'End', 'ArrowLeft', 'ArrowRight'].includes(event.key)) event.stopPropagation() - if (event.key !== 'Enter' || event.nativeEvent.isComposing || first === undefined) return - event.preventDefault() - choose(first.login) - }} /> + onKeyDown={(event) => { searchFieldKeyDown(event, first === undefined ? undefined : () => { choose(first.login) }) }} />
{body}
diff --git a/packages/experimental/client-ui-forge/src/client/menu-search.ts b/packages/experimental/client-ui-forge/src/client/menu-search.ts new file mode 100644 index 0000000000..efd11a2580 --- /dev/null +++ b/packages/experimental/client-ui-forge/src/client/menu-search.ts @@ -0,0 +1,16 @@ +/** Keys of the search field at the top of a menu that lists what the search matches. */ + +import type { KeyboardEvent } from 'react' + +/** + * Keep the edge and arrow keys in a menu's search field, so they move the caret instead of the menu's focus, and choose + * the first listed row with Enter outside an input method composition. + * @param event - the key event of the search field. + * @param chooseFirst - chooses the first listed row, or undefined while none is listed. + */ +export function searchFieldKeyDown(event: KeyboardEvent, chooseFirst: (() => void) | undefined): void { + if (['Home', 'End', 'ArrowLeft', 'ArrowRight'].includes(event.key)) event.stopPropagation() + if (event.key !== 'Enter' || event.nativeEvent.isComposing || chooseFirst === undefined) return + event.preventDefault() + chooseFirst() +}