feat(ui): refine download controls and package motion
Move the global package disclosure action into a responsive right-aligned toolbar group and disable it for empty queues. Replace the decorative package title with a compact neutral filter group, coordinate disclosure opacity with height transitions, and make contextual help follow combined pointer and keyboard focus state.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { ReactElement } from "react";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { ContextInfoButton } from "../src/renderer/ui/ContextInfoButton";
|
||||
import {
|
||||
DataTable,
|
||||
@@ -12,6 +13,11 @@ import { Icon } from "../src/renderer/ui/Icon";
|
||||
import { Toolbar, ToolbarGroup, ToolbarSearch } from "../src/renderer/ui/Toolbar";
|
||||
import { getThemeVariables, UI_FOCUS_RING_VARIABLE } from "../src/renderer/ui/theme";
|
||||
|
||||
vi.mock("react", async () => {
|
||||
const actual = await vi.importActual<typeof import("react")>("react");
|
||||
return { ...actual, useId: () => "context-info-test", useRef: <T,>(value: T) => ({ current: value }) };
|
||||
});
|
||||
|
||||
const expectedThemes = {
|
||||
dark: {
|
||||
"--ui-canvas": "#0F0F0F",
|
||||
@@ -181,4 +187,36 @@ describe("new UI primitives", () => {
|
||||
expect(html).toContain("aria-label=\"Informationen zu Downloads\"");
|
||||
expect(html).toContain("Vorhandene <strong>Download-Hilfe</strong>");
|
||||
});
|
||||
|
||||
it("keeps context help open until both pointer and focus leave the shared region", () => {
|
||||
const changes: boolean[] = [];
|
||||
const component = ContextInfoButton({
|
||||
contextName: "Downloads",
|
||||
content: "Download-Hilfe",
|
||||
open: false,
|
||||
onOpenChange: (open) => changes.push(open)
|
||||
}) as ReactElement<Record<string, unknown>>;
|
||||
const props = component.props as unknown as {
|
||||
onPointerEnter: () => void;
|
||||
onPointerLeave: () => void;
|
||||
onFocus: () => void;
|
||||
onBlur: (event: { currentTarget: { contains: (target: unknown) => boolean }; relatedTarget: unknown }) => void;
|
||||
children: ReactElement<Record<string, unknown>>[];
|
||||
};
|
||||
const inside = {};
|
||||
const outside = {};
|
||||
const button = props.children[0] as ReactElement<{ onClick: () => void }>;
|
||||
|
||||
props.onPointerEnter();
|
||||
props.onFocus();
|
||||
props.onPointerLeave();
|
||||
props.onBlur({ currentTarget: { contains: (target) => target === inside }, relatedTarget: inside });
|
||||
props.onBlur({ currentTarget: { contains: (target) => target === inside }, relatedTarget: outside });
|
||||
props.onPointerEnter();
|
||||
props.onBlur({ currentTarget: { contains: (target) => target === inside }, relatedTarget: outside });
|
||||
props.onPointerLeave();
|
||||
button.props.onClick();
|
||||
|
||||
expect(changes).toEqual([true, true, false, true, false, true]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user