feat(drill): DrillableCell — hover-reveal button wrapper
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
// @vitest-environment happy-dom
|
||||
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
import { afterEach, describe, it, expect, vi } from "vitest";
|
||||
import { cleanup, render, screen, fireEvent } from "@testing-library/react";
|
||||
import { DrillableCell } from "@/components/drill/DrillableCell";
|
||||
|
||||
// happy-dom keeps `document.body` between tests; without cleanup,
|
||||
// `screen.getByRole("button")` finds buttons from earlier renders.
|
||||
afterEach(() => cleanup());
|
||||
|
||||
describe("DrillableCell", () => {
|
||||
it("renders children, applies hover affordance classes, calls onClick", () => {
|
||||
const onClick = vi.fn();
|
||||
render(
|
||||
<DrillableCell onClick={onClick}>
|
||||
<span>CLM-114</span>
|
||||
</DrillableCell>,
|
||||
);
|
||||
const btn = screen.getByRole("button") as HTMLButtonElement;
|
||||
expect(btn.classList.contains("drillable")).toBe(true);
|
||||
fireEvent.click(btn);
|
||||
expect(onClick).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("disabled state hides affordance and blocks click", () => {
|
||||
const onClick = vi.fn();
|
||||
render(
|
||||
<DrillableCell onClick={onClick} disabled>
|
||||
<span>unavailable</span>
|
||||
</DrillableCell>,
|
||||
);
|
||||
const btn = screen.getByRole("button") as HTMLButtonElement;
|
||||
expect(btn.disabled).toBe(true);
|
||||
expect(btn.classList.contains("drillable")).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
onClick: () => void;
|
||||
disabled?: boolean;
|
||||
/** Optional aria-label; defaults to the visible text content. */
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap any clickable cell with hover-reveal affordance:
|
||||
* cursor: pointer + accent background tint + trailing "›" chevron,
|
||||
* applied via the `drillable` class on hover (see `src/index.css`
|
||||
* in Task 1.4).
|
||||
*
|
||||
* Renders as a <button> (disabled when `disabled`) so it gets keyboard
|
||||
* activation (Enter/Space) and the standard disabled-button semantics.
|
||||
* The `drillable` affordance class is omitted when disabled.
|
||||
*/
|
||||
export function DrillableCell({ children, onClick, disabled, ariaLabel }: Props) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
className={cn(
|
||||
!disabled && "drillable",
|
||||
"inline-flex items-center gap-0 rounded-sm border-0 bg-transparent p-0 text-left",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
||||
disabled && "text-muted-foreground cursor-not-allowed",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user