/**
 * useUIElement Hook for React Native
 *
 * Register a native element with UI Bridge for control and observation.
 */
import type { NativeElementType, NativeStandardAction, NativeCustomAction, NativeElementState, NativeElementIdentifier, RegisteredNativeElement, NativeElementRef } from '../core/types';
type AnyHandler = (...args: any[]) => any;
/**
 * A press handler for `button`/`pressable` types. Matches the loose RN
 * `Pressable` `onPress` shape (no required argument), so consumers can pass
 * either a no-arg callback or one that consumes the gesture event.
 */
export type PressHandler = (event?: unknown) => void;
/**
 * Element types that require a press handler at registration. The TS
 * signature on `useUIElement` rejects these types unless `handlers.onPress`
 * is provided in options.
 *
 * Picked from the action-executor in `control/action-executor.ts` — the
 * `press` action looks up `props.onPress` (or `onPressIn` /
 * `onResponderRelease`); registering a button without one is a guaranteed
 * dead-button per the 2026-05-20 manual-test session.
 */
export type PressNeedingNativeElementType = 'button' | 'pressable';
/**
 * Base options for `useUIElement`. The discriminated union below layers
 * `handlers` requirements on top of this — see {@link UseUIElementOptions}.
 */
export interface UseUIElementOptionsBase<T extends NativeElementType = NativeElementType> {
    /** Unique identifier for the element */
    id: string;
    /** Element type (defaults to 'custom') */
    type?: T;
    /** Human-readable label */
    label?: string;
    /** Override available actions */
    actions?: NativeStandardAction[];
    /** Custom actions */
    customActions?: Record<string, NativeCustomAction>;
    /**
     * Current controlled value for text inputs. When provided, it is threaded
     * into the registered element's `state.value` so a `GET /control/element/:id`
     * (or `/state`) reflects what the user sees — without this, the input
     * registers with `value: undefined` and a bridge read returns null even
     * though the field is populated. Pass the same value you bind to the RN
     * `<TextInput value={...} />` prop; the hook keeps the registry in sync as
     * it changes.
     */
    value?: string;
    /** Whether to automatically register on mount */
    autoRegister?: boolean;
    /** Callback when state changes */
    onStateChange?: (state: NativeElementState) => void;
    /** Parent component path for tree path generation */
    parentPath?: string;
    /** RN style prop — will be flattened for design review */
    style?: unknown;
    /** State-specific style overrides for design review (pressed, focused, disabled) */
    stateStyles?: {
        pressed?: unknown;
        focused?: unknown;
        disabled?: unknown;
    };
}
/**
 * Options shape for press-needing types — `handlers.onPress` is REQUIRED.
 * Registering a `button`/`pressable` without an `onPress` produces a
 * "No press handler found on element" error when the bridge fires
 * `POST /control/element/:id/action {"action":"press"}`. Phase 1 of plan
 * `2026-05-20-manual-test-remediation` makes that a compile-time error.
 *
 * Consumers that wire `onPress` lazily (e.g. computed from props during
 * render) should use {@link useUIElementWithProps} + `captureProps({ onPress })`
 * instead. The runtime guard in this hook also warns once per id when
 * `onPress` never reaches the registry.
 */
export interface UseUIElementOptionsHandlersRequired<T extends PressNeedingNativeElementType = PressNeedingNativeElementType> extends UseUIElementOptionsBase<T> {
    /**
     * Handler props to auto-register with the bridge for action execution.
     * For `button`/`pressable`, `onPress` is required — UI Bridge invokes it
     * when a `press` action is dispatched.
     *
     * @example
     * ```tsx
     * const { ref, onLayout, bridgeProps } = useUIElement({
     *   id: 'my-button',
     *   type: 'pressable',
     *   handlers: { onPress: handlePress },
     * });
     * ```
     */
    handlers: {
        /** Required — UI Bridge invokes this on `press`/`click` actions. */
        onPress: PressHandler;
        /** Additional handlers (`onLongPress`, `onPressIn`, etc.) */
        [key: string]: AnyHandler | undefined;
    };
}
/**
 * Options shape for non-press-needing types — `handlers` is optional.
 * Applies to `input`, `text`, `view`, `list`, etc. — anything where a
 * missing `onPress` doesn't indicate a dead button.
 */
export interface UseUIElementOptionsHandlersOptional<T extends NativeElementType = NativeElementType> extends UseUIElementOptionsBase<T> {
    /**
     * Handler props to auto-register with the bridge for action execution.
     * Optional for non-press-needing types.
     */
    handlers?: Record<string, AnyHandler | undefined>;
}
/**
 * useUIElement options — discriminated union over element type.
 *
 * For `type: 'button' | 'pressable'`, `handlers.onPress` is required.
 * For all other types, `handlers` is optional.
 */
export type UseUIElementOptions<T extends NativeElementType = NativeElementType> = T extends PressNeedingNativeElementType ? UseUIElementOptionsHandlersRequired<T> : UseUIElementOptionsHandlersOptional<T>;
/**
 * Bridge props to spread onto the component
 */
export interface UIBridgeProps {
    /** Test ID for automation */
    testID: string;
    /** Accessibility label */
    accessibilityLabel?: string;
}
/**
 * useUIElement return value
 */
export interface UseUIElementReturn {
    /** Ref to attach to the element */
    ref: React.RefObject<NativeElementRef>;
    /** onLayout handler to spread onto the element - uses generic type for RN version compatibility */
    onLayout: (event: {
        nativeEvent: {
            layout: {
                x: number;
                y: number;
                width: number;
                height: number;
            };
        };
    }) => void;
    /** Props to spread onto the element for identification */
    bridgeProps: UIBridgeProps;
    /** Whether the element is registered */
    registered: boolean;
    /** Get current state */
    getState: () => NativeElementState | null;
    /** Get element identifier */
    getIdentifier: () => NativeElementIdentifier | null;
    /** Trigger an action on this element */
    trigger: (action: NativeStandardAction | string, params?: Record<string, unknown>) => Promise<void>;
    /** Manually register the element */
    register: () => void;
    /** Manually unregister the element */
    unregister: () => void;
    /** The registered element info */
    registeredElement: RegisteredNativeElement | null;
    /** Update style for design review (flattens and stores in registry) */
    updateStyle: (style: unknown, stateStyles?: {
        pressed?: unknown;
        focused?: unknown;
        disabled?: unknown;
    }) => void;
    /**
     * Re-publish the element's label (and the mirrored `accessibilityLabel` /
     * `testId` so spec-check and a11y stay in sync). Idempotent — no-op when
     * the new label equals the current registered value.
     *
     * Labels passed via `useUIElement({ id, label })` are captured ONCE at
     * registration; if the source state changes (e.g. a tab's active suffix,
     * or a list's "N events" count), the registry would otherwise hold the
     * mount-time label forever. Call `updateLabel(...)` from a `useEffect`
     * (or directly from a handler) to keep the registry in sync.
     *
     * @example
     * ```tsx
     * const label = `${events.length} events`;
     * const { updateLabel } = useUIElement({ id: 'events-list', label, type: 'list' });
     * useEffect(() => { updateLabel(label); }, [label, updateLabel]);
     * ```
     */
    updateLabel: (newLabel: string) => void;
}
export declare function useUIElement<T extends NativeElementType = NativeElementType>(options: UseUIElementOptions<T>): UseUIElementReturn;
/**
 * useUIElementWithProps hook
 *
 * Extended version that also captures component props for action execution.
 * Useful when you need the bridge to be able to call onPress, onChangeText, etc.
 *
 * @example
 * ```tsx
 * function TextInputField({ onChangeText, value }) {
 *   const { ref, onLayout, bridgeProps, captureProps } = useUIElementWithProps({
 *     id: 'email-input',
 *     type: 'input',
 *   });
 *
 *   // Capture props so bridge can call onChangeText
 *   captureProps({ onChangeText, value });
 *
 *   return (
 *     <TextInput
 *       ref={ref}
 *       onLayout={onLayout}
 *       {...bridgeProps}
 *       value={value}
 *       onChangeText={onChangeText}
 *     />
 *   );
 * }
 * ```
 */
export interface UseUIElementWithPropsReturn extends UseUIElementReturn {
    /** Capture props for action execution */
    captureProps: (props: Record<string, unknown>) => void;
}
/**
 * Loose options for `useUIElementWithProps` — `handlers` is optional for ALL
 * element types because the consumer will later call `captureProps({ onPress,
 * ... })` from the render body. The runtime warning in {@link useUIElement}
 * still backstops the "captured but never called with onPress" case.
 */
export type UseUIElementWithPropsOptions<T extends NativeElementType = NativeElementType> = UseUIElementOptionsHandlersOptional<T>;
export declare function useUIElementWithProps<T extends NativeElementType = NativeElementType>(options: UseUIElementWithPropsOptions<T>): UseUIElementWithPropsReturn;
export {};
//# sourceMappingURL=useUIElement.d.ts.map