@khanacademy/perseus 44.0.0 → 45.1.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.
@@ -5,9 +5,30 @@
5
5
  *
6
6
  * TODO(aria): Move this out of interactive2
7
7
  */
8
- declare const _default: {
9
- pluck: (table: any, subKey: string) => any;
10
- mapObject: <K extends string, V, U>(obj: Record<K, V>, lambda: (arg1: V, arg2: K) => U) => Record<K, U>;
11
- mapObjectFromArray: <K extends string, V>(arr: ReadonlyArray<K>, lambda: (arg1: K) => V) => Record<K, V>;
12
- };
13
- export default _default;
8
+ /**
9
+ * Does a pluck on keys inside objects in an object
10
+ *
11
+ * Ex:
12
+ * tools = {
13
+ * translation: {
14
+ * enabled: true
15
+ * },
16
+ * rotation: {
17
+ * enabled: false
18
+ * }
19
+ * };
20
+ * pluckObject(tools, "enabled") returns {
21
+ * translation: true
22
+ * rotation: false
23
+ * }
24
+ */
25
+ export declare const pluck: (table: any, subKey: string) => any;
26
+ /**
27
+ * Maps an object to an object
28
+ *
29
+ * > mapObject({a: '1', b: '2'}, (value, key) => {
30
+ * return value + 1;
31
+ * });
32
+ * {a: 2, b: 3}
33
+ */
34
+ export declare const mapObject: <K extends string, V, U>(obj: Record<K, V>, lambda: (arg1: V, arg2: K) => U) => Record<K, U>;
@@ -4,72 +4,99 @@ export type Range = Interval;
4
4
  export type Size = [number, number];
5
5
  export type CollinearTuple = [vec.Vector2, vec.Vector2];
6
6
  export type ShowSolutions = "all" | "selected" | "none";
7
+ /**
8
+ * Our core set of Perseus widgets.
9
+ *
10
+ * This interface is the basis for "registering" all Perseus widget types.
11
+ * There should be one key/value pair for each supported widget. If you create
12
+ * a new widget, an entry should be added to this interface. Note that this
13
+ * only registers the widget options type, you'll also need to register the
14
+ * widget so that it's available at runtime (@see
15
+ * {@link file://./widgets.ts#registerWidget}).
16
+ *
17
+ * Importantly, the key should be the name that is used in widget IDs. For most
18
+ * widgets that is the same as the widget option's `type` field. In cases where
19
+ * a widget has been deprecated and replaced with the deprecated-standin
20
+ * widget, it should be the original widget type!
21
+ *
22
+ * If you define the widget outside of this package, you can still add the new
23
+ * widget to this interface by writing the following in that package that
24
+ * contains the widget. TypeScript will merge that definition of the
25
+ * `PerseusWidgets` with the one defined below.
26
+ *
27
+ * ```typescript
28
+ * declare module "@khanacademy/perseus" {
29
+ * interface PerseusWidgetTypes {
30
+ * // A new widget
31
+ * "new-awesomeness": MyAwesomeNewWidget;
32
+ *
33
+ * // A deprecated widget
34
+ * "super-old-widget": AutoCorrectWidget;
35
+ * }
36
+ * }
37
+ *
38
+ * // The new widget's options definition
39
+ * type MyAwesomeNewWidget = WidgetOptions<'new-awesomeness', MyAwesomeNewWidgetOptions>;
40
+ *
41
+ * // The deprecated widget's options definition
42
+ * type SuperOldWidget = WidgetOptions<'super-old-widget', object>;
43
+ * ```
44
+ *
45
+ * This interface can be extended through the magic of TypeScript "Declaration
46
+ * merging". Specifically, we augment this module and extend this interface.
47
+ *
48
+ * @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
49
+ */
50
+ export interface PerseusWidgetTypes {
51
+ categorizer: CategorizerWidget;
52
+ "cs-program": CSProgramWidget;
53
+ definition: DefinitionWidget;
54
+ dropdown: DropdownWidget;
55
+ explanation: ExplanationWidget;
56
+ expression: ExpressionWidget;
57
+ grapher: GrapherWidget;
58
+ "graded-group-set": GradedGroupSetWidget;
59
+ "graded-group": GradedGroupWidget;
60
+ group: GroupWidget;
61
+ iframe: IFrameWidget;
62
+ image: ImageWidget;
63
+ "input-number": InputNumberWidget;
64
+ interaction: InteractionWidget;
65
+ "interactive-graph": InteractiveGraphWidget;
66
+ "label-image": LabelImageWidget;
67
+ matcher: MatcherWidget;
68
+ matrix: MatrixWidget;
69
+ measurer: MeasurerWidget;
70
+ "molecule-renderer": MoleculeRendererWidget;
71
+ "number-line": NumberLineWidget;
72
+ "numeric-input": NumericInputWidget;
73
+ orderer: OrdererWidget;
74
+ "passage-ref-target": RefTargetWidget;
75
+ "passage-ref": PassageRefWidget;
76
+ passage: PassageWidget;
77
+ "phet-simulation": PhetSimulationWidget;
78
+ "python-program": PythonProgramWidget;
79
+ plotter: PlotterWidget;
80
+ radio: RadioWidget;
81
+ sorter: SorterWidget;
82
+ table: TableWidget;
83
+ video: VideoWidget;
84
+ sequence: AutoCorrectWidget;
85
+ }
86
+ /**
87
+ * A map of widget IDs to widget options. This is most often used as the type
88
+ * for a set of widgets defined in a `PerseusItem` but can also be useful to
89
+ * represent a function parameter where only `widgets` from a `PerseusItem` are
90
+ * needed. Today Widget IDs are made up of the widget type and an incrementing
91
+ * integer (eg. `interactive-graph 1` or `radio 3`). It is suggested to avoid
92
+ * reading/parsing the widget id to derive any information from it, except in
93
+ * the case of this map.
94
+ *
95
+ * @see {@link PerseusWidgetTypes} additional widgets can be added to this map type
96
+ * by augmenting the PerseusWidgetTypes with new widget types!
97
+ */
7
98
  export type PerseusWidgetsMap = {
8
- [key in `categorizer ${number}`]: CategorizerWidget;
9
- } & {
10
- [key in `cs-program ${number}`]: CSProgramWidget;
11
- } & {
12
- [key in `definition ${number}`]: DefinitionWidget;
13
- } & {
14
- [key in `dropdown ${number}`]: DropdownWidget;
15
- } & {
16
- [key in `explanation ${number}`]: ExplanationWidget;
17
- } & {
18
- [key in `expression ${number}`]: ExpressionWidget;
19
- } & {
20
- [key in `grapher ${number}`]: GrapherWidget;
21
- } & {
22
- [key in `group ${number}`]: GroupWidget;
23
- } & {
24
- [key in `graded-group ${number}`]: GradedGroupWidget;
25
- } & {
26
- [key in `graded-group-set ${number}`]: GradedGroupSetWidget;
27
- } & {
28
- [key in `iframe ${number}`]: IFrameWidget;
29
- } & {
30
- [key in `image ${number}`]: ImageWidget;
31
- } & {
32
- [key in `input-number ${number}`]: InputNumberWidget;
33
- } & {
34
- [key in `interaction ${number}`]: InteractionWidget;
35
- } & {
36
- [key in `interactive-graph ${number}`]: InteractiveGraphWidget;
37
- } & {
38
- [key in `label-image ${number}`]: LabelImageWidget;
39
- } & {
40
- [key in `matcher ${number}`]: MatcherWidget;
41
- } & {
42
- [key in `matrix ${number}`]: MatrixWidget;
43
- } & {
44
- [key in `measurer ${number}`]: MeasurerWidget;
45
- } & {
46
- [key in `molecule-renderer ${number}`]: MoleculeRendererWidget;
47
- } & {
48
- [key in `number-line ${number}`]: NumberLineWidget;
49
- } & {
50
- [key in `numeric-input ${number}`]: NumericInputWidget;
51
- } & {
52
- [key in `orderer ${number}`]: OrdererWidget;
53
- } & {
54
- [key in `passage ${number}`]: PassageWidget;
55
- } & {
56
- [key in `passage-ref ${number}`]: PassageRefWidget;
57
- } & {
58
- [key in `passage-ref-target ${number}`]: PassageRefWidget;
59
- } & {
60
- [key in `phet-simulation ${number}`]: PhetSimulationWidget;
61
- } & {
62
- [key in `plotter ${number}`]: PlotterWidget;
63
- } & {
64
- [key in `python-program ${number}`]: PythonProgramWidget;
65
- } & {
66
- [key in `radio ${number}`]: RadioWidget;
67
- } & {
68
- [key in `sorter ${number}`]: SorterWidget;
69
- } & {
70
- [key in `table ${number}`]: TableWidget;
71
- } & {
72
- [key in `video ${number}`]: VideoWidget;
99
+ [Property in keyof PerseusWidgetTypes as `${Property} ${number}`]: PerseusWidgetTypes[Property];
73
100
  };
74
101
  /**
75
102
  * A "PerseusItem" is a classic Perseus item. It is rendered by the
@@ -101,6 +128,9 @@ export type PerseusArticle = PerseusRenderer | ReadonlyArray<PerseusRenderer>;
101
128
  * A "MultiItem" is an advanced Perseus item. It is rendered by the
102
129
  * `MultiRenderer` and you can control the layout of individual parts of the
103
130
  * item.
131
+ *
132
+ * @deprecated MultiItem support is slated for removal in a future Perseus
133
+ * release.
104
134
  */
105
135
  export type MultiItem = {
106
136
  _multi: any;
@@ -110,11 +140,25 @@ export type Version = {
110
140
  minor: number;
111
141
  };
112
142
  export type PerseusRenderer = {
143
+ /**
144
+ * Translatable Markdown content to be rendered. May include references to
145
+ * widgets (as [[☃ widgetName]]) or images (as ![image text](imageUrl)).
146
+ * For each image found in this content, there can be an entry in the
147
+ * `images` dict (below) with the key being the image's url which defines
148
+ * additional attributes for the image.
149
+ */
113
150
  content: string;
151
+ /**
152
+ * A dictionary of {[widgetName]: Widget} to be referenced from the content
153
+ * field.
154
+ */
114
155
  widgets: PerseusWidgetsMap;
115
156
  metadata?: ReadonlyArray<string>;
157
+ /**
158
+ * A dictionary of {[imageUrl]: PerseusImageDetail}.
159
+ */
116
160
  images: {
117
- [key: string]: PerseusImageDetail;
161
+ [imageUrl: string]: PerseusImageDetail;
118
162
  };
119
163
  };
120
164
  export type Hint = PerseusRenderer & {
@@ -131,6 +175,10 @@ export type PerseusImageDetail = {
131
175
  };
132
176
  export declare const ItemExtras: readonly ["calculator", "chi2Table", "financialCalculatorMonthlyPayment", "financialCalculatorTotalAmount", "financialCalculatorTimeToPayOff", "periodicTable", "periodicTableWithKey", "tTable", "zTable"];
133
177
  export type PerseusAnswerArea = Record<(typeof ItemExtras)[number], boolean>;
178
+ /**
179
+ * The type representing the common structure of all widget's options. The
180
+ * `Options` generic type represents the widget-specific option data.
181
+ */
134
182
  export type WidgetOptions<Type extends string, Options> = {
135
183
  type: Type;
136
184
  static?: boolean;
@@ -173,8 +221,11 @@ export type InputNumberWidget = WidgetOptions<'input-number', PerseusInputNumber
173
221
  export type MoleculeRendererWidget = WidgetOptions<'molecule-renderer', PerseusMoleculeRendererWidgetOptions>;
174
222
  export type RefTargetWidget = WidgetOptions<'passage-ref-target', PerseusPassageRefTargetWidgetOptions>;
175
223
  export type VideoWidget = WidgetOptions<'video', PerseusVideoWidgetOptions>;
176
- export type AutoCorrectWidget = WidgetOptions<'deprecated-standin', PerseusWidgetOptions>;
224
+ export type AutoCorrectWidget = WidgetOptions<'deprecated-standin', object>;
177
225
  export type PerseusWidget = CategorizerWidget | CSProgramWidget | DefinitionWidget | DropdownWidget | ExplanationWidget | ExpressionWidget | GradedGroupSetWidget | GradedGroupWidget | GrapherWidget | GroupWidget | IFrameWidget | ImageWidget | InputNumberWidget | InteractionWidget | InteractiveGraphWidget | LabelImageWidget | MatcherWidget | MatrixWidget | MeasurerWidget | MoleculeRendererWidget | NumberLineWidget | NumericInputWidget | OrdererWidget | PassageRefWidget | PassageWidget | PhetSimulationWidget | PlotterWidget | PythonProgramWidget | RadioWidget | RefTargetWidget | SorterWidget | TableWidget | VideoWidget | AutoCorrectWidget;
226
+ /**
227
+ * A background image applied to various widgets.
228
+ */
178
229
  export type PerseusImageBackground = {
179
230
  url: string | null | undefined;
180
231
  width?: number;
@@ -334,8 +385,8 @@ export type PerseusImageLabel = {
334
385
  };
335
386
  export type PerseusInteractiveGraphWidgetOptions = {
336
387
  step: [number, number];
337
- gridStep: [number, number];
338
- snapStep: [number, number];
388
+ gridStep?: [x: number, y: number];
389
+ snapStep?: [x: number, y: number];
339
390
  backgroundImage?: PerseusImageBackground;
340
391
  /**
341
392
  * The type of markings to display on the graph.
@@ -344,7 +395,7 @@ export type PerseusInteractiveGraphWidgetOptions = {
344
395
  * - none: shows no markings
345
396
  */
346
397
  markings: "graph" | "grid" | "none";
347
- labels: ReadonlyArray<string>;
398
+ labels?: ReadonlyArray<string>;
348
399
  showProtractor: boolean;
349
400
  /**
350
401
  * Whether to show the Ruler tool overlayed on top of the graph.
@@ -621,7 +672,7 @@ export type PerseusNumericInputAnswerForm = {
621
672
  };
622
673
  export type PerseusNumericInputWidgetOptions = {
623
674
  answers: ReadonlyArray<PerseusNumericInputAnswer>;
624
- labelText: string;
675
+ labelText?: string | undefined;
625
676
  size: string;
626
677
  coefficient: boolean;
627
678
  rightAlign?: boolean;
@@ -630,7 +681,7 @@ export type PerseusNumericInputWidgetOptions = {
630
681
  };
631
682
  export type PerseusNumericInputAnswer = {
632
683
  message: string;
633
- value: number;
684
+ value?: number;
634
685
  status: string;
635
686
  answerForms?: ReadonlyArray<MathFormat>;
636
687
  strict: boolean;
@@ -1,8 +1,10 @@
1
- import type { PerseusWidgetsMap } from "./perseus-types";
1
+ import type { PerseusRenderer, PerseusWidgetsMap } from "./perseus-types";
2
2
  import type { PerseusStrings } from "./strings";
3
3
  import type { PerseusScore } from "./types";
4
4
  import type { UserInputMap } from "./validation.types";
5
+ export declare function getUpgradedWidgetOptions(oldWidgetOptions: PerseusWidgetsMap): PerseusWidgetsMap;
5
6
  export declare function emptyWidgetsFunctional(widgets: PerseusWidgetsMap, widgetIds: Array<string>, userInputMap: UserInputMap, strings: PerseusStrings, locale: string): ReadonlyArray<string>;
6
- export declare function scoreWidgetsFunctional(widgets: PerseusWidgetsMap, widgetIds: Array<string>, userInputMap: UserInputMap, strings: PerseusStrings, locale: string): {
7
+ export declare function scorePerseusItem(perseusRenderData: PerseusRenderer, userInputMap: UserInputMap, strings: PerseusStrings, locale: string): PerseusScore;
8
+ export declare function scoreWidgetsFunctional(widgets: PerseusWidgetsMap, widgetIds: ReadonlyArray<string>, userInputMap: UserInputMap, strings: PerseusStrings, locale: string): {
7
9
  [widgetId: string]: PerseusScore;
8
10
  };
@@ -103,7 +103,6 @@ declare class Renderer extends React.Component<Props, State> implements GetPromp
103
103
  widgetInfo: State["widgetInfo"];
104
104
  widgetProps: State["widgetProps"];
105
105
  };
106
- _getAllWidgetsInfo: (props: Props) => PerseusWidgetsMap;
107
106
  _getAllWidgetsStartProps: (allWidgetInfo: PerseusWidgetsMap, props: Props) => PerseusWidgetsMap;
108
107
  _getDefaultWidgetInfo: (widgetId: string) => any;
109
108
  _getWidgetInfo: (widgetId: string) => PerseusWidget;
@@ -193,9 +192,15 @@ declare class Renderer extends React.Component<Props, State> implements GetPromp
193
192
  blurPath: (path: FocusPath) => void;
194
193
  blur: () => void;
195
194
  serialize: () => Record<any, any>;
195
+ /**
196
+ * Returns an array of widget ids that are empty (meaning widgets where the
197
+ * learner has not interacted with the widget yet or has not filled in all
198
+ * fields). For example, the `interactive-graph` widget is considered
199
+ * empty if the graph is in the starting state.
200
+ */
196
201
  emptyWidgets(): ReadonlyArray<string>;
197
202
  _setWidgetProps: SetWidgetPropsFn;
198
- setInputValue: (path: FocusPath, newValue: string, focus?: () => unknown) => void;
203
+ setInputValue: (path: FocusPath, newValue: string, cb?: () => void) => void;
199
204
  /**
200
205
  * Returns an array of the widget `.getUserInput()` results
201
206
  *
@@ -218,18 +223,15 @@ declare class Renderer extends React.Component<Props, State> implements GetPromp
218
223
  */
219
224
  getPromptJSON(): RendererPromptJSON;
220
225
  /**
221
- * Returns an object mapping from widget ID to perseus-style score.
222
- * The keys of this object are the values of the array returned
223
- * from `getWidgetIds`.
226
+ * Scores the content.
227
+ *
228
+ * @deprecated use scorePerseusItem
224
229
  */
225
- scoreWidgets(): {
226
- [widgetId: string]: PerseusScore;
227
- };
230
+ score(): PerseusScore;
228
231
  /**
229
- * Grades the content.
232
+ * @deprecated use scorePerseusItem
230
233
  */
231
- score(): PerseusScore;
232
- guessAndScore(): [UserInputArray, PerseusScore];
234
+ guessAndScore: () => [UserInputArray, PerseusScore];
233
235
  examples: () => ReadonlyArray<string> | null | undefined;
234
236
  handletranslationLintErrors: (lintErrors: ReadonlyArray<string>) => void;
235
237
  render(): React.ReactNode;
@@ -12,12 +12,14 @@ import { PerseusI18nContext } from "./components/i18n-context";
12
12
  import Renderer from "./renderer";
13
13
  import type { PerseusItem, ShowSolutions } from "./perseus-types";
14
14
  import type { FocusPath, PerseusDependenciesV2, SharedRendererProps } from "./types";
15
+ import type { UserInputArray, UserInputMap } from "./validation.types";
15
16
  import type { GetPromptJSONInterface, RendererPromptJSON } from "./widget-ai-utils/prompt-types";
16
17
  import type { KeypadAPI } from "@khanacademy/math-input";
17
18
  import type { KeypadContextRendererInterface, RendererInterface, KEScore } from "@khanacademy/perseus-core";
18
19
  type OwnProps = {
19
20
  hintsVisible?: number;
20
21
  item: PerseusItem;
22
+ score?: KEScore | null;
21
23
  problemNum?: number;
22
24
  reviewMode?: boolean;
23
25
  keypadElement?: KeypadAPI | null | undefined;
@@ -30,8 +32,23 @@ type HOCProps = {
30
32
  type Props = SharedRendererProps & OwnProps & HOCProps;
31
33
  type DefaultProps = Required<Pick<Props, "apiOptions" | "onRendered" | "linterContext">>;
32
34
  type State = {
35
+ /**
36
+ * questionCompleted is used to signal that a learner has attempted
37
+ * the exercise. This is used when widgets want to show things like
38
+ * rationale or partial correctness.
39
+ */
33
40
  questionCompleted: boolean;
34
- questionHighlightedWidgets: ReadonlyArray<any>;
41
+ /**
42
+ * As far as I can tell, this is used to highlight empty widgets
43
+ * after a learner has clicked the "check" button. I don't think this could
44
+ * still be used though, because the "check" button is disabled while there
45
+ * are empty widgets.
46
+ */
47
+ questionHighlightedWidgets: ReadonlyArray<string>;
48
+ /**
49
+ * Keeps track of whether each asset (SvgImage or TeX) rendered by
50
+ * the questionRenderer has finished loading or rendering.
51
+ */
35
52
  assetStatuses: {
36
53
  [assetKey: string]: boolean;
37
54
  };
@@ -76,8 +93,22 @@ export declare class ServerItemRenderer extends React.Component<Props, State> im
76
93
  blur(): void;
77
94
  getNumHints(): number;
78
95
  getPromptJSON(): RendererPromptJSON;
96
+ /**
97
+ * Returns an array of the widget `.getUserInput()` results
98
+ *
99
+ * TODO: can we remove this? Seems to be just for backwards
100
+ * compatibility with old Perseus Chrome logging
101
+ * @deprecated use getUserInput
102
+ */
103
+ getUserInputLegacy(): UserInputArray;
104
+ /**
105
+ * Returns an object of the widget `.getUserInput()` results
106
+ */
107
+ getUserInput(): UserInputMap;
79
108
  /**
80
109
  * Grades the item.
110
+ *
111
+ * @deprecated use scorePerseusItem
81
112
  */
82
113
  scoreInput(): KEScore;
83
114
  /**
package/dist/types.d.ts CHANGED
@@ -46,6 +46,12 @@ export interface Widget {
46
46
  } | boolean;
47
47
  getDOMNodeForPath?: (path: FocusPath) => Element | Text | null;
48
48
  deselectIncorrectSelectedChoices?: () => void;
49
+ /**
50
+ * Returns widget state that can be passed back to `restoreSerializedState`
51
+ * to put the widget back into exactly the same state. If the widget does
52
+ * not implement this function, the renderer simply returns all of the
53
+ * widget's props.
54
+ */
49
55
  getSerializedState?: () => SerializedState;
50
56
  restoreSerializedState?: (props: any, callback: () => void) => any;
51
57
  blurInputPath?: (path: FocusPath) => void;
@@ -103,7 +109,7 @@ export type ChangeHandler = (arg1: {
103
109
  selected?: number;
104
110
  plot?: any;
105
111
  graph?: PerseusGraphType;
106
- }, callback?: () => unknown | null | undefined, silent?: boolean) => unknown;
112
+ }, callback?: () => void, silent?: boolean) => unknown;
107
113
  export type ImageUploader = (file: File, callback: (url: string) => unknown) => unknown;
108
114
  export type Path = ReadonlyArray<string>;
109
115
  type StubTagEditorType = any;
@@ -297,6 +303,17 @@ type InitialRequestUrlInterface = {
297
303
  protocol: string;
298
304
  };
299
305
  export type VideoKind = "YOUTUBE_ID" | "READABLE_ID";
306
+ /**
307
+ * An object for dependency injection, to allow different clients
308
+ * to provide different methods for logging, translation, network
309
+ * requests, etc.
310
+ *
311
+ * NOTE: You should avoid adding new dependencies here as this type was added
312
+ * as a quick fix to get around the fact that some of the dependencies Perseus
313
+ * needs are used in places where neither `APIOptions` nor a React Context
314
+ * could be used. Aim to shrink the footprint of PerseusDependencies and try to
315
+ * use alternative methods where possible.
316
+ */
300
317
  export type PerseusDependencies = {
301
318
  JIPT: JIPT;
302
319
  graphieMovablesJiptLabels: JiptLabelStore;
@@ -353,6 +370,11 @@ type TrackingSequenceExtraArguments = {
353
370
  };
354
371
  export type Alignment = "default" | "block" | "inline-block" | "inline" | "float-left" | "float-right" | "full-width";
355
372
  type WidgetOptions = any;
373
+ /**
374
+ * A transform that maps the WidgetOptions (sometimes referred to as
375
+ * EditorProps) to the props used to render the widget. Often this is an
376
+ * identity transform.
377
+ */
356
378
  export type WidgetTransform = (arg1: WidgetOptions, strings: PerseusStrings, problemNumber?: number) => any;
357
379
  export type WidgetScorerFunction = (userInput: UserInput, rubric: Rubric, string?: PerseusStrings, locale?: string) => PerseusScore;
358
380
  export type WidgetExports<T extends React.ComponentType<any> & Widget = React.ComponentType<any>> = Readonly<{
@@ -364,11 +386,12 @@ export type WidgetExports<T extends React.ComponentType<any> & Widget = React.Co
364
386
  /** Supresses widget from showing up in the dropdown in the content editor */
365
387
  hidden?: boolean;
366
388
  /**
367
- The widget version. Any time the _major_ version changes, the widget
368
- should provide a new entry in the propUpgrades map to migrate from the
369
- older version to the current (new) version. Minor version changes must
370
- be backwards compatible with previous minor versions widget options.
371
- This key defaults to `{major: 0, minor: 0}` if not provided.
389
+ * The widget version. Any time the _major_ version changes, the widget
390
+ * should provide a new entry in the propUpgrades map to migrate from the
391
+ * older version to the current (new) version. Minor version changes must
392
+ * be backwards compatible with previous minor versions widget options.
393
+ *
394
+ * This key defaults to `{major: 0, minor: 0}` if not provided.
372
395
  */
373
396
  version?: Version;
374
397
  supportedAlignments?: ReadonlyArray<Alignment>;
@@ -377,25 +400,44 @@ export type WidgetExports<T extends React.ComponentType<any> & Widget = React.Co
377
400
  isLintable?: boolean;
378
401
  tracking?: Tracking;
379
402
  traverseChildWidgets?: any;
380
- /** transforms the widget options to the props used to render the widget */
403
+ /**
404
+ * Transforms the widget options to the props used to render the widget.
405
+ */
381
406
  transform?: WidgetTransform;
382
- /** transforms the widget options to the props used to render the widget for
383
- static renders */
407
+ /**
408
+ * Transforms the widget options to the props used to render the widget for
409
+ * static renders.
410
+ */
384
411
  staticTransform?: WidgetTransform;
412
+ /**
413
+ * A function that scores user input (the guess) for the widget.
414
+ */
385
415
  scorer?: WidgetScorerFunction;
386
416
  getOneCorrectAnswerFromRubric?: (rubric: Rubric) => string | null | undefined;
387
417
  /**
388
- A map of major version numbers (as a string, eg "1") to a function that
389
- migrates from the _previous_ major version.
390
- Example:
391
- propUpgrades: {'1': (options) => ({...options})}
392
- would migrate from major version 0 to 1.
393
- */
418
+ * A map of major version numbers (as a string, eg "1") to a function that
419
+ * migrates from the _previous_ major version.
420
+ *
421
+ * Example:
422
+ * ```
423
+ * propUpgrades: {'1': (options) => ({...options})}
424
+ * ```
425
+ *
426
+ * This configuration would migrate options from major version 0 to 1.
427
+ */
394
428
  propUpgrades?: {
395
- [key: string]: (arg1: any) => any;
429
+ [targetMajorVersion: string]: (arg1: any) => any;
396
430
  };
397
431
  }>;
398
432
  export type FilterCriterion = string | ((id: string, widgetInfo: PerseusWidget, widget?: Widget | null | undefined) => boolean);
433
+ /**
434
+ * The full set of props provided to all widgets when they are rendered. The
435
+ * `RenderProps` generic argument are the widget-specific props that originate
436
+ * from the stored PerseusItem. Note that they may not match the serialized
437
+ * widget options exactly as they are the result of running the options through
438
+ * any `propUpgrades` the widget defines as well as its `transform` or
439
+ * `staticTransform` functions (depending on the options `static` flag).
440
+ */
399
441
  export type WidgetProps<RenderProps, Rubric = Empty, TrackingExtraArgs = Empty> = RenderProps & {
400
442
  widgetId: string;
401
443
  alignment: string | null | undefined;
@@ -403,6 +445,11 @@ export type WidgetProps<RenderProps, Rubric = Empty, TrackingExtraArgs = Empty>
403
445
  problemNum: number | null | undefined;
404
446
  apiOptions: APIOptionsWithDefaults;
405
447
  keypadElement?: any;
448
+ /**
449
+ * questionCompleted is used to signal that a learner has attempted
450
+ * the exercise. This is used when widgets want to show things like
451
+ * rationale or partial correctness.
452
+ */
406
453
  questionCompleted?: boolean;
407
454
  onFocus: (blurPath: FocusPath) => void;
408
455
  onBlur: (blurPath: FocusPath) => void;
@@ -0,0 +1,2 @@
1
+ import type { PartialParser } from "../parser-types";
2
+ export declare const stringToNumber: PartialParser<string | number, number>;
@@ -27,7 +27,7 @@
27
27
  * } & Perseus<Widget>ValidationData;
28
28
  * ```
29
29
  */
30
- import type { GrapherAnswerTypes, PerseusDropdownChoice, PerseusExpressionAnswerForm, PerseusGradedGroupSetWidgetOptions, PerseusGradedGroupWidgetOptions, PerseusGraphType, PerseusGroupWidgetOptions, PerseusMatcherWidgetOptions, PerseusMatrixWidgetAnswers, PerseusNumberLineWidgetOptions, PerseusNumericInputAnswer, PerseusOrdererWidgetOptions, PerseusRadioChoice, PerseusGraphCorrectType } from "./perseus-types";
30
+ import type { GrapherAnswerTypes, PerseusDropdownChoice, PerseusExpressionAnswerForm, PerseusGradedGroupSetWidgetOptions, PerseusGradedGroupWidgetOptions, PerseusGraphType, PerseusGroupWidgetOptions, PerseusMatcherWidgetOptions, PerseusMatrixWidgetAnswers, PerseusNumericInputAnswer, PerseusOrdererWidgetOptions, PerseusRadioChoice, PerseusGraphCorrectType } from "./perseus-types";
31
31
  import type { InteractiveMarkerType } from "./widgets/label-image/types";
32
32
  import type { Relationship } from "./widgets/number-line/number-line";
33
33
  export type UserInputStatus = "correct" | "incorrect" | "incomplete";
@@ -57,6 +57,7 @@ export type PerseusExpressionRubric = {
57
57
  };
58
58
  export type PerseusExpressionUserInput = string;
59
59
  export type PerseusGroupRubric = PerseusGroupWidgetOptions;
60
+ export type PerseusGroupUserInput = UserInputMap;
60
61
  export type PerseusGradedGroupRubric = PerseusGradedGroupWidgetOptions;
61
62
  export type PerseusGradedGroupSetRubric = PerseusGradedGroupSetWidgetOptions;
62
63
  export type PerseusGrapherRubric = {
@@ -99,7 +100,11 @@ export type PerseusMatrixValidationData = Empty;
99
100
  export type PerseusMatrixUserInput = {
100
101
  answers: PerseusMatrixRubric["answers"];
101
102
  };
102
- export type PerseusNumberLineRubric = PerseusNumberLineWidgetOptions & {
103
+ export type PerseusNumberLineScoringData = {
104
+ correctRel: string | null | undefined;
105
+ correctX: number;
106
+ range: ReadonlyArray<number>;
107
+ initialX: number | null | undefined;
103
108
  isInequality: boolean;
104
109
  };
105
110
  export type PerseusNumberLineUserInput = {
@@ -144,7 +149,7 @@ export type PerseusTableRubric = {
144
149
  answers: ReadonlyArray<ReadonlyArray<string>>;
145
150
  };
146
151
  export type PerseusTableUserInput = ReadonlyArray<ReadonlyArray<string>>;
147
- export type Rubric = PerseusCategorizerScoringData | PerseusCSProgramRubric | PerseusDropdownRubric | PerseusExpressionRubric | PerseusGroupRubric | PerseusGradedGroupRubric | PerseusGradedGroupSetRubric | PerseusGrapherRubric | PerseusIFrameRubric | PerseusInputNumberRubric | PerseusInteractiveGraphRubric | PerseusLabelImageRubric | PerseusMatcherRubric | PerseusMatrixRubric | PerseusNumberLineRubric | PerseusNumericInputRubric | PerseusOrdererRubric | PerseusPlotterScoringData | PerseusRadioRubric | PerseusSorterRubric | PerseusTableRubric;
152
+ export type Rubric = PerseusCategorizerScoringData | PerseusCSProgramRubric | PerseusDropdownRubric | PerseusExpressionRubric | PerseusGroupRubric | PerseusGradedGroupRubric | PerseusGradedGroupSetRubric | PerseusGrapherRubric | PerseusIFrameRubric | PerseusInputNumberRubric | PerseusInteractiveGraphRubric | PerseusLabelImageRubric | PerseusMatcherRubric | PerseusMatrixRubric | PerseusNumberLineScoringData | PerseusNumericInputRubric | PerseusOrdererRubric | PerseusPlotterScoringData | PerseusRadioRubric | PerseusSorterRubric | PerseusTableRubric;
148
153
  export type UserInput = PerseusCategorizerUserInput | PerseusCSProgramUserInput | PerseusDropdownUserInput | PerseusExpressionUserInput | PerseusGrapherUserInput | PerseusIFrameUserInput | PerseusInputNumberUserInput | PerseusInteractiveGraphUserInput | PerseusLabelImageUserInput | PerseusMatcherUserInput | PerseusMatrixUserInput | PerseusNumberLineUserInput | PerseusNumericInputUserInput | PerseusOrdererUserInput | PerseusPlotterUserInput | PerseusRadioUserInput | PerseusSorterUserInput | PerseusTableUserInput;
149
154
  export type UserInputMap = {
150
155
  [widgetId: string]: UserInput | UserInputMap;
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { PerseusI18nContext } from "../../components/i18n-context";
3
3
  import type { Widget } from "../../types";
4
- type Props = any;
4
+ type Props = object;
5
5
  declare class DeprecatedStandin extends React.Component<Props> implements Widget {
6
6
  static contextType: React.Context<{
7
7
  strings: import("../../strings").PerseusStrings;
@@ -172,7 +172,7 @@ declare const _default: {
172
172
  visibleLabel: PerseusExpressionWidgetOptions["visibleLabel"];
173
173
  ariaLabel: PerseusExpressionWidgetOptions["ariaLabel"];
174
174
  value: string;
175
- }, "ariaLabel" | "static" | "onChange" | "keypadElement" | "containerSizeClass" | "widgetId" | "problemNum" | "questionCompleted" | "findWidgets" | "trackInteraction" | "reviewMode" | keyof import("../..").PerseusDependenciesV2 | "alignment" | "reviewModeRubric" | "isLastUsedWidget" | "visibleLabel" | "buttonsVisible" | "keypadConfiguration"> & {
175
+ }, "ariaLabel" | "static" | "onChange" | "keypadElement" | "containerSizeClass" | "widgetId" | "problemNum" | "questionCompleted" | "findWidgets" | "trackInteraction" | "alignment" | "reviewMode" | keyof import("../..").PerseusDependenciesV2 | "reviewModeRubric" | "isLastUsedWidget" | "visibleLabel" | "buttonsVisible" | "keypadConfiguration"> & {
176
176
  value?: string | undefined;
177
177
  onFocus?: ((blurPath: FocusPath) => void) | undefined;
178
178
  onBlur?: ((blurPath: FocusPath) => void) | undefined;
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { PerseusI18nContext } from "../../components/i18n-context";
3
3
  import Renderer from "../../renderer";
4
+ import scoreGroup from "./score-group";
4
5
  import type { PerseusGroupWidgetOptions } from "../../perseus-types";
5
6
  import type { ChangeFn, FocusPath, Widget, WidgetProps } from "../../types";
6
7
  import type { PerseusGroupRubric, UserInputArray } from "../../validation.types";
@@ -23,7 +24,7 @@ declare class Group extends React.Component<Props> implements Widget {
23
24
  static defaultProps: DefaultProps;
24
25
  componentDidMount(): void;
25
26
  change: ChangeFn;
26
- getUserInputMap(): import("../../validation.types").UserInputMap | undefined;
27
+ getUserInputMap(): import("../..").UserInputMap | undefined;
27
28
  /**
28
29
  * @deprecated getUserInputMap should be used for Groups
29
30
  */
@@ -44,6 +45,7 @@ declare const _default: {
44
45
  displayName: string;
45
46
  widget: typeof Group;
46
47
  traverseChildWidgets: (props: any, traverseRenderer: any) => any;
48
+ scorer: typeof scoreGroup;
47
49
  hidden: true;
48
50
  isLintable: true;
49
51
  };
@@ -0,0 +1,5 @@
1
+ import type { PerseusStrings } from "../../strings";
2
+ import type { PerseusScore } from "../../types";
3
+ import type { PerseusGroupRubric, PerseusGroupUserInput } from "../../validation.types";
4
+ declare function scoreGroup(userInput: PerseusGroupUserInput, options: PerseusGroupRubric, strings: PerseusStrings, locale: string): PerseusScore;
5
+ export default scoreGroup;