/** * `openTargetProps` — the ONE house pattern for a whole-row / whole-card "open" * affordance. * * A navigable list entry (a table ``, a card `
`) has a * single natural destination: opening it. The industry-standard affordance is to * make the WHOLE entry the click target — not only the name link buried in its * first cell — while never HIJACKING the interactive elements nested inside it * (the name link itself, an actions kebab, a Run button, an expandable preview). * This helper is that affordance, extracted once so every surface spreads the * same object rather than hand-rolling — and subtly diverging on — the yield * rules. * * The contract, spread onto the entry element: * - `cursor: pointer`, so the whole entry reads as activatable. * - a click handler that opens the entry, EXCEPT when the click * • landed on (or inside) a nested interactive element — a `button`, an * `a`, or an inline `[role="menu"]`/`[role="menuitem"]` — which owns its * own activation, or * • is the tail of a press-drag that SELECTED text (a non-collapsed * selection), which is a read gesture, not an open intent. * - with `keyboard`, `tabIndex: 0` and an Enter/Space handler under the same * yield rules, so the entry is operable without a pointer. * * Keyboard note: PREFER giving the entry a real nested interactive element (the * name `AppLink`) as its accessible activation path and leaving `keyboard` off — * the helper yields to that element, so it stays the one keyboard/AT target and * the whole-entry click is a pure pointer convenience layered over it. Reach for * `keyboard` only when the entry genuinely has no such nested control (a run row * of timestamps and badges), where the entry itself must become the focus stop. * * Dependency-free: it reads only the DOM `event.target`, `window.getSelection()`, * and returns plain React attributes — nothing to bundle, nothing to mock. */ import type { KeyboardEvent, MouseEvent } from 'react'; export interface OpenTargetOptions { /** Open the entry. `undefined` disables the affordance entirely — the helper * returns empty props so the element stays inert (no cursor, no handlers), * which lets a caller wire the whole thing behind an optional prop. */ readonly onOpen: (() => void) | undefined; /** Extra selector(s) that also count as "nested interactive" for THIS surface, * merged with the built-in set. Use it for a marked non-`button`/`a` subtree * that owns its own clicks (e.g. an expandable preview keyed by a data * attribute). Standard CSS selector syntax, comma-separated. */ readonly ignoreWithin?: string; /** Make the entry itself keyboard-operable: a `tabIndex: 0` focus stop with * Enter/Space activation. Leave off when a nested interactive element already * carries the accessible path (see the keyboard note above) — adding it there * would create a duplicate tab stop. */ readonly keyboard?: boolean; } /** The React attributes {@link openTargetProps} yields — spread onto the entry * element (``, card `
`). Every field is optional so the disabled case * is the empty object. */ export interface OpenTargetProps { readonly onClick?: (event: MouseEvent) => void; readonly onKeyDown?: (event: KeyboardEvent) => void; readonly tabIndex?: number; readonly style?: { readonly cursor: 'pointer'; }; } /** * Build the whole-target open props for one entry. See the module doc for the * contract; pass `onOpen: undefined` to get an inert entry (empty props). */ export declare function openTargetProps({ onOpen, ignoreWithin, keyboard, }: OpenTargetOptions): OpenTargetProps; //# sourceMappingURL=open-target.d.ts.map