mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
fix: reveal SecretInput controls on hover
This commit is contained in:
parent
d0fc0ed941
commit
c5bb1446b4
10 changed files with 27 additions and 3 deletions
|
|
@ -97,6 +97,7 @@ export default function MCPConfigDialog({
|
|||
autoComplete="new-password"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
controlsOnHover
|
||||
placeholder={localize('com_ui_mcp_enter_var', { 0: details.title })}
|
||||
className="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white sm:text-sm"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ const InputWithLabel: FC<InputWithLabelProps> = forwardRef((props, ref) => {
|
|||
autoComplete="new-password"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
controlsOnHover
|
||||
placeholder={`${localize('com_endpoint_config_value')} ${label}`}
|
||||
className={cn('flex h-10 max-h-10 w-full resize-none px-3 py-2', inputClassName)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ function AuthField({ name, config, hasValue, control, errors, autoFocus }: AuthF
|
|||
autoComplete="new-password"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
controlsOnHover
|
||||
/* autoFocus is generally disabled due to the fact that it can disorient users,
|
||||
* but in this case, the required field would logically be immediately navigated to anyways, and the component's
|
||||
* functionality emulates that of a new modal opening, where users would expect focus to be shifted to the new content */
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export const QRPhase: React.FC<QRPhaseProps> = ({ secret, otpauthUrl, onNext })
|
|||
value={secret}
|
||||
readOnly
|
||||
showCopy
|
||||
controlsOnHover
|
||||
aria-label={localize('com_ui_secret_key')}
|
||||
className="font-mono text-lg tracking-wider"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ function CreateKeyDialog({ onKeyCreated }: { onKeyCreated?: () => void }) {
|
|||
value={newKey}
|
||||
readOnly
|
||||
showCopy
|
||||
controlsOnHover
|
||||
onCopy={handleCopy}
|
||||
aria-label={localize('com_ui_your_api_key')}
|
||||
className="font-mono text-sm"
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ function PluginAuthForm({ plugin, onSubmit, isEntityTool }: TPluginAuthFormProps
|
|||
autoComplete="new-password"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
controlsOnHover
|
||||
id={authField}
|
||||
aria-invalid={!!errors[authField]}
|
||||
aria-describedby={`${authField}-error`}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ export default function InputSection({
|
|||
autoComplete="one-time-code"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
controlsOnHover
|
||||
className="mb-2"
|
||||
{...register(name as keyof SearchApiKeyFormData)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ const ApiKey = () => {
|
|||
<SecretInput
|
||||
placeholder="<HIDDEN>"
|
||||
autoComplete="new-password"
|
||||
controlsOnHover
|
||||
className={inputClasses}
|
||||
{...register('api_key', { required: type === AuthTypeEnum.ServiceHttp })}
|
||||
/>
|
||||
|
|
@ -311,6 +312,7 @@ const OAuth = () => {
|
|||
<SecretInput
|
||||
placeholder="<HIDDEN>"
|
||||
autoComplete="new-password"
|
||||
controlsOnHover
|
||||
className={inputClasses}
|
||||
{...register('oauth_client_id', { required: false })}
|
||||
/>
|
||||
|
|
@ -318,6 +320,7 @@ const OAuth = () => {
|
|||
<SecretInput
|
||||
placeholder="<HIDDEN>"
|
||||
autoComplete="new-password"
|
||||
controlsOnHover
|
||||
className={inputClasses}
|
||||
{...register('oauth_client_secret', { required: false })}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -105,7 +105,12 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
|
|||
<Label htmlFor="api_key" className="text-sm font-medium">
|
||||
{localize('com_ui_api_key')}
|
||||
</Label>
|
||||
<SecretInput id="api_key" placeholder="sk-..." {...register('auth.api_key')} />
|
||||
<SecretInput
|
||||
id="api_key"
|
||||
placeholder="sk-..."
|
||||
controlsOnHover
|
||||
{...register('auth.api_key')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -165,6 +170,7 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
|
|||
autoComplete="new-password"
|
||||
data-lpignore="true"
|
||||
data-1p-ignore="true"
|
||||
controlsOnHover
|
||||
placeholder={isEditMode ? localize('com_ui_leave_blank_to_keep') : ''}
|
||||
aria-invalid={errors.auth?.oauth_client_id ? 'true' : 'false'}
|
||||
aria-describedby={
|
||||
|
|
@ -190,6 +196,7 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
|
|||
<SecretInput
|
||||
id="oauth_client_secret"
|
||||
placeholder={isEditMode ? localize('com_ui_leave_blank_to_keep') : ''}
|
||||
controlsOnHover
|
||||
{...register('auth.oauth_client_secret')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export interface SecretInputProps
|
|||
containerClassName?: string;
|
||||
controlsClassName?: string;
|
||||
buttonClassName?: string;
|
||||
controlsOnHover?: boolean;
|
||||
}
|
||||
|
||||
const SecretInput = React.forwardRef<HTMLInputElement, SecretInputProps>(
|
||||
|
|
@ -29,6 +30,7 @@ const SecretInput = React.forwardRef<HTMLInputElement, SecretInputProps>(
|
|||
containerClassName,
|
||||
controlsClassName,
|
||||
buttonClassName,
|
||||
controlsOnHover = false,
|
||||
onCopy,
|
||||
copyFeedbackDuration = 2000,
|
||||
disabled,
|
||||
|
|
@ -68,7 +70,7 @@ const SecretInput = React.forwardRef<HTMLInputElement, SecretInputProps>(
|
|||
}, [value, isCopied, disabled, onCopy, copyFeedbackDuration]);
|
||||
|
||||
return (
|
||||
<div className={cn('relative flex items-center', containerClassName)}>
|
||||
<div className={cn('group/secret-input relative flex items-center', containerClassName)}>
|
||||
<input
|
||||
id={id}
|
||||
type={isVisible ? 'text' : 'password'}
|
||||
|
|
@ -90,7 +92,12 @@ const SecretInput = React.forwardRef<HTMLInputElement, SecretInputProps>(
|
|||
</label>
|
||||
)}
|
||||
<div
|
||||
className={cn('absolute inset-y-0 right-2 flex items-center gap-0.5', controlsClassName)}
|
||||
className={cn(
|
||||
'absolute inset-y-0 right-2 flex items-center gap-0.5',
|
||||
controlsOnHover &&
|
||||
'pointer-events-none opacity-0 transition-opacity duration-150 group-focus-within/secret-input:pointer-events-auto group-focus-within/secret-input:opacity-100 group-hover/secret-input:pointer-events-auto group-hover/secret-input:opacity-100',
|
||||
controlsClassName,
|
||||
)}
|
||||
>
|
||||
{showCopy && (
|
||||
<button
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue