@khanacademy/perseus 65.4.0 → 65.5.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.
@@ -1,15 +1,5 @@
1
- import { vec } from "mafs";
2
1
  import React from "react";
3
2
  import type { I18nContextType } from "../../../components/i18n-context";
4
- import type { GraphConfig } from "../reducer/use-graph-config";
5
- import type { GraphDimensions } from "../types";
6
- export declare const fontSize = 14;
7
3
  export default function AxisLabels({ i18n }: {
8
4
  i18n: I18nContextType;
9
5
  }): React.JSX.Element;
10
- export declare const getLabelTransform: (labelLocation: GraphConfig["labelLocation"]) => {
11
- xLabelTransform: string;
12
- yLabelTransform: string;
13
- };
14
- export declare const clampLabelPosition: (labelPosition: vec.Vector2, graphInfo: GraphDimensions) => vec.Vector2;
15
- export declare const getLabelPosition: (graphInfo: GraphDimensions, labelLocation: GraphConfig["labelLocation"]) => vec.Vector2[];
@@ -1,7 +1,2 @@
1
1
  import * as React from "react";
2
- import type { Interval } from "mafs";
3
- export declare const shouldShowLabel: (currentTick: number, range: [Interval, Interval], tickStep: number) => boolean;
4
- export declare function generateTickLocations(tickStep: number, min: number, max: number): number[];
5
- export declare const countSignificantDecimals: (number: number) => number;
6
- export declare function divideByAndShowPi(value: number): string;
7
2
  export declare const AxisTicks: () => React.JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { vec } from "mafs";
2
+ import type { GraphConfig } from "../reducer/use-graph-config";
3
+ import type { GraphDimensions } from "../types";
4
+ import type { Interval } from "mafs";
5
+ export declare const fontSize = 14;
6
+ export declare const clampLabelPosition: (labelPosition: vec.Vector2, graphInfo: GraphDimensions) => vec.Vector2;
7
+ export declare const getLabelTransform: (labelLocation: GraphConfig["labelLocation"]) => {
8
+ xLabelTransform: string;
9
+ yLabelTransform: string;
10
+ };
11
+ /**
12
+ * Calculate the maximum number of digits needed to display tick labels on the y-axis.
13
+ * This accounts for both the integer part of the range values and decimal places in the tick step.
14
+ */
15
+ export declare const calculateMaxDigitsInRange: (range: [number, number], tickStep: number) => number;
16
+ export declare const getLabelPosition: (graphInfo: GraphDimensions, labelLocation: GraphConfig["labelLocation"], tickStep: GraphConfig["tickStep"]) => vec.Vector2[];
17
+ export declare const shouldShowLabel: (currentTick: number, range: [Interval, Interval], tickStep: number) => boolean;
18
+ export declare function generateTickLocations(tickStep: number, min: number, max: number): number[];
19
+ export declare const countSignificantDecimals: (number: number) => number;
20
+ export declare function divideByAndShowPi(value: number): string;
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import type { InteractiveGraphAction } from "./reducer/interactive-graph-action";
3
3
  import type { InteractiveGraphState, InteractiveGraphProps } from "./types";
4
- import type { vec } from "mafs";
5
4
  import "mafs/core.css";
6
5
  import "./mafs-styles.css";
7
6
  export type MafsGraphProps = {
@@ -24,7 +23,3 @@ export type MafsGraphProps = {
24
23
  static: boolean | null | undefined;
25
24
  };
26
25
  export declare const MafsGraph: (props: MafsGraphProps) => React.JSX.Element;
27
- export declare const calculateNestedSVGCoords: (range: vec.Vector2[], width: number, height: number) => {
28
- viewboxX: number;
29
- viewboxY: number;
30
- };
@@ -34,3 +34,7 @@ export declare const mathOnlyParser: import("@khanacademy/simple-markdown").Pars
34
34
  */
35
35
  export declare function replaceOutsideTeX(mathString: string): string;
36
36
  export declare function getBaseMafsGraphPropsForTests(): MafsGraphProps;
37
+ export declare const calculateNestedSVGCoords: (range: vec.Vector2[], width: number, height: number) => {
38
+ viewboxX: number;
39
+ viewboxY: number;
40
+ };
@@ -16,7 +16,7 @@ export type RenderProps = {
16
16
  choiceStates?: ChoiceState[];
17
17
  values?: boolean[];
18
18
  };
19
- type Props = WidgetProps<RenderProps, PerseusRadioUserInput, PerseusRadioRubric>;
19
+ export type Props = WidgetProps<RenderProps, PerseusRadioUserInput, PerseusRadioRubric>;
20
20
  type DefaultProps = Required<Pick<Props, "choices" | "multipleSelect" | "countChoices" | "deselectEnabled" | "linterContext" | "showSolutions">>;
21
21
  export type RadioChoiceWithMetadata = PerseusRadioChoice & {
22
22
  originalIndex: number;
@@ -27,13 +27,16 @@ declare class Radio extends React.Component<Props> implements Widget {
27
27
  context: React.ContextType<typeof PerseusI18nContext>;
28
28
  focusFunction: FocusFunction;
29
29
  static defaultProps: DefaultProps;
30
- static getUserInputFromProps(props: Props, unshuffle?: boolean): PerseusRadioUserInput;
31
30
  _renderRenderer: (content?: string) => React.ReactElement;
32
31
  focus(choiceIndex?: number | null): boolean;
33
32
  registerFocusFunction(fun: FocusFunction): void;
34
33
  updateChoices: (newValueLists: Readonly<{
35
34
  checked: ReadonlyArray<boolean>;
36
35
  }>) => void;
36
+ /**
37
+ * TODO: remove this when everything is pulling from Renderer state
38
+ * @deprecated get user input from Renderer state
39
+ */
37
40
  getUserInput(): PerseusRadioUserInput;
38
41
  getPromptJSON(): RadioPromptJSON;
39
42
  render(): React.ReactNode;
@@ -29,7 +29,10 @@ export interface RadioChoiceWithMetadata extends PerseusRadioChoice {
29
29
  */
30
30
  declare class Radio extends React.Component<Props> implements Widget {
31
31
  static defaultProps: DefaultProps;
32
- static getUserInputFromProps(props: Props, unshuffle?: boolean): PerseusRadioUserInput;
32
+ /**
33
+ * TODO: remove this when everything is pulling from Renderer state
34
+ * @deprecated get user input from Renderer state
35
+ */
33
36
  getUserInput(): PerseusRadioUserInput;
34
37
  getPromptJSON(): RadioPromptJSON;
35
38
  render(): React.ReactNode;
@@ -1,18 +1,21 @@
1
1
  import Radio from "./radio.ff";
2
+ import { getUserInputFromSerializedState } from "./util";
2
3
  import type { RenderProps } from "./radio-component";
3
4
  import type { PerseusStrings } from "../../strings";
4
- import type { PerseusRadioWidgetOptions } from "@khanacademy/perseus-core";
5
+ import type { PerseusRadioUserInput, PerseusRadioWidgetOptions, RadioPublicWidgetOptions } from "@khanacademy/perseus-core";
6
+ declare function getStartUserInput(options: RadioPublicWidgetOptions): PerseusRadioUserInput;
5
7
  declare const _default: {
6
8
  name: string;
7
9
  displayName: string;
8
10
  widget: typeof Radio;
9
11
  transform: (widgetOptions: PerseusRadioWidgetOptions, strings: PerseusStrings, problemNum?: number | null) => RenderProps;
10
12
  staticTransform: (widgetOptions: PerseusRadioWidgetOptions, strings: PerseusStrings, problemNum?: number | null) => RenderProps;
13
+ getStartUserInput: typeof getStartUserInput;
11
14
  version: import("@khanacademy/perseus-core").Version | undefined;
12
15
  isLintable: true;
13
16
  /**
14
17
  * @deprecated - do not use in new code.
15
18
  */
16
- getUserInputFromSerializedState: typeof import("./radio-component").default.getUserInputFromProps;
19
+ getUserInputFromSerializedState: typeof getUserInputFromSerializedState;
17
20
  };
18
21
  export default _default;
@@ -1,9 +1,13 @@
1
+ import { type PerseusRadioRubric, type PerseusRadioUserInput } from "@khanacademy/perseus-core";
1
2
  import * as React from "react";
2
3
  import RadioOld from "./radio-component";
3
4
  import type { RenderProps } from "./radio-component";
4
- import type { WidgetProps } from "../../types";
5
- import type { PerseusRadioRubric, PerseusRadioUserInput } from "@khanacademy/perseus-core";
5
+ import type { ChoiceState, WidgetProps } from "../../types";
6
6
  type Props = WidgetProps<RenderProps, PerseusRadioUserInput, PerseusRadioRubric>;
7
+ type ChoiceStateWithoutSelected = Omit<ChoiceState, "selected">;
8
+ type State = {
9
+ choiceStates: ChoiceStateWithoutSelected[];
10
+ };
7
11
  /**
8
12
  * This is a wrapper around the old radio widget that allows us to
9
13
  * conditionally render the new radio widget when the feature flag is on.
@@ -16,7 +20,93 @@ type Props = WidgetProps<RenderProps, PerseusRadioUserInput, PerseusRadioRubric>
16
20
  declare class Radio extends RadioOld {
17
21
  ffIsOn: boolean;
18
22
  radioRef: React.RefObject<RadioOld>;
23
+ state: State;
19
24
  constructor(props: Props);
25
+ /**
26
+ * @deprecated and likely very broken API
27
+ * [LEMS-3185] do not trust serializedState/restoreSerializedState
28
+ */
29
+ getSerializedState(): {
30
+ numCorrect: number;
31
+ hasNoneOfTheAbove?: boolean;
32
+ multipleSelect?: boolean;
33
+ countChoices?: boolean;
34
+ deselectEnabled?: boolean;
35
+ choices: import("./radio-component").RadioChoiceWithMetadata[];
36
+ selectedChoices: import("@khanacademy/perseus-core").PerseusRadioChoice["correct"][];
37
+ showSolutions?: import("@khanacademy/perseus-core").ShowSolutions;
38
+ choiceStates?: ChoiceState[];
39
+ values?: boolean[];
40
+ reviewModeRubric?: PerseusRadioRubric | null | undefined;
41
+ trackInteraction: (extraData?: Empty | undefined) => void;
42
+ widgetId: string;
43
+ alignment: string | null | undefined;
44
+ static: boolean | null | undefined;
45
+ problemNum: number | null | undefined;
46
+ apiOptions: Readonly<Readonly<{
47
+ isArticle?: boolean;
48
+ onFocusChange?: (newFocusPath: import("../..").FocusPath, oldFocusPath: import("../..").FocusPath, keypadHeight?: number, focusedElement?: HTMLElement) => unknown;
49
+ GroupMetadataEditor?: React.ComponentType<any>;
50
+ showAlignmentOptions?: boolean;
51
+ readOnly?: boolean;
52
+ answerableCallback?: (arg1: boolean) => unknown;
53
+ getAnotherHint?: () => unknown;
54
+ interactionCallback?: (widgetData: {
55
+ [widgetId: string]: any;
56
+ }) => void;
57
+ groupAnnotator?: (groupNumber: number, widgetId: string) => React.ReactNode;
58
+ imagePlaceholder?: React.ReactNode;
59
+ widgetPlaceholder?: React.ReactNode;
60
+ baseElements?: {
61
+ Link: React.ComponentType<any>;
62
+ };
63
+ imagePreloader?: (dimensions: import("../../types").Dimensions) => React.ReactNode;
64
+ trackInteraction?: (args: {
65
+ type: string;
66
+ id: string;
67
+ correct?: boolean;
68
+ } & Partial<import("../../types").TrackingGradedGroupExtraArguments> & Partial<{
69
+ visible: number;
70
+ }>) => void;
71
+ customKeypad?: boolean;
72
+ nativeKeypadProxy?: (blur: () => void) => import("@khanacademy/math-input").KeypadAPI;
73
+ isMobile?: boolean;
74
+ isMobileApp?: boolean;
75
+ setDrawingAreaAvailable?: (arg1: boolean) => unknown;
76
+ hintProgressColor?: string;
77
+ canScrollPage?: boolean;
78
+ editorChangeDelay?: number;
79
+ flags?: Record<"new-radio-widget", boolean>;
80
+ onWidgetStartProps?: (widgets: import("@khanacademy/perseus-core").PerseusWidgetsMap) => void;
81
+ }> & {
82
+ baseElements: NonNullable<import("../..").APIOptions["baseElements"]>;
83
+ canScrollPage: NonNullable<import("../..").APIOptions["canScrollPage"]>;
84
+ editorChangeDelay: NonNullable<import("../..").APIOptions["editorChangeDelay"]>;
85
+ groupAnnotator: NonNullable<import("../..").APIOptions["groupAnnotator"]>;
86
+ isArticle: NonNullable<import("../..").APIOptions["isArticle"]>;
87
+ isMobile: NonNullable<import("../..").APIOptions["isMobile"]>;
88
+ isMobileApp: NonNullable<import("../..").APIOptions["isMobileApp"]>;
89
+ onFocusChange: NonNullable<import("../..").APIOptions["onFocusChange"]>;
90
+ readOnly: NonNullable<import("../..").APIOptions["readOnly"]>;
91
+ setDrawingAreaAvailable: NonNullable<import("../..").APIOptions["setDrawingAreaAvailable"]>;
92
+ showAlignmentOptions: NonNullable<import("../..").APIOptions["showAlignmentOptions"]>;
93
+ }>;
94
+ keypadElement?: any;
95
+ questionCompleted?: boolean;
96
+ onFocus: (blurPath: import("../..").FocusPath) => void;
97
+ onBlur: (blurPath: import("../..").FocusPath) => void;
98
+ findWidgets: (criterion: import("../../types").FilterCriterion) => ReadonlyArray<import("../../types").Widget>;
99
+ reviewMode: boolean;
100
+ onChange: import("../..").ChangeHandler;
101
+ handleUserInput: (newUserInput: PerseusRadioUserInput, cb?: () => void, silent?: boolean) => void;
102
+ isLastUsedWidget: boolean;
103
+ linterContext: import("@khanacademy/perseus-linter").LinterContextProps;
104
+ containerSizeClass: import("../../util/sizing-utils").SizeClass;
105
+ };
106
+ _handleChange(arg: {
107
+ choiceStates?: ChoiceState[];
108
+ }): void;
109
+ _mergePropsAndState(): Props;
20
110
  focus(choiceIndex?: number | null): boolean;
21
111
  render(): React.ReactNode;
22
112
  }
@@ -1,7 +1,10 @@
1
+ import type { Props } from "./radio-component";
1
2
  import type { PerseusStrings } from "../../strings";
3
+ import type { PerseusRadioUserInput } from "@khanacademy/perseus-core";
2
4
  /**
3
5
  * Given a choice's position in the radio widget, return the corresponding
4
6
  * "choice letter". (For example, in English, `getChoiceLetter(0)` is "A",
5
7
  * `getChoiceLetter(1)` is "B", etc.)
6
8
  */
7
9
  export declare function getChoiceLetter(pos: number, strings: PerseusStrings): string;
10
+ export declare function getUserInputFromSerializedState(props: Props, unshuffle?: boolean): PerseusRadioUserInput;
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": "65.4.0",
6
+ "version": "65.5.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -42,37 +42,37 @@
42
42
  "tiny-invariant": "1.3.1",
43
43
  "uuid": "^10.0.0",
44
44
  "@khanacademy/kas": "2.0.9",
45
- "@khanacademy/keypad-context": "3.0.23",
46
- "@khanacademy/kmath": "2.0.23",
47
- "@khanacademy/math-input": "26.0.12",
48
- "@khanacademy/perseus-core": "16.1.1",
49
- "@khanacademy/perseus-linter": "4.0.10",
50
- "@khanacademy/perseus-score": "7.1.10",
45
+ "@khanacademy/keypad-context": "3.0.24",
46
+ "@khanacademy/kmath": "2.0.24",
47
+ "@khanacademy/math-input": "26.0.13",
48
+ "@khanacademy/perseus-core": "17.0.0",
49
+ "@khanacademy/perseus-linter": "4.0.11",
50
+ "@khanacademy/perseus-score": "7.1.11",
51
51
  "@khanacademy/perseus-utils": "2.0.5",
52
- "@khanacademy/pure-markdown": "2.0.9",
53
- "@khanacademy/simple-markdown": "2.0.9"
52
+ "@khanacademy/pure-markdown": "2.0.10",
53
+ "@khanacademy/simple-markdown": "2.0.10"
54
54
  },
55
55
  "devDependencies": {
56
- "@khanacademy/wonder-blocks-banner": "4.2.0",
57
- "@khanacademy/wonder-blocks-button": "10.2.4",
58
- "@khanacademy/wonder-blocks-clickable": "7.1.9",
56
+ "@khanacademy/wonder-blocks-banner": "4.2.4",
57
+ "@khanacademy/wonder-blocks-button": "10.2.8",
58
+ "@khanacademy/wonder-blocks-clickable": "7.1.12",
59
59
  "@khanacademy/wonder-blocks-core": "12.3.0",
60
60
  "@khanacademy/wonder-blocks-data": "14.1.4",
61
- "@khanacademy/wonder-blocks-dropdown": "10.1.10",
62
- "@khanacademy/wonder-blocks-form": "7.1.22",
63
- "@khanacademy/wonder-blocks-icon-button": "10.3.3",
64
- "@khanacademy/wonder-blocks-icon": "5.2.3",
65
- "@khanacademy/wonder-blocks-labeled-field": "3.0.17",
66
- "@khanacademy/wonder-blocks-layout": "3.1.20",
67
- "@khanacademy/wonder-blocks-link": "9.1.9",
68
- "@khanacademy/wonder-blocks-pill": "3.1.22",
69
- "@khanacademy/wonder-blocks-popover": "6.1.11",
70
- "@khanacademy/wonder-blocks-progress-spinner": "3.1.20",
71
- "@khanacademy/wonder-blocks-switch": "3.3.2",
72
- "@khanacademy/wonder-blocks-tokens": "11.1.0",
73
- "@khanacademy/wonder-blocks-tooltip": "4.1.25",
74
- "@khanacademy/wonder-blocks-typography": "4.2.4",
75
- "@khanacademy/wonder-stuff-core": "1.5.4",
61
+ "@khanacademy/wonder-blocks-dropdown": "10.2.2",
62
+ "@khanacademy/wonder-blocks-form": "7.1.26",
63
+ "@khanacademy/wonder-blocks-icon-button": "10.3.7",
64
+ "@khanacademy/wonder-blocks-icon": "5.2.6",
65
+ "@khanacademy/wonder-blocks-labeled-field": "3.0.21",
66
+ "@khanacademy/wonder-blocks-layout": "3.1.23",
67
+ "@khanacademy/wonder-blocks-link": "9.1.12",
68
+ "@khanacademy/wonder-blocks-pill": "3.1.27",
69
+ "@khanacademy/wonder-blocks-popover": "6.1.15",
70
+ "@khanacademy/wonder-blocks-progress-spinner": "3.1.23",
71
+ "@khanacademy/wonder-blocks-switch": "3.3.5",
72
+ "@khanacademy/wonder-blocks-tokens": "11.2.1",
73
+ "@khanacademy/wonder-blocks-tooltip": "4.1.29",
74
+ "@khanacademy/wonder-blocks-typography": "4.2.8",
75
+ "@khanacademy/wonder-stuff-core": "1.5.5",
76
76
  "@phosphor-icons/core": "2.0.2",
77
77
  "@popperjs/core": "2.10.2",
78
78
  "aphrodite": "1.2.5",
@@ -90,26 +90,26 @@
90
90
  "raphael": "1.5.4"
91
91
  },
92
92
  "peerDependencies": {
93
- "@khanacademy/wonder-blocks-banner": "^4.2.0",
94
- "@khanacademy/wonder-blocks-button": "^10.2.4",
95
- "@khanacademy/wonder-blocks-clickable": "^7.1.9",
93
+ "@khanacademy/wonder-blocks-banner": "^4.2.4",
94
+ "@khanacademy/wonder-blocks-button": "^10.2.8",
95
+ "@khanacademy/wonder-blocks-clickable": "^7.1.12",
96
96
  "@khanacademy/wonder-blocks-core": "^12.3.0",
97
97
  "@khanacademy/wonder-blocks-data": "^14.1.4",
98
- "@khanacademy/wonder-blocks-dropdown": "^10.1.10",
99
- "@khanacademy/wonder-blocks-form": "^7.1.22",
100
- "@khanacademy/wonder-blocks-icon": "^5.2.3",
101
- "@khanacademy/wonder-blocks-icon-button": "^10.3.3",
102
- "@khanacademy/wonder-blocks-labeled-field": "^3.0.17",
103
- "@khanacademy/wonder-blocks-layout": "^3.1.20",
104
- "@khanacademy/wonder-blocks-link": "^9.1.9",
105
- "@khanacademy/wonder-blocks-pill": "^3.1.22",
106
- "@khanacademy/wonder-blocks-popover": "^6.1.11",
107
- "@khanacademy/wonder-blocks-progress-spinner": "^3.1.20",
108
- "@khanacademy/wonder-blocks-switch": "^3.3.2",
109
- "@khanacademy/wonder-blocks-tokens": "^11.1.0",
110
- "@khanacademy/wonder-blocks-tooltip": "^4.1.25",
111
- "@khanacademy/wonder-blocks-typography": "^4.2.4",
112
- "@khanacademy/wonder-stuff-core": "^1.5.4",
98
+ "@khanacademy/wonder-blocks-dropdown": "^10.2.2",
99
+ "@khanacademy/wonder-blocks-form": "^7.1.26",
100
+ "@khanacademy/wonder-blocks-icon": "^5.2.6",
101
+ "@khanacademy/wonder-blocks-icon-button": "^10.3.7",
102
+ "@khanacademy/wonder-blocks-labeled-field": "^3.0.21",
103
+ "@khanacademy/wonder-blocks-layout": "^3.1.23",
104
+ "@khanacademy/wonder-blocks-link": "^9.1.12",
105
+ "@khanacademy/wonder-blocks-pill": "^3.1.27",
106
+ "@khanacademy/wonder-blocks-popover": "^6.1.15",
107
+ "@khanacademy/wonder-blocks-progress-spinner": "^3.1.23",
108
+ "@khanacademy/wonder-blocks-switch": "^3.3.5",
109
+ "@khanacademy/wonder-blocks-tokens": "^11.2.1",
110
+ "@khanacademy/wonder-blocks-tooltip": "^4.1.29",
111
+ "@khanacademy/wonder-blocks-typography": "^4.2.8",
112
+ "@khanacademy/wonder-stuff-core": "^1.5.5",
113
113
  "@phosphor-icons/core": "^2.0.2",
114
114
  "@popperjs/core": "^2.10.2",
115
115
  "aphrodite": "^1.2.5",