@redocly/theme
Version:
Shared UI components lib
80 lines (66 loc) • 2.07 kB
text/typescript
import { useState, useCallback, useMemo } from 'react';
import debounce from 'lodash.debounce';
import type { MCPOption } from '../types';
import { useThemeHooks } from './use-theme-hooks';
import { useMCPConfig } from './use-mcp-config';
import { ClipboardService } from '../utils/clipboard-service';
export type McpButtonOptions = {
options?: MCPOption[];
};
export type McpButtonSettings = {
isCopied: boolean;
cursorUrl: string;
vscodeUrl: string;
triggerButtonText: string;
visibleOptions: MCPOption[];
handleAction: (action: MCPOption) => void;
};
const COPIED_RESET_TIMEOUT = 1000;
export function useConnectMCPButton({
options = ['cursor', 'vscode', 'copy'],
}: McpButtonOptions = {}): McpButtonSettings {
const { useTranslate } = useThemeHooks();
const { translate } = useTranslate();
const { serverName, serverUrl, cursorUrl, vscodeUrl } = useMCPConfig();
const [isCopied, setIsCopied] = useState(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
const resetCopied = useCallback(
debounce(() => setIsCopied(false), COPIED_RESET_TIMEOUT),
[],
);
const handleAction = useCallback(
(action: MCPOption) => {
if (action === 'copy') {
const config = {
[serverName]: {
url: serverUrl,
description: 'MCP Server',
},
};
ClipboardService.copyCustom(JSON.stringify(config, null, 2));
setIsCopied(true);
resetCopied();
return;
}
const urlMap: Record<Exclude<MCPOption, 'copy'>, string> = {
cursor: cursorUrl,
vscode: vscodeUrl,
};
window.open(urlMap[action], '_blank');
},
[cursorUrl, vscodeUrl, serverUrl, serverName, resetCopied],
);
const triggerButtonText = useMemo(
() => translate('page.actions.connectMcp', 'Connect MCP'),
[translate],
);
const visibleOptions = useMemo(() => options.filter(Boolean), [options]);
return {
isCopied,
cursorUrl,
vscodeUrl,
triggerButtonText,
visibleOptions,
handleAction,
};
}