import type { ILogger } from "./logging/log";
import type { SizeClass } from "./util/sizing-utils";
import type { WidgetPromptJSON } from "./widget-ai-utils/prompt-types";
import type { KeypadAPI } from "@khanacademy/math-input";
import type { Hint, PerseusAnswerArea, PerseusFeatureFlags, PerseusWidget, PerseusWidgetsMap, AnalyticsEventHandlerFn, Version, LabelImageMarkerPublicData, PerseusLabelImageMarker, ShowSolutions } from "@khanacademy/perseus-core";
import type { LinterContextProps } from "@khanacademy/perseus-linter";
import type { Result } from "@khanacademy/wonder-blocks-data";
import type $ from "jquery";
import type * as React from "react";
export type FocusPath = ReadonlyArray<string> | null | undefined;
export type Dimensions = {
    width?: number;
    height?: number;
};
export type DeviceType = "phone" | "tablet" | "desktop";
/**
 * This is the type returned by a widget's `getSerializedState` function. However,
 * note that in most cases the widgets do _not_ implement these functions.
 * In that case, the `Renderer` just returns the widget's render props as the
 * serialized state.
 */
/**
 * @deprecated and likely a very broken API
 * [LEMS-3185] do not trust serializedState
 */
export type SerializedState = Record<string, any>;
/**
 * The Widget type represents the common API that the Renderer uses to interact
 * with all widgets. All widgets must implement the methods in this API, unless
 * they are marked as optional (?: ...).
 *
 * These methods are called on the widget ref and allow the renderer to
 * communicate with the individual widgets to coordinate actions such as
 * scoring, state serialization/deserialization, and focus management.
 */
export interface Widget {
    /**
     * don't use isWidget; it's just a dummy property to help TypeScript's weak
     * typing to recognize non-interactive widgets as Widgets
     * @deprecated
     */
    isWidget?: true;
    focus?: () => {
        id: string;
        path: FocusPath;
    } | boolean;
    getDOMNodeForPath?: (path: FocusPath) => Element | Text | null;
    /**
     * If the widget does not implement this function,
     * the renderer simply returns all of the widget's props.
     */
    /**
     * @deprecated - do not use in new code.
     */
    getSerializedState?: () => SerializedState;
    blurInputPath?: (path: FocusPath) => void;
    focusInputPath?: (path: FocusPath) => void;
    getInputPaths?: () => ReadonlyArray<FocusPath>;
    getPromptJSON?: () => WidgetPromptJSON;
}
export type ImageDict = {
    [url: string]: Dimensions;
};
export type EditorMode = "edit" | "preview" | "json";
export type ChoiceState = {
    selected: boolean;
};
/**
 * TODO(LEMS-3245) remove ChangeHandler
 *
 * @deprecated
 */
export type ChangeHandler = (arg1: {
    hints?: ReadonlyArray<Hint>;
    replace?: boolean;
    content?: string;
    widgets?: PerseusWidgetsMap;
    images?: ImageDict;
    question?: any;
    answerArea?: PerseusAnswerArea | null;
    editorMode?: EditorMode;
    jsonMode?: boolean;
    choiceStates?: ReadonlyArray<ChoiceState>;
    divisionRange?: number[];
    markers?: Array<LabelImageMarkerPublicData | PerseusLabelImageMarker>;
}, callback?: () => void, silent?: boolean) => unknown;
export type ImageUploader = (file: File, callback: (url: string) => unknown) => unknown;
export type Path = ReadonlyArray<string>;
type TrackInteractionArgs = {
    type: string;
    id: string;
    correct?: boolean;
} & Partial<TrackingGradedGroupExtraArguments> & Partial<TrackingSequenceExtraArguments>;
type GenerateUrlContext = "image_loader:image_url" | "python_program:program_url" | "video:video_url";
export type GenerateUrlArgs = {
    url: string;
    context: GenerateUrlContext;
    kaLocale?: string;
};
/**
 * APIOptions provides different ways to customize the behaviour of Perseus.
 *
 * @see {@link APIOptionsWithDefaults}
 */
export type APIOptions = Readonly<{
    isArticle?: boolean;
    onFocusChange?: (newFocusPath: FocusPath, oldFocusPath: FocusPath, keypadHeight?: number, focusedElement?: HTMLElement) => unknown;
    showAlignmentOptions?: boolean;
    /**
     * A boolean that indicates whether the associated problem has been
     * answered correctly and should no longer be interactive.
     */
    readOnly?: boolean;
    /**
     * A boolean that indicates whether the editor interface should be
     * disabled, preventing content creators from making changes.
     */
    editingDisabled?: boolean;
    answerableCallback?: (arg1: boolean) => unknown;
    getAnotherHint?: () => unknown;
    interactionCallback?: (widgetData: {
        [widgetId: string]: any;
    }) => void;
    /**
     * If imagePlaceholder is set, Perseus will render the placeholder instead
     * of the image node.
     */
    imagePlaceholder?: React.ReactNode;
    /**
     * If widgetPlaceholder is set, Perseus will render the placeholder instead
     * of the widget node.
     */
    widgetPlaceholder?: React.ReactNode;
    /**
     * Base React elements that can be used in place of the standard DOM
     * DOM elements. For example, when provided, <Link /> will be used
     * in place of <a />. This allows clients to provide pre-styled
     * components or components with custom behavior.
     */
    baseElements?: {
        /**
         * The <Link /> component provided here must adhere to the same
         * interface as React's base <a /> component.
         */
        Link: React.ComponentType<any>;
    };
    /**
     * Function that takes dimensions and returns a React component
     * to display while an image is loading.
     */
    imagePreloader?: (dimensions: Dimensions) => React.ReactNode;
    /**
     * A function that is called when the user has interacted with a widget. It
     * also includes any extra parameters that the originating widget provided.
     * This is used for keeping track of widget interactions.
     */
    trackInteraction?: (args: TrackInteractionArgs) => void;
    /**
     * A boolean that indicates whether or not a custom keypad is
     * being used.  For mobile web this will be the ProvidedKeypad
     * component.  In this situation we use the MathInput component
     * from the math-input repo instead of the existing perseus math
     * input components.
     */
    customKeypad?: boolean;
    /**
     * If this is provided, it is called instead of appending an instance
     * of `math-input`'s keypad to the body. This is used by the native
     * apps so they can have the keypad be defined on the native side.
     * It is called with an function that, when called, blurs the input,
     * and is expected to return an object of the shape
     * keypadElementPropType from math-input/src/prop-types.js.
     */
    nativeKeypadProxy?: (blur: () => void) => KeypadAPI;
    /** Indicates whether or not to use mobile styling. */
    isMobile?: boolean;
    /** Indicates whether or not to use mobile app styling. */
    isMobileApp?: boolean;
    /** A function, called with a bool indicating whether use of the
     * drawing area (scratchpad) should be allowed/disallowed.
     *
     * Previously handled by `Khan.scratchpad.enable/disable`
     * @deprecated setDrawingAreaAvailable is not used in frontend code.
     */
    setDrawingAreaAvailable?: (arg1: boolean) => unknown;
    /** The color used for the hint progress indicator (eg. 1 / 3) */
    hintProgressColor?: string;
    /**
     * Whether this Renderer is allowed to auto-scroll the rest of the
     * page. For example, if this is enabled, the most recently used
     * radio widget will attempt to keep the "selected" answer in view
     * after entering review mode.
     *
     * Defaults to `false`.
     * @deprecated canScrollPage has no effect.
     */
    canScrollPage?: boolean;
    /**
     * The value in milliseconds by which the local state of content
     * in a editor is delayed before propagated to a prop. For example,
     * when text is typed in the text area of an Editor component,
     * there will be a delay equal to the value of `editorChangeDelay`
     * before the change is propagated. This is added for better
     * responsiveness of the editor when used in certain contexts such
     * as StructuredItem exercises where constant re-rendering for each
     * keystroke caused text typed in the text area to appear in it
     * only after a good few seconds.
     * @deprecated editorChangeDelay has no effect.
     */
    editorChangeDelay?: number;
    /**
     * Feature flags that can be passed from consuming application.
     * Define the feature flag name in packages/perseus-core/src/feature-flags.ts
     */
    flags?: Record<(typeof PerseusFeatureFlags)[number], boolean>;
}>;
type TeXProps = {
    children: string;
    onClick?: () => unknown;
    onRender?: (root?: any) => unknown;
    style?: any;
};
export type DomInsertCheckFn = (text: string, node: HTMLElement, attribute?: string, jiptString?: string) => string | false;
type JIPT = {
    useJIPT: boolean;
};
/**
 * A label element returned by graphie.label().
 * This is a JQuery element with custom methods attached for positioning
 * and rendering text/math content.
 */
export type GraphieLabelElement = ReturnType<typeof $<HTMLElement>> & {
    setPosition: (point: [number, number]) => void;
    processMath: (math: string, force: boolean) => void;
    processText: (text: string) => void;
};
export type JiptLabelStore = {
    addLabel: (label?: GraphieLabelElement, useMath?: boolean) => void;
};
export interface JiptRenderer {
    replaceJiptContent: (content: string, paragraphIndex: number) => void;
}
type JiptTranslationComponents = {
    addComponent: (renderer: JiptRenderer) => number;
    removeComponentAtIndex: (index: number) => void;
};
export type VideoData = {
    __typename: "Video";
    id: string;
    title: string | null | undefined;
    /**
     * Unique identifier on YouTube.
     * If this is a dubbed video, this is always the original English version on
     * YouTube. If the localized version is needed, use translatedYoutubeId.
     * Example: KL6sMOn7ULo
     */
    youtubeId: string | null | undefined;
    contentId: string | null | undefined;
};
interface StaticUrlFn {
    (maybeRelativeUrl: string): string;
    (maybeRelativeUrl?: undefined | null | undefined): undefined | null | undefined;
}
type InitialRequestUrlInterface = {
    origin: string;
    host: string;
    protocol: string;
};
export type VideoKind = "YOUTUBE_ID" | "READABLE_ID";
/**
 * An object for dependency injection, to allow different clients
 * to provide different methods for logging, translation, network
 * requests, etc.
 *
 * NOTE: You should avoid adding new dependencies here as this type was added
 * as a quick fix to get around the fact that some of the dependencies Perseus
 * needs are used in places where neither `APIOptions` nor a React Context
 * could be used. Aim to shrink the footprint of PerseusDependencies and try to
 * use alternative methods where possible.
 */
export type PerseusDependencies = {
    JIPT: JIPT;
    graphieMovablesJiptLabels: JiptLabelStore;
    svgImageJiptLabels: JiptLabelStore;
    rendererTranslationComponents: JiptTranslationComponents;
    TeX: React.ComponentType<TeXProps>;
    /**
     * @deprecated Use `PerseusDependenciesV2.generateUrl` instead.
     */
    staticUrl: StaticUrlFn;
    InitialRequestUrl: InitialRequestUrlInterface;
    Log: ILogger;
    isDevServer: boolean;
    kaLocale: string;
};
/**
 * The modern iteration of Perseus Depedndencies. These dependencies are
 * provided to Perseus through its entrypoints (for example:
 * ServerItemRenderer) and then attached to the DependenciesContext so they are
 * available anywhere down the React render tree.
 *
 * Prefer using this type over `PerseusDependencies` when possible.
 */
export interface PerseusDependenciesV2 {
    analytics: {
        onAnalyticsEvent: AnalyticsEventHandlerFn;
    };
    /**
     * A function that takes a URL or partial url and may modify it to return
     * the full URL. This may be used to request a resource from a different
     * app to where the widget is rendered, like when embedding a video
     * cross-domain.
     */
    generateUrl: (args: GenerateUrlArgs) => string;
    useVideo(id: string, kind: VideoKind): Result<{
        video: VideoData | null | undefined;
    }>;
}
/**
 * APIOptionsWithDefaults represents the type that is provided to all widgets.
 * The Renderer fills in these defaults when providing APIOptions to any
 * widget.
 */
export type APIOptionsWithDefaults = Readonly<APIOptions & {
    baseElements: NonNullable<APIOptions["baseElements"]>;
    canScrollPage: NonNullable<APIOptions["canScrollPage"]>;
    editorChangeDelay: NonNullable<APIOptions["editorChangeDelay"]>;
    isArticle: NonNullable<APIOptions["isArticle"]>;
    isMobile: NonNullable<APIOptions["isMobile"]>;
    isMobileApp: NonNullable<APIOptions["isMobileApp"]>;
    editingDisabled: NonNullable<APIOptions["editingDisabled"]>;
    onFocusChange: NonNullable<APIOptions["onFocusChange"]>;
    readOnly: NonNullable<APIOptions["readOnly"]>;
    setDrawingAreaAvailable: NonNullable<APIOptions["setDrawingAreaAvailable"]>;
    showAlignmentOptions: NonNullable<APIOptions["showAlignmentOptions"]>;
}>;
export type Tracking = "" | "all";
export type TrackingGradedGroupExtraArguments = {
    status: "correct" | "incorrect" | "invalid";
};
type TrackingSequenceExtraArguments = {
    visible: number;
};
type WidgetOptions = any;
export type WidgetExports<T extends React.ComponentType<any> & Widget = React.ComponentType<any>, TUserInput = Empty> = Readonly<{
    name: string;
    displayName: string;
    getWidget?: () => T;
    widget: T;
    /** Supresses widget from showing up in the dropdown in the content editor */
    hidden?: boolean;
    /**
     * The widget version. Any time the _major_ version changes, the widget
     * should provide a new entry in the widget parser to migrate from the
     * older version to the current (new) version. Minor version changes must
     * be backwards compatible with previous minor versions widget options.
     *
     * This key defaults to `{major: 0, minor: 0}` if not provided.
     */
    version?: Version;
    isLintable?: boolean;
    tracking?: Tracking;
    /** When true, the widget editor shows a "Graded" toggle. */
    supportsUngraded?: boolean;
    getOneCorrectAnswerFromRubric?: (rubric: WidgetOptions) => string | null | undefined;
    /**
     * @deprecated - do not use in new code.
     */
    getUserInputFromSerializedState?: (serializedState: unknown, widgetOptions?: WidgetOptions) => TUserInput;
    getCorrectUserInput?: (widgetOptions: WidgetOptions) => TUserInput;
    getStartUserInput?: (widgetOptions: WidgetOptions, problemNum: number) => TUserInput;
}>;
export type FindWidgetsFunction = (filterFunc: FilterCriterion) => ReadonlyArray<Widget | null | undefined>;
export type FilterCriterion = string | ((id: string, widgetInfo: PerseusWidget, widget?: Widget | null | undefined) => boolean);
/**
 * The full set of props provided to all widgets when they are rendered. The
 * `TWidgetOptions` generic argument are the widget-specific props that originate
 * from the PerseusItem.
 */
export type WidgetProps<TWidgetOptions, TUserInput = Empty, TrackingExtraArgs = Empty> = TWidgetOptions & UniversalWidgetProps<TUserInput, TrackingExtraArgs>;
/**
 * The props passed to every widget, regardless of its `type`.
 */
type UniversalWidgetProps<TUserInput = Empty, TrackingExtraArgs = Empty> = {
    trackInteraction: (extraData?: TrackingExtraArgs) => void;
    widgetId: string;
    widgetIndex: number;
    alignment: string | null | undefined;
    static: boolean | null | undefined;
    graded?: boolean | null;
    problemNum: number | null | undefined;
    apiOptions: APIOptionsWithDefaults;
    keypadElement?: any;
    onFocus: (blurPath: FocusPath) => void;
    onBlur: (blurPath: FocusPath) => void;
    findWidgets: FindWidgetsFunction;
    reviewMode: boolean;
    showSolutions?: ShowSolutions;
    handleUserInput: (newUserInput: TUserInput, cb?: () => void, silent?: boolean) => void;
    userInput: TUserInput;
    linterContext: LinterContextProps;
    containerSizeClass: SizeClass;
};
export type ChangeFn = (newPropsOrSinglePropName: string | {
    [key: string]: any;
}, propValue?: any, callback?: () => unknown) => any;
export type SharedRendererProps = {
    apiOptions: APIOptions;
    linterContext: LinterContextProps;
};
export interface Focusable {
    focus: () => void;
    blur: () => void;
}
export {};
