import * as React from "react"; import { PerseusI18nContext } from "./components/i18n-context"; import InteractionTracker from "./interaction-tracker"; import TranslationLinter from "./translation-linter"; import WidgetContainer from "./widget-container"; import type { DependenciesContext } from "./dependencies"; import type { PerseusStrings } from "./strings"; import type { APIOptions, APIOptionsWithDefaults, FilterCriterion, FocusPath, Widget, WidgetProps } from "./types"; import type { HandleUserInputCallback, InitializeUserInputCallback } from "./user-input-manager"; import type { GetPromptJSONInterface, RendererPromptJSON } from "./widget-ai-utils/prompt-types"; import type { KeypadAPI } from "@khanacademy/math-input"; import type { PerseusRenderer, PerseusWidget, PerseusWidgetOptions, PerseusWidgetsMap, ShowSolutions, PerseusScore, UserInputMap } from "@khanacademy/perseus-core"; import type { LinterContextProps } from "@khanacademy/perseus-linter"; import "./styles/perseus-renderer.css"; type WidgetState = { isMobile?: boolean; inTable?: boolean; key?: number; paragraphIndex?: number; foundFullWidth?: boolean; baseElements?: any; }; type Props = Partial> & { userInput?: UserInputMap; handleUserInput?: HandleUserInputCallback; initializeUserInput?: InitializeUserInputCallback; apiOptions?: APIOptions; alwaysUpdate?: boolean; findExternalWidgets: any; images: PerseusRenderer["images"]; keypadElement?: KeypadAPI | null; onRender: (node?: any) => void; problemNum?: number; reviewMode?: boolean | null | undefined; highlightEmptyWidgets?: boolean; /** * If set to "all", all rationales or solutions will be shown. If set to * "selected", soltions will only be shown for selected choices. If set to * "none", solutions will not be shown-- equivalent to `undefined`. */ showSolutions?: ShowSolutions; content: PerseusRenderer["content"]; /** * If linterContext.highlightLint is true, then content will be passed to * the linter and any warnings will be highlighted in the rendered output. */ linterContext: LinterContextProps; legacyPerseusLint?: ReadonlyArray; widgets: PerseusRenderer["widgets"]; /** * Skip adding paragraph class */ inline?: boolean; strings: PerseusStrings; }; type State = { translationLintErrors: ReadonlyArray; widgetInfo: Readonly; jiptContent: any; }; type DefaultProps = Required>; /** * We want to be able to reset the question state when we go * from one question to another question. However it's kind of tricky: * 1. Content could be the same * 2. Problem number could be the same * 3. We don't want to reset when going from answerless to answerful data * So compare the prev props to the next props, but use * answerless for both for the comparison */ export type DifferentQuestionPartialProps = Pick; export declare function isDifferentQuestion(propsA: DifferentQuestionPartialProps, propsB: DifferentQuestionPartialProps): boolean; declare class Renderer extends React.Component implements GetPromptJSONInterface { static contextType: React.Context; context: React.ContextType; _currentFocus: FocusPath | null | undefined; _foundTextNodes: boolean; _interactionTrackers: { [id: string]: InteractionTracker; }; _isMounted: boolean; _isTwoColumn: boolean; _translationLinter: TranslationLinter; _widgetContainers: Map; translationIndex: number; widgetIds: Array; static defaultProps: DefaultProps; constructor(props: Props); componentDidMount(): void; UNSAFE_componentWillReceiveProps(nextProps: Props): void; shouldComponentUpdate(nextProps: Props, nextState: State): any | boolean; componentDidUpdate(prevProps: Props, prevState: State): void; componentWillUnmount(): void; getApiOptions: () => APIOptionsWithDefaults; _getInitialWidgetState: (props: Props) => { widgetInfo: State["widgetInfo"]; }; _getDefaultWidgetInfo: (widgetId: string) => any; _getWidgetInfo: (widgetId: string) => PerseusWidget; _isAnswerable(): boolean; renderWidget: (impliedType: string, id: string, state: WidgetState) => null | React.ReactNode; _getWidgetIndexById(id: string): number; getWidgetProps(widgetId: string): WidgetProps; /** * Serializes the questions state so it can be recovered. * * If an instance of widgetProps is passed in, it generates the serialized * state from that instead of the current widget props. */ /** * @deprecated - do not use in new code. */ getSerializedState(): Record; /** * Allows inter-widget communication. * * This function yields this Renderer's own internal widgets, and it's used * in two places. * * First, we expose our own internal widgets to each other by giving them * a `findWidgets` function that, in turn, calls this function. * * Second, we expose our own internal widgets to this Renderer's parent, * by allowing it to call this function directly. That way, it can hook us * up to other Renderers on the page, by writing a `findExternalWidgets` * prop that calls each other Renderer's `findInternalWidgets` function. * * Takes a `filterCriterion` on which widgets to return. * `filterCriterion` can be one of: * * A string widget id * * A string widget type * * a function from (id, widgetInfo, widgetComponent) to true or false * * Returns an array of the matching widget components. * * If you need to do logic with more than the components, it is possible * to do such logic inside the filter, rather than on the result array. * * "Remember: abilities are not inherently good or evil, it's how you use * them." ~ Kyle Katarn * Please use this one with caution. */ findInternalWidgets: (filterCriterion: FilterCriterion) => ReadonlyArray; /** * Allows inter-widget communication. * * Includes both widgets internal to this Renderer, and external widgets * exposed by the `findExternalWidgets` prop. * * See `findInteralWidgets` for more information. */ findWidgets: (filterCriterion: FilterCriterion) => any; getWidgetInstance: (id: string) => Widget | null | undefined; _onWidgetFocus: (id: string, focusPath?: ReadonlyArray) => void; _onWidgetBlur: (id: string, blurPath: FocusPath) => void; getContent: (props: Props, state: State) => any; shouldRenderJiptPlaceholder: (props: Props, state: State) => boolean; replaceJiptContent: (content: string, paragraphIndex: number) => void; outputMarkdown: (ast: any, state: WidgetState) => React.ReactElement; outputNested: (ast: any, state: WidgetState) => React.ReactElement; outputNode: (node: any, nestedOutput: any, state: WidgetState) => any | null | React.ReactElement> | React.ReactElement> | React.ReactNode; handleRender: (prevProps: Props) => void; _setCurrentFocus: (path: FocusPath) => void; focus: () => boolean | null | undefined; getDOMNodeForPath: (path: FocusPath) => Element | Text | null | undefined; getInputPaths: () => ReadonlyArray; focusPath: (path: FocusPath) => void; blurPath: (path: FocusPath) => void; blur: () => void; /** * Serializes widget state. Seems to be used only by editors though. * * @deprecated and likely a very broken API * [LEMS-3185] do not trust serializedState */ serialize: () => Record; /** * Returns an array of widget ids that are empty (meaning widgets where the * learner has not interacted with the widget yet or has not filled in all * fields). For example, the `interactive-graph` widget is considered * empty if the graph is in the starting state. */ emptyWidgets(): ReadonlyArray; /** * Returns an object of the widget `.getUserInput()` results */ getUserInputMap(): UserInputMap; /** * Returns an array of all widget IDs in the order they occur in * the content. */ getWidgetIds: () => ReadonlyArray; /** * Returns a JSON representation of the content and widgets * that can be passed to an LLM for prompt context. */ getPromptJSON(): RendererPromptJSON; /** * Scores the content. * * @deprecated use scorePerseusItem */ score(): PerseusScore; handletranslationLintErrors: (lintErrors: ReadonlyArray) => void; render(): React.ReactNode; } export default Renderer;