@khanacademy/perseus 33.2.1 → 33.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +94 -46
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +97 -46
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -0
- package/dist/perseus-types.d.ts +9 -5
- package/dist/server-item-renderer.d.ts +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/util.d.ts +2 -1
- package/dist/widgets/expression/expression.d.ts +6 -0
- package/dist/widgets/interactive-graph.d.ts +3 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point-view.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +2 -1
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +10 -4
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +8 -1
- package/dist/widgets/interactive-graphs/types.d.ts +5 -2
- package/dist/widgets/label-image/label-image.d.ts +2 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -23977,9 +23977,8 @@ const BaseRadio = function (props) {
|
|
|
23977
23977
|
// element) We have to add some extra behavior to make
|
|
23978
23978
|
// sure that we can still check the choice.
|
|
23979
23979
|
let listElem = null;
|
|
23980
|
-
let clickHandler
|
|
23980
|
+
let clickHandler;
|
|
23981
23981
|
if (editMode) {
|
|
23982
|
-
// @ts-expect-error - TS2322 - Type '(e: any) => void' is not assignable to type 'null'.
|
|
23983
23982
|
clickHandler = e => {
|
|
23984
23983
|
// Traverse the parent nodes of the clicked
|
|
23985
23984
|
// element.
|
|
@@ -24006,19 +24005,11 @@ const BaseRadio = function (props) {
|
|
|
24006
24005
|
// somehow break something happening inside a choice's
|
|
24007
24006
|
// child Renderers, by changing when we mount/unmount?
|
|
24008
24007
|
return /*#__PURE__*/React__namespace.createElement("li", {
|
|
24009
|
-
key: i
|
|
24010
|
-
|
|
24011
|
-
,
|
|
24012
|
-
|
|
24013
|
-
|
|
24014
|
-
,
|
|
24015
|
-
className: className
|
|
24016
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'MouseEventHandler<HTMLLIElement> | undefined'.
|
|
24017
|
-
,
|
|
24018
|
-
onClick: clickHandler
|
|
24019
|
-
// @ts-expect-error - TS2322 - Type '((e: TouchEvent) => void) | null' is not assignable to type 'TouchEventHandler<HTMLLIElement> | undefined'.
|
|
24020
|
-
,
|
|
24021
|
-
onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$1
|
|
24008
|
+
key: i,
|
|
24009
|
+
ref: e => listElem = e,
|
|
24010
|
+
className: className,
|
|
24011
|
+
onClick: clickHandler,
|
|
24012
|
+
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
24022
24013
|
}, /*#__PURE__*/React__namespace.createElement(Element, _extends({}, elementProps, {
|
|
24023
24014
|
ref: ref
|
|
24024
24015
|
})));
|
|
@@ -29718,9 +29709,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
29718
29709
|
onFocus: this._handleFocus,
|
|
29719
29710
|
onBlur: this._handleBlur,
|
|
29720
29711
|
onKeyPress: this._handleBlur,
|
|
29721
|
-
onKeyDown: this._onKeyDown
|
|
29722
|
-
// @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
|
|
29723
|
-
,
|
|
29712
|
+
onKeyDown: this._onKeyDown,
|
|
29724
29713
|
onTouchStart: captureScratchpadTouchStart,
|
|
29725
29714
|
defaultValue: toNumericString(this.props.value, this.state.format),
|
|
29726
29715
|
value: undefined
|
|
@@ -30359,7 +30348,8 @@ const actions = {
|
|
|
30359
30348
|
addPoint,
|
|
30360
30349
|
removePoint,
|
|
30361
30350
|
focusPoint,
|
|
30362
|
-
blurPoint
|
|
30351
|
+
blurPoint,
|
|
30352
|
+
clickPoint
|
|
30363
30353
|
},
|
|
30364
30354
|
polygon: {
|
|
30365
30355
|
movePoint,
|
|
@@ -30421,6 +30411,13 @@ function blurPoint() {
|
|
|
30421
30411
|
type: BLUR_POINT
|
|
30422
30412
|
};
|
|
30423
30413
|
}
|
|
30414
|
+
const CLICK_POINT = "click-point";
|
|
30415
|
+
function clickPoint(index) {
|
|
30416
|
+
return {
|
|
30417
|
+
type: CLICK_POINT,
|
|
30418
|
+
index
|
|
30419
|
+
};
|
|
30420
|
+
}
|
|
30424
30421
|
const MOVE_ALL = "move-all";
|
|
30425
30422
|
function moveAll(delta) {
|
|
30426
30423
|
return {
|
|
@@ -30749,10 +30746,14 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
|
|
|
30749
30746
|
},
|
|
30750
30747
|
"data-testid": "movable-point",
|
|
30751
30748
|
tabIndex: disableKeyboardInteraction ? -1 : tabIndex(focusBehavior),
|
|
30752
|
-
onFocus:
|
|
30753
|
-
|
|
30749
|
+
onFocus: event => {
|
|
30750
|
+
const callback = getOnFocusChangeCallback(focusBehavior);
|
|
30751
|
+
callback && callback(event, true);
|
|
30752
|
+
},
|
|
30753
|
+
onBlur: event => {
|
|
30754
|
+
const callback = getOnFocusChangeCallback(focusBehavior);
|
|
30755
|
+
callback && callback(event, false);
|
|
30754
30756
|
},
|
|
30755
|
-
onBlur: () => getOnFocusChangeCallback(focusBehavior)(false),
|
|
30756
30757
|
onClick: onClick
|
|
30757
30758
|
}, /*#__PURE__*/React__namespace.createElement("circle", {
|
|
30758
30759
|
className: "movable-point-hitbox",
|
|
@@ -31406,6 +31407,7 @@ const MovablePoint$1 = props => {
|
|
|
31406
31407
|
point,
|
|
31407
31408
|
onMove = () => {},
|
|
31408
31409
|
onFocusChange = () => {},
|
|
31410
|
+
onClick = () => {},
|
|
31409
31411
|
cursor,
|
|
31410
31412
|
color = wonderBlocksTokens.color.blue,
|
|
31411
31413
|
constrain = p => snap(snapStep, p)
|
|
@@ -31428,7 +31430,10 @@ const MovablePoint$1 = props => {
|
|
|
31428
31430
|
tabIndex: 0,
|
|
31429
31431
|
onFocusChange
|
|
31430
31432
|
},
|
|
31431
|
-
onClick: () =>
|
|
31433
|
+
onClick: () => {
|
|
31434
|
+
onClick && onClick();
|
|
31435
|
+
elementRef.current?.focus();
|
|
31436
|
+
},
|
|
31432
31437
|
cursor: cursor
|
|
31433
31438
|
});
|
|
31434
31439
|
};
|
|
@@ -31639,6 +31644,11 @@ function getGradableGraph(state, initialGraph) {
|
|
|
31639
31644
|
allowReflexAngles: state.allowReflexAngles
|
|
31640
31645
|
};
|
|
31641
31646
|
}
|
|
31647
|
+
if (state.type === "none" && initialGraph.type === "none") {
|
|
31648
|
+
return {
|
|
31649
|
+
type: "none"
|
|
31650
|
+
};
|
|
31651
|
+
}
|
|
31642
31652
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
31643
31653
|
}
|
|
31644
31654
|
|
|
@@ -32036,12 +32046,18 @@ function UnlimitedPointGraph(props) {
|
|
|
32036
32046
|
key: i,
|
|
32037
32047
|
point: point,
|
|
32038
32048
|
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
|
|
32039
|
-
onFocusChange: isFocused => {
|
|
32049
|
+
onFocusChange: (event, isFocused) => {
|
|
32040
32050
|
if (isFocused) {
|
|
32041
32051
|
dispatch(actions.pointGraph.focusPoint(i));
|
|
32042
32052
|
} else {
|
|
32053
|
+
if (event.relatedTarget?.id === REMOVE_BUTTON_ID) {
|
|
32054
|
+
return;
|
|
32055
|
+
}
|
|
32043
32056
|
dispatch(actions.pointGraph.blurPoint());
|
|
32044
32057
|
}
|
|
32058
|
+
},
|
|
32059
|
+
onClick: () => {
|
|
32060
|
+
dispatch(actions.pointGraph.clickPoint(i));
|
|
32045
32061
|
}
|
|
32046
32062
|
})));
|
|
32047
32063
|
}
|
|
@@ -32200,6 +32216,7 @@ function useDraggablePx(args) {
|
|
|
32200
32216
|
* - Protractor
|
|
32201
32217
|
* - Interactive Graph Elements
|
|
32202
32218
|
*/
|
|
32219
|
+
const REMOVE_BUTTON_ID = "perseus_mafs_remove_button";
|
|
32203
32220
|
const MafsGraph = props => {
|
|
32204
32221
|
const {
|
|
32205
32222
|
state,
|
|
@@ -32324,10 +32341,10 @@ const MafsGraph = props => {
|
|
|
32324
32341
|
zoom: false,
|
|
32325
32342
|
width: width,
|
|
32326
32343
|
height: height
|
|
32327
|
-
}, props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
|
|
32344
|
+
}, /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
|
|
32328
32345
|
state,
|
|
32329
32346
|
dispatch
|
|
32330
|
-
}))))), renderGraphControls({
|
|
32347
|
+
})))))), renderGraphControls({
|
|
32331
32348
|
state,
|
|
32332
32349
|
dispatch,
|
|
32333
32350
|
width
|
|
@@ -32338,26 +32355,17 @@ const renderPointGraphControls = props => /*#__PURE__*/React__namespace.createEl
|
|
|
32338
32355
|
flexDirection: "row",
|
|
32339
32356
|
width: props.width
|
|
32340
32357
|
}
|
|
32341
|
-
}, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
32342
|
-
|
|
32343
|
-
style: {
|
|
32344
|
-
width: "100%",
|
|
32345
|
-
marginLeft: "20px"
|
|
32346
|
-
},
|
|
32347
|
-
tabIndex: 0,
|
|
32348
|
-
onClick: () => {
|
|
32349
|
-
props.dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32350
|
-
}
|
|
32351
|
-
}, "Add Point"), (props.state.focusedPointIndex !== null || props.state.previouslyFocusedPointIndex !== null) && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
32358
|
+
}, props.state.showRemovePointButton && props.state.focusedPointIndex !== null && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
32359
|
+
id: REMOVE_BUTTON_ID,
|
|
32352
32360
|
kind: "secondary",
|
|
32353
32361
|
color: "destructive",
|
|
32354
|
-
tabIndex:
|
|
32362
|
+
tabIndex: -1,
|
|
32355
32363
|
style: {
|
|
32356
32364
|
width: "100%",
|
|
32357
32365
|
marginLeft: "20px"
|
|
32358
32366
|
},
|
|
32359
32367
|
onClick: event => {
|
|
32360
|
-
props.dispatch(actions.pointGraph.removePoint(props.state.
|
|
32368
|
+
props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));
|
|
32361
32369
|
}
|
|
32362
32370
|
}, "Remove Point"));
|
|
32363
32371
|
const renderGraphControls = props => {
|
|
@@ -32492,6 +32500,8 @@ const renderGraph = props => {
|
|
|
32492
32500
|
graphState: state,
|
|
32493
32501
|
dispatch: dispatch
|
|
32494
32502
|
});
|
|
32503
|
+
case "none":
|
|
32504
|
+
return null;
|
|
32495
32505
|
default:
|
|
32496
32506
|
throw new wonderStuffCore.UnreachableCaseError(type);
|
|
32497
32507
|
}
|
|
@@ -32550,7 +32560,7 @@ function initializeGraphState(params) {
|
|
|
32550
32560
|
coords: getPointCoords(graph, range, step),
|
|
32551
32561
|
numPoints: graph.numPoints || 0,
|
|
32552
32562
|
focusedPointIndex: null,
|
|
32553
|
-
|
|
32563
|
+
showRemovePointButton: false
|
|
32554
32564
|
};
|
|
32555
32565
|
case "circle":
|
|
32556
32566
|
return {
|
|
@@ -32584,6 +32594,11 @@ function initializeGraphState(params) {
|
|
|
32584
32594
|
allowReflexAngles: Boolean(graph.allowReflexAngles),
|
|
32585
32595
|
snapDegrees: Number(graph.snapDegrees)
|
|
32586
32596
|
};
|
|
32597
|
+
case "none":
|
|
32598
|
+
return {
|
|
32599
|
+
...shared,
|
|
32600
|
+
type: "none"
|
|
32601
|
+
};
|
|
32587
32602
|
default:
|
|
32588
32603
|
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
32589
32604
|
}
|
|
@@ -32816,6 +32831,8 @@ function interactiveGraphReducer(state, action) {
|
|
|
32816
32831
|
return doBlurPoint(state);
|
|
32817
32832
|
case DELETE_INTENT:
|
|
32818
32833
|
return doDeleteIntent(state);
|
|
32834
|
+
case CLICK_POINT:
|
|
32835
|
+
return doClickPoint(state, action);
|
|
32819
32836
|
default:
|
|
32820
32837
|
throw new wonderStuffCore.UnreachableCaseError(action);
|
|
32821
32838
|
}
|
|
@@ -32847,13 +32864,26 @@ function doBlurPoint(state, action) {
|
|
|
32847
32864
|
case "point":
|
|
32848
32865
|
return {
|
|
32849
32866
|
...state,
|
|
32850
|
-
|
|
32851
|
-
|
|
32867
|
+
focusedPointIndex: null,
|
|
32868
|
+
showRemovePointButton: false
|
|
32852
32869
|
};
|
|
32853
32870
|
default:
|
|
32854
32871
|
return state;
|
|
32855
32872
|
}
|
|
32856
32873
|
}
|
|
32874
|
+
function doClickPoint(state, action) {
|
|
32875
|
+
if (state.type !== "point") {
|
|
32876
|
+
return state;
|
|
32877
|
+
}
|
|
32878
|
+
if (state.numPoints === "unlimited") {
|
|
32879
|
+
return {
|
|
32880
|
+
...state,
|
|
32881
|
+
focusedPointIndex: action.index,
|
|
32882
|
+
showRemovePointButton: true
|
|
32883
|
+
};
|
|
32884
|
+
}
|
|
32885
|
+
return state;
|
|
32886
|
+
}
|
|
32857
32887
|
function doMovePointInFigure(state, action) {
|
|
32858
32888
|
switch (state.type) {
|
|
32859
32889
|
case "segment":
|
|
@@ -32894,6 +32924,8 @@ function doMovePointInFigure(state, action) {
|
|
|
32894
32924
|
}
|
|
32895
32925
|
case "angle":
|
|
32896
32926
|
case "circle":
|
|
32927
|
+
throw new Error("FIXME implement circle reducer");
|
|
32928
|
+
case "none":
|
|
32897
32929
|
case "point":
|
|
32898
32930
|
case "polygon":
|
|
32899
32931
|
case "quadratic":
|
|
@@ -33209,7 +33241,8 @@ function doAddPoint(state, action) {
|
|
|
33209
33241
|
return {
|
|
33210
33242
|
...state,
|
|
33211
33243
|
hasBeenInteractedWith: true,
|
|
33212
|
-
coords: [...state.coords, snappedPoint]
|
|
33244
|
+
coords: [...state.coords, snappedPoint],
|
|
33245
|
+
showRemovePointButton: false
|
|
33213
33246
|
};
|
|
33214
33247
|
}
|
|
33215
33248
|
function doRemovePoint(state, action) {
|
|
@@ -33220,7 +33253,7 @@ function doRemovePoint(state, action) {
|
|
|
33220
33253
|
...state,
|
|
33221
33254
|
coords: state.coords.filter((_, i) => i !== action.index),
|
|
33222
33255
|
focusedPointIndex: null,
|
|
33223
|
-
|
|
33256
|
+
showRemovePointButton: false
|
|
33224
33257
|
};
|
|
33225
33258
|
}
|
|
33226
33259
|
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
@@ -33619,6 +33652,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
33619
33652
|
const snapTo = graph.type === "polygon" ? graph.snapTo : null;
|
|
33620
33653
|
const showAngles = graph.type === "polygon" ? graph.showAngles : null;
|
|
33621
33654
|
const showSides = graph.type === "polygon" ? graph.showSides : null;
|
|
33655
|
+
const startCoords = "startCoords" in graph ? graph.startCoords : null;
|
|
33622
33656
|
const originalPropsRef = React.useRef(props);
|
|
33623
33657
|
const latestPropsRef = wonderBlocksCore.useLatestRef(props);
|
|
33624
33658
|
React.useEffect(() => {
|
|
@@ -33629,7 +33663,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
33629
33663
|
if (latestPropsRef.current !== originalPropsRef.current) {
|
|
33630
33664
|
dispatch(reinitialize(latestPropsRef.current));
|
|
33631
33665
|
}
|
|
33632
|
-
}, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef,
|
|
33666
|
+
}, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef, startCoords]);
|
|
33633
33667
|
|
|
33634
33668
|
// If the graph is static, it always displays the correct answer. This is
|
|
33635
33669
|
// standard behavior for Perseus widgets (e.g. compare the Radio widget).
|
|
@@ -33955,6 +33989,8 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
33955
33989
|
___default["default"].invoke(this.points, "remove");
|
|
33956
33990
|
this.line?.remove();
|
|
33957
33991
|
};
|
|
33992
|
+
addNoneControls = () => {};
|
|
33993
|
+
removeNoneControls = () => {};
|
|
33958
33994
|
addLinearControls = () => {
|
|
33959
33995
|
this.addLine("line");
|
|
33960
33996
|
};
|
|
@@ -35157,6 +35193,9 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35157
35193
|
});
|
|
35158
35194
|
});
|
|
35159
35195
|
}
|
|
35196
|
+
static getNoneEquationString() {
|
|
35197
|
+
return "";
|
|
35198
|
+
}
|
|
35160
35199
|
static getLinearEquationString(props) {
|
|
35161
35200
|
const coords = InteractiveGraph.getLineCoords(props.graph, props);
|
|
35162
35201
|
if (eq(coords[0][0], coords[1][0])) {
|
|
@@ -35270,6 +35309,16 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35270
35309
|
return angle.toFixed(0) + "\u00B0 angle" + " at (" + coords[1].join(", ") + ")";
|
|
35271
35310
|
}
|
|
35272
35311
|
static validate(userInput, rubric, component) {
|
|
35312
|
+
// None-type graphs are not graded
|
|
35313
|
+
if (userInput.type === "none" && rubric.correct.type === "none") {
|
|
35314
|
+
return {
|
|
35315
|
+
type: "points",
|
|
35316
|
+
earned: 0,
|
|
35317
|
+
total: 0,
|
|
35318
|
+
message: null
|
|
35319
|
+
};
|
|
35320
|
+
}
|
|
35321
|
+
|
|
35273
35322
|
// When nothing has moved, there will neither be coords nor the
|
|
35274
35323
|
// circle's center/radius fields. When those fields are absent, skip
|
|
35275
35324
|
// all these checks; just go mark the answer as empty.
|
|
@@ -35485,6 +35534,8 @@ function shouldUseMafs(mafsFlags, graph) {
|
|
|
35485
35534
|
return false;
|
|
35486
35535
|
}
|
|
35487
35536
|
switch (graph.type) {
|
|
35537
|
+
case "none":
|
|
35538
|
+
return true;
|
|
35488
35539
|
case "point":
|
|
35489
35540
|
if (graph.numPoints === UNLIMITED) {
|
|
35490
35541
|
return Boolean(mafsFlags["unlimited-point"]);
|
|
@@ -45048,7 +45099,7 @@ const init = function (options) {
|
|
|
45048
45099
|
|
|
45049
45100
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45050
45101
|
const libName = "@khanacademy/perseus";
|
|
45051
|
-
const libVersion = "33.
|
|
45102
|
+
const libVersion = "33.3.0";
|
|
45052
45103
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45053
45104
|
|
|
45054
45105
|
const apiVersion = {
|