@khanacademy/perseus 78.1.0 → 78.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/components/button-group.d.ts +4 -0
  2. package/dist/components/gif-image.d.ts +2 -1
  3. package/dist/components/svg-image.d.ts +2 -0
  4. package/dist/es/index.css +1 -1
  5. package/dist/es/index.css.map +1 -1
  6. package/dist/es/index.js +43 -29
  7. package/dist/es/index.js.map +1 -1
  8. package/dist/es/strings.js +1 -1
  9. package/dist/es/strings.js.map +1 -1
  10. package/dist/index.css +1 -1
  11. package/dist/index.css.map +1 -1
  12. package/dist/index.js +43 -29
  13. package/dist/index.js.map +1 -1
  14. package/dist/perseus-markdown.new.d.ts +11 -0
  15. package/dist/renderer.d.ts +15 -202
  16. package/dist/renderer.new.d.ts +200 -0
  17. package/dist/renderer.old.d.ts +211 -0
  18. package/dist/server-item-renderer.d.ts +1 -1
  19. package/dist/strings.d.ts +136 -12
  20. package/dist/strings.js +1 -1
  21. package/dist/strings.js.map +1 -1
  22. package/dist/testing/feature-flags-util.d.ts +7 -12
  23. package/dist/testing/item-renderer-hooks.d.ts +1 -1
  24. package/dist/widgets/dropdown/dropdown.d.ts +1 -1
  25. package/dist/widgets/expression/expression.d.ts +2 -2
  26. package/dist/widgets/image/components/image-info-area.d.ts +3 -1
  27. package/dist/widgets/image/utils.d.ts +7 -0
  28. package/dist/widgets/interactive-graphs/graphs/components/movable-point-labels-layer/index.d.ts +1 -0
  29. package/dist/widgets/interactive-graphs/graphs/components/movable-point-labels-layer/movable-point-labels-layer.d.ts +7 -0
  30. package/dist/widgets/interactive-graphs/interactive-graph.d.ts +1 -1
  31. package/dist/widgets/interactive-graphs/label-stroke-filter.d.ts +15 -0
  32. package/dist/widgets/interactive-graphs/mafs-graph.d.ts +2 -0
  33. package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +2 -0
  34. package/dist/widgets/interactive-graphs/types.d.ts +2 -0
  35. package/dist/widgets/interactive-graphs/use-reinitialize-on-graph-change.d.ts +8 -0
  36. package/dist/widgets/interactive-graphs/utils/movable-point-labels.d.ts +10 -0
  37. package/dist/widgets/label-image/label-image.d.ts +1 -1
  38. package/dist/widgets/mock-widgets/mock-widget.d.ts +1 -1
  39. package/dist/widgets/numeric-input/numeric-input.class.d.ts +1 -1
  40. package/dist/widgets/numeric-input/numeric-input.d.ts +2 -2
  41. package/dist/widgets/table/table.d.ts +1 -1
  42. package/package.json +8 -8
  43. /package/dist/widgets/interactive-graphs/{point-labels.d.ts → utils/point-labels/point-labels.d.ts} +0 -0
@@ -0,0 +1,11 @@
1
+ declare const _default: {
2
+ characterCount: (source: string) => number;
3
+ traverseContent: (ast: any, cb: (node: any) => void) => void;
4
+ parse: (source: string, state: any) => any;
5
+ parseInline: (source: string, state: any) => any;
6
+ reactFor: (arg1: import("@khanacademy/simple-markdown").ReactNodeOutput) => import("@khanacademy/simple-markdown").ReactOutput;
7
+ ruleOutput: any;
8
+ basicOutput: any;
9
+ sanitizeUrl: (url?: string | null | undefined) => string | null | undefined;
10
+ };
11
+ export default _default;
@@ -1,206 +1,19 @@
1
1
  import * as React from "react";
2
- import { PerseusI18nContext } from "./components/i18n-context";
3
- import InteractionTracker from "./interaction-tracker";
4
- import TranslationLinter from "./translation-linter";
5
- import WidgetContainer from "./widget-container";
6
- import type { DependenciesContext } from "./dependencies";
7
- import type { PerseusStrings } from "./strings";
8
- import type { APIOptions, APIOptionsWithDefaults, FilterCriterion, FindWidgetsFunction, FocusPath, Widget, WidgetProps } from "./types";
9
- import type { HandleUserInputCallback, InitializeUserInputCallback } from "./user-input-manager";
10
- import type { GetPromptJSONInterface, RendererPromptJSON } from "./widget-ai-utils/prompt-types";
11
- import type { KeypadAPI } from "@khanacademy/math-input";
12
- import type { PerseusRenderer, PerseusWidget, PerseusWidgetOptions, PerseusWidgetsMap, ShowSolutions, PerseusScore, UserInputMap } from "@khanacademy/perseus-core";
13
- import type { LinterContextProps } from "@khanacademy/perseus-linter";
14
- import "./styles/perseus-renderer.css";
15
- type WidgetState = {
16
- isMobile?: boolean;
17
- inTable?: boolean;
18
- key?: number;
19
- paragraphIndex?: number;
20
- foundFullWidth?: boolean;
21
- baseElements?: any;
22
- };
23
- type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
24
- content: PerseusRenderer["content"];
25
- widgets: PerseusRenderer["widgets"];
26
- images: PerseusRenderer["images"];
27
- apiOptions?: APIOptions;
28
- userInput?: UserInputMap;
29
- handleUserInput?: HandleUserInputCallback;
30
- initializeUserInput?: InitializeUserInputCallback;
31
- alwaysUpdate?: boolean;
32
- findExternalWidgets: FindWidgetsFunction;
33
- keypadElement?: KeypadAPI | null;
34
- onRender: (node?: any) => void;
35
- problemNum?: number;
36
- reviewMode?: boolean | null | undefined;
37
- /**
38
- * If set to "all", all rationales or solutions will be shown. If set to
39
- * "selected", soltions will only be shown for selected choices. If set to
40
- * "none", solutions will not be shown-- equivalent to `undefined`.
41
- */
42
- showSolutions?: ShowSolutions;
43
- /**
44
- * If linterContext.highlightLint is true, then content will be passed to
45
- * the linter and any warnings will be highlighted in the rendered output.
46
- */
47
- linterContext: LinterContextProps;
48
- legacyPerseusLint?: ReadonlyArray<string>;
49
- /**
50
- * Skip adding paragraph class
51
- */
52
- inline?: boolean;
53
- strings: PerseusStrings;
54
- };
55
- type State = {
56
- translationLintErrors: ReadonlyArray<string>;
57
- widgetInfo: Readonly<PerseusWidgetsMap>;
58
- jiptContent: any;
59
- };
60
- type DefaultProps = Required<Pick<Props, "alwaysUpdate" | "content" | "findExternalWidgets" | "images" | "linterContext" | "onRender" | "showSolutions" | "reviewMode" | "widgets">>;
2
+ import RendererNew from "./renderer.new";
3
+ import RendererOld from "./renderer.old";
4
+ import type { Props as InternalProps } from "./renderer.old";
5
+ export { isDifferentQuestion } from "./renderer.old";
6
+ export type { DifferentQuestionPartialProps } from "./renderer.old";
61
7
  /**
62
- * We want to be able to reset the question state when we go
63
- * from one question to another question. However it's kind of tricky:
64
- * 1. Content could be the same
65
- * 2. Problem number could be the same
66
- * 3. We don't want to reset when going from answerless to answerful data
67
- * So compare the prev props to the next props, but use
68
- * answerless for both for the comparison
8
+ * Props that the underlying class renderers supply via `defaultProps`, so
9
+ * callers are allowed to omit them.
10
+ *
11
+ * The old/new renderers are class components and relied on React's
12
+ * `defaultProps` to make these optional at the JSX call site. `forwardRef`
13
+ * does not carry `defaultProps` through its type, so we have to express that
14
+ * optionality explicitly here to preserve the public API.
69
15
  */
70
- export type DifferentQuestionPartialProps = Pick<Props, "content" | "widgets" | "problemNum">;
71
- export declare function isDifferentQuestion(propsA: DifferentQuestionPartialProps, propsB: DifferentQuestionPartialProps): boolean;
72
- declare class Renderer extends React.Component<Props, State> implements GetPromptJSONInterface {
73
- static contextType: React.Context<import("./components/i18n-context").I18nContextType>;
74
- context: React.ContextType<typeof PerseusI18nContext>;
75
- _currentFocus: FocusPath | null | undefined;
76
- _foundTextNodes: boolean;
77
- _interactionTrackers: {
78
- [id: string]: InteractionTracker<any>;
79
- };
80
- _isMounted: boolean;
81
- _isTwoColumn: boolean;
82
- _translationLinter: TranslationLinter;
83
- _widgetContainers: Map<string, WidgetContainer>;
84
- translationIndex: number;
85
- widgetIds: Array<string>;
86
- static defaultProps: DefaultProps;
87
- constructor(props: Props);
88
- componentDidMount(): void;
89
- UNSAFE_componentWillReceiveProps(nextProps: Props): void;
90
- shouldComponentUpdate(nextProps: Props, nextState: State): any | boolean;
91
- componentDidUpdate(prevProps: Props, prevState: State): void;
92
- componentWillUnmount(): void;
93
- getApiOptions: () => APIOptionsWithDefaults;
94
- _getInitialWidgetState: (props: Props) => {
95
- widgetInfo: State["widgetInfo"];
96
- };
97
- _getDefaultWidgetInfo: (widgetId: string) => any;
98
- _getWidgetInfo: (widgetId: string) => PerseusWidget;
99
- _isAnswerable(): boolean;
100
- renderWidget: (impliedType: string, id: string, state: WidgetState) => null | React.ReactNode;
101
- _getWidgetIndexById(id: string): number;
102
- getWidgetProps(widgetId: string): WidgetProps<any, any, PerseusWidgetOptions>;
103
- /**
104
- * Serializes the questions state so it can be recovered.
105
- *
106
- * If an instance of widgetProps is passed in, it generates the serialized
107
- * state from that instead of the current widget props.
108
- */
109
- /**
110
- * @deprecated - do not use in new code.
111
- */
112
- getSerializedState(): Record<string, any>;
113
- /**
114
- * Allows inter-widget communication.
115
- *
116
- * This function yields this Renderer's own internal widgets, and it's used
117
- * in two places.
118
- *
119
- * First, we expose our own internal widgets to each other by giving them
120
- * a `findWidgets` function that, in turn, calls this function.
121
- *
122
- * Second, we expose our own internal widgets to this Renderer's parent,
123
- * by allowing it to call this function directly. That way, it can hook us
124
- * up to other Renderers on the page, by writing a `findExternalWidgets`
125
- * prop that calls each other Renderer's `findInternalWidgets` function.
126
- *
127
- * Takes a `filterCriterion` on which widgets to return.
128
- * `filterCriterion` can be one of:
129
- * * A string widget id
130
- * * A string widget type
131
- * * a function from (id, widgetInfo, widgetComponent) to true or false
132
- *
133
- * Returns an array of the matching widget components.
134
- *
135
- * If you need to do logic with more than the components, it is possible
136
- * to do such logic inside the filter, rather than on the result array.
137
- *
138
- * "Remember: abilities are not inherently good or evil, it's how you use
139
- * them." ~ Kyle Katarn
140
- * Please use this one with caution.
141
- */
142
- findInternalWidgets: (filterCriterion: FilterCriterion) => ReadonlyArray<Widget | null | undefined>;
143
- /**
144
- * Allows inter-widget communication.
145
- *
146
- * Includes both widgets internal to this Renderer, and external widgets
147
- * exposed by the `findExternalWidgets` prop.
148
- *
149
- * See `findInternalWidgets` for more information.
150
- */
151
- findWidgets: (filterCriterion: FilterCriterion) => any;
152
- getWidgetInstance: (id: string) => Widget | null | undefined;
153
- _onWidgetFocus: (id: string, focusPath?: ReadonlyArray<string>) => void;
154
- _onWidgetBlur: (id: string, blurPath: FocusPath) => void;
155
- getContent: (props: Props, state: State) => any;
156
- shouldRenderJiptPlaceholder: (props: Props, state: State) => boolean;
157
- replaceJiptContent: (content: string, paragraphIndex: number) => void;
158
- outputMarkdown: (ast: any, state: WidgetState) => React.ReactElement;
159
- outputNested: (ast: any, state: WidgetState) => React.ReactElement;
160
- outputNode: (node: any, nestedOutput: any, state: WidgetState) => any | null | React.ReactElement<React.ComponentProps<"div">> | React.ReactElement<React.ComponentProps<"span">> | React.ReactNode;
161
- handleRender: (prevProps: Props) => void;
162
- _setCurrentFocus: (path: FocusPath) => void;
163
- focus: () => boolean | null | undefined;
164
- getDOMNodeForPath: (path: FocusPath) => Element | Text | null | undefined;
165
- getInputPaths: () => ReadonlyArray<FocusPath>;
166
- focusPath: (path: FocusPath) => void;
167
- blurPath: (path: FocusPath) => void;
168
- blur: () => void;
169
- /**
170
- * Serializes widget state. Seems to be used only by editors though.
171
- *
172
- * @deprecated and likely a very broken API
173
- * [LEMS-3185] do not trust serializedState
174
- */
175
- serialize: () => Record<any, any>;
176
- /**
177
- * Returns an array of widget ids that are empty (meaning widgets where the
178
- * learner has not interacted with the widget yet or has not filled in all
179
- * fields). For example, the `interactive-graph` widget is considered
180
- * empty if the graph is in the starting state.
181
- */
182
- emptyWidgets(): ReadonlyArray<string>;
183
- /**
184
- * Returns an object of the widget `.getUserInput()` results
185
- */
186
- getUserInputMap(): UserInputMap;
187
- /**
188
- * Returns an array of all widget IDs in the order they occur in
189
- * the content.
190
- */
191
- getWidgetIds: () => ReadonlyArray<string>;
192
- /**
193
- * Returns a JSON representation of the content and widgets
194
- * that can be passed to an LLM for prompt context.
195
- */
196
- getPromptJSON(): RendererPromptJSON;
197
- /**
198
- * Scores the content.
199
- *
200
- * @deprecated use scorePerseusItem
201
- */
202
- score(): PerseusScore;
203
- handletranslationLintErrors: (lintErrors: ReadonlyArray<string>) => void;
204
- render(): React.ReactNode;
205
- }
16
+ type DefaultedPropKeys = "content" | "widgets" | "images" | "findExternalWidgets" | "onRender" | "alwaysUpdate" | "reviewMode" | "showSolutions" | "linterContext";
17
+ type Renderer = InstanceType<typeof RendererNew> | InstanceType<typeof RendererOld>;
18
+ declare const Renderer: React.ForwardRefExoticComponent<Omit<InternalProps, DefaultedPropKeys> & Partial<Pick<InternalProps, DefaultedPropKeys>> & React.RefAttributes<Renderer>>;
206
19
  export default Renderer;
@@ -0,0 +1,200 @@
1
+ /***********************************************************************
2
+ * *
3
+ * WARNING!!!! THERE ARE ACTIVE CHANGES HAPPENING IN THE RENDERER! *
4
+ * *
5
+ ***********************************************************************/
6
+ import * as React from "react";
7
+ import { PerseusI18nContext } from "./components/i18n-context";
8
+ import InteractionTracker from "./interaction-tracker";
9
+ import TranslationLinter from "./translation-linter";
10
+ import WidgetContainer from "./widget-container";
11
+ import type { DependenciesContext } from "./dependencies";
12
+ import type { PerseusStrings } from "./strings";
13
+ import type { APIOptions, APIOptionsWithDefaults, FilterCriterion, FindWidgetsFunction, FocusPath, Widget, WidgetProps } from "./types";
14
+ import type { HandleUserInputCallback, InitializeUserInputCallback } from "./user-input-manager";
15
+ import type { GetPromptJSONInterface, RendererPromptJSON } from "./widget-ai-utils/prompt-types";
16
+ import type { KeypadAPI } from "@khanacademy/math-input";
17
+ import type { PerseusRenderer, PerseusWidget, PerseusWidgetOptions, PerseusWidgetsMap, ShowSolutions, PerseusScore, UserInputMap } from "@khanacademy/perseus-core";
18
+ import type { LinterContextProps } from "@khanacademy/perseus-linter";
19
+ import "./styles/perseus-renderer.new.css";
20
+ type WidgetState = {
21
+ isMobile?: boolean;
22
+ inTable?: boolean;
23
+ key?: number;
24
+ paragraphIndex?: number;
25
+ foundFullWidth?: boolean;
26
+ baseElements?: any;
27
+ };
28
+ type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
29
+ content: PerseusRenderer["content"];
30
+ widgets: PerseusRenderer["widgets"];
31
+ images: PerseusRenderer["images"];
32
+ apiOptions?: APIOptions;
33
+ userInput?: UserInputMap;
34
+ handleUserInput?: HandleUserInputCallback;
35
+ initializeUserInput?: InitializeUserInputCallback;
36
+ alwaysUpdate?: boolean;
37
+ findExternalWidgets: FindWidgetsFunction;
38
+ keypadElement?: KeypadAPI | null;
39
+ onRender: (node?: any) => void;
40
+ problemNum?: number;
41
+ reviewMode?: boolean | null | undefined;
42
+ /**
43
+ * If set to "all", all rationales or solutions will be shown. If set to
44
+ * "selected", soltions will only be shown for selected choices. If set to
45
+ * "none", solutions will not be shown-- equivalent to `undefined`.
46
+ */
47
+ showSolutions?: ShowSolutions;
48
+ /**
49
+ * If linterContext.highlightLint is true, then content will be passed to
50
+ * the linter and any warnings will be highlighted in the rendered output.
51
+ */
52
+ linterContext: LinterContextProps;
53
+ legacyPerseusLint?: ReadonlyArray<string>;
54
+ /**
55
+ * Skip adding paragraph class
56
+ */
57
+ inline?: boolean;
58
+ strings: PerseusStrings;
59
+ };
60
+ type State = {
61
+ translationLintErrors: ReadonlyArray<string>;
62
+ widgetInfo: Readonly<PerseusWidgetsMap>;
63
+ jiptContent: any;
64
+ };
65
+ type DefaultProps = Required<Pick<Props, "alwaysUpdate" | "content" | "findExternalWidgets" | "images" | "linterContext" | "onRender" | "showSolutions" | "reviewMode" | "widgets">>;
66
+ declare class Renderer extends React.Component<Props, State> implements GetPromptJSONInterface {
67
+ static contextType: React.Context<import("./components/i18n-context").I18nContextType>;
68
+ context: React.ContextType<typeof PerseusI18nContext>;
69
+ _currentFocus: FocusPath | null | undefined;
70
+ _foundTextNodes: boolean;
71
+ _interactionTrackers: {
72
+ [id: string]: InteractionTracker<any>;
73
+ };
74
+ _isMounted: boolean;
75
+ _isTwoColumn: boolean;
76
+ _translationLinter: TranslationLinter;
77
+ _widgetContainers: Map<string, WidgetContainer>;
78
+ translationIndex: number;
79
+ widgetIds: Array<string>;
80
+ static defaultProps: DefaultProps;
81
+ constructor(props: Props);
82
+ componentDidMount(): void;
83
+ UNSAFE_componentWillReceiveProps(nextProps: Props): void;
84
+ shouldComponentUpdate(nextProps: Props, nextState: State): any | boolean;
85
+ componentDidUpdate(prevProps: Props, prevState: State): void;
86
+ componentWillUnmount(): void;
87
+ getApiOptions: () => APIOptionsWithDefaults;
88
+ _getInitialWidgetState: (props: Props) => {
89
+ widgetInfo: State["widgetInfo"];
90
+ };
91
+ _getDefaultWidgetInfo: (widgetId: string) => any;
92
+ _getWidgetInfo: (widgetId: string) => PerseusWidget;
93
+ _isAnswerable(): boolean;
94
+ renderWidget: (impliedType: string, id: string, state: WidgetState) => null | React.ReactNode;
95
+ _getWidgetIndexById(id: string): number;
96
+ getWidgetProps(widgetId: string): WidgetProps<any, any, PerseusWidgetOptions>;
97
+ /**
98
+ * Serializes the questions state so it can be recovered.
99
+ *
100
+ * If an instance of widgetProps is passed in, it generates the serialized
101
+ * state from that instead of the current widget props.
102
+ */
103
+ /**
104
+ * @deprecated - do not use in new code.
105
+ */
106
+ getSerializedState(): Record<string, any>;
107
+ /**
108
+ * Allows inter-widget communication.
109
+ *
110
+ * This function yields this Renderer's own internal widgets, and it's used
111
+ * in two places.
112
+ *
113
+ * First, we expose our own internal widgets to each other by giving them
114
+ * a `findWidgets` function that, in turn, calls this function.
115
+ *
116
+ * Second, we expose our own internal widgets to this Renderer's parent,
117
+ * by allowing it to call this function directly. That way, it can hook us
118
+ * up to other Renderers on the page, by writing a `findExternalWidgets`
119
+ * prop that calls each other Renderer's `findInternalWidgets` function.
120
+ *
121
+ * Takes a `filterCriterion` on which widgets to return.
122
+ * `filterCriterion` can be one of:
123
+ * * A string widget id
124
+ * * A string widget type
125
+ * * a function from (id, widgetInfo, widgetComponent) to true or false
126
+ *
127
+ * Returns an array of the matching widget components.
128
+ *
129
+ * If you need to do logic with more than the components, it is possible
130
+ * to do such logic inside the filter, rather than on the result array.
131
+ *
132
+ * "Remember: abilities are not inherently good or evil, it's how you use
133
+ * them." ~ Kyle Katarn
134
+ * Please use this one with caution.
135
+ */
136
+ findInternalWidgets: (filterCriterion: FilterCriterion) => ReadonlyArray<Widget | null | undefined>;
137
+ /**
138
+ * Allows inter-widget communication.
139
+ *
140
+ * Includes both widgets internal to this Renderer, and external widgets
141
+ * exposed by the `findExternalWidgets` prop.
142
+ *
143
+ * See `findInternalWidgets` for more information.
144
+ */
145
+ findWidgets: (filterCriterion: FilterCriterion) => any;
146
+ getWidgetInstance: (id: string) => Widget | null | undefined;
147
+ _onWidgetFocus: (id: string, focusPath?: ReadonlyArray<string>) => void;
148
+ _onWidgetBlur: (id: string, blurPath: FocusPath) => void;
149
+ getContent: (props: Props, state: State) => any;
150
+ shouldRenderJiptPlaceholder: (props: Props, state: State) => boolean;
151
+ replaceJiptContent: (content: string, paragraphIndex: number) => void;
152
+ outputMarkdown: (ast: any, state: WidgetState) => React.ReactElement;
153
+ outputNested: (ast: any, state: WidgetState) => React.ReactElement;
154
+ outputNode: (node: any, nestedOutput: any, state: WidgetState) => any | null | React.ReactElement<React.ComponentProps<"div">> | React.ReactElement<React.ComponentProps<"span">> | React.ReactNode;
155
+ handleRender: (prevProps: Props) => void;
156
+ _setCurrentFocus: (path: FocusPath) => void;
157
+ focus: () => boolean | null | undefined;
158
+ getDOMNodeForPath: (path: FocusPath) => Element | Text | null | undefined;
159
+ getInputPaths: () => ReadonlyArray<FocusPath>;
160
+ focusPath: (path: FocusPath) => void;
161
+ blurPath: (path: FocusPath) => void;
162
+ blur: () => void;
163
+ /**
164
+ * Serializes widget state. Seems to be used only by editors though.
165
+ *
166
+ * @deprecated and likely a very broken API
167
+ * [LEMS-3185] do not trust serializedState
168
+ */
169
+ serialize: () => Record<any, any>;
170
+ /**
171
+ * Returns an array of widget ids that are empty (meaning widgets where the
172
+ * learner has not interacted with the widget yet or has not filled in all
173
+ * fields). For example, the `interactive-graph` widget is considered
174
+ * empty if the graph is in the starting state.
175
+ */
176
+ emptyWidgets(): ReadonlyArray<string>;
177
+ /**
178
+ * Returns an object of the widget `.getUserInput()` results
179
+ */
180
+ getUserInputMap(): UserInputMap;
181
+ /**
182
+ * Returns an array of all widget IDs in the order they occur in
183
+ * the content.
184
+ */
185
+ getWidgetIds: () => ReadonlyArray<string>;
186
+ /**
187
+ * Returns a JSON representation of the content and widgets
188
+ * that can be passed to an LLM for prompt context.
189
+ */
190
+ getPromptJSON(): RendererPromptJSON;
191
+ /**
192
+ * Scores the content.
193
+ *
194
+ * @deprecated use scorePerseusItem
195
+ */
196
+ score(): PerseusScore;
197
+ handletranslationLintErrors: (lintErrors: ReadonlyArray<string>) => void;
198
+ render(): React.ReactNode;
199
+ }
200
+ export default Renderer;
@@ -0,0 +1,211 @@
1
+ /***********************************************************************
2
+ * *
3
+ * WARNING!!!! THERE ARE ACTIVE CHANGES HAPPENING IN THE RENDERER! *
4
+ * *
5
+ ***********************************************************************/
6
+ import * as React from "react";
7
+ import { PerseusI18nContext } from "./components/i18n-context";
8
+ import InteractionTracker from "./interaction-tracker";
9
+ import TranslationLinter from "./translation-linter";
10
+ import WidgetContainer from "./widget-container";
11
+ import type { DependenciesContext } from "./dependencies";
12
+ import type { PerseusStrings } from "./strings";
13
+ import type { APIOptions, APIOptionsWithDefaults, FilterCriterion, FindWidgetsFunction, FocusPath, Widget, WidgetProps } from "./types";
14
+ import type { HandleUserInputCallback, InitializeUserInputCallback } from "./user-input-manager";
15
+ import type { GetPromptJSONInterface, RendererPromptJSON } from "./widget-ai-utils/prompt-types";
16
+ import type { KeypadAPI } from "@khanacademy/math-input";
17
+ import type { PerseusRenderer, PerseusWidget, PerseusWidgetOptions, PerseusWidgetsMap, ShowSolutions, PerseusScore, UserInputMap } from "@khanacademy/perseus-core";
18
+ import type { LinterContextProps } from "@khanacademy/perseus-linter";
19
+ import "./styles/perseus-renderer.css";
20
+ type WidgetState = {
21
+ isMobile?: boolean;
22
+ inTable?: boolean;
23
+ key?: number;
24
+ paragraphIndex?: number;
25
+ foundFullWidth?: boolean;
26
+ baseElements?: any;
27
+ };
28
+ export type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
29
+ content: PerseusRenderer["content"];
30
+ widgets: PerseusRenderer["widgets"];
31
+ images: PerseusRenderer["images"];
32
+ apiOptions?: APIOptions;
33
+ userInput?: UserInputMap;
34
+ handleUserInput?: HandleUserInputCallback;
35
+ initializeUserInput?: InitializeUserInputCallback;
36
+ alwaysUpdate?: boolean;
37
+ findExternalWidgets: FindWidgetsFunction;
38
+ keypadElement?: KeypadAPI | null;
39
+ onRender: (node?: any) => void;
40
+ problemNum?: number;
41
+ reviewMode?: boolean | null | undefined;
42
+ /**
43
+ * If set to "all", all rationales or solutions will be shown. If set to
44
+ * "selected", soltions will only be shown for selected choices. If set to
45
+ * "none", solutions will not be shown-- equivalent to `undefined`.
46
+ */
47
+ showSolutions?: ShowSolutions;
48
+ /**
49
+ * If linterContext.highlightLint is true, then content will be passed to
50
+ * the linter and any warnings will be highlighted in the rendered output.
51
+ */
52
+ linterContext: LinterContextProps;
53
+ legacyPerseusLint?: ReadonlyArray<string>;
54
+ /**
55
+ * Skip adding paragraph class
56
+ */
57
+ inline?: boolean;
58
+ strings: PerseusStrings;
59
+ };
60
+ type State = {
61
+ translationLintErrors: ReadonlyArray<string>;
62
+ widgetInfo: Readonly<PerseusWidgetsMap>;
63
+ jiptContent: any;
64
+ };
65
+ type DefaultProps = Required<Pick<Props, "alwaysUpdate" | "content" | "findExternalWidgets" | "images" | "linterContext" | "onRender" | "showSolutions" | "reviewMode" | "widgets">>;
66
+ /**
67
+ * We want to be able to reset the question state when we go
68
+ * from one question to another question. However it's kind of tricky:
69
+ * 1. Content could be the same
70
+ * 2. Problem number could be the same
71
+ * 3. We don't want to reset when going from answerless to answerful data
72
+ * So compare the prev props to the next props, but use
73
+ * answerless for both for the comparison
74
+ */
75
+ export type DifferentQuestionPartialProps = Pick<Props, "content" | "widgets" | "problemNum">;
76
+ export declare function isDifferentQuestion(propsA: DifferentQuestionPartialProps, propsB: DifferentQuestionPartialProps): boolean;
77
+ declare class Renderer extends React.Component<Props, State> implements GetPromptJSONInterface {
78
+ static contextType: React.Context<import("./components/i18n-context").I18nContextType>;
79
+ context: React.ContextType<typeof PerseusI18nContext>;
80
+ _currentFocus: FocusPath | null | undefined;
81
+ _foundTextNodes: boolean;
82
+ _interactionTrackers: {
83
+ [id: string]: InteractionTracker<any>;
84
+ };
85
+ _isMounted: boolean;
86
+ _isTwoColumn: boolean;
87
+ _translationLinter: TranslationLinter;
88
+ _widgetContainers: Map<string, WidgetContainer>;
89
+ translationIndex: number;
90
+ widgetIds: Array<string>;
91
+ static defaultProps: DefaultProps;
92
+ constructor(props: Props);
93
+ componentDidMount(): void;
94
+ UNSAFE_componentWillReceiveProps(nextProps: Props): void;
95
+ shouldComponentUpdate(nextProps: Props, nextState: State): any | boolean;
96
+ componentDidUpdate(prevProps: Props, prevState: State): void;
97
+ componentWillUnmount(): void;
98
+ getApiOptions: () => APIOptionsWithDefaults;
99
+ _getInitialWidgetState: (props: Props) => {
100
+ widgetInfo: State["widgetInfo"];
101
+ };
102
+ _getDefaultWidgetInfo: (widgetId: string) => any;
103
+ _getWidgetInfo: (widgetId: string) => PerseusWidget;
104
+ _isAnswerable(): boolean;
105
+ renderWidget: (impliedType: string, id: string, state: WidgetState) => null | React.ReactNode;
106
+ _getWidgetIndexById(id: string): number;
107
+ getWidgetProps(widgetId: string): WidgetProps<any, any, PerseusWidgetOptions>;
108
+ /**
109
+ * Serializes the questions state so it can be recovered.
110
+ *
111
+ * If an instance of widgetProps is passed in, it generates the serialized
112
+ * state from that instead of the current widget props.
113
+ */
114
+ /**
115
+ * @deprecated - do not use in new code.
116
+ */
117
+ getSerializedState(): Record<string, any>;
118
+ /**
119
+ * Allows inter-widget communication.
120
+ *
121
+ * This function yields this Renderer's own internal widgets, and it's used
122
+ * in two places.
123
+ *
124
+ * First, we expose our own internal widgets to each other by giving them
125
+ * a `findWidgets` function that, in turn, calls this function.
126
+ *
127
+ * Second, we expose our own internal widgets to this Renderer's parent,
128
+ * by allowing it to call this function directly. That way, it can hook us
129
+ * up to other Renderers on the page, by writing a `findExternalWidgets`
130
+ * prop that calls each other Renderer's `findInternalWidgets` function.
131
+ *
132
+ * Takes a `filterCriterion` on which widgets to return.
133
+ * `filterCriterion` can be one of:
134
+ * * A string widget id
135
+ * * A string widget type
136
+ * * a function from (id, widgetInfo, widgetComponent) to true or false
137
+ *
138
+ * Returns an array of the matching widget components.
139
+ *
140
+ * If you need to do logic with more than the components, it is possible
141
+ * to do such logic inside the filter, rather than on the result array.
142
+ *
143
+ * "Remember: abilities are not inherently good or evil, it's how you use
144
+ * them." ~ Kyle Katarn
145
+ * Please use this one with caution.
146
+ */
147
+ findInternalWidgets: (filterCriterion: FilterCriterion) => ReadonlyArray<Widget | null | undefined>;
148
+ /**
149
+ * Allows inter-widget communication.
150
+ *
151
+ * Includes both widgets internal to this Renderer, and external widgets
152
+ * exposed by the `findExternalWidgets` prop.
153
+ *
154
+ * See `findInternalWidgets` for more information.
155
+ */
156
+ findWidgets: (filterCriterion: FilterCriterion) => any;
157
+ getWidgetInstance: (id: string) => Widget | null | undefined;
158
+ _onWidgetFocus: (id: string, focusPath?: ReadonlyArray<string>) => void;
159
+ _onWidgetBlur: (id: string, blurPath: FocusPath) => void;
160
+ getContent: (props: Props, state: State) => any;
161
+ shouldRenderJiptPlaceholder: (props: Props, state: State) => boolean;
162
+ replaceJiptContent: (content: string, paragraphIndex: number) => void;
163
+ outputMarkdown: (ast: any, state: WidgetState) => React.ReactElement;
164
+ outputNested: (ast: any, state: WidgetState) => React.ReactElement;
165
+ outputNode: (node: any, nestedOutput: any, state: WidgetState) => any | null | React.ReactElement<React.ComponentProps<"div">> | React.ReactElement<React.ComponentProps<"span">> | React.ReactNode;
166
+ handleRender: (prevProps: Props) => void;
167
+ _setCurrentFocus: (path: FocusPath) => void;
168
+ focus: () => boolean | null | undefined;
169
+ getDOMNodeForPath: (path: FocusPath) => Element | Text | null | undefined;
170
+ getInputPaths: () => ReadonlyArray<FocusPath>;
171
+ focusPath: (path: FocusPath) => void;
172
+ blurPath: (path: FocusPath) => void;
173
+ blur: () => void;
174
+ /**
175
+ * Serializes widget state. Seems to be used only by editors though.
176
+ *
177
+ * @deprecated and likely a very broken API
178
+ * [LEMS-3185] do not trust serializedState
179
+ */
180
+ serialize: () => Record<any, any>;
181
+ /**
182
+ * Returns an array of widget ids that are empty (meaning widgets where the
183
+ * learner has not interacted with the widget yet or has not filled in all
184
+ * fields). For example, the `interactive-graph` widget is considered
185
+ * empty if the graph is in the starting state.
186
+ */
187
+ emptyWidgets(): ReadonlyArray<string>;
188
+ /**
189
+ * Returns an object of the widget `.getUserInput()` results
190
+ */
191
+ getUserInputMap(): UserInputMap;
192
+ /**
193
+ * Returns an array of all widget IDs in the order they occur in
194
+ * the content.
195
+ */
196
+ getWidgetIds: () => ReadonlyArray<string>;
197
+ /**
198
+ * Returns a JSON representation of the content and widgets
199
+ * that can be passed to an LLM for prompt context.
200
+ */
201
+ getPromptJSON(): RendererPromptJSON;
202
+ /**
203
+ * Scores the content.
204
+ *
205
+ * @deprecated use scorePerseusItem
206
+ */
207
+ score(): PerseusScore;
208
+ handletranslationLintErrors: (lintErrors: ReadonlyArray<string>) => void;
209
+ render(): React.ReactNode;
210
+ }
211
+ export default Renderer;
@@ -118,7 +118,7 @@ declare const _default: React.ForwardRefExoticComponent<Omit<Pick<SharedRenderer
118
118
  isMobile?: boolean;
119
119
  isMobileApp?: boolean;
120
120
  hintProgressColor?: string;
121
- flags?: Record<"input-number-to-numeric-input" | "grapher-to-interactive-graph", boolean>;
121
+ flags?: Record<"input-number-to-numeric-input" | "perseus-renderer-upgrade" | "grapher-to-interactive-graph" | "desmos-calculator" | "perseus-enable-point-label-field", boolean>;
122
122
  }> | undefined;
123
123
  linterContext?: PerseusLinter.LinterContextProps | undefined;
124
124
  onRendered?: ((isRendered: boolean) => void) | undefined;