mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-25 13:45:52 +00:00
* Refactor dropdown components to use MenuDropdown for improved functionality and keyboard accessibility - Replaced Dropdown with MenuDropdown in various components including BodyModeSelector, AuthMode, and RequestBodyMode. - Updated styles and structure for better usability and accessibility. - Removed unused Dropdown component and its associated styles. - Enhanced action buttons in ResponsePane and Collection components with ActionIcon for better UI consistency. * fix: Update HttpMethodSelector styles and tests for improved accessibility - Changed the class name for the "Add Custom" button to include 'text-link' for better styling. - Updated tests to use role-based queries for dropdown items, enhancing accessibility checks. - Ensured the correct application of classes in tests to reflect the updated structure. * refactor: Improve component accessibility and consistency * fix: update hover behavior for collection actions menu in runner.ts * refactor: streamline hover interactions for collection actions across tests * refactor: enhance component structure and accessibility across response actions * fix: correct fill property syntax in StyledWrapper for consistent styling * refactor: simplify isDisabled logic in response components for clarity * fix: correct tabIndex logic in ResponseCopy component for improved accessibility * fix: update tabIndex logic in ResponseBookmark component for improved accessibility * fix: enable action buttons in ResponsePaneActions for improved usability * refactor: remove unnecessary tabIndex attributes in response components for improved accessibility * refactor: remove keyDown event handlers from response components for cleaner interaction * refactor: remove SidebarHeader component and related styles for improved structure
151 lines
3.9 KiB
JavaScript
151 lines
3.9 KiB
JavaScript
import React, { useState, useRef, useMemo, useCallback } from 'react';
|
|
import { IconCaretDown } from '@tabler/icons';
|
|
import MenuDropdown from 'ui/MenuDropdown';
|
|
import StyledWrapper from './StyledWrapper';
|
|
|
|
const STANDARD_METHODS = Object.freeze(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD', 'TRACE', 'CONNECT']);
|
|
|
|
const KEY = Object.freeze({ ENTER: 'Enter', ESCAPE: 'Escape' });
|
|
|
|
const DEFAULT_METHOD = 'GET';
|
|
|
|
const TriggerButton = ({ method, ...props }) => {
|
|
return (
|
|
<button
|
|
type="button"
|
|
className="cursor-pointer flex items-center text-left w-full pr-4 select-none"
|
|
{...props}
|
|
>
|
|
<span
|
|
className="px-3 truncate method-span"
|
|
id="create-new-request-method"
|
|
title={method}
|
|
>
|
|
{method}
|
|
</span>
|
|
<IconCaretDown className="caret" size={16} strokeWidth={2} />
|
|
</button>
|
|
);
|
|
};
|
|
|
|
const HttpMethodSelector = ({ method = DEFAULT_METHOD, onMethodSelect }) => {
|
|
const [isCustomMode, setIsCustomMode] = useState(false);
|
|
const inputRef = useRef();
|
|
|
|
const blurInput = () => inputRef.current?.blur();
|
|
|
|
const handleInputChange = (e) => {
|
|
const val = e.target.value.toUpperCase();
|
|
onMethodSelect(val);
|
|
};
|
|
|
|
const handleMethodSelect = useCallback((verb) => {
|
|
onMethodSelect(verb);
|
|
setIsCustomMode(false);
|
|
blurInput();
|
|
}, [onMethodSelect]);
|
|
|
|
const handleBlur = (e) => {
|
|
// Keep the current value when blurring
|
|
const currentValue = e.target.value ? e.target.value.toUpperCase() : method;
|
|
onMethodSelect(currentValue);
|
|
setIsCustomMode(false);
|
|
};
|
|
|
|
const handleAddCustomMethod = useCallback(() => {
|
|
setIsCustomMode(true);
|
|
onMethodSelect('');
|
|
|
|
setTimeout(() => {
|
|
inputRef.current?.focus();
|
|
inputRef.current?.select();
|
|
}, 0);
|
|
}, [onMethodSelect]);
|
|
|
|
const handleKeyDown = (e) => {
|
|
switch (e.key) {
|
|
case KEY.ESCAPE: {
|
|
setIsCustomMode(false);
|
|
blurInput();
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return;
|
|
}
|
|
case KEY.ENTER: {
|
|
onMethodSelect(e.target.value ? e.target.value.toUpperCase() : DEFAULT_METHOD);
|
|
setIsCustomMode(false);
|
|
blurInput();
|
|
return;
|
|
}
|
|
default: {
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Convert STANDARD_METHODS to MenuDropdown items format
|
|
const menuItems = useMemo(() => {
|
|
const items = STANDARD_METHODS.map((verb) => ({
|
|
id: verb.toLowerCase(),
|
|
label: verb,
|
|
onClick: () => handleMethodSelect(verb)
|
|
}));
|
|
|
|
// Add "Add Custom" item
|
|
items.push({
|
|
id: 'add-custom',
|
|
label: '+ Add Custom',
|
|
onClick: handleAddCustomMethod,
|
|
className: 'font-normal mt-1 text-link'
|
|
});
|
|
|
|
return items;
|
|
}, [handleMethodSelect, handleAddCustomMethod]);
|
|
|
|
// Determine selected item ID (only if method is a standard method)
|
|
const selectedItemId = useMemo(() => {
|
|
if (isCustomMode || !STANDARD_METHODS.includes(method)) {
|
|
return null;
|
|
}
|
|
return method.toLowerCase();
|
|
}, [method, isCustomMode]);
|
|
|
|
// If in custom mode, render input field instead of dropdown
|
|
if (isCustomMode) {
|
|
return (
|
|
<StyledWrapper>
|
|
<div className="flex method-selector">
|
|
<div className="flex flex-col w-full">
|
|
<input
|
|
ref={inputRef}
|
|
type="text"
|
|
className="px-2 w-full focus:bg-transparent"
|
|
value={method}
|
|
onChange={handleInputChange}
|
|
onBlur={handleBlur}
|
|
onKeyDown={handleKeyDown}
|
|
title={method}
|
|
autoFocus
|
|
/>
|
|
</div>
|
|
</div>
|
|
</StyledWrapper>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<StyledWrapper>
|
|
<div className="flex method-selector">
|
|
<MenuDropdown
|
|
items={menuItems}
|
|
placement="bottom-start"
|
|
selectedItemId={selectedItemId}
|
|
>
|
|
<TriggerButton method={method} />
|
|
</MenuDropdown>
|
|
</div>
|
|
</StyledWrapper>
|
|
);
|
|
};
|
|
export default HttpMethodSelector;
|