mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(web): suppress focus ring on pointer interactions while preserving keyboard accessibility
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { diffLines } from 'diff'
|
||||
import { useMemo } from 'react'
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
|
||||
import { usePointerFocusRing } from '@/hooks/usePointerFocusRing'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export function DiffView(props: {
|
||||
@@ -10,6 +11,7 @@ export function DiffView(props: {
|
||||
variant?: 'preview' | 'inline'
|
||||
}) {
|
||||
const variant = props.variant ?? 'preview'
|
||||
const { suppressFocusRing, onTriggerPointerDown, onTriggerKeyDown, onTriggerBlur } = usePointerFocusRing()
|
||||
|
||||
const stats = useMemo(() => {
|
||||
const oldChars = props.oldString.length
|
||||
@@ -37,7 +39,16 @@ export function DiffView(props: {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button type="button" className="w-full text-left">
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'w-full text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--app-link)]',
|
||||
suppressFocusRing && 'focus-visible:ring-0'
|
||||
)}
|
||||
onPointerDown={onTriggerPointerDown}
|
||||
onKeyDown={onTriggerKeyDown}
|
||||
onBlur={onTriggerBlur}
|
||||
>
|
||||
<div className="overflow-hidden rounded-md border border-[var(--app-border)] bg-[var(--app-subtle-bg)] hover:bg-[var(--app-secondary-bg)] transition-colors">
|
||||
{props.filePath ? (
|
||||
<div className="border-b border-[var(--app-border)] bg-[var(--app-subtle-bg)] px-2 py-1 text-xs text-[var(--app-hint)] truncate">
|
||||
|
||||
@@ -13,6 +13,8 @@ import { isAskUserQuestionToolName } from '@/components/ToolCard/askUserQuestion
|
||||
import { getToolPresentation } from '@/components/ToolCard/knownTools'
|
||||
import { getToolFullViewComponent, getToolViewComponent } from '@/components/ToolCard/views/_all'
|
||||
import { getToolResultViewComponent } from '@/components/ToolCard/views/_results'
|
||||
import { usePointerFocusRing } from '@/hooks/usePointerFocusRing'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
function isObject(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value) && typeof value === 'object'
|
||||
@@ -341,6 +343,7 @@ function ToolCardInner(props: ToolCardProps) {
|
||||
))
|
||||
const hasBody = showInline || taskSummary !== null || showsPermissionFooter
|
||||
const stateColor = statusColorClass(props.block.tool.state)
|
||||
const { suppressFocusRing, onTriggerPointerDown, onTriggerKeyDown, onTriggerBlur } = usePointerFocusRing()
|
||||
|
||||
const header = (
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -378,7 +381,16 @@ function ToolCardInner(props: ToolCardProps) {
|
||||
<CardHeader className="p-3 space-y-0">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button type="button" className="w-full text-left">
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'w-full text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--app-link)]',
|
||||
suppressFocusRing && 'focus-visible:ring-0'
|
||||
)}
|
||||
onPointerDown={onTriggerPointerDown}
|
||||
onKeyDown={onTriggerKeyDown}
|
||||
onBlur={onTriggerBlur}
|
||||
>
|
||||
{header}
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { useCallback, useState, type FocusEvent, type KeyboardEvent, type PointerEvent } from 'react'
|
||||
|
||||
export function usePointerFocusRing() {
|
||||
const [suppressFocusRing, setSuppressFocusRing] = useState(false)
|
||||
|
||||
const onTriggerPointerDown = useCallback((_event: PointerEvent<HTMLElement>) => {
|
||||
setSuppressFocusRing(true)
|
||||
}, [])
|
||||
|
||||
const onTriggerKeyDown = useCallback((_event: KeyboardEvent<HTMLElement>) => {
|
||||
setSuppressFocusRing(false)
|
||||
}, [])
|
||||
|
||||
const onTriggerBlur = useCallback((_event: FocusEvent<HTMLElement>) => {
|
||||
setSuppressFocusRing(false)
|
||||
}, [])
|
||||
|
||||
return {
|
||||
suppressFocusRing,
|
||||
onTriggerPointerDown,
|
||||
onTriggerKeyDown,
|
||||
onTriggerBlur
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user