@khanacademy/perseus 61.2.0 → 62.0.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.
- package/dist/es/index.js +18 -15
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +18 -14
- package/dist/index.js.map +1 -1
- package/dist/server-item-renderer.d.ts +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/widgets/expression/expression.d.ts +2 -0
- package/dist/widgets/grapher/grapher.d.ts +4 -7
- package/dist/widgets/numeric-input/numeric-input.d.ts +2 -0
- package/dist/widgets/phet-simulation/phet-simulation.d.ts +20 -0
- package/dist/widgets/radio/base-radio.new.d.ts +1 -3
- package/dist/widgets/radio/choice-none-above.new.d.ts +1 -1
- package/dist/widgets/radio/{radio-component.new.d.ts → radio.class.new.d.ts} +7 -20
- package/dist/widgets/radio/radio.ff.d.ts +1 -2
- package/dist/widgets/radio/radio.new.d.ts +30 -0
- package/dist/widgets.d.ts +15 -15
- package/package.json +11 -11
|
@@ -144,6 +144,7 @@ declare const ref: React.ForwardRefExoticComponent<Omit<Pick<SharedRendererProps
|
|
|
144
144
|
customKeypad?: boolean;
|
|
145
145
|
nativeKeypadProxy?: (blur: () => void) => KeypadAPI;
|
|
146
146
|
isMobile?: boolean;
|
|
147
|
+
isMobileApp?: boolean;
|
|
147
148
|
setDrawingAreaAvailable?: (arg1: boolean) => unknown;
|
|
148
149
|
hintProgressColor?: string;
|
|
149
150
|
canScrollPage?: boolean;
|
package/dist/types.d.ts
CHANGED
|
@@ -186,6 +186,8 @@ export type APIOptions = Readonly<{
|
|
|
186
186
|
nativeKeypadProxy?: (blur: () => void) => KeypadAPI;
|
|
187
187
|
/** Indicates whether or not to use mobile styling. */
|
|
188
188
|
isMobile?: boolean;
|
|
189
|
+
/** Indicates whether or not to use mobile app styling. */
|
|
190
|
+
isMobileApp?: boolean;
|
|
189
191
|
/** A function, called with a bool indicating whether use of the
|
|
190
192
|
* drawing area (scratchpad) should be allowed/disallowed.
|
|
191
193
|
*
|
|
@@ -332,6 +334,7 @@ export type APIOptionsWithDefaults = Readonly<APIOptions & {
|
|
|
332
334
|
groupAnnotator: NonNullable<APIOptions["groupAnnotator"]>;
|
|
333
335
|
isArticle: NonNullable<APIOptions["isArticle"]>;
|
|
334
336
|
isMobile: NonNullable<APIOptions["isMobile"]>;
|
|
337
|
+
isMobileApp: NonNullable<APIOptions["isMobileApp"]>;
|
|
335
338
|
onFocusChange: NonNullable<APIOptions["onFocusChange"]>;
|
|
336
339
|
readOnly: NonNullable<APIOptions["readOnly"]>;
|
|
337
340
|
setDrawingAreaAvailable: NonNullable<APIOptions["setDrawingAreaAvailable"]>;
|
|
@@ -115,6 +115,7 @@ declare const _default: {
|
|
|
115
115
|
customKeypad?: boolean;
|
|
116
116
|
nativeKeypadProxy?: (blur: () => void) => import("@khanacademy/math-input").KeypadAPI;
|
|
117
117
|
isMobile?: boolean;
|
|
118
|
+
isMobileApp?: boolean;
|
|
118
119
|
setDrawingAreaAvailable?: (arg1: boolean) => unknown;
|
|
119
120
|
hintProgressColor?: string;
|
|
120
121
|
canScrollPage?: boolean;
|
|
@@ -130,6 +131,7 @@ declare const _default: {
|
|
|
130
131
|
groupAnnotator: NonNullable<import("../..").APIOptions["groupAnnotator"]>;
|
|
131
132
|
isArticle: NonNullable<import("../..").APIOptions["isArticle"]>;
|
|
132
133
|
isMobile: NonNullable<import("../..").APIOptions["isMobile"]>;
|
|
134
|
+
isMobileApp: NonNullable<import("../..").APIOptions["isMobileApp"]>;
|
|
133
135
|
onFocusChange: NonNullable<import("../..").APIOptions["onFocusChange"]>;
|
|
134
136
|
readOnly: NonNullable<import("../..").APIOptions["readOnly"]>;
|
|
135
137
|
setDrawingAreaAvailable: NonNullable<import("../..").APIOptions["setDrawingAreaAvailable"]>;
|
|
@@ -4,17 +4,14 @@ import type { Coord } from "../../interactive2/types";
|
|
|
4
4
|
import type { Widget, WidgetProps } from "../../types";
|
|
5
5
|
import type { GridDimensions } from "../../util";
|
|
6
6
|
import type { GrapherPromptJSON } from "../../widget-ai-utils/grapher/grapher-ai-utils";
|
|
7
|
-
import type {
|
|
7
|
+
import type { PerseusGrapherWidgetOptions, PerseusGrapherUserInput, GrapherPublicWidgetOptions } from "@khanacademy/perseus-core";
|
|
8
8
|
import type { PropsFor } from "@khanacademy/wonder-blocks-core";
|
|
9
|
-
type RenderProps = {
|
|
10
|
-
|
|
11
|
-
graph: PerseusGrapherWidgetOptions["graph"];
|
|
12
|
-
plot?: any;
|
|
9
|
+
type RenderProps = Pick<GrapherPublicWidgetOptions, "availableTypes" | "graph"> & {
|
|
10
|
+
plot?: PerseusGrapherWidgetOptions["correct"];
|
|
13
11
|
};
|
|
14
12
|
type ExternalProps = WidgetProps<RenderProps>;
|
|
15
13
|
type Props = ExternalProps & {
|
|
16
14
|
plot: NonNullable<RenderProps["plot"]>;
|
|
17
|
-
markings: MarkingsType;
|
|
18
15
|
};
|
|
19
16
|
type DefaultProps = {
|
|
20
17
|
plot: RenderProps["plot"];
|
|
@@ -43,7 +40,7 @@ declare const _default: {
|
|
|
43
40
|
displayName: string;
|
|
44
41
|
hidden: true;
|
|
45
42
|
widget: typeof Grapher;
|
|
46
|
-
transform: (arg1:
|
|
43
|
+
transform: (arg1: GrapherPublicWidgetOptions) => RenderProps;
|
|
47
44
|
staticTransform: (arg1: PerseusGrapherWidgetOptions) => RenderProps;
|
|
48
45
|
};
|
|
49
46
|
export default _default;
|
|
@@ -36,6 +36,7 @@ export declare const NumericInputComponent: React.ForwardRefExoticComponent<impo
|
|
|
36
36
|
customKeypad?: boolean;
|
|
37
37
|
nativeKeypadProxy?: (blur: () => void) => import("@khanacademy/math-input").KeypadAPI;
|
|
38
38
|
isMobile?: boolean;
|
|
39
|
+
isMobileApp?: boolean;
|
|
39
40
|
setDrawingAreaAvailable?: (arg1: boolean) => unknown;
|
|
40
41
|
hintProgressColor?: string;
|
|
41
42
|
canScrollPage?: boolean;
|
|
@@ -51,6 +52,7 @@ export declare const NumericInputComponent: React.ForwardRefExoticComponent<impo
|
|
|
51
52
|
groupAnnotator: NonNullable<import("../..").APIOptions["groupAnnotator"]>;
|
|
52
53
|
isArticle: NonNullable<import("../..").APIOptions["isArticle"]>;
|
|
53
54
|
isMobile: NonNullable<import("../..").APIOptions["isMobile"]>;
|
|
55
|
+
isMobileApp: NonNullable<import("../..").APIOptions["isMobileApp"]>;
|
|
54
56
|
onFocusChange: NonNullable<import("../..").APIOptions["onFocusChange"]>;
|
|
55
57
|
readOnly: NonNullable<import("../..").APIOptions["readOnly"]>;
|
|
56
58
|
setDrawingAreaAvailable: NonNullable<import("../..").APIOptions["setDrawingAreaAvailable"]>;
|
|
@@ -15,6 +15,7 @@ type State = {
|
|
|
15
15
|
kind: "warning" | "critical";
|
|
16
16
|
} | null;
|
|
17
17
|
url: URL | null;
|
|
18
|
+
isFullScreen: boolean;
|
|
18
19
|
};
|
|
19
20
|
export declare class PhetSimulation extends React.Component<Props, State> implements Widget {
|
|
20
21
|
static contextType: React.Context<import("../../components/i18n-context").I18nContextType>;
|
|
@@ -31,6 +32,25 @@ export declare class PhetSimulation extends React.Component<Props, State> implem
|
|
|
31
32
|
displayLoadFailure: () => void;
|
|
32
33
|
updateSimState(urlString: string): Promise<void>;
|
|
33
34
|
showLocaleWarning(url: URL): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Mobile App Fullscreen Implementation
|
|
37
|
+
*
|
|
38
|
+
* The mobile app environment doesn't support the standard browser fullscreen API.
|
|
39
|
+
* Instead, we implement a "fake" fullscreen mode with the following approach:
|
|
40
|
+
*
|
|
41
|
+
* 1. When fullscreen is toggled, we use a fixed position container that covers
|
|
42
|
+
* almost the entire viewport (appFullScreenWidgetContainer)
|
|
43
|
+
* 2. We leave space at the bottom for the mobile app's Check Answer bar (66px)
|
|
44
|
+
* 3. We position a close button in the top-right corner for exiting fullscreen
|
|
45
|
+
* 4. The iframe container expands to fill the available space
|
|
46
|
+
*
|
|
47
|
+
* This differs from the web implementation which uses the browser's
|
|
48
|
+
* native Fullscreen API via requestFullscreen().
|
|
49
|
+
*
|
|
50
|
+
* Note: Unfortunately, full screen is not supported in iOS mobile web due to
|
|
51
|
+
* the lack of support for the Fullscreen API.
|
|
52
|
+
*/
|
|
53
|
+
toggleFullScreen: () => void;
|
|
34
54
|
render(): React.ReactNode;
|
|
35
55
|
}
|
|
36
56
|
export declare const makeSafeUrl: (urlString: string, locale: string) => URL | null;
|
|
@@ -16,7 +16,6 @@ export type ChoiceType = {
|
|
|
16
16
|
revealNoneOfTheAbove: boolean;
|
|
17
17
|
disabled: boolean;
|
|
18
18
|
};
|
|
19
|
-
export type FocusFunction = (choiceIndex?: number | null | undefined) => boolean;
|
|
20
19
|
type Props = {
|
|
21
20
|
apiOptions: APIOptions;
|
|
22
21
|
choices: ReadonlyArray<ChoiceType>;
|
|
@@ -32,7 +31,6 @@ type Props = {
|
|
|
32
31
|
checked: ReadonlyArray<boolean>;
|
|
33
32
|
crossedOut: ReadonlyArray<boolean>;
|
|
34
33
|
}) => void;
|
|
35
|
-
registerFocusFunction?: (arg1: FocusFunction) => void;
|
|
36
34
|
isLastUsedWidget?: boolean;
|
|
37
35
|
};
|
|
38
36
|
/**
|
|
@@ -45,5 +43,5 @@ type Props = {
|
|
|
45
43
|
*
|
|
46
44
|
* TODO(LEMS-2994): Clean up this file.
|
|
47
45
|
*/
|
|
48
|
-
declare const BaseRadio: ({ apiOptions, reviewModeRubric, reviewMode, choices, editMode, multipleSelect, labelWrap, countChoices, numCorrect, isLastUsedWidget, onChange,
|
|
46
|
+
declare const BaseRadio: ({ apiOptions, reviewModeRubric, reviewMode, choices, editMode, multipleSelect, labelWrap, countChoices, numCorrect, isLastUsedWidget, onChange, }: Props) => React.ReactElement;
|
|
49
47
|
export default BaseRadio;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type { ChoiceProps } from "./choice";
|
|
2
|
+
import type { ChoiceProps } from "./choice.new";
|
|
3
3
|
declare const _default: React.ForwardRefExoticComponent<ChoiceProps & {
|
|
4
4
|
showContent?: boolean;
|
|
5
5
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { PerseusI18nContext } from "../../components/i18n-context";
|
|
3
|
-
import type { FocusFunction } from "./base-radio.new";
|
|
4
2
|
import type { WidgetProps, ChoiceState, Widget } from "../../types";
|
|
5
3
|
import type { RadioPromptJSON } from "../../widget-ai-utils/radio/radio-ai-utils";
|
|
6
|
-
import type { PerseusRadioChoice, ShowSolutions, PerseusRadioRubric, PerseusRadioUserInput,
|
|
4
|
+
import type { PerseusRadioChoice, ShowSolutions, PerseusRadioRubric, PerseusRadioUserInput, PerseusRadioWidgetOptions } from "@khanacademy/perseus-core";
|
|
7
5
|
export type RenderProps = {
|
|
8
6
|
numCorrect: number;
|
|
9
7
|
hasNoneOfTheAbove?: boolean;
|
|
@@ -23,37 +21,26 @@ export type RadioChoiceWithMetadata = PerseusRadioChoice & {
|
|
|
23
21
|
correct?: boolean;
|
|
24
22
|
};
|
|
25
23
|
/**
|
|
26
|
-
* This component is
|
|
27
|
-
* for the Radio Revitalization Project. (LEMS-2933)
|
|
28
|
-
* This component will be
|
|
29
|
-
*
|
|
30
|
-
* the feature flag is no longer needed.
|
|
24
|
+
* This component is holds the class methods for the radio widget, that were split
|
|
25
|
+
* out of radio-component.new.tsx for the Radio Revitalization Project. (LEMS-2933)
|
|
26
|
+
* This component will be the main entry point for the radio widget when the feature
|
|
27
|
+
* flag is no longer needed.
|
|
31
28
|
*
|
|
32
29
|
* TODO(LEMS-2994): Clean up this file.
|
|
33
30
|
*/
|
|
34
31
|
declare class Radio extends React.Component<Props> implements Widget {
|
|
35
|
-
static contextType: React.Context<import("../../components/i18n-context").I18nContextType>;
|
|
36
|
-
context: React.ContextType<typeof PerseusI18nContext>;
|
|
37
|
-
focusFunction: FocusFunction;
|
|
38
32
|
static defaultProps: DefaultProps;
|
|
39
33
|
static getUserInputFromProps(props: Props, unshuffle?: boolean): PerseusRadioUserInput;
|
|
40
|
-
componentDidUpdate(prevProps: Props): void;
|
|
41
|
-
_renderRenderer: (content?: string) => React.ReactElement;
|
|
42
|
-
focus(choiceIndex?: number | null): boolean;
|
|
43
|
-
registerFocusFunction(fun: FocusFunction): void;
|
|
44
|
-
updateChoices: (newValueLists: Readonly<{
|
|
45
|
-
checked: ReadonlyArray<boolean>;
|
|
46
|
-
crossedOut: ReadonlyArray<boolean>;
|
|
47
|
-
}>) => void;
|
|
48
34
|
getUserInput(): PerseusRadioUserInput;
|
|
49
35
|
getPromptJSON(): RadioPromptJSON;
|
|
50
36
|
/**
|
|
51
37
|
* Turn on rationale display for the currently selected choices. Note that
|
|
52
38
|
* this leaves rationales on for choices that are already showing
|
|
53
39
|
* rationales.
|
|
40
|
+
* TODO: LEMS-3077 Remove deprecated class function
|
|
54
41
|
* @deprecated Internal only. Use `showSolutions` prop instead.
|
|
55
42
|
*/
|
|
56
|
-
showRationalesForCurrentlySelectedChoices: (arg1:
|
|
43
|
+
showRationalesForCurrentlySelectedChoices: (arg1: PerseusRadioWidgetOptions) => void;
|
|
57
44
|
/**
|
|
58
45
|
* Deselects any currently-selected choices that are not correct choices.
|
|
59
46
|
*/
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import RadioOld from "./radio-component";
|
|
3
|
-
import RadioNew from "./radio-component.new";
|
|
4
3
|
import type { RenderProps } from "./radio-component";
|
|
5
4
|
import type { WidgetProps } from "../../types";
|
|
6
5
|
import type { PerseusRadioRubric } from "@khanacademy/perseus-core";
|
|
@@ -16,7 +15,7 @@ type Props = WidgetProps<RenderProps, PerseusRadioRubric>;
|
|
|
16
15
|
*/
|
|
17
16
|
declare class Radio extends RadioOld {
|
|
18
17
|
ffIsOn: boolean;
|
|
19
|
-
radioRef: React.RefObject<RadioOld
|
|
18
|
+
radioRef: React.RefObject<RadioOld>;
|
|
20
19
|
constructor(props: Props);
|
|
21
20
|
focus(choiceIndex?: number | null): boolean;
|
|
22
21
|
render(): React.ReactNode;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { WidgetProps, ChoiceState } from "../../types";
|
|
3
|
+
import type { PerseusRadioChoice, ShowSolutions, PerseusRadioRubric } from "@khanacademy/perseus-core";
|
|
4
|
+
export interface RadioChoiceWithMetadata extends PerseusRadioChoice {
|
|
5
|
+
originalIndex: number;
|
|
6
|
+
correct?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface RenderProps {
|
|
9
|
+
numCorrect: number;
|
|
10
|
+
hasNoneOfTheAbove?: boolean;
|
|
11
|
+
multipleSelect?: boolean;
|
|
12
|
+
countChoices?: boolean;
|
|
13
|
+
deselectEnabled?: boolean;
|
|
14
|
+
choices: ReadonlyArray<RadioChoiceWithMetadata>;
|
|
15
|
+
selectedChoices: ReadonlyArray<PerseusRadioChoice["correct"]>;
|
|
16
|
+
showSolutions?: ShowSolutions;
|
|
17
|
+
choiceStates?: ReadonlyArray<ChoiceState>;
|
|
18
|
+
values?: ReadonlyArray<boolean>;
|
|
19
|
+
}
|
|
20
|
+
type RadioComponentProps = WidgetProps<RenderProps, PerseusRadioRubric>;
|
|
21
|
+
/**
|
|
22
|
+
* This component is a duplicate of the Radio component in radio.tsx
|
|
23
|
+
* for the Radio Revitalization Project. (LEMS-2933)
|
|
24
|
+
* This component has been split up to move the rendering logic to a new functional component.
|
|
25
|
+
* The class methods are now in radio.class.new.tsx.
|
|
26
|
+
*
|
|
27
|
+
* TODO(LEMS-2994): Clean up this file.
|
|
28
|
+
*/
|
|
29
|
+
declare const RadioComponent: (props: RadioComponentProps) => React.JSX.Element;
|
|
30
|
+
export default RadioComponent;
|
package/dist/widgets.d.ts
CHANGED
|
@@ -3,38 +3,38 @@ import type { Tracking, WidgetExports, WidgetTransform } from "./types";
|
|
|
3
3
|
import type { PerseusWidget, Version } from "@khanacademy/perseus-core";
|
|
4
4
|
import type * as React from "react";
|
|
5
5
|
type Editor = any;
|
|
6
|
-
export declare const registerWidget: (
|
|
7
|
-
export declare const registerWidgets: (
|
|
6
|
+
export declare const registerWidget: (type: string, widget: WidgetExports) => void;
|
|
7
|
+
export declare const registerWidgets: (widgetArr: ReadonlyArray<WidgetExports>) => void;
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
10
|
+
* @param type - the widget that you are trying to replace
|
|
11
|
+
* @param replacementType - the type of the widget that takes its place
|
|
12
12
|
*
|
|
13
13
|
* e.g. replaceWidget("transformer", "deprecated-standin") will make it so the
|
|
14
14
|
* transformer widget is replaced by the always correct widget
|
|
15
15
|
*/
|
|
16
|
-
export declare const replaceWidget: (
|
|
16
|
+
export declare const replaceWidget: (type: string, replacementType: string) => void;
|
|
17
17
|
export declare const replaceDeprecatedWidgets: () => void;
|
|
18
18
|
export declare const registerEditors: (editorsToRegister: ReadonlyArray<Editor>) => void;
|
|
19
19
|
/**
|
|
20
20
|
*
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
21
|
+
* @param type - the widget that you are trying to replace
|
|
22
|
+
* @param replacementType - the type of the widget that takes its place
|
|
23
23
|
*
|
|
24
24
|
* e.g. replaceEditor("transformer", "deprecated-standin") will make it so the
|
|
25
25
|
* transformer widget is replaced by the deprecated stand-in widget
|
|
26
26
|
*/
|
|
27
|
-
export declare const replaceEditor: (
|
|
27
|
+
export declare const replaceEditor: (type: string, replacementType: string) => void;
|
|
28
28
|
export declare const replaceDeprecatedEditors: () => void;
|
|
29
|
-
export declare const getWidget: (
|
|
30
|
-
export declare const getWidgetExport: (
|
|
31
|
-
export declare const getEditor: (
|
|
32
|
-
export declare const getTransform: (
|
|
33
|
-
export declare const getVersion: (
|
|
29
|
+
export declare const getWidget: (type: string) => React.ComponentType<any> | null | undefined;
|
|
30
|
+
export declare const getWidgetExport: (type: string) => WidgetExports | null;
|
|
31
|
+
export declare const getEditor: (type: string) => Editor | null;
|
|
32
|
+
export declare const getTransform: (type: string) => WidgetTransform | null | undefined;
|
|
33
|
+
export declare const getVersion: (type: string) => Version | undefined;
|
|
34
34
|
export declare const getVersionVector: () => {
|
|
35
35
|
[key: string]: Version;
|
|
36
36
|
};
|
|
37
|
-
export declare const getPublicWidgets: () =>
|
|
37
|
+
export declare const getPublicWidgets: () => Record<string, WidgetExports>;
|
|
38
38
|
export declare const isAccessible: (widgetInfo: PerseusWidget) => boolean;
|
|
39
39
|
export declare const getAllWidgetTypes: () => ReadonlyArray<string>;
|
|
40
40
|
export declare const getRendererPropsForWidgetInfo: (widgetInfo: PerseusWidget, strings: PerseusStrings, problemNum?: number) => PerseusWidget;
|
|
@@ -47,7 +47,7 @@ export declare const traverseChildWidgets: (widgetInfo: PerseusWidget, traverseR
|
|
|
47
47
|
* A widget implicitly supports static mode if it exports a
|
|
48
48
|
* staticTransform function.
|
|
49
49
|
*/
|
|
50
|
-
export declare const supportsStaticMode: (type: string) => boolean;
|
|
50
|
+
export declare const supportsStaticMode: (type: string) => boolean | undefined;
|
|
51
51
|
/**
|
|
52
52
|
* Return the staticTransform function used to convert the editorProps to
|
|
53
53
|
* the rendered widget state.
|
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": "
|
|
6
|
+
"version": "62.0.0",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -41,16 +41,16 @@
|
|
|
41
41
|
"mafs": "0.19.0",
|
|
42
42
|
"tiny-invariant": "^1.3.1",
|
|
43
43
|
"uuid": "^10.0.0",
|
|
44
|
-
"@khanacademy/kas": "2.0.
|
|
45
|
-
"@khanacademy/
|
|
46
|
-
"@khanacademy/
|
|
47
|
-
"@khanacademy/
|
|
48
|
-
"@khanacademy/
|
|
49
|
-
"@khanacademy/perseus-linter": "3.0.
|
|
50
|
-
"@khanacademy/perseus-score": "
|
|
51
|
-
"@khanacademy/perseus-utils": "2.0.
|
|
52
|
-
"@khanacademy/pure-markdown": "2.0.
|
|
53
|
-
"@khanacademy/simple-markdown": "2.0.
|
|
44
|
+
"@khanacademy/kas": "2.0.4",
|
|
45
|
+
"@khanacademy/keypad-context": "3.0.9",
|
|
46
|
+
"@khanacademy/kmath": "2.0.9",
|
|
47
|
+
"@khanacademy/math-input": "25.1.4",
|
|
48
|
+
"@khanacademy/perseus-core": "11.0.0",
|
|
49
|
+
"@khanacademy/perseus-linter": "3.0.9",
|
|
50
|
+
"@khanacademy/perseus-score": "6.0.0",
|
|
51
|
+
"@khanacademy/perseus-utils": "2.0.3",
|
|
52
|
+
"@khanacademy/pure-markdown": "2.0.4",
|
|
53
|
+
"@khanacademy/simple-markdown": "2.0.4"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@khanacademy/wonder-blocks-banner": "4.1.12",
|