A button whose text is a title or a name is now `selectable` (FocusSafeButton, under Pressable and Button): Chrome selects inside a button once it is user-select: text (measured), and the click that ends a selection, or a press dragged past the slop, opens nothing. 23 surfaces carry it (cards, rows, people, channels, playlists, users, views, messages, log lines, description links); the Plex caption div gets the same guard. A contract test pins every plain Pressable with its reason, so a new one has to choose.
38 lines
1.6 KiB
TypeScript
38 lines
1.6 KiB
TypeScript
import { forwardRef } from "react";
|
|
import type { ButtonHTMLAttributes } from "react";
|
|
import clsx from "clsx";
|
|
import { FocusSafeButton } from "./FocusSafeButton";
|
|
|
|
// A click SURFACE: a button whose content is the control — a card, a list row, a poster tile, a menu
|
|
// row, a thumbnail that opens its video. It is not an action button (that is `Button`, with a label and
|
|
// a rung) and not a glyph (`IconButton`); it owns what every such surface needs and kept forgetting:
|
|
// `type="button"` (never a stray form submit), a left-aligned body, the focus-safe disabled state, and,
|
|
// on request, the B3 state layer for a row that has no hover of its own. `className` lays the surface
|
|
// out; its paint is the surface's own (a card's glass, a row's layer).
|
|
export const Pressable = forwardRef<
|
|
HTMLButtonElement,
|
|
ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
/** Paint the B3 hover/pressed layer (a plain row or menu item; a card has its own hover). */
|
|
layer?: boolean;
|
|
/** A tile with a caption under a picture reads centred; everything else left. */
|
|
align?: "left" | "center";
|
|
/** Working: unavailable and announced as busy. */
|
|
busy?: boolean;
|
|
/** Its text is a title or a name: it stays selectable (see FocusSafeButton). */
|
|
selectable?: boolean;
|
|
}
|
|
>(function Pressable({ type, layer = false, align = "left", className, ...rest }, ref) {
|
|
return (
|
|
<FocusSafeButton
|
|
ref={ref}
|
|
type={type ?? "button"}
|
|
className={clsx(
|
|
align === "center" ? "text-center" : "text-left",
|
|
layer && "state-layer",
|
|
className,
|
|
)}
|
|
{...rest}
|
|
/>
|
|
);
|
|
});
|