@khanacademy/perseus 20.8.1 → 21.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.
Files changed (27) hide show
  1. package/dist/es/index.js +716 -359
  2. package/dist/es/index.js.map +1 -1
  3. package/dist/index.d.ts +5 -4
  4. package/dist/index.js +739 -366
  5. package/dist/index.js.map +1 -1
  6. package/dist/types.d.ts +2 -0
  7. package/dist/util/extract-perseus-data.d.ts +7 -8
  8. package/dist/util/snowman-utils.d.ts +0 -72
  9. package/dist/util/test-utils.d.ts +37 -2
  10. package/dist/util/widget-enum-utils.d.ts +1 -3
  11. package/dist/widget-type-utils.d.ts +64 -0
  12. package/dist/widgets/interactive-graph.d.ts +3 -3
  13. package/dist/widgets/interactive-graphs/axis-arrows.d.ts +2 -0
  14. package/dist/widgets/interactive-graphs/graphs/components/angle.d.ts +12 -2
  15. package/dist/widgets/interactive-graphs/graphs/components/css-transform-wrapper.d.ts +7 -0
  16. package/dist/widgets/interactive-graphs/graphs/components/text-label.d.ts +6 -0
  17. package/dist/widgets/interactive-graphs/graphs/point.d.ts +5 -0
  18. package/dist/widgets/interactive-graphs/graphs/utils.d.ts +2 -0
  19. package/dist/widgets/interactive-graphs/mafs-graph.d.ts +15 -74
  20. package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
  21. package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +10 -3
  22. package/dist/widgets/interactive-graphs/reducer/interactive-graph-reducer.d.ts +1 -1
  23. package/dist/widgets/interactive-graphs/reducer/interactive-graph-state.d.ts +1 -1
  24. package/dist/widgets/interactive-graphs/reducer/use-graph-state.d.ts +11 -0
  25. package/dist/widgets/interactive-graphs/types.d.ts +30 -9
  26. package/dist/widgets/interactive-graphs/utils.d.ts +2 -2
  27. package/package.json +1 -1
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { ILogger } from "./logging/log";
2
2
  import type { Item } from "./multi-items/item-types";
3
3
  import type { PerseusAnswerArea, PerseusRenderer, PerseusWidget, PerseusWidgetsMap } from "./perseus-types";
4
4
  import type { SizeClass } from "./util/sizing-utils";
5
+ import type { InteractiveGraphState } from "./widgets/interactive-graphs/types";
5
6
  import type { KeypadAPI } from "@khanacademy/math-input";
6
7
  import type { AnalyticsEventHandlerFn } from "@khanacademy/perseus-core";
7
8
  import type { LinterContextProps } from "@khanacademy/perseus-linter";
@@ -65,6 +66,7 @@ export type ChangeHandler = (arg1: {
65
66
  currentValue?: string;
66
67
  selected?: number;
67
68
  plot?: any;
69
+ graph?: InteractiveGraphState;
68
70
  }, callback?: () => unknown | null | undefined, silent?: boolean) => unknown;
69
71
  export type ImageUploader = (file: string, callback: (url: string) => unknown) => unknown;
70
72
  export type WidgetSize = "normal" | "small" | "mini";
@@ -1,4 +1,4 @@
1
- import type { PerseusItem, PerseusRenderer } from "../perseus-types";
1
+ import type { PerseusItem, PerseusWidgetsMap, PerseusRenderer } from "../perseus-types";
2
2
  /**
3
3
  * This function extracts the answers from the widgets.
4
4
  *
@@ -22,12 +22,11 @@ declare function getAnswersFromWidgets(widgets: PerseusRenderer["widgets"]): Rea
22
22
  * @param {PerseusRenderer["widgets"]} widgets
23
23
  * @returns
24
24
  */
25
- declare function injectWidgets(content: string, widgets: PerseusRenderer["widgets"]): string;
26
- export declare const getWidgetTypeFromWidgetKey: (widgetKey: string) => string;
27
- export declare const isWrongAnswerSupported: (widgetKeys: Array<string>) => boolean;
28
- export declare const shouldHaveIndividualAnswer: (widgetKey: string) => boolean;
25
+ declare function injectWidgets(content: string, widgets: PerseusRenderer["widgets"], widgetProps?: PerseusWidgetsMap): string;
26
+ export declare const isWrongAnswerSupported: (widgetIds: Array<string>, widgetMap: PerseusWidgetsMap) => boolean;
27
+ export declare const shouldHaveIndividualAnswer: (widgetId: string, widgetMap: PerseusWidgetsMap) => boolean;
29
28
  export declare const getAnswerFromUserInput: (widgetType: string, userInput: any) => any;
30
- export declare const getCorrectAnswerForWidgetKey: (widgetKey: string, itemData: PerseusItem) => string | undefined;
31
- export declare const isWidgetKeyInContent: (perseusItem: PerseusItem, widgetKey: string) => boolean;
32
- export declare const getValidWidgetKeys: (perseusItem: PerseusItem) => Array<string>;
29
+ export declare const getCorrectAnswerForWidgetId: (widgetId: string, itemData: PerseusItem) => string | undefined;
30
+ export declare const isWidgetIdInContent: (perseusItem: PerseusItem, widgetId: string) => boolean;
31
+ export declare const getValidWidgetIds: (perseusItem: PerseusItem) => Array<string>;
33
32
  export { getAnswersFromWidgets, injectWidgets };
@@ -1,43 +1,3 @@
1
- export declare enum WidgetType {
2
- Categorizer = "categorizer",
3
- CSProgram = "cs-program",
4
- Definition = "definition",
5
- Dropdown = "dropdown",
6
- Explanation = "explanation",
7
- Expression = "expression",
8
- GradedGroup = "graded-group",
9
- GradedGroupAnswerBar = "graded-group-answer-bar",
10
- GradedGroupSet = "graded-group-set",
11
- Grapher = "grapher",
12
- Group = "group",
13
- Iframe = "iframe",
14
- Image = "image",
15
- InputNumber = "input-number",
16
- Interaction = "interaction",
17
- InteractiveGraph = "interactive-graph",
18
- InteractiveNumberLine = "interactive-number-line",
19
- LabelImage = "label-image",
20
- Matcher = "matcher",
21
- Matrix = "matrix",
22
- Measurer = "measurer",
23
- Molecule = "molecule",
24
- NumberLine = "number-line",
25
- NumericInput = "numeric-input",
26
- Orderer = "orderer",
27
- Passage = "passage",
28
- PassageRef = "passage-ref",
29
- PassageRefTarget = "passage-ref-target",
30
- Plotter = "plotter",
31
- Protractor = "protractor",
32
- PythonProgram = "python-program",
33
- Radio = "radio",
34
- Sorter = "sorter",
35
- Table = "table",
36
- Unit = "unit",
37
- Video = "video",
38
- VideoTranscriptLink = "video-transcript-link"
39
- }
40
- export type WidgetId = `${WidgetType} ${number}`;
41
1
  export declare const QUESTION_WIDGETS: ReadonlyArray<string>;
42
2
  /**
43
3
  * Regex for widget placeholders in a string.
@@ -55,35 +15,3 @@ export declare function getWidgetRegex(): RegExp;
55
15
  * @returns {string}
56
16
  */
57
17
  export declare function addWidget(id: string): string;
58
- /**
59
- * Extract all widget IDs, which includes the widget type and instance number.
60
- * example output: ['radio 1', 'categorizer 1', 'categorizor 2']
61
- *
62
- * Content should contain Perseus widget placeholders,
63
- * which look like: '[[☃ radio 1]]'.
64
- *
65
- * @param {string} content
66
- * @returns {Array<WidgetId>} widgets
67
- */
68
- export declare function getAllWidgetIds(content: string): Array<WidgetId>;
69
- /**
70
- * Extract all widget types from a Perseus JSON content string.
71
- * This does not include the instance number and prevents duplicates.
72
- * example output: ['radio', 'categorizer']
73
- *
74
- * @param {string} content
75
- * @returns {Array<WidgetId>}
76
- */
77
- export declare function getAllWidgetTypes(content: string): Array<WidgetId>;
78
- /**
79
- * Extract the widget IDs of all widgets considered question widgets. Widget IDs
80
- * include widget type and instance number.
81
- * example output: ['radio 1', 'categorizer 1']
82
- *
83
- * Content should contain Perseus widget placeholders,
84
- * which look like: '[[☃ radio 1]]'.
85
- *
86
- * @param {string} content
87
- * @returns Array<WidgetId>
88
- */
89
- export declare function getQuestionWidgetIds(content: string): Array<WidgetId>;
@@ -1,4 +1,4 @@
1
- import type { PerseusItem } from "../perseus-types";
1
+ import type { CategorizerWidget, ExpressionWidget, InteractiveGraphWidget, NumericInputWidget, PerseusItem, RadioWidget } from "../perseus-types";
2
2
  export declare const genericPerseusItemData: PerseusItem;
3
3
  /**
4
4
  * Generate a Perseus item object for testing purposes.
@@ -7,6 +7,41 @@ export declare const genericPerseusItemData: PerseusItem;
7
7
  * uses a basic Perseus object and updates it with custom values as needed.
8
8
  *
9
9
  * @param {Partial<PerseusItem>} customFields
10
- * @returns PerseusItem
10
+ * @returns {PerseusItem}
11
11
  */
12
12
  export declare function generateTestPerseusItem(customFields?: Partial<PerseusItem>): PerseusItem;
13
+ /**
14
+ * Creates an object with the bare amount
15
+ * of data to be a properly typed RadioWidget
16
+ *
17
+ * @returns {RadioWidget} skeleton RadioWidget for testing
18
+ */
19
+ export declare function generateTestRadioWidget(): RadioWidget;
20
+ /**
21
+ * Creates an object with the bare amount
22
+ * of data to be a properly typed InteractiveGraphWidget
23
+ *
24
+ * @returns {InteractiveGraphWidget} skeleton InteractiveGraphWidget for testing
25
+ */
26
+ export declare function generateTestInteractiveGraphWidget(): InteractiveGraphWidget;
27
+ /**
28
+ * Creates an object with the bare amount
29
+ * of data to be a properly typed InteractiveGraphWidget
30
+ *
31
+ * @returns {InteractiveGraphWidget} skeleton InteractiveGraphWidget for testing
32
+ */
33
+ export declare function generateTestCategorizerWidget(): CategorizerWidget;
34
+ /**
35
+ * Creates an object with the bare amount
36
+ * of data to be a properly typed ExpressionWidget
37
+ *
38
+ * @returns {ExpressionWidget} skeleton ExpressionWidget for testing
39
+ */
40
+ export declare function generateTestExpressionWidget(): ExpressionWidget;
41
+ /**
42
+ * Creates an object with the bare amount
43
+ * of data to be a properly typed NumericInputWidget
44
+ *
45
+ * @returns {NumericInputWidget} skeleton NumericInputWidget for testing
46
+ */
47
+ export declare function generateTestNumericInputWidget(): NumericInputWidget;
@@ -4,8 +4,6 @@
4
4
  * PerseusWidgetUsedInProblemAttempt CEDAR event, we needed
5
5
  * to: get the type and convert that to an enum value.
6
6
  */
7
- type WidgetName = "categorizer" | "cs-program" | "definition" | "deprecated-standin" | "dropdown" | "explanation" | "expression" | "graded-group-set" | "graded-group" | "grapher" | "group" | "iframe" | "image" | "input-number" | "interaction" | "interactive-graph" | "label-image" | "lights-puzzle" | "matcher" | "matrix" | "measurer" | "molecule-renderer" | "number-line" | "numeric-input" | "orderer" | "passage" | "passage-ref" | "passage-ref-target" | "plotter" | "python-program" | "reaction-diagram" | "radio" | "sequence" | "simulator" | "sorter" | "table" | "unit-input" | "video";
8
7
  type WidgetEnum = "CATEGORIZER" | "CS_PROGRAM" | "DEFINITION" | "DEPRECATED_STANDIN" | "DROPDOWN" | "EXPLANATION" | "EXPRESSION" | "GRADED_GROUP" | "GRADED_GROUP_SET" | "GRAPHER" | "GROUP" | "IFRAME" | "IMAGE" | "INPUT_NUMBER" | "INTERACTIVE" | "INTERACTIVE_GRAPH" | "LABEL_IMAGE" | "LIGHTS_PUZZLE" | "MATCHER" | "MATRIX" | "MEASURER" | "MOLECULE" | "NUMBER_LINE" | "NUMERIC_INPUT" | "ORDERER" | "PASSAGE" | "PASSAGE_REF" | "PASSAGE_REF_TARGET" | "PLOTTER" | "PYTHON_PROGRAM" | "REACTION_DIAGRAM" | "RADIO" | "SEQUENCE" | "SIMULATOR" | "SORTER" | "TABLE" | "UNIT" | "VIDEO";
9
- export declare function convertWidgetNameToEnum(name: WidgetName): WidgetEnum;
10
- export declare function getWidgetTypeFromWidgetId(widgetId: string): WidgetName;
8
+ export declare function convertWidgetNameToEnum(name: string): WidgetEnum;
11
9
  export {};
@@ -0,0 +1,64 @@
1
+ import type { PerseusItem, PerseusWidget, PerseusWidgetsMap } from "./perseus-types";
2
+ /**
3
+ * Get a widget type by a widget's ID
4
+ * (please don't derive type from ID)
5
+ *
6
+ * @param {string} widgetId the ID of the widget
7
+ * @param {PerseusWidgetsMap} widgetMap widget ID to widget map
8
+ * @returns {string} the widget type (ie "radio")
9
+ */
10
+ export declare function getWidgetTypeByWidgetId(WidgetId: string, widgetMap: PerseusWidgetsMap): string | null;
11
+ /**
12
+ * Does the content have a specific type of widget?
13
+ *
14
+ * @param {string} type the type of the widget in question (ie "radio")
15
+ * @param {string} content the string to search through
16
+ * @param {PerseusWidgetsMap} widgetMap widget ID to widget map
17
+ * @returns {boolean} if the content includes the widget type
18
+ */
19
+ export declare function contentHasWidgetType(type: string, content: string, widgetMap: PerseusWidgetsMap): boolean;
20
+ /**
21
+ * Extract all widget IDs, which includes the widget type and instance number.
22
+ * example output: ['radio 1', 'categorizer 1', 'categorizor 2']
23
+ *
24
+ * Content should contain Perseus widget placeholders,
25
+ * which look like: '[[☃ radio 1]]'.
26
+ *
27
+ * @param {string} content
28
+ * @returns {ReadonlyArray<string>} widgetIds
29
+ */
30
+ export declare function getWidgetIdsFromContent(content: string): ReadonlyArray<string>;
31
+ /**
32
+ * Get a list of widget IDs from content,
33
+ * but only for specific widget types
34
+ *
35
+ * @param {string} type the type of widget (ie "radio")
36
+ * @param {string} content the string to parse
37
+ * @param {PerseusWidgetsMap} widgetMap widget ID to widget map
38
+ * @returns {ReadonlyArray<string>} the widget type (ie "radio")
39
+ */
40
+ export declare function getWidgetIdsFromContentByType(type: string, content: string, widgetMap: PerseusWidgetsMap): ReadonlyArray<string>;
41
+ /**
42
+ * Pull the widget map out of ItemData
43
+ *
44
+ * @param {PerseusItem} PerseusItem containing a widgetMap
45
+ * @returns {WidgetMap} the widget map in the PerseusItem
46
+ */
47
+ export declare function getWidgetsMapFromItemData(itemData: PerseusItem): PerseusWidgetsMap;
48
+ /**
49
+ * Get the widget information from a WidgetMap
50
+ *
51
+ * @param {string} widgetId the ID of the widget
52
+ * @returns {PerseusWidget | null} the widget data if it exists, otherwise null
53
+ */
54
+ export declare function getWidgetFromWidgetMap(widgetId: string, widgetMap: PerseusWidgetsMap): PerseusWidget | null;
55
+ /**
56
+ * Get select widgets from a widget map.
57
+ * Useful for multi-items that needs to split
58
+ * one PerseusItem into several
59
+ *
60
+ * @param {ReadonlyArray<string>} widgetIds to extract
61
+ * @param {PerseusWidgetsMap} widgetMap to extract from
62
+ * @return {PerseusWidgetsMap} a new widget map with requested widgets
63
+ */
64
+ export declare function getWidgetsFromWidgetMap(widgetIds: ReadonlyArray<string>, widgetMap: PerseusWidgetsMap): PerseusWidgetsMap;
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import type { Coord } from "../interactive2/types";
3
3
  import type { PerseusGraphType, PerseusGraphTypeAngle, PerseusGraphTypePoint, PerseusGraphTypePolygon, PerseusGraphTypeSegment, PerseusInteractiveGraphWidgetOptions } from "../perseus-types";
4
4
  import type { Widget } from "../renderer";
5
- import type { PerseusScore, WidgetProps } from "../types";
5
+ import type { ChangeHandler, PerseusScore, WidgetProps } from "../types";
6
6
  import type { QuadraticCoefficient, SineCoefficient, Range } from "../util/geometry";
7
7
  type RenderProps = PerseusInteractiveGraphWidgetOptions;
8
8
  type Rubric = PerseusInteractiveGraphWidgetOptions;
@@ -81,7 +81,7 @@ declare class LegacyInteractiveGraph extends React.Component<Props, State> {
81
81
  createPointForPolygonType: (arg1: Coord, arg2: number) => any;
82
82
  updateCoordsFromPoints: () => void;
83
83
  clearCoords: () => void;
84
- onChange: (arg1: any) => void;
84
+ onChange: ChangeHandler;
85
85
  addPointControls: () => void;
86
86
  removePointControls: () => void;
87
87
  addSegmentControls: () => void;
@@ -155,7 +155,7 @@ declare class InteractiveGraph extends React.Component<Props, State> {
155
155
  static getRayEquationString(props: Props): string;
156
156
  static getPolygonEquationString(props: Props): string;
157
157
  static getAngleEquationString(props: Props): string;
158
- static validate(state: PerseusGraphType, rubric: Rubric, component: any): PerseusScore;
158
+ static validate(userInput: PerseusGraphType, rubric: Rubric, component: any): PerseusScore;
159
159
  static getUserInputFromProps(props: Props): PerseusGraphType;
160
160
  }
161
161
  declare const _default: Readonly<{
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export default function AxisArrows(): JSX.Element;
@@ -1,13 +1,23 @@
1
1
  /// <reference types="react" />
2
2
  import { vec } from "mafs";
3
+ import type { CollinearTuple } from "../../../../perseus-types";
3
4
  import type { Interval } from "mafs";
4
5
  interface Props {
5
6
  centerPoint: vec.Vector2;
6
7
  endPoints: [vec.Vector2, vec.Vector2];
7
- polygonPoints: readonly vec.Vector2[];
8
+ polygonLines: readonly CollinearTuple[];
8
9
  active: boolean;
9
10
  range: [Interval, Interval];
10
11
  showAngles: boolean;
11
12
  }
12
- export declare const Angle: ({ centerPoint, endPoints, range, polygonPoints, showAngles, }: Props) => JSX.Element | null;
13
+ export declare const Angle: ({ centerPoint, endPoints, range, polygonLines, showAngles, }: Props) => JSX.Element | null;
14
+ /**
15
+ * Determines if an angle is an inside (false) or outside (true) angle.
16
+ * They way, we know to flip the `largeArc` and `sweepArc` flags.
17
+ * Uses the priciple that a ray from a point inside a polygon will intersect
18
+ * with an odd number of lines, while a ray from a point outside the polygon
19
+ * will intersect with an even number of lines.
20
+ * https://stackoverflow.com/questions/217578/how-can-i-determine-whether-a-2d-point-is-within-a-polygon
21
+ */
22
+ export declare const shouldDrawArcOutside: (midpoint: vec.Vector2, vertex: vec.Vector2, range: [Interval, Interval], polygonLines: readonly CollinearTuple[]) => boolean;
13
23
  export {};
@@ -0,0 +1,7 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Wrapper with Mafs transform styles for SVG elements.
4
+ * Scales and translates the SVG element to match the Mafs view.
5
+ * Use if you do not need/want to use the hook in `use-transform.ts`.
6
+ */
7
+ export declare const MafsCssTransformWrapper: ({ children, }: React.PropsWithChildren<unknown>) => JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { TextProps } from "mafs";
2
+ import type { PropsWithChildren } from "react";
3
+ type Props = PropsWithChildren<Pick<TextProps, "x" | "y" | "attach" | "attachDistance">>;
4
+ export declare const TextLabel: ({ children, ...rest }: Props) => JSX.Element;
5
+ export declare const SvgDefs: () => JSX.Element;
6
+ export {};
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import type { PointGraphState, MafsGraphProps } from "../types";
3
+ type PointGraphProps = MafsGraphProps<PointGraphState>;
4
+ export declare function PointGraph(props: PointGraphProps): JSX.Element;
5
+ export {};
@@ -1,3 +1,4 @@
1
+ import type { CollinearTuple } from "../../../perseus-types";
1
2
  import type { Interval, vec } from "mafs";
2
3
  /**
3
4
  * Given two points, find the tips that extends through the points to the edge of the range.
@@ -5,3 +6,4 @@ import type { Interval, vec } from "mafs";
5
6
  * @param extendFrom - The point that the line extends from to the edge of the graph.
6
7
  */
7
8
  export declare const getRayIntersectionCoords: (collinearPoint: vec.Vector2, extendFrom: vec.Vector2, range: [Interval, Interval]) => [number, number];
9
+ export declare const getLines: (points: readonly vec.Vector2[]) => CollinearTuple[];
@@ -1,80 +1,21 @@
1
1
  import * as React from "react";
2
+ import type { InteractiveGraphProps } from "./types";
2
3
  import type { Widget } from "../../renderer";
3
4
  import "mafs/core.css";
4
5
  import "./mafs-styles.css";
5
- export declare const MafsGraph: React.ForwardRefExoticComponent<import("../..").PerseusInteractiveGraphWidgetOptions & {
6
- widgetId: string;
7
- alignment: string | null | undefined;
8
- static: boolean | null | undefined;
9
- problemNum: number | null | undefined;
10
- apiOptions: Readonly<Readonly<{
11
- isArticle?: boolean | undefined;
12
- onInputError?: ((widgetId: any, value: string, message?: string | null | undefined) => unknown) | undefined;
13
- onFocusChange?: ((newFocusPath: import("../..").FocusPath, oldFocusPath: import("../..").FocusPath, keypadHeight?: number | undefined, focusedElement?: HTMLElement | undefined) => unknown) | undefined;
14
- GroupMetadataEditor?: React.ComponentType<any> | undefined;
15
- showAlignmentOptions?: boolean | undefined;
16
- readOnly?: boolean | undefined;
17
- answerableCallback?: ((arg1: boolean) => unknown) | undefined;
18
- getAnotherHint?: (() => unknown) | undefined;
19
- interactionCallback?: ((widgetData: {
20
- [widgetId: string]: any;
21
- }) => void) | undefined;
22
- groupAnnotator?: ((groupNumber: number, widgetId: string) => React.ReactNode) | undefined;
23
- imagePlaceholder?: React.ReactNode;
24
- widgetPlaceholder?: React.ReactNode;
25
- baseElements?: {
26
- Link: React.ComponentType<any>;
27
- } | undefined;
28
- imagePreloader?: ((dimensions: import("../../types").Dimensions) => React.ReactNode) | undefined;
29
- trackInteraction?: ((args: {
30
- type: string;
31
- id: string;
32
- correct?: boolean | undefined;
33
- } & Partial<import("../../types").TrackingGradedGroupExtraArguments> & Partial<import("../../types").TrackingSequenceExtraArguments>) => void) | undefined;
34
- customKeypad?: boolean | undefined;
35
- nativeKeypadProxy?: ((blur: () => void) => import("@khanacademy/math-input").KeypadAPI) | undefined;
36
- isMobile?: boolean | undefined;
37
- setDrawingAreaAvailable?: ((arg1: boolean) => unknown) | undefined;
38
- useDraftEditor?: boolean | undefined;
39
- hintProgressColor?: string | undefined;
40
- canScrollPage?: boolean | undefined;
41
- inModal?: boolean | undefined;
42
- crossOutEnabled?: boolean | undefined;
43
- editorChangeDelay?: number | undefined;
44
- flags?: Record<string, boolean | Record<string, boolean>> | undefined;
45
- onWidgetStartProps?: ((widgets: import("../..").PerseusWidgetsMap) => import("../..").PerseusWidgetsMap) | undefined;
46
- }> & {
47
- GroupMetadataEditor: NonNullable<React.ComponentType<any> | undefined>;
48
- baseElements: {
49
- Link: React.ComponentType<any>;
50
- };
51
- canScrollPage: NonNullable<boolean | undefined>;
52
- crossOutEnabled: NonNullable<boolean | undefined>;
53
- editorChangeDelay: number;
54
- groupAnnotator: (groupNumber: number, widgetId: string) => React.ReactNode;
55
- inModal: NonNullable<boolean | undefined>;
56
- isArticle: NonNullable<boolean | undefined>;
57
- isMobile: NonNullable<boolean | undefined>;
58
- onFocusChange: (newFocusPath: import("../..").FocusPath, oldFocusPath: import("../..").FocusPath, keypadHeight?: number | undefined, focusedElement?: HTMLElement | undefined) => unknown;
59
- onInputError: (widgetId: any, value: string, message?: string | null | undefined) => unknown;
60
- readOnly: NonNullable<boolean | undefined>;
61
- setDrawingAreaAvailable: (arg1: boolean) => unknown;
62
- showAlignmentOptions: NonNullable<boolean | undefined>;
63
- useDraftEditor: NonNullable<boolean | undefined>;
64
- }>;
65
- keypadElement?: any;
66
- questionCompleted?: boolean | undefined;
67
- onFocus: (blurPath: import("../..").FocusPath) => void;
68
- onBlur: (blurPath: import("../..").FocusPath) => void;
69
- findWidgets: (arg1: import("../../types").FilterCriterion) => readonly any[];
70
- reviewModeRubric: import("../..").PerseusInteractiveGraphWidgetOptions;
71
- onChange: import("../..").ChangeHandler;
72
- trackInteraction: (extraData?: {} | undefined) => void;
73
- isLastUsedWidget: boolean;
74
- linterContext: import("@khanacademy/perseus-linter").LinterContextProps;
75
- containerSizeClass: import("../../util/sizing-utils").SizeClass;
76
- } & {
77
- children?: React.ReactNode;
78
- } & {
6
+ export type MafsWrapperProps = {
79
7
  box: [number, number];
8
+ backgroundImage?: InteractiveGraphProps["backgroundImage"];
9
+ graph: InteractiveGraphProps["graph"];
10
+ lockedFigures?: InteractiveGraphProps["lockedFigures"];
11
+ range: InteractiveGraphProps["range"];
12
+ snapStep: InteractiveGraphProps["snapStep"];
13
+ step: InteractiveGraphProps["step"];
14
+ gridStep: InteractiveGraphProps["gridStep"];
15
+ containerSizeClass: InteractiveGraphProps["containerSizeClass"];
16
+ markings: InteractiveGraphProps["markings"];
17
+ onChange: InteractiveGraphProps["onChange"];
18
+ };
19
+ export declare const MafsGraph: React.ForwardRefExoticComponent<MafsWrapperProps & {
20
+ children?: React.ReactNode;
80
21
  } & React.RefAttributes<Partial<Widget>>>;
@@ -1,3 +1,3 @@
1
- export declare const mafsSupportedGraphTypes: readonly ["segment", "linear", "linear-system", "ray", "polygon"];
1
+ export declare const mafsSupportedGraphTypes: readonly ["segment", "linear", "linear-system", "ray", "polygon", "point"];
2
2
  export type MafsSupportedGraphType = (typeof mafsSupportedGraphTypes)[number];
3
3
  export declare const trueForAllMafsSupportedGraphTypes: Record<MafsSupportedGraphType, true>;
@@ -1,13 +1,13 @@
1
1
  import type { vec } from "mafs";
2
- export type InteractiveGraphAction = MoveControlPoint | MoveLine | MoveAll;
2
+ export type InteractiveGraphAction = MoveControlPoint | MoveLine | MoveAll | MovePoint;
3
3
  export declare const MOVE_CONTROL_POINT = "move-control-point";
4
4
  export interface MoveControlPoint {
5
5
  type: typeof MOVE_CONTROL_POINT;
6
- itemIndex?: number;
6
+ itemIndex: number;
7
7
  pointIndex: number;
8
8
  destination: vec.Vector2;
9
9
  }
10
- export declare function moveControlPoint(pointIndex: number, destination: vec.Vector2, itemIndex?: number): MoveControlPoint;
10
+ export declare function moveControlPoint(pointIndex: number, destination: vec.Vector2, itemIndex: number): MoveControlPoint;
11
11
  export declare const MOVE_ALL = "move-all";
12
12
  export declare const MOVE_LINE = "move-line";
13
13
  interface MoveItem {
@@ -24,4 +24,11 @@ export interface MoveAll extends MoveItem {
24
24
  export declare function moveLine(itemIndex: number, delta: vec.Vector2): MoveLine;
25
25
  /** This action assumes a flat array of vectors */
26
26
  export declare const moveAll: (delta: vec.Vector2) => MoveAll;
27
+ export declare const MOVE_POINT = "move-point";
28
+ export interface MovePoint {
29
+ type: typeof MOVE_POINT;
30
+ index: number;
31
+ destination: vec.Vector2;
32
+ }
33
+ export declare function movePoint(index: number, destination: vec.Vector2): MovePoint;
27
34
  export {};
@@ -1,3 +1,3 @@
1
1
  import { type InteractiveGraphAction } from "./interactive-graph-action";
2
2
  import type { InteractiveGraphState } from "../types";
3
- export declare function interactiveGraphReducer<GraphState extends InteractiveGraphState>(state: Readonly<GraphState>, action: InteractiveGraphAction): GraphState;
3
+ export declare function interactiveGraphReducer(state: InteractiveGraphState, action: InteractiveGraphAction): InteractiveGraphState;
@@ -7,4 +7,4 @@ export declare function initializeGraphState(params: {
7
7
  snapStep: vec.Vector2;
8
8
  graph: PerseusGraphType;
9
9
  }): InteractiveGraphState;
10
- export declare function getGradableGraph<GraphType extends PerseusGraphType>(state: InteractiveGraphState, initialGraph: GraphType): GraphType;
10
+ export declare function getGradableGraph(state: InteractiveGraphState, initialGraph: PerseusGraphType): PerseusGraphType;
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import type { InteractiveGraphAction } from "./interactive-graph-action";
3
+ import type { InteractiveGraphState } from "../types";
4
+ export declare const GraphStateContext: React.Context<{
5
+ state: InteractiveGraphState;
6
+ dispatch: React.Dispatch<InteractiveGraphAction>;
7
+ }>;
8
+ export default function useGraphState(): {
9
+ state: InteractiveGraphState;
10
+ dispatch: React.Dispatch<InteractiveGraphAction>;
11
+ };
@@ -1,6 +1,7 @@
1
1
  import type { InteractiveGraphAction } from "./reducer/interactive-graph-action";
2
- import type { CollinearTuple, PerseusGraphType, PerseusGraphTypeLinearSystem, PerseusGraphTypePolygon, PerseusGraphTypeRay, PerseusGraphTypeSegment, PerseusInteractiveGraphWidgetOptions } from "../../perseus-types";
2
+ import type { PerseusGraphType, PerseusInteractiveGraphWidgetOptions } from "../../perseus-types";
3
3
  import type { WidgetProps } from "../../types";
4
+ import type { Coord } from "@khanacademy/perseus";
4
5
  import type { Interval, vec } from "mafs";
5
6
  export type InteractiveGraphProps = WidgetProps<PerseusInteractiveGraphWidgetOptions, PerseusInteractiveGraphWidgetOptions>;
6
7
  export type MafsGraphProps<T extends InteractiveGraphState> = {
@@ -12,17 +13,37 @@ export interface InitializeGraphStateParams<T extends PerseusGraphType> {
12
13
  range: [Interval, Interval];
13
14
  step: vec.Vector2;
14
15
  }
15
- export type InteractiveGraphState = SegmentGraphState | LinearGraphState | RayGraphState | PolygonGraphState;
16
+ export type InteractiveGraphState = SegmentGraphState | LinearGraphState | RayGraphState | PolygonGraphState | PointGraphState | CircleGraphState;
16
17
  export interface InteractiveGraphStateCommon {
17
18
  hasBeenInteractedWith: boolean;
18
19
  range: [Interval, Interval];
19
20
  snapStep: vec.Vector2;
20
21
  }
21
- export type SegmentGraphState = InteractiveGraphStateCommon & Omit<PerseusGraphTypeSegment, "numSegments">;
22
- export type LinearGraphState = InteractiveGraphStateCommon & Omit<PerseusGraphTypeLinearSystem, "type"> & {
22
+ export interface SegmentGraphState extends InteractiveGraphStateCommon {
23
+ type: "segment";
24
+ coords: PairOfPoints[];
25
+ }
26
+ export interface LinearGraphState extends InteractiveGraphStateCommon {
23
27
  type: "linear" | "linear-system";
24
- };
25
- export type RayGraphState = InteractiveGraphStateCommon & Omit<PerseusGraphTypeRay, "coords"> & {
26
- coords: readonly CollinearTuple[];
27
- };
28
- export type PolygonGraphState = InteractiveGraphStateCommon & PerseusGraphTypePolygon;
28
+ coords: PairOfPoints[];
29
+ }
30
+ export interface PointGraphState extends InteractiveGraphStateCommon {
31
+ type: "point";
32
+ coords: Coord[];
33
+ }
34
+ export interface RayGraphState extends InteractiveGraphStateCommon {
35
+ type: "ray";
36
+ coords: PairOfPoints[];
37
+ }
38
+ export interface PolygonGraphState extends InteractiveGraphStateCommon {
39
+ type: "polygon";
40
+ showAngles: boolean;
41
+ showSides: boolean;
42
+ coords: Coord[];
43
+ }
44
+ export interface CircleGraphState extends InteractiveGraphStateCommon {
45
+ type: "circle";
46
+ center: Coord;
47
+ radius: number;
48
+ }
49
+ export type PairOfPoints = [Coord, Coord];
@@ -5,5 +5,5 @@ import type { PerseusInteractiveGraphWidgetOptions } from "../../perseus-types";
5
5
  * https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
6
6
  */
7
7
  export declare const TARGET_SIZE = 44;
8
- export declare const normalizePoints: <A extends readonly Coord[]>(range: PerseusInteractiveGraphWidgetOptions["range"], step: PerseusInteractiveGraphWidgetOptions["step"], coordsList: A, noSnap?: boolean) => A;
9
- export declare const normalizeCoords: <A extends readonly Coord[]>(coordsList: A, ranges: PerseusInteractiveGraphWidgetOptions["range"]) => A;
8
+ export declare const normalizePoints: <A extends Coord[]>(range: PerseusInteractiveGraphWidgetOptions["range"], step: PerseusInteractiveGraphWidgetOptions["step"], coordsList: A, noSnap?: boolean) => A;
9
+ export declare const normalizeCoords: <A extends Coord[]>(coordsList: A, ranges: PerseusInteractiveGraphWidgetOptions["range"]) => A;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Core Perseus API (includes renderers and widgets)",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "20.8.1",
6
+ "version": "21.1.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },