mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🧰 feat: Accessible MCP Tool Lists (#10695)
* feat: add aria-label for expansion chevron in Agent Builder's MCP tool list dropdown * fix: remove duplicate tool info button in MCPTool so it doesn't get picked up via keyboard nav (still exists on mouse hover as it should to provide tooltip description of tool) * feat: use InfoHoverCard rather than Ariakit components for tool descriptions * chore: remove unused i18n keys
This commit is contained in:
parent
b1e31fdc97
commit
58f73626e7
2 changed files with 20 additions and 57 deletions
|
|
@ -1,17 +1,17 @@
|
|||
import React, { useState } from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { Constants } from 'librechat-data-provider';
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
||||
import {
|
||||
Label,
|
||||
ESide,
|
||||
Checkbox,
|
||||
OGDialog,
|
||||
Accordion,
|
||||
TrashIcon,
|
||||
InfoHoverCard,
|
||||
AccordionItem,
|
||||
CircleHelpIcon,
|
||||
OGDialogTrigger,
|
||||
AccordionContent,
|
||||
OGDialogTemplate,
|
||||
|
|
@ -31,7 +31,6 @@ export default function MCPTool({ serverInfo }: { serverInfo?: MCPServerInfo })
|
|||
const [isFocused, setIsFocused] = useState(false);
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
const [accordionValue, setAccordionValue] = useState<string>('');
|
||||
const [hoveredToolId, setHoveredToolId] = useState<string | null>(null);
|
||||
|
||||
if (!serverInfo) {
|
||||
return null;
|
||||
|
|
@ -183,7 +182,16 @@ export default function MCPTool({ serverInfo }: { serverInfo?: MCPServerInfo })
|
|||
'flex h-7 w-7 items-center justify-center rounded transition-colors duration-200 hover:bg-surface-active-alt focus:translate-x-0 focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1',
|
||||
isExpanded && 'bg-surface-active-alt',
|
||||
)}
|
||||
aria-hidden="true"
|
||||
aria-label={
|
||||
isExpanded
|
||||
? localize('com_ui_tool_list_collapse', {
|
||||
serverName: currentServerName,
|
||||
})
|
||||
: localize('com_ui_tool_list_expand', {
|
||||
serverName: currentServerName,
|
||||
})
|
||||
}
|
||||
aria-expanded={isExpanded}
|
||||
tabIndex={0}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
>
|
||||
|
|
@ -227,15 +235,13 @@ export default function MCPTool({ serverInfo }: { serverInfo?: MCPServerInfo })
|
|||
key={subTool.tool_id}
|
||||
htmlFor={subTool.tool_id}
|
||||
className={cn(
|
||||
'border-token-border-light hover:bg-token-surface-secondary flex cursor-pointer items-center rounded-lg border p-2',
|
||||
'group/item border-token-border-light hover:bg-token-surface-secondary flex cursor-pointer items-center rounded-lg border p-2',
|
||||
'ml-2 mr-1 focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background',
|
||||
)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onMouseEnter={() => setHoveredToolId(subTool.tool_id)}
|
||||
onMouseLeave={() => setHoveredToolId(null)}
|
||||
>
|
||||
<Checkbox
|
||||
id={subTool.tool_id}
|
||||
|
|
@ -264,54 +270,9 @@ export default function MCPTool({ serverInfo }: { serverInfo?: MCPServerInfo })
|
|||
{subTool.metadata.name}
|
||||
</span>
|
||||
{subTool.metadata.description && (
|
||||
<Ariakit.HovercardProvider placement="left-start">
|
||||
<div className="ml-auto flex h-6 w-6 items-center justify-center">
|
||||
<Ariakit.HovercardAnchor
|
||||
render={
|
||||
<Ariakit.Button
|
||||
className={cn(
|
||||
'flex h-5 w-5 cursor-help items-center rounded-full text-text-secondary transition-opacity duration-200',
|
||||
hoveredToolId === subTool.tool_id ? 'opacity-100' : 'opacity-0',
|
||||
)}
|
||||
aria-label={localize('com_ui_tool_info')}
|
||||
>
|
||||
<CircleHelpIcon className="h-4 w-4" />
|
||||
<Ariakit.VisuallyHidden>
|
||||
{localize('com_ui_tool_info')}
|
||||
</Ariakit.VisuallyHidden>
|
||||
</Ariakit.Button>
|
||||
}
|
||||
/>
|
||||
<Ariakit.HovercardDisclosure
|
||||
className="rounded-full text-text-secondary focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
aria-label={localize('com_ui_tool_more_info')}
|
||||
aria-expanded={hoveredToolId === subTool.tool_id}
|
||||
aria-controls={`tool-description-${subTool.tool_id}`}
|
||||
>
|
||||
<Ariakit.VisuallyHidden>
|
||||
{localize('com_ui_tool_more_info')}
|
||||
</Ariakit.VisuallyHidden>
|
||||
<ChevronDown className="h-4 w-4" aria-hidden="true" />
|
||||
</Ariakit.HovercardDisclosure>
|
||||
</div>
|
||||
<Ariakit.Hovercard
|
||||
id={`tool-description-${subTool.tool_id}`}
|
||||
gutter={14}
|
||||
shift={40}
|
||||
flip={false}
|
||||
className="z-[999] w-80 scale-95 rounded-2xl border border-border-medium bg-surface-secondary p-4 text-text-primary opacity-0 shadow-md transition-all duration-200 data-[enter]:scale-100 data-[leave]:scale-95 data-[enter]:opacity-100 data-[leave]:opacity-0"
|
||||
portal={true}
|
||||
unmountOnHide={true}
|
||||
role="tooltip"
|
||||
aria-label={subTool.metadata.description}
|
||||
>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm text-text-secondary">
|
||||
{subTool.metadata.description}
|
||||
</p>
|
||||
</div>
|
||||
</Ariakit.Hovercard>
|
||||
</Ariakit.HovercardProvider>
|
||||
<div className="ml-auto flex items-center opacity-0 transition-opacity duration-200 group-focus-within/item:opacity-100 group-hover/item:opacity-100">
|
||||
<InfoHoverCard side={ESide.Left} text={subTool.metadata.description} />
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -782,6 +782,7 @@
|
|||
"com_ui_close_settings": "Close Settings",
|
||||
"com_ui_close_window": "Close Window",
|
||||
"com_ui_code": "Code",
|
||||
"com_ui_collapse": "Collapse",
|
||||
"com_ui_collapse_chat": "Collapse Chat",
|
||||
"com_ui_command_placeholder": "Optional: Enter a command for the prompt or name will be used",
|
||||
"com_ui_command_usage_placeholder": "Select a Prompt by command or name",
|
||||
|
|
@ -918,6 +919,7 @@
|
|||
"com_ui_error_updating_preferences": "Error updating preferences",
|
||||
"com_ui_everyone_permission_level": "Everyone's permission level",
|
||||
"com_ui_examples": "Examples",
|
||||
"com_ui_expand": "Expand",
|
||||
"com_ui_expand_chat": "Expand Chat",
|
||||
"com_ui_export_convo_modal": "Export Conversation Modal",
|
||||
"com_ui_feedback_more": "More...",
|
||||
|
|
@ -1282,8 +1284,8 @@
|
|||
"com_ui_token_url": "Token URL",
|
||||
"com_ui_tokens": "tokens",
|
||||
"com_ui_tool_collection_prefix": "A collection of tools from",
|
||||
"com_ui_tool_info": "Tool Information",
|
||||
"com_ui_tool_more_info": "More information about this tool",
|
||||
"com_ui_tool_list_collapse": "Collapse {{serverName}} tool list",
|
||||
"com_ui_tool_list_expand": "Expand {{serverName}} tool list",
|
||||
"com_ui_tools": "Tools",
|
||||
"com_ui_tools_and_actions": "Tools and Actions",
|
||||
"com_ui_transferred_to": "Transferred to",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue