mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-11 14:58:39 +03:00
fix(webui): soften form control focus rings
This commit is contained in:
+1
-1
@@ -362,7 +362,7 @@ function AuthForm({
|
|||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
aria-invalid={validationError ? true : undefined}
|
aria-invalid={validationError ? true : undefined}
|
||||||
aria-describedby={validationError ? "webui-auth-error" : undefined}
|
aria-describedby={validationError ? "webui-auth-error" : undefined}
|
||||||
className="pr-10 focus-visible:ring-1 focus-visible:ring-ring/30 focus-visible:ring-offset-0"
|
className="pr-10"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { cn } from "@/lib/utils";
|
|||||||
export const SETTINGS_SEARCH_INPUT_CLASS = cn(
|
export const SETTINGS_SEARCH_INPUT_CLASS = cn(
|
||||||
"border-border/45 bg-settings-surface transition-colors hover:border-border/70",
|
"border-border/45 bg-settings-surface transition-colors hover:border-border/70",
|
||||||
"focus-visible:border-border/70 focus-visible:bg-background",
|
"focus-visible:border-border/70 focus-visible:bg-background",
|
||||||
"focus-visible:ring-0 focus-visible:ring-offset-0",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export function CapabilityInstallNotice({
|
export function CapabilityInstallNotice({
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { formControlFocusClassName } from "@/components/ui/form-control";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { SegmentedControl } from "@/components/ui/segmented-control";
|
import { SegmentedControl } from "@/components/ui/segmented-control";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
@@ -835,7 +836,10 @@ export function AutomationEditDialog({
|
|||||||
everyUnit: event.target.value as AutomationEveryUnit,
|
everyUnit: event.target.value as AutomationEveryUnit,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
className="h-10 w-full rounded-[12px] border border-input bg-background px-3 text-[13px] text-foreground outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
|
className={cn(
|
||||||
|
"h-10 w-full rounded-[12px] border border-input bg-background px-3 text-[13px] text-foreground transition-colors",
|
||||||
|
formControlFocusClassName,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{AUTOMATION_EVERY_UNITS.map((unit) => (
|
{AUTOMATION_EVERY_UNITS.map((unit) => (
|
||||||
<option key={unit.value} value={unit.value}>
|
<option key={unit.value} value={unit.value}>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ListTree, Search } from "lucide-react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { formControlFocusClassName } from "@/components/ui/form-control";
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetContent,
|
SheetContent,
|
||||||
@@ -83,7 +84,8 @@ export function PromptNavigator({
|
|||||||
placeholder={t("thread.promptNavigator.search")}
|
placeholder={t("thread.promptNavigator.search")}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-10 w-full rounded-full border border-border bg-background pl-9 pr-3 text-sm",
|
"h-10 w-full rounded-full border border-border bg-background pl-9 pr-3 text-sm",
|
||||||
"outline-none transition focus:border-ring focus:ring-2 focus:ring-ring/20",
|
"transition-colors",
|
||||||
|
formControlFocusClassName,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -256,10 +256,7 @@ export function WorkspaceProjectPicker({
|
|||||||
aria-label={t("workspace.dialog.manual")}
|
aria-label={t("workspace.dialog.manual")}
|
||||||
aria-invalid={pathError || error ? true : undefined}
|
aria-invalid={pathError || error ? true : undefined}
|
||||||
aria-describedby={pathError || error ? pathErrorId : undefined}
|
aria-describedby={pathError || error ? pathErrorId : undefined}
|
||||||
className={cn(
|
className="h-9 rounded-full border-border/55 bg-background/80 px-3 text-[12.5px]"
|
||||||
"h-9 rounded-full border-border/55 bg-background/80 px-3 text-[12.5px]",
|
|
||||||
"focus-visible:ring-1 focus-visible:ring-foreground/10 focus-visible:ring-offset-0",
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export const formControlFocusClassName =
|
||||||
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/50";
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { formControlFocusClassName } from "@/components/ui/form-control";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
||||||
@@ -10,7 +11,8 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
formControlFocusClassName,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { formControlFocusClassName } from "@/components/ui/form-control";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||||
@@ -9,7 +10,8 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
formControlFocusClassName,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
|
||||||
|
describe("form control focus styles", () => {
|
||||||
|
it.each([
|
||||||
|
["input", <Input aria-label="input" />],
|
||||||
|
["textarea", <Textarea aria-label="textarea" />],
|
||||||
|
])("uses a subdued inset focus ring for the %s", (label, control) => {
|
||||||
|
render(control);
|
||||||
|
|
||||||
|
const element = screen.getByLabelText(label);
|
||||||
|
expect(element).toHaveClass(
|
||||||
|
"focus-visible:ring-2",
|
||||||
|
"focus-visible:ring-inset",
|
||||||
|
"focus-visible:ring-ring/50",
|
||||||
|
);
|
||||||
|
expect(element).not.toHaveClass(
|
||||||
|
"ring-offset-background",
|
||||||
|
"focus-visible:ring-ring",
|
||||||
|
"focus-visible:ring-offset-2",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -834,8 +834,9 @@ describe("Settings channels", () => {
|
|||||||
|
|
||||||
const emailRow = await screen.findByRole("button", { name: "View Email settings" });
|
const emailRow = await screen.findByRole("button", { name: "View Email settings" });
|
||||||
expect(screen.getByPlaceholderText("Search channels")).toHaveClass(
|
expect(screen.getByPlaceholderText("Search channels")).toHaveClass(
|
||||||
"focus-visible:ring-0",
|
"focus-visible:ring-2",
|
||||||
"focus-visible:ring-offset-0",
|
"focus-visible:ring-inset",
|
||||||
|
"focus-visible:ring-ring/50",
|
||||||
);
|
);
|
||||||
expect(screen.queryByRole("switch", { name: "Email channel" })).not.toBeInTheDocument();
|
expect(screen.queryByRole("switch", { name: "Email channel" })).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user