@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/es/index.js
CHANGED
|
@@ -23743,9 +23743,8 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23743
23743
|
// element) We have to add some extra behavior to make
|
|
23744
23744
|
// sure that we can still check the choice.
|
|
23745
23745
|
let listElem = null;
|
|
23746
|
-
let clickHandler
|
|
23746
|
+
let clickHandler;
|
|
23747
23747
|
if (editMode) {
|
|
23748
|
-
// @ts-expect-error - TS2322 - Type '(e: any) => void' is not assignable to type 'null'.
|
|
23749
23748
|
clickHandler = e => {
|
|
23750
23749
|
// Traverse the parent nodes of the clicked
|
|
23751
23750
|
// element.
|
|
@@ -23772,19 +23771,11 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23772
23771
|
// somehow break something happening inside a choice's
|
|
23773
23772
|
// child Renderers, by changing when we mount/unmount?
|
|
23774
23773
|
return /*#__PURE__*/React.createElement("li", {
|
|
23775
|
-
key: i
|
|
23776
|
-
|
|
23777
|
-
,
|
|
23778
|
-
|
|
23779
|
-
|
|
23780
|
-
,
|
|
23781
|
-
className: className
|
|
23782
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'MouseEventHandler<HTMLLIElement> | undefined'.
|
|
23783
|
-
,
|
|
23784
|
-
onClick: clickHandler
|
|
23785
|
-
// @ts-expect-error - TS2322 - Type '((e: TouchEvent) => void) | null' is not assignable to type 'TouchEventHandler<HTMLLIElement> | undefined'.
|
|
23786
|
-
,
|
|
23787
|
-
onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$1
|
|
23774
|
+
key: i,
|
|
23775
|
+
ref: e => listElem = e,
|
|
23776
|
+
className: className,
|
|
23777
|
+
onClick: clickHandler,
|
|
23778
|
+
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
23788
23779
|
}, /*#__PURE__*/React.createElement(Element, _extends({}, elementProps, {
|
|
23789
23780
|
ref: ref
|
|
23790
23781
|
})));
|
|
@@ -29386,9 +29377,7 @@ class NumberInput extends React.Component {
|
|
|
29386
29377
|
onFocus: this._handleFocus,
|
|
29387
29378
|
onBlur: this._handleBlur,
|
|
29388
29379
|
onKeyPress: this._handleBlur,
|
|
29389
|
-
onKeyDown: this._onKeyDown
|
|
29390
|
-
// @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
|
|
29391
|
-
,
|
|
29380
|
+
onKeyDown: this._onKeyDown,
|
|
29392
29381
|
onTouchStart: captureScratchpadTouchStart,
|
|
29393
29382
|
defaultValue: toNumericString(this.props.value, this.state.format),
|
|
29394
29383
|
value: undefined
|
|
@@ -30045,7 +30034,8 @@ const actions = {
|
|
|
30045
30034
|
addPoint,
|
|
30046
30035
|
removePoint,
|
|
30047
30036
|
focusPoint,
|
|
30048
|
-
blurPoint
|
|
30037
|
+
blurPoint,
|
|
30038
|
+
clickPoint
|
|
30049
30039
|
},
|
|
30050
30040
|
polygon: {
|
|
30051
30041
|
movePoint,
|
|
@@ -30107,6 +30097,13 @@ function blurPoint() {
|
|
|
30107
30097
|
type: BLUR_POINT
|
|
30108
30098
|
};
|
|
30109
30099
|
}
|
|
30100
|
+
const CLICK_POINT = "click-point";
|
|
30101
|
+
function clickPoint(index) {
|
|
30102
|
+
return {
|
|
30103
|
+
type: CLICK_POINT,
|
|
30104
|
+
index
|
|
30105
|
+
};
|
|
30106
|
+
}
|
|
30110
30107
|
const MOVE_ALL = "move-all";
|
|
30111
30108
|
function moveAll(delta) {
|
|
30112
30109
|
return {
|
|
@@ -30431,10 +30428,14 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30431
30428
|
},
|
|
30432
30429
|
"data-testid": "movable-point",
|
|
30433
30430
|
tabIndex: disableKeyboardInteraction ? -1 : tabIndex(focusBehavior),
|
|
30434
|
-
onFocus:
|
|
30435
|
-
|
|
30431
|
+
onFocus: event => {
|
|
30432
|
+
const callback = getOnFocusChangeCallback(focusBehavior);
|
|
30433
|
+
callback && callback(event, true);
|
|
30434
|
+
},
|
|
30435
|
+
onBlur: event => {
|
|
30436
|
+
const callback = getOnFocusChangeCallback(focusBehavior);
|
|
30437
|
+
callback && callback(event, false);
|
|
30436
30438
|
},
|
|
30437
|
-
onBlur: () => getOnFocusChangeCallback(focusBehavior)(false),
|
|
30438
30439
|
onClick: onClick
|
|
30439
30440
|
}, /*#__PURE__*/React.createElement("circle", {
|
|
30440
30441
|
className: "movable-point-hitbox",
|
|
@@ -31080,6 +31081,7 @@ const MovablePoint$1 = props => {
|
|
|
31080
31081
|
point,
|
|
31081
31082
|
onMove = () => {},
|
|
31082
31083
|
onFocusChange = () => {},
|
|
31084
|
+
onClick = () => {},
|
|
31083
31085
|
cursor,
|
|
31084
31086
|
color: color$1 = color.blue,
|
|
31085
31087
|
constrain = p => snap(snapStep, p)
|
|
@@ -31104,7 +31106,8 @@ const MovablePoint$1 = props => {
|
|
|
31104
31106
|
},
|
|
31105
31107
|
onClick: () => {
|
|
31106
31108
|
var _elementRef$current;
|
|
31107
|
-
|
|
31109
|
+
onClick && onClick();
|
|
31110
|
+
(_elementRef$current = elementRef.current) == null || _elementRef$current.focus();
|
|
31108
31111
|
},
|
|
31109
31112
|
cursor: cursor
|
|
31110
31113
|
});
|
|
@@ -31306,6 +31309,11 @@ function getGradableGraph(state, initialGraph) {
|
|
|
31306
31309
|
allowReflexAngles: state.allowReflexAngles
|
|
31307
31310
|
});
|
|
31308
31311
|
}
|
|
31312
|
+
if (state.type === "none" && initialGraph.type === "none") {
|
|
31313
|
+
return {
|
|
31314
|
+
type: "none"
|
|
31315
|
+
};
|
|
31316
|
+
}
|
|
31309
31317
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
31310
31318
|
}
|
|
31311
31319
|
|
|
@@ -31703,12 +31711,19 @@ function UnlimitedPointGraph(props) {
|
|
|
31703
31711
|
key: i,
|
|
31704
31712
|
point: point,
|
|
31705
31713
|
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
|
|
31706
|
-
onFocusChange: isFocused => {
|
|
31714
|
+
onFocusChange: (event, isFocused) => {
|
|
31707
31715
|
if (isFocused) {
|
|
31708
31716
|
dispatch(actions.pointGraph.focusPoint(i));
|
|
31709
31717
|
} else {
|
|
31718
|
+
var _event$relatedTarget;
|
|
31719
|
+
if (((_event$relatedTarget = event.relatedTarget) == null ? void 0 : _event$relatedTarget.id) === REMOVE_BUTTON_ID) {
|
|
31720
|
+
return;
|
|
31721
|
+
}
|
|
31710
31722
|
dispatch(actions.pointGraph.blurPoint());
|
|
31711
31723
|
}
|
|
31724
|
+
},
|
|
31725
|
+
onClick: () => {
|
|
31726
|
+
dispatch(actions.pointGraph.clickPoint(i));
|
|
31712
31727
|
}
|
|
31713
31728
|
})));
|
|
31714
31729
|
}
|
|
@@ -31867,6 +31882,7 @@ function useDraggablePx(args) {
|
|
|
31867
31882
|
* - Protractor
|
|
31868
31883
|
* - Interactive Graph Elements
|
|
31869
31884
|
*/
|
|
31885
|
+
const REMOVE_BUTTON_ID = "perseus_mafs_remove_button";
|
|
31870
31886
|
const MafsGraph = props => {
|
|
31871
31887
|
const {
|
|
31872
31888
|
state,
|
|
@@ -31992,10 +32008,10 @@ const MafsGraph = props => {
|
|
|
31992
32008
|
zoom: false,
|
|
31993
32009
|
width: width,
|
|
31994
32010
|
height: height
|
|
31995
|
-
}, props.showProtractor && /*#__PURE__*/React.createElement(Protractor, null), renderGraph({
|
|
32011
|
+
}, /*#__PURE__*/React.createElement("svg", nestedSVGAttributes, props.showProtractor && /*#__PURE__*/React.createElement(Protractor, null), renderGraph({
|
|
31996
32012
|
state,
|
|
31997
32013
|
dispatch
|
|
31998
|
-
}))))), renderGraphControls({
|
|
32014
|
+
})))))), renderGraphControls({
|
|
31999
32015
|
state,
|
|
32000
32016
|
dispatch,
|
|
32001
32017
|
width
|
|
@@ -32006,26 +32022,17 @@ const renderPointGraphControls = props => /*#__PURE__*/React.createElement(View,
|
|
|
32006
32022
|
flexDirection: "row",
|
|
32007
32023
|
width: props.width
|
|
32008
32024
|
}
|
|
32009
|
-
}, /*#__PURE__*/React.createElement(Button, {
|
|
32010
|
-
|
|
32011
|
-
style: {
|
|
32012
|
-
width: "100%",
|
|
32013
|
-
marginLeft: "20px"
|
|
32014
|
-
},
|
|
32015
|
-
tabIndex: 0,
|
|
32016
|
-
onClick: () => {
|
|
32017
|
-
props.dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32018
|
-
}
|
|
32019
|
-
}, "Add Point"), (props.state.focusedPointIndex !== null || props.state.previouslyFocusedPointIndex !== null) && /*#__PURE__*/React.createElement(Button, {
|
|
32025
|
+
}, props.state.showRemovePointButton && props.state.focusedPointIndex !== null && /*#__PURE__*/React.createElement(Button, {
|
|
32026
|
+
id: REMOVE_BUTTON_ID,
|
|
32020
32027
|
kind: "secondary",
|
|
32021
32028
|
color: "destructive",
|
|
32022
|
-
tabIndex:
|
|
32029
|
+
tabIndex: -1,
|
|
32023
32030
|
style: {
|
|
32024
32031
|
width: "100%",
|
|
32025
32032
|
marginLeft: "20px"
|
|
32026
32033
|
},
|
|
32027
32034
|
onClick: event => {
|
|
32028
|
-
props.dispatch(actions.pointGraph.removePoint(props.state.
|
|
32035
|
+
props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));
|
|
32029
32036
|
}
|
|
32030
32037
|
}, "Remove Point"));
|
|
32031
32038
|
const renderGraphControls = props => {
|
|
@@ -32160,6 +32167,8 @@ const renderGraph = props => {
|
|
|
32160
32167
|
graphState: state,
|
|
32161
32168
|
dispatch: dispatch
|
|
32162
32169
|
});
|
|
32170
|
+
case "none":
|
|
32171
|
+
return null;
|
|
32163
32172
|
default:
|
|
32164
32173
|
throw new UnreachableCaseError(type);
|
|
32165
32174
|
}
|
|
@@ -32213,7 +32222,7 @@ function initializeGraphState(params) {
|
|
|
32213
32222
|
coords: getPointCoords(graph, range, step),
|
|
32214
32223
|
numPoints: graph.numPoints || 0,
|
|
32215
32224
|
focusedPointIndex: null,
|
|
32216
|
-
|
|
32225
|
+
showRemovePointButton: false
|
|
32217
32226
|
});
|
|
32218
32227
|
case "circle":
|
|
32219
32228
|
return _extends({}, shared, {
|
|
@@ -32242,6 +32251,10 @@ function initializeGraphState(params) {
|
|
|
32242
32251
|
allowReflexAngles: Boolean(graph.allowReflexAngles),
|
|
32243
32252
|
snapDegrees: Number(graph.snapDegrees)
|
|
32244
32253
|
});
|
|
32254
|
+
case "none":
|
|
32255
|
+
return _extends({}, shared, {
|
|
32256
|
+
type: "none"
|
|
32257
|
+
});
|
|
32245
32258
|
default:
|
|
32246
32259
|
throw new UnreachableCaseError(graph);
|
|
32247
32260
|
}
|
|
@@ -32477,6 +32490,8 @@ function interactiveGraphReducer(state, action) {
|
|
|
32477
32490
|
return doBlurPoint(state);
|
|
32478
32491
|
case DELETE_INTENT:
|
|
32479
32492
|
return doDeleteIntent(state);
|
|
32493
|
+
case CLICK_POINT:
|
|
32494
|
+
return doClickPoint(state, action);
|
|
32480
32495
|
default:
|
|
32481
32496
|
throw new UnreachableCaseError(action);
|
|
32482
32497
|
}
|
|
@@ -32506,13 +32521,25 @@ function doBlurPoint(state, action) {
|
|
|
32506
32521
|
switch (state.type) {
|
|
32507
32522
|
case "point":
|
|
32508
32523
|
return _extends({}, state, {
|
|
32509
|
-
|
|
32510
|
-
|
|
32524
|
+
focusedPointIndex: null,
|
|
32525
|
+
showRemovePointButton: false
|
|
32511
32526
|
});
|
|
32512
32527
|
default:
|
|
32513
32528
|
return state;
|
|
32514
32529
|
}
|
|
32515
32530
|
}
|
|
32531
|
+
function doClickPoint(state, action) {
|
|
32532
|
+
if (state.type !== "point") {
|
|
32533
|
+
return state;
|
|
32534
|
+
}
|
|
32535
|
+
if (state.numPoints === "unlimited") {
|
|
32536
|
+
return _extends({}, state, {
|
|
32537
|
+
focusedPointIndex: action.index,
|
|
32538
|
+
showRemovePointButton: true
|
|
32539
|
+
});
|
|
32540
|
+
}
|
|
32541
|
+
return state;
|
|
32542
|
+
}
|
|
32516
32543
|
function doMovePointInFigure(state, action) {
|
|
32517
32544
|
switch (state.type) {
|
|
32518
32545
|
case "segment":
|
|
@@ -32551,6 +32578,8 @@ function doMovePointInFigure(state, action) {
|
|
|
32551
32578
|
}
|
|
32552
32579
|
case "angle":
|
|
32553
32580
|
case "circle":
|
|
32581
|
+
throw new Error("FIXME implement circle reducer");
|
|
32582
|
+
case "none":
|
|
32554
32583
|
case "point":
|
|
32555
32584
|
case "polygon":
|
|
32556
32585
|
case "quadratic":
|
|
@@ -32852,7 +32881,8 @@ function doAddPoint(state, action) {
|
|
|
32852
32881
|
// If there's no point in spot where we want the new point to go we add it there
|
|
32853
32882
|
return _extends({}, state, {
|
|
32854
32883
|
hasBeenInteractedWith: true,
|
|
32855
|
-
coords: [...state.coords, snappedPoint]
|
|
32884
|
+
coords: [...state.coords, snappedPoint],
|
|
32885
|
+
showRemovePointButton: false
|
|
32856
32886
|
});
|
|
32857
32887
|
}
|
|
32858
32888
|
function doRemovePoint(state, action) {
|
|
@@ -32862,7 +32892,7 @@ function doRemovePoint(state, action) {
|
|
|
32862
32892
|
return _extends({}, state, {
|
|
32863
32893
|
coords: state.coords.filter((_, i) => i !== action.index),
|
|
32864
32894
|
focusedPointIndex: null,
|
|
32865
|
-
|
|
32895
|
+
showRemovePointButton: false
|
|
32866
32896
|
});
|
|
32867
32897
|
}
|
|
32868
32898
|
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
@@ -33246,6 +33276,7 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
33246
33276
|
const snapTo = graph.type === "polygon" ? graph.snapTo : null;
|
|
33247
33277
|
const showAngles = graph.type === "polygon" ? graph.showAngles : null;
|
|
33248
33278
|
const showSides = graph.type === "polygon" ? graph.showSides : null;
|
|
33279
|
+
const startCoords = "startCoords" in graph ? graph.startCoords : null;
|
|
33249
33280
|
const originalPropsRef = useRef(props);
|
|
33250
33281
|
const latestPropsRef = useLatestRef(props);
|
|
33251
33282
|
useEffect(() => {
|
|
@@ -33256,7 +33287,7 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
33256
33287
|
if (latestPropsRef.current !== originalPropsRef.current) {
|
|
33257
33288
|
dispatch(reinitialize(latestPropsRef.current));
|
|
33258
33289
|
}
|
|
33259
|
-
}, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef,
|
|
33290
|
+
}, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef, startCoords]);
|
|
33260
33291
|
|
|
33261
33292
|
// If the graph is static, it always displays the correct answer. This is
|
|
33262
33293
|
// standard behavior for Perseus widgets (e.g. compare the Radio widget).
|
|
@@ -33533,6 +33564,8 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
33533
33564
|
_.invoke(this.points, "remove");
|
|
33534
33565
|
(_this$line = this.line) == null || _this$line.remove();
|
|
33535
33566
|
};
|
|
33567
|
+
this.addNoneControls = () => {};
|
|
33568
|
+
this.removeNoneControls = () => {};
|
|
33536
33569
|
this.addLinearControls = () => {
|
|
33537
33570
|
this.addLine("line");
|
|
33538
33571
|
};
|
|
@@ -34800,6 +34833,9 @@ class InteractiveGraph extends React.Component {
|
|
|
34800
34833
|
});
|
|
34801
34834
|
});
|
|
34802
34835
|
}
|
|
34836
|
+
static getNoneEquationString() {
|
|
34837
|
+
return "";
|
|
34838
|
+
}
|
|
34803
34839
|
static getLinearEquationString(props) {
|
|
34804
34840
|
const coords = InteractiveGraph.getLineCoords(props.graph, props);
|
|
34805
34841
|
if (eq(coords[0][0], coords[1][0])) {
|
|
@@ -34913,6 +34949,16 @@ class InteractiveGraph extends React.Component {
|
|
|
34913
34949
|
return angle.toFixed(0) + "\u00B0 angle" + " at (" + coords[1].join(", ") + ")";
|
|
34914
34950
|
}
|
|
34915
34951
|
static validate(userInput, rubric, component) {
|
|
34952
|
+
// None-type graphs are not graded
|
|
34953
|
+
if (userInput.type === "none" && rubric.correct.type === "none") {
|
|
34954
|
+
return {
|
|
34955
|
+
type: "points",
|
|
34956
|
+
earned: 0,
|
|
34957
|
+
total: 0,
|
|
34958
|
+
message: null
|
|
34959
|
+
};
|
|
34960
|
+
}
|
|
34961
|
+
|
|
34916
34962
|
// When nothing has moved, there will neither be coords nor the
|
|
34917
34963
|
// circle's center/radius fields. When those fields are absent, skip
|
|
34918
34964
|
// all these checks; just go mark the answer as empty.
|
|
@@ -35142,6 +35188,8 @@ function shouldUseMafs(mafsFlags, graph) {
|
|
|
35142
35188
|
return false;
|
|
35143
35189
|
}
|
|
35144
35190
|
switch (graph.type) {
|
|
35191
|
+
case "none":
|
|
35192
|
+
return true;
|
|
35145
35193
|
case "point":
|
|
35146
35194
|
if (graph.numPoints === UNLIMITED) {
|
|
35147
35195
|
return Boolean(mafsFlags["unlimited-point"]);
|
|
@@ -44692,7 +44740,7 @@ const init = function init(options) {
|
|
|
44692
44740
|
|
|
44693
44741
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44694
44742
|
const libName = "@khanacademy/perseus";
|
|
44695
|
-
const libVersion = "33.
|
|
44743
|
+
const libVersion = "33.3.0";
|
|
44696
44744
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44697
44745
|
|
|
44698
44746
|
const apiVersion = {
|