/** * Direct image labeling widget. * * Label on image widget enables creating more natural, conceptual questions * that involve the use of images, and enable learners to demonstrate their * knowledge by directly interacting with the image. */ import * as React from "react"; import { PerseusI18nContext } from "../../components/i18n-context"; import Marker from "./marker"; import type { DependencyProps } from "../../dependencies"; import type { Widget, WidgetProps } from "../../types"; import type { LabelImagePromptJSON } from "../../widget-ai-utils/label-image/label-image-ai-utils"; import type { InteractiveMarkerType, PerseusLabelImageWidgetOptions, PerseusLabelImageUserInput, LabelImagePublicWidgetOptions, ShowSolutions, PerseusLabelImageUserInputMarker } from "@khanacademy/perseus-core"; type PreferredPopoverDirection = "NONE" | "UP" | "DOWN" | "LEFT" | "RIGHT"; /** * Represents a direction vector. * No diagonals allowed. */ type Direction = { x: 0; y: 1 | -1; } | { x: 1 | -1; y: 0; } | { x: 0; y: 0; }; type Point = { x: number; y: number; }; export type OptionalAnswersMarkerType = Omit & { answers?: string[]; }; type Options = Omit & { markers: ReadonlyArray; }; type Props = WidgetProps & { analytics: DependencyProps["analytics"]; preferredPopoverDirection?: PreferredPopoverDirection; }; type LabelImageState = { activeMarkerIndex: number; markersInteracted: boolean; hideAnswers: boolean; }; /** * Get user input marker with the appropriate selection state for current display mode. * When showing solutions, it auto-selects correct answers, or clears * selections for markers without answers. * * @param marker - The widget options marker (possibly with answer). * @param userInputMarker - The user input marker (with user selection). * @returns A modified version of user input, possibly with correct answer. */ export declare function getComputedSelectedState(marker: OptionalAnswersMarkerType, userInputMarker: PerseusLabelImageUserInputMarker, reviewMode: boolean, showSolutions?: ShowSolutions): PerseusLabelImageUserInputMarker; export declare class LabelImage extends React.Component implements Widget { static contextType: React.Context; context: React.ContextType; _markers: Array; _mounted: boolean; /** * Test whether point is contained within triangle. * * Implementation taken from: https://stackoverflow.com/a/2049593 */ static pointInTriangle(p: Point, a: Point, b: Point, c: Point): boolean; /** * Determine the image side given a marker position (as percent of size). */ static imageSideForMarkerPosition(x: number, y: number, preferredDirection: PreferredPopoverDirection | undefined): "bottom" | "left" | "right" | "top" | "center"; /** * Calculate the next marker to navigate to, from the "this marker". * * Given a cardinal navigation direction (in the x or y axis), return the * next marker index to visit. */ static navigateToMarkerIndex(navigateDirection: Direction, markers: ReadonlyArray<{ x: number; y: number; showCorrectness?: "correct" | "incorrect"; }>, thisIndex: number): number; constructor(props: Props); componentDidMount(): void; componentWillUnmount(): void; getPromptJSON(): LabelImagePromptJSON; handleMarkerChange(index: number, marker: PerseusLabelImageUserInput["markers"][number]): void; activateMarker(index: number, opened: boolean): void; handleMarkerKeyDown(index: number, e: React.KeyboardEvent): void; handleAnswerChoicesChangeForMarker(index: number, selection: ReadonlyArray): void; renderMarkers(): ReadonlyArray; renderInstructions(): React.ReactNode; /** * @deprecated and likely very broken API * [LEMS-3185] do not trust serializedState */ getSerializedState(): any; render(): React.ReactNode; } declare function getStartUserInput(options: LabelImagePublicWidgetOptions): PerseusLabelImageUserInput; /** * @deprecated and likely a very broken API * [LEMS-3185] do not trust serializedState */ declare function getUserInputFromSerializedState(serializedState: any): PerseusLabelImageUserInput; declare function getCorrectUserInput(options: PerseusLabelImageWidgetOptions): PerseusLabelImageUserInput; declare const _default: { name: string; displayName: string; widget: React.ForwardRefExoticComponent & { markers: ReadonlyArray; } & { trackInteraction: (extraData?: Empty | undefined) => void; widgetId: string; widgetIndex: number; alignment: string | null | undefined; static: boolean | null | undefined; problemNum: number | null | undefined; apiOptions: Readonly unknown; showAlignmentOptions?: boolean; readOnly?: boolean; editingDisabled?: boolean; answerableCallback?: (arg1: boolean) => unknown; getAnotherHint?: () => unknown; interactionCallback?: (widgetData: { [widgetId: string]: any; }) => void; imagePlaceholder?: React.ReactNode; widgetPlaceholder?: React.ReactNode; baseElements?: { Link: React.ComponentType; }; imagePreloader?: (dimensions: import("../../types").Dimensions) => React.ReactNode; trackInteraction?: (args: { type: string; id: string; correct?: boolean; } & Partial & Partial<{ visible: number; }>) => void; customKeypad?: boolean; nativeKeypadProxy?: (blur: () => void) => import("@khanacademy/math-input").KeypadAPI; isMobile?: boolean; isMobileApp?: boolean; setDrawingAreaAvailable?: (arg1: boolean) => unknown; hintProgressColor?: string; canScrollPage?: boolean; editorChangeDelay?: number; flags?: Record<"new-radio-widget" | "image-widget-upgrade-gif-controls" | "image-widget-upgrade-scale", boolean>; }> & { baseElements: NonNullable; canScrollPage: NonNullable; editorChangeDelay: NonNullable; isArticle: NonNullable; isMobile: NonNullable; isMobileApp: NonNullable; editingDisabled: NonNullable; onFocusChange: NonNullable; readOnly: NonNullable; setDrawingAreaAvailable: NonNullable; showAlignmentOptions: NonNullable; }>; keypadElement?: any; questionCompleted?: boolean; onFocus: (blurPath: import("../..").FocusPath) => void; onBlur: (blurPath: import("../..").FocusPath) => void; findWidgets: (criterion: import("../../types").FilterCriterion) => ReadonlyArray; reviewMode: boolean; showSolutions?: ShowSolutions; handleUserInput: (newUserInput: PerseusLabelImageUserInput, cb?: () => void, silent?: boolean) => void; userInput: PerseusLabelImageUserInput; linterContext: import("@khanacademy/perseus-linter").LinterContextProps; containerSizeClass: import("../../util/sizing-utils").SizeClass; } & { analytics: DependencyProps["analytics"]; preferredPopoverDirection?: PreferredPopoverDirection; }, keyof import("../..").PerseusDependenciesV2> & React.RefAttributes>; isLintable: true; getStartUserInput: typeof getStartUserInput; getCorrectUserInput: typeof getCorrectUserInput; getUserInputFromSerializedState: typeof getUserInputFromSerializedState; }; export default _default;