/** * `ScrollRegion` — a horizontally scrollable container that becomes a keyboard * target ONLY while it actually overflows. * * A pane that scrolls must be reachable without a pointer (WCAG 2.1.1), which * needs `tabIndex`, `role="region"` and a name. Applying those unconditionally * would litter every screen with phantom landmarks and dead tab stops for tables * that happen to fit, so the attributes are driven by a live measurement: * `scrollWidth > clientWidth`, re-taken whenever the container or its content * resizes and whenever the content is replaced. * * `useOverflowRegion` is the same measurement for a component that IS its own * scrolling box (a `
`, a JSON pane) and therefore cannot be wrapped in a
 * `
` without gaining a second scroller. `useProseScrollRegions` applies the * rules to the surfaces React never renders — the tables and code blocks inside * `dangerouslySetInnerHTML` (rendered README/markdown), which cannot be wrapped * in a component and are therefore instrumented imperatively. * * Both hooks hand back a CALLBACK REF for the element they measure, rather than * reading one the caller holds: a ref object tells a hook nothing about WHEN it * is filled, so a hook that read one would never instrument an element that * mounts later than the hook (a README that arrives with the second render) and * would never notice one being swapped for another. */ import type { CSSProperties, ReactNode, Ref, RefCallback } from 'react'; import { type OverflowAxis } from './overflow-measure'; export type { OverflowAxis } from './overflow-measure'; export interface ScrollRegionProps { /** The region's accessible name, applied only while it actually scrolls. */ readonly label: string; readonly children: ReactNode; readonly className?: string; readonly style?: CSSProperties; /** * The dimension overflow is measured on. `horizontal` (the default) fits a pane * that scrolls sideways; `vertical` fits a bounded, capped-height box that scrolls * down. The caller styles the box's own overflow to match. */ readonly axis?: OverflowAxis; /** * The one arbitrary attribute this component forwards. The measured attributes * — `tabindex`, `role` and `aria-label` — are the component's own and appear * and disappear with the overflow, so a general attribute spread would let a * caller set them statically and defeat the measurement. A test hook cannot, * which is why it is the exception rather than the first of a set. */ readonly 'data-testid'?: string; /** A consumer ref for the scrolling `div` itself. */ readonly ref?: Ref; } /** The fallback name per instrumented surface, when no heading precedes it. */ export interface ProseScrollLabels { readonly table?: string; readonly pre?: string; } /** The attribute set a scrolling box wears; every value is absent while it fits. */ export interface OverflowRegionAttributes { /** Attach to the scrolling element; it is what the measurement follows. */ readonly ref: RefCallback; readonly tabIndex?: 0; readonly role?: 'region'; readonly 'aria-label'?: string; } /** * The conditional region attributes for a scrolling box, alongside the ref that * names it. The ref must go on the scrolling box ITSELF — a `
`, a JSON
 * pane, or the `div` `ScrollRegion` renders. Use the hook when wrapping the
 * content in a `ScrollRegion` would give the surface a second scroller.
 *
 * The box is measured as it is attached, whenever it or any child resizes, and
 * whenever its content changes — replaced, appended, or edited in place. A
 * replaced child is a NEW element, so the registration is re-pointed at the
 * current children before each measurement, adding and dropping only the ones
 * that actually changed; both sides of that are registrations on the shared
 * observers, not observers of this mount's own. The only DOM change a
 * measurement can cause is the region ATTRIBUTES this hook returns, and
 * attributes are deliberately left unobserved — that, not an absence of
 * mutation, is what stops the pair from re-triggering each other.
 *
 * @param ref - a consumer ref that wants the same element, or `undefined`.
 * @param label - its accessible name, applied only while it actually scrolls.
 * @param axis - the dimension to measure overflow on (`horizontal` by default;
 *   `vertical` for a bounded, capped-height box that scrolls down).
 */
export declare function useOverflowRegion(ref: Ref | undefined, label: string, axis?: OverflowAxis): OverflowRegionAttributes;
export declare function ScrollRegion({ label, children, className, style, axis, 'data-testid': testId, ref, }: ScrollRegionProps): import("react").JSX.Element;
/**
 * Instruments the scrollable surfaces under the element the returned ref is
 * attached to — every `` and every `
` — as scroll regions. React
 * cannot wrap markup it did not create, so this walks the DOM instead. A table
 * is moved into a `div.tai-scroll-region` (once — the pass is idempotent)
 * because the table itself is not the scrolling box; a `
` already IS its
 * own scrolling box, so it is instrumented in place. Either way the scrolling
 * element carries the same conditional `tabindex`/`role`/`aria-label` as
 * `ScrollRegion`.
 *
 * The name is the nearest heading preceding the surface — read for all of them
 * in one document-order pass — so a reader landing on the region hears which
 * section it belongs to; `labels` covers a surface with no heading above it, and
 * a name shared by several surfaces is numbered so no two regions answer to the
 * same one.
 *
 * The pass runs from the ref callback rather than an effect, which puts it in
 * the commit phase, BEFORE the browser paints: `.tai-prose table` is
 * `width: 100%` with no overflow of its own — the scroller exists only on the
 * wrapper this builds — so a pass that ran after paint would show one frame at
 * 320/360 px with the table overflowing the document, then jolt sideways. A
 * passive-effect probe measured exactly that: at first paint wrappers=0 and the
 * table's parent was `.tai-prose`.
 *
 * Injected HTML is replaced wholesale when its source changes, so the pass is
 * re-run from a `MutationObserver` on the subtree rather than on attachment
 * alone.
 *
 * @param labels - the names for surfaces with no preceding heading.
 * @returns the ref for the element whose subtree holds the injected markup.
 */
export declare function useProseScrollRegions(labels?: ProseScrollLabels): RefCallback;
//# sourceMappingURL=scroll-region.d.ts.map