import { PropertyValues } from 'lit'; import { SpectrumElement } from '../../element/index.js'; import { KeyboardActivation, TabDensity, TabsDirection } from './Tabs.types.js'; /** * Base class for a tabbed interface container. * * Manages selection state, tab/panel association, ARIA wiring, * keyboard navigation, and event dispatching. Concrete classes * supply the stylesheet, render template, and visual behaviors * such as the selection indicator. * * Public API follows the Spectrum 2 / Spectrum Design–aligned surface * from the tabs migration plan: `keyboard-activation` and `density` * instead of legacy `auto`, `compact`, `quiet`, `emphasized`, and * t-shirt `size` attributes. * * @slot - Tab items (elements with `role="tab"`) * @slot tab-panel - Tab panel content (elements with `role="tabpanel"`) * * @fires change - The selected tab has changed. Cancelable — * calling `preventDefault()` reverts the selection. */ export declare abstract class TabsBase extends SpectrumElement { /** * @internal * * Valid direction values for validation and CEM/stories. */ static readonly VALID_DIRECTIONS: readonly TabsDirection[]; /** * @internal */ static readonly VALID_KEYBOARD_ACTIVATIONS: readonly KeyboardActivation[]; /** * @internal */ static readonly VALID_DENSITIES: readonly TabDensity[]; /** * Whether selection follows keyboard focus (`automatic`, default) or the * user must press Enter or Space to activate (`manual`). Prefer `manual` * when tab panels are expensive to render or not fully present in the DOM. * * @see https://w3c.github.io/aria-practices/#kbd_selection_follows_focus */ get keyboardActivation(): KeyboardActivation; set keyboardActivation(value: string); /** @internal */ private _keyboardActivation; /** * Layout density: `regular` (default) or `compact` (reduced tab spacing). */ get density(): TabDensity; set density(value: string); /** @internal */ private _density; /** * The layout direction of the tab list. * * **Breaking change:** `'vertical-right'` is no longer supported. * Use `'vertical'` instead. * * @default 'horizontal' */ get direction(): TabsDirection; set direction(value: TabsDirection); /** @internal */ private _direction; /** * Whether the entire tab list is disabled. When `true`, * `aria-disabled="true"` is applied to the tablist element and * all interaction is suppressed. */ disabled: boolean; /** * Accessible label for the tablist. Rendered as `aria-label` on the * element with `role="tablist"` in the concrete template. */ accessibleLabel: string; /** * The `tab-id` of the currently selected tab. Setting this property * updates which tab appears selected and which panel is visible. */ selected: string; /** @internal */ private static readonly INDICATOR_BASE_SIZE; /** * @internal * * Inline style applied to the selection indicator element. * Computed from the selected tab's position and dimensions. */ protected selectionIndicatorStyle: string; /** * @internal * * Suppresses the transition on the very first indicator placement * so it doesn't animate from the origin. */ protected shouldAnimate: boolean; /** * @internal * * Cached list of tab elements managed by this container. Updated * via `handleTabSlotChange`. */ private _tabs; /** * Whether an assigned node is treated as a tab. `role="tab"` is set in * each tab's `firstUpdated`, so `slotchange` may run before that — accept * known tab host tag names so the tab list and selection indicator sync. */ private static isTabSlotNode; /** * Called by the concrete class when the default slot's content * changes. Rebuilds the internal tab list and syncs selection * state. */ protected handleTabSlotChange(event: Event): void; /** * Called by the concrete class when the `tab-panel` slot's content * changes. Wires up `aria-controls` / `aria-labelledby` between * each tab and its panel. */ protected handlePanelSlotChange(event: Event): void; /** * Click handler bound to the tablist wrapper in the concrete * template. Activates the clicked tab. */ protected handleClick(event: Event): void; /** * Full keyboard handler per WAI-ARIA APG Tabs pattern. * * **Horizontal:** Left/Right navigate; Up/Down ignored. * **Vertical:** Up/Down navigate; Left/Right ignored. * **RTL:** Left/Right swap in `dir="rtl"`. * **Wrapping:** Navigation wraps from last to first and vice versa. * **Disabled tabs:** Disabled tabs receive focus via arrows but * are not activatable by Enter/Space. * **Automatic activation:** When `keyboard-activation` is `automatic`, * selection follows focus on arrow key navigation. * **Home/End:** Jump to first/last tab. */ protected handleKeyDown(event: KeyboardEvent): void; /** * Maps a keyboard code to a navigation delta (+1 or -1) based * on orientation and text direction. Returns `null` when the key * does not apply to the current orientation. */ private getNavigationDelta; /** * Moves focus by `delta` positions from the currently focused tab, * wrapping around the list. All tabs (including disabled) receive * focus per APG. In automatic activation mode, the newly focused tab * is also selected. */ private focusByDelta; /** * Focuses the tab at the given index and, when in automatic * activation mode, also selects it. Selection runs before `focus()` * so `change` listeners observe the updated value before focus moves. */ private focusTabAtIndex; /** * Wraps an index into the valid range `[0, tabs.length)`. */ private wrapIndex; /** * Updates roving tabindex so only the given tab has * `tabindex="0"` and all others have `tabindex="-1"`. */ private setRovingTabindex; /** * Attempts to select the given tab element. Dispatches a cancelable * `change` event — if the consumer calls `preventDefault()`, the * selection reverts to the previous value. */ private selectTarget; /** * Synchronizes the `selected` attribute and roving tabindex on * each child tab to match the container's `selected` value. * Ensures at least one tab has `tabindex="0"` for Tab-key entry * when the container is not disabled. When the container is * disabled, all tabs get `tabindex="-1"` to prevent Tab-key * entry into the tab list. */ private updateCheckedState; /** * Wires up cross-element ARIA relationships between tabs and * panels. Each tab gets `aria-controls` pointing at its panel's * `id`, and each panel gets `aria-labelledby` pointing at its * tab's `id`. */ private managePanels; /** * @internal * * Recalculates the selection indicator's position and size based * on the currently selected tab element. Uses CSS transforms for * smooth animation between tab positions. * * The indicator is a fixed-size element (100px base) that gets * `scaleX`/`scaleY` to match the selected tab's width/height, * and `translateX`/`translateY` to match its offset position. */ protected updateSelectionIndicator: () => Promise; /** @internal */ private _resizeObserver?; /** * @internal * * Watches for `dir` attribute changes so the indicator recalculates * when writing direction flips at runtime. `getComputedStyle` in * `updateSelectionIndicator` resolves inherited direction correctly, * but nothing else observes it: a `dir` flip on the document root or * an ancestor doesn't resize this element, so the `ResizeObserver` * below won't catch it. Mirrors the `dir`-watching pattern in * `placement-controller.ts`. */ private _directionObserver?; protected willUpdate(changes: PropertyValues): void; connectedCallback(): void; disconnectedCallback(): void; /** * Focuses the selected tab, or the first tab when none is selected yet. * Slotted tabs live in the light DOM; this is more reliable than relying * only on shadow `delegatesFocus` across browsers and test harnesses. */ focus(options?: FocusOptions): void; protected firstUpdated(changes: PropertyValues): void; /** * Waits for all child tab elements to finish their update cycle * before resolving so layout-dependent callers see stable geometry. */ getUpdateComplete(): Promise; }