@khanacademy/perseus 21.0.0 → 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.
- package/dist/es/index.js +312 -73
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +317 -67
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/util/extract-perseus-data.d.ts +2 -2
- package/dist/widgets/interactive-graph.d.ts +2 -2
- package/dist/widgets/interactive-graphs/axis-arrows.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/point.d.ts +5 -0
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +15 -74
- package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +10 -3
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-reducer.d.ts +1 -1
- package/dist/widgets/interactive-graphs/reducer/use-graph-state.d.ts +11 -0
- package/dist/widgets/interactive-graphs/types.d.ts +30 -9
- package/dist/widgets/interactive-graphs/utils.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25026,9 +25026,22 @@ class Explanation extends React__namespace.Component {
|
|
|
25026
25026
|
// Special styling is needed to fit the button in a block of text without throwing off the line spacing.
|
|
25027
25027
|
// While the button is not normally included in a block of text, it needs to be able to accommodate such a case.
|
|
25028
25028
|
const buttonStyleOverrides = {
|
|
25029
|
-
height: "
|
|
25029
|
+
height: "auto",
|
|
25030
25030
|
marginLeft: "-2px",
|
|
25031
|
-
|
|
25031
|
+
// transfer space on the left side to the padding
|
|
25032
|
+
marginRight: "2px",
|
|
25033
|
+
// adds space between the right border and any text that follows
|
|
25034
|
+
paddingLeft: "2px" // adds space between the left border and the button text
|
|
25035
|
+
};
|
|
25036
|
+
|
|
25037
|
+
const labelStyle = {
|
|
25038
|
+
fontSize: "18px",
|
|
25039
|
+
lineHeight: "20px",
|
|
25040
|
+
// The following property adjusts the large space between the button text and the caret icon.
|
|
25041
|
+
// Since we are unable to adjust the styling of the icon (where the extra space exists),
|
|
25042
|
+
// we are adjusting it on the text label by using a negative margin.
|
|
25043
|
+
marginRight: "-6px",
|
|
25044
|
+
"white-space": "normal"
|
|
25032
25045
|
};
|
|
25033
25046
|
const contentStyling = [styles$p.content, this.state.expanded ? styles$p.contentExpanded : styles$p.contentCollapsed, allowTransition && (this.state.expanded ? styles$p.transitionExpanded : styles$p.transitionCollapsed)];
|
|
25034
25047
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
|
|
@@ -25039,8 +25052,9 @@ class Explanation extends React__namespace.Component {
|
|
|
25039
25052
|
"aria-controls": ids.get("content"),
|
|
25040
25053
|
endIcon: caretIcon,
|
|
25041
25054
|
kind: "tertiary",
|
|
25055
|
+
labelStyle: labelStyle,
|
|
25042
25056
|
onClick: this._onClick,
|
|
25043
|
-
size: "
|
|
25057
|
+
size: "small",
|
|
25044
25058
|
style: buttonStyleOverrides
|
|
25045
25059
|
}, promptText), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
25046
25060
|
id: ids.get("content"),
|
|
@@ -28342,6 +28356,14 @@ const moveAll = delta => ({
|
|
|
28342
28356
|
type: MOVE_ALL,
|
|
28343
28357
|
delta
|
|
28344
28358
|
});
|
|
28359
|
+
const MOVE_POINT = "move-point";
|
|
28360
|
+
function movePoint(index, destination) {
|
|
28361
|
+
return {
|
|
28362
|
+
type: MOVE_POINT,
|
|
28363
|
+
index,
|
|
28364
|
+
destination
|
|
28365
|
+
};
|
|
28366
|
+
}
|
|
28345
28367
|
|
|
28346
28368
|
/**
|
|
28347
28369
|
* 44 is touch best practice and AAA compliant for WCAG
|
|
@@ -28567,7 +28589,9 @@ const SegmentGraph = props => {
|
|
|
28567
28589
|
onMoveLine: delta => {
|
|
28568
28590
|
dispatch(moveLine(i, delta));
|
|
28569
28591
|
},
|
|
28570
|
-
onMovePoint: (endpointIndex, destination) =>
|
|
28592
|
+
onMovePoint: (endpointIndex, destination) => {
|
|
28593
|
+
dispatch(moveControlPoint(endpointIndex, destination, i));
|
|
28594
|
+
},
|
|
28571
28595
|
"data-testid": "segment" + i
|
|
28572
28596
|
})));
|
|
28573
28597
|
};
|
|
@@ -28931,11 +28955,73 @@ const PolygonGraph = props => {
|
|
|
28931
28955
|
}), points.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
28932
28956
|
key: "point-" + i,
|
|
28933
28957
|
point: point,
|
|
28934
|
-
onMove: destination => dispatch(
|
|
28958
|
+
onMove: destination => dispatch(movePoint(i, destination)),
|
|
28935
28959
|
"data-testid": type + i
|
|
28936
28960
|
})));
|
|
28937
28961
|
};
|
|
28938
28962
|
|
|
28963
|
+
function PointGraph(props) {
|
|
28964
|
+
const {
|
|
28965
|
+
dispatch
|
|
28966
|
+
} = props;
|
|
28967
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.graphState.coords.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
28968
|
+
key: i,
|
|
28969
|
+
point: point,
|
|
28970
|
+
onMove: destination => dispatch(movePoint(i, destination))
|
|
28971
|
+
})));
|
|
28972
|
+
}
|
|
28973
|
+
|
|
28974
|
+
const GraphStateContext = /*#__PURE__*/React.createContext({
|
|
28975
|
+
state: {},
|
|
28976
|
+
dispatch: () => {}
|
|
28977
|
+
});
|
|
28978
|
+
function useGraphState() {
|
|
28979
|
+
return React__default["default"].useContext(GraphStateContext);
|
|
28980
|
+
}
|
|
28981
|
+
|
|
28982
|
+
function Arrow(props) {
|
|
28983
|
+
const {
|
|
28984
|
+
userTransform,
|
|
28985
|
+
viewTransform
|
|
28986
|
+
} = mafs.useTransformContext();
|
|
28987
|
+
const point = [props.x, props.y];
|
|
28988
|
+
const userTransformedPoint = mafs.vec.transform(point, userTransform);
|
|
28989
|
+
const viewTransformedPoint = mafs.vec.transform(userTransformedPoint, viewTransform);
|
|
28990
|
+
return /*#__PURE__*/React__default["default"].createElement("g", {
|
|
28991
|
+
transform: `translate(${viewTransformedPoint[0]} ${viewTransformedPoint[1]}) rotate(${props.rotate}) scale(1.25)`
|
|
28992
|
+
}, /*#__PURE__*/React__default["default"].createElement("g", {
|
|
28993
|
+
transform: "translate(-1)"
|
|
28994
|
+
}, /*#__PURE__*/React__default["default"].createElement("path", {
|
|
28995
|
+
d: "M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4",
|
|
28996
|
+
fill: "none"
|
|
28997
|
+
})));
|
|
28998
|
+
}
|
|
28999
|
+
function AxisArrows() {
|
|
29000
|
+
const {
|
|
29001
|
+
state
|
|
29002
|
+
} = useGraphState();
|
|
29003
|
+
const range = state.range;
|
|
29004
|
+
const [xMin, xMax] = range[0];
|
|
29005
|
+
const [yMin, yMax] = range[1];
|
|
29006
|
+
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29007
|
+
x: xMax,
|
|
29008
|
+
y: 0,
|
|
29009
|
+
rotate: 0
|
|
29010
|
+
}), /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29011
|
+
x: 0,
|
|
29012
|
+
y: yMin,
|
|
29013
|
+
rotate: 90
|
|
29014
|
+
}), /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29015
|
+
x: xMin,
|
|
29016
|
+
y: 0,
|
|
29017
|
+
rotate: 180
|
|
29018
|
+
}), /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29019
|
+
x: 0,
|
|
29020
|
+
y: yMax,
|
|
29021
|
+
rotate: 270
|
|
29022
|
+
}));
|
|
29023
|
+
}
|
|
29024
|
+
|
|
28939
29025
|
const renderLineLabel = (n, _ref) => {
|
|
28940
29026
|
let [min, max] = _ref;
|
|
28941
29027
|
return n !== -1 && n !== min && n !== max;
|
|
@@ -28946,10 +29032,10 @@ const axisOptions = (props, index) => ({
|
|
|
28946
29032
|
subdivisions: props.step[index] / props.gridStep[index],
|
|
28947
29033
|
labels: n => renderLineLabel(n, props.range[index]) ? n : ""
|
|
28948
29034
|
});
|
|
28949
|
-
const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
29035
|
+
const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
28950
29036
|
xAxis: axisOptions(props, 0),
|
|
28951
29037
|
yAxis: axisOptions(props, 1)
|
|
28952
|
-
});
|
|
29038
|
+
}), props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisArrows, null));
|
|
28953
29039
|
|
|
28954
29040
|
// Displays a stylized open eye: lint warnings are visible
|
|
28955
29041
|
const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
|
|
@@ -29647,22 +29733,32 @@ const LegacyGrid = _ref => {
|
|
|
29647
29733
|
return null;
|
|
29648
29734
|
};
|
|
29649
29735
|
|
|
29650
|
-
/** Determine if coords is type CollinearTuple[] */
|
|
29651
|
-
const isCollinearTuples = coords => Array.isArray(coords[0][0]);
|
|
29652
|
-
|
|
29653
|
-
// Generic type makes returned state match input state
|
|
29654
29736
|
function interactiveGraphReducer(state, action) {
|
|
29737
|
+
switch (action.type) {
|
|
29738
|
+
case MOVE_CONTROL_POINT:
|
|
29739
|
+
return doMoveControlPoint(state, action);
|
|
29740
|
+
case MOVE_LINE:
|
|
29741
|
+
return doMoveLine(state, action);
|
|
29742
|
+
case MOVE_ALL:
|
|
29743
|
+
return doMoveAll(state, action);
|
|
29744
|
+
case MOVE_POINT:
|
|
29745
|
+
return doMovePoint(state, action);
|
|
29746
|
+
default:
|
|
29747
|
+
throw new wonderStuffCore.UnreachableCaseError(action);
|
|
29748
|
+
}
|
|
29749
|
+
}
|
|
29750
|
+
function doMoveControlPoint(state, action) {
|
|
29655
29751
|
const {
|
|
29656
29752
|
snapStep,
|
|
29657
29753
|
range
|
|
29658
29754
|
} = state;
|
|
29659
|
-
|
|
29660
|
-
|
|
29661
|
-
|
|
29662
|
-
|
|
29663
|
-
case
|
|
29755
|
+
switch (state.type) {
|
|
29756
|
+
case "segment":
|
|
29757
|
+
case "linear":
|
|
29758
|
+
case "linear-system":
|
|
29759
|
+
case "ray":
|
|
29664
29760
|
{
|
|
29665
|
-
const newCoords =
|
|
29761
|
+
const newCoords = updateAtIndex({
|
|
29666
29762
|
array: state.coords,
|
|
29667
29763
|
index: action.itemIndex,
|
|
29668
29764
|
update: tuple => setAtIndex({
|
|
@@ -29677,23 +29773,9 @@ function interactiveGraphReducer(state, action) {
|
|
|
29677
29773
|
})
|
|
29678
29774
|
})
|
|
29679
29775
|
})
|
|
29680
|
-
}) : setAtIndex({
|
|
29681
|
-
array: state.coords,
|
|
29682
|
-
index: action.pointIndex,
|
|
29683
|
-
newValue: snap({
|
|
29684
|
-
snapStep,
|
|
29685
|
-
point: bound$1({
|
|
29686
|
-
snapStep,
|
|
29687
|
-
range,
|
|
29688
|
-
point: action.destination
|
|
29689
|
-
})
|
|
29690
|
-
})
|
|
29691
29776
|
});
|
|
29692
|
-
|
|
29693
|
-
|
|
29694
|
-
// so this may seem redundant, but it's necessary for type safety.
|
|
29695
|
-
const coordsToCheck = isCollinearTuples(newCoords) && action.itemIndex !== undefined ? newCoords[action.itemIndex] : newCoords;
|
|
29696
|
-
if (!isCollinearTuples(coordsToCheck) && coordsOverlap(coordsToCheck)) {
|
|
29777
|
+
const coordsToCheck = newCoords[action.itemIndex];
|
|
29778
|
+
if (coordsOverlap(coordsToCheck)) {
|
|
29697
29779
|
return state;
|
|
29698
29780
|
}
|
|
29699
29781
|
return {
|
|
@@ -29702,15 +29784,30 @@ function interactiveGraphReducer(state, action) {
|
|
|
29702
29784
|
coords: newCoords
|
|
29703
29785
|
};
|
|
29704
29786
|
}
|
|
29705
|
-
case
|
|
29787
|
+
case "circle":
|
|
29788
|
+
throw new Error("FIXME implement circle reducer");
|
|
29789
|
+
case "point":
|
|
29790
|
+
case "polygon":
|
|
29791
|
+
throw new Error(`Don't use moveControlPoint for ${state.type} graphs. Use movePoint instead!`);
|
|
29792
|
+
default:
|
|
29793
|
+
throw new wonderStuffCore.UnreachableCaseError(state);
|
|
29794
|
+
}
|
|
29795
|
+
}
|
|
29796
|
+
function doMoveLine(state, action) {
|
|
29797
|
+
const {
|
|
29798
|
+
snapStep,
|
|
29799
|
+
range
|
|
29800
|
+
} = state;
|
|
29801
|
+
switch (state.type) {
|
|
29802
|
+
case "segment":
|
|
29803
|
+
case "linear":
|
|
29804
|
+
case "linear-system":
|
|
29805
|
+
case "ray":
|
|
29706
29806
|
{
|
|
29707
|
-
if (!isCollinearTuples(state.coords)) {
|
|
29708
|
-
throw new Error("Cannot call this action unless coords is array of CollinearTuple.");
|
|
29709
|
-
}
|
|
29710
29807
|
if (action.itemIndex === undefined) {
|
|
29711
29808
|
throw new Error("Please provide index of line to move");
|
|
29712
29809
|
}
|
|
29713
|
-
const currentLine = state.coords
|
|
29810
|
+
const currentLine = state.coords[action.itemIndex];
|
|
29714
29811
|
if (!currentLine) {
|
|
29715
29812
|
throw new Error("No line to move");
|
|
29716
29813
|
}
|
|
@@ -29732,15 +29829,25 @@ function interactiveGraphReducer(state, action) {
|
|
|
29732
29829
|
});
|
|
29733
29830
|
return {
|
|
29734
29831
|
...state,
|
|
29832
|
+
type: state.type,
|
|
29735
29833
|
hasBeenInteractedWith: true,
|
|
29736
29834
|
coords: newCoords
|
|
29737
29835
|
};
|
|
29738
29836
|
}
|
|
29739
|
-
|
|
29837
|
+
default:
|
|
29838
|
+
// The MoveLine action doesn't make sense for other graph types;
|
|
29839
|
+
// ignore it if it somehow happens
|
|
29840
|
+
return state;
|
|
29841
|
+
}
|
|
29842
|
+
}
|
|
29843
|
+
function doMoveAll(state, action) {
|
|
29844
|
+
const {
|
|
29845
|
+
snapStep,
|
|
29846
|
+
range
|
|
29847
|
+
} = state;
|
|
29848
|
+
switch (state.type) {
|
|
29849
|
+
case "polygon":
|
|
29740
29850
|
{
|
|
29741
|
-
if (isCollinearTuples(state.coords)) {
|
|
29742
|
-
throw new Error("Cannot call this action unless coords is array of vectors.");
|
|
29743
|
-
}
|
|
29744
29851
|
const change = getChange(state.coords, action.delta, {
|
|
29745
29852
|
snapStep,
|
|
29746
29853
|
range
|
|
@@ -29756,7 +29863,34 @@ function interactiveGraphReducer(state, action) {
|
|
|
29756
29863
|
};
|
|
29757
29864
|
}
|
|
29758
29865
|
default:
|
|
29759
|
-
|
|
29866
|
+
// MoveAll is not supported for other state types; just ignore it.
|
|
29867
|
+
return state;
|
|
29868
|
+
}
|
|
29869
|
+
}
|
|
29870
|
+
function doMovePoint(state, action) {
|
|
29871
|
+
switch (state.type) {
|
|
29872
|
+
case "point":
|
|
29873
|
+
case "polygon":
|
|
29874
|
+
{
|
|
29875
|
+
return {
|
|
29876
|
+
...state,
|
|
29877
|
+
hasBeenInteractedWith: true,
|
|
29878
|
+
coords: setAtIndex({
|
|
29879
|
+
array: state.coords,
|
|
29880
|
+
index: action.index,
|
|
29881
|
+
newValue: snap({
|
|
29882
|
+
snapStep: state.snapStep,
|
|
29883
|
+
point: bound$1({
|
|
29884
|
+
snapStep: state.snapStep,
|
|
29885
|
+
range: state.range,
|
|
29886
|
+
point: action.destination
|
|
29887
|
+
})
|
|
29888
|
+
})
|
|
29889
|
+
})
|
|
29890
|
+
};
|
|
29891
|
+
}
|
|
29892
|
+
default:
|
|
29893
|
+
throw new Error("The movePoint action is only for point and polygon graphs");
|
|
29760
29894
|
}
|
|
29761
29895
|
}
|
|
29762
29896
|
const getChange = (coords, delta, constraintOpts) => {
|
|
@@ -29843,7 +29977,7 @@ function clamp(value, min, max) {
|
|
|
29843
29977
|
const coordsOverlap = coords => coords.some((coord, i) => coords.some((c, j) => i !== j && kmath.vector.equal(coord, c)));
|
|
29844
29978
|
function updateAtIndex(args) {
|
|
29845
29979
|
const {
|
|
29846
|
-
array
|
|
29980
|
+
array,
|
|
29847
29981
|
index,
|
|
29848
29982
|
update
|
|
29849
29983
|
} = args;
|
|
@@ -29856,13 +29990,12 @@ function updateAtIndex(args) {
|
|
|
29856
29990
|
}
|
|
29857
29991
|
function setAtIndex(args) {
|
|
29858
29992
|
const {
|
|
29859
|
-
array
|
|
29993
|
+
array,
|
|
29860
29994
|
index,
|
|
29861
29995
|
newValue
|
|
29862
29996
|
} = args;
|
|
29863
29997
|
const copy = [...array];
|
|
29864
29998
|
copy[index] = newValue;
|
|
29865
|
-
// restoring readonly to array
|
|
29866
29999
|
return copy;
|
|
29867
30000
|
}
|
|
29868
30001
|
|
|
@@ -29904,18 +30037,31 @@ function initializeGraphState(params) {
|
|
|
29904
30037
|
};
|
|
29905
30038
|
case "polygon":
|
|
29906
30039
|
return {
|
|
30040
|
+
type: "polygon",
|
|
29907
30041
|
hasBeenInteractedWith: false,
|
|
29908
30042
|
range,
|
|
29909
30043
|
snapStep,
|
|
29910
|
-
|
|
30044
|
+
showAngles: Boolean(graph.showAngles),
|
|
30045
|
+
showSides: Boolean(graph.showSides),
|
|
29911
30046
|
coords: getPolygonCoords({
|
|
29912
30047
|
graph,
|
|
29913
30048
|
range,
|
|
29914
30049
|
step
|
|
29915
30050
|
})
|
|
29916
30051
|
};
|
|
29917
|
-
case "angle":
|
|
29918
30052
|
case "point":
|
|
30053
|
+
return {
|
|
30054
|
+
type: graph.type,
|
|
30055
|
+
hasBeenInteractedWith: false,
|
|
30056
|
+
range,
|
|
30057
|
+
snapStep,
|
|
30058
|
+
coords: getDefaultPoints({
|
|
30059
|
+
graph,
|
|
30060
|
+
step,
|
|
30061
|
+
range
|
|
30062
|
+
})
|
|
30063
|
+
};
|
|
30064
|
+
case "angle":
|
|
29919
30065
|
case "circle":
|
|
29920
30066
|
case "sinusoid":
|
|
29921
30067
|
case "quadratic":
|
|
@@ -29924,6 +30070,46 @@ function initializeGraphState(params) {
|
|
|
29924
30070
|
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
29925
30071
|
}
|
|
29926
30072
|
}
|
|
30073
|
+
const getDefaultPoints = _ref => {
|
|
30074
|
+
let {
|
|
30075
|
+
graph,
|
|
30076
|
+
range,
|
|
30077
|
+
step
|
|
30078
|
+
} = _ref;
|
|
30079
|
+
const numPoints = graph.numPoints || 1;
|
|
30080
|
+
let coords = graph.coords?.slice();
|
|
30081
|
+
if (coords) {
|
|
30082
|
+
return coords;
|
|
30083
|
+
}
|
|
30084
|
+
switch (numPoints) {
|
|
30085
|
+
case 1:
|
|
30086
|
+
// Back in the day, one point's coords were in graph.coord
|
|
30087
|
+
coords = [graph.coord || [0, 0]];
|
|
30088
|
+
break;
|
|
30089
|
+
case 2:
|
|
30090
|
+
coords = [[-5, 0], [5, 0]];
|
|
30091
|
+
break;
|
|
30092
|
+
case 3:
|
|
30093
|
+
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
30094
|
+
break;
|
|
30095
|
+
case 4:
|
|
30096
|
+
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
30097
|
+
break;
|
|
30098
|
+
case 5:
|
|
30099
|
+
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
30100
|
+
break;
|
|
30101
|
+
case 6:
|
|
30102
|
+
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
30103
|
+
break;
|
|
30104
|
+
default:
|
|
30105
|
+
coords = [];
|
|
30106
|
+
break;
|
|
30107
|
+
}
|
|
30108
|
+
// Transform coords from their -10 to 10 space to 0 to 1
|
|
30109
|
+
// because of the old graph.coord, and also it's easier.
|
|
30110
|
+
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
30111
|
+
return normalizePoints(range, step, newCoords);
|
|
30112
|
+
};
|
|
29927
30113
|
|
|
29928
30114
|
// TS v4 doesn't narrow return types, while v5 does.
|
|
29929
30115
|
// Instead of updating to v5, using generic type to relate input and output types.
|
|
@@ -29948,13 +30134,13 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29948
30134
|
if (state.type === "linear" && initialGraph.type === "linear") {
|
|
29949
30135
|
return {
|
|
29950
30136
|
...initialGraph,
|
|
29951
|
-
coords: state.coords
|
|
30137
|
+
coords: state.coords[0]
|
|
29952
30138
|
};
|
|
29953
30139
|
}
|
|
29954
30140
|
if (state.type === "ray" && initialGraph.type === "ray") {
|
|
29955
30141
|
return {
|
|
29956
30142
|
...initialGraph,
|
|
29957
|
-
coords: state.coords
|
|
30143
|
+
coords: state.coords[0]
|
|
29958
30144
|
};
|
|
29959
30145
|
}
|
|
29960
30146
|
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
@@ -29963,14 +30149,20 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29963
30149
|
coords: state.coords
|
|
29964
30150
|
};
|
|
29965
30151
|
}
|
|
30152
|
+
if (state.type === "point" && initialGraph.type === "point") {
|
|
30153
|
+
return {
|
|
30154
|
+
...initialGraph,
|
|
30155
|
+
coords: state.coords
|
|
30156
|
+
};
|
|
30157
|
+
}
|
|
29966
30158
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
29967
30159
|
}
|
|
29968
|
-
const getDefaultSegments =
|
|
30160
|
+
const getDefaultSegments = _ref2 => {
|
|
29969
30161
|
let {
|
|
29970
30162
|
graph,
|
|
29971
30163
|
range,
|
|
29972
30164
|
step
|
|
29973
|
-
} =
|
|
30165
|
+
} = _ref2;
|
|
29974
30166
|
const ys = n => {
|
|
29975
30167
|
switch (n) {
|
|
29976
30168
|
case 2:
|
|
@@ -29996,24 +30188,24 @@ const getDefaultSegments = _ref => {
|
|
|
29996
30188
|
});
|
|
29997
30189
|
};
|
|
29998
30190
|
const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
|
|
29999
|
-
const getLineCoords =
|
|
30191
|
+
const getLineCoords = _ref3 => {
|
|
30000
30192
|
let {
|
|
30001
30193
|
graph,
|
|
30002
30194
|
range,
|
|
30003
30195
|
step
|
|
30004
|
-
} =
|
|
30196
|
+
} = _ref3;
|
|
30005
30197
|
return (
|
|
30006
30198
|
// Return two lines for a linear system, one for a ray or linear
|
|
30007
30199
|
graph.coords ?? graph.type === "linear-system" ? defaultLinearCoords.map(collinear => normalizePoints(range, step, collinear)) : [normalizePoints(range, step, defaultLinearCoords[0])]
|
|
30008
30200
|
);
|
|
30009
30201
|
};
|
|
30010
|
-
const getPolygonCoords =
|
|
30202
|
+
const getPolygonCoords = _ref4 => {
|
|
30011
30203
|
let {
|
|
30012
30204
|
graph,
|
|
30013
30205
|
range,
|
|
30014
30206
|
step
|
|
30015
|
-
} =
|
|
30016
|
-
let coords = graph.coords;
|
|
30207
|
+
} = _ref4;
|
|
30208
|
+
let coords = graph.coords?.slice();
|
|
30017
30209
|
if (coords) {
|
|
30018
30210
|
return coords;
|
|
30019
30211
|
}
|
|
@@ -30067,6 +30259,13 @@ const renderGraph = props => {
|
|
|
30067
30259
|
graphState: state,
|
|
30068
30260
|
dispatch: dispatch
|
|
30069
30261
|
});
|
|
30262
|
+
case "point":
|
|
30263
|
+
return /*#__PURE__*/React__namespace.createElement(PointGraph, {
|
|
30264
|
+
graphState: state,
|
|
30265
|
+
dispatch: dispatch
|
|
30266
|
+
});
|
|
30267
|
+
case "circle":
|
|
30268
|
+
throw new Error("the circle graph type is not yet implemented");
|
|
30070
30269
|
default:
|
|
30071
30270
|
return new wonderStuffCore.UnreachableCaseError(type);
|
|
30072
30271
|
}
|
|
@@ -30074,10 +30273,24 @@ const renderGraph = props => {
|
|
|
30074
30273
|
const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
30075
30274
|
const [width, height] = props.box;
|
|
30076
30275
|
const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
30276
|
+
const prevState = React.useRef(state);
|
|
30277
|
+
React.useEffect(() => {
|
|
30278
|
+
if (prevState.current !== state) {
|
|
30279
|
+
props.onChange({
|
|
30280
|
+
graph: state
|
|
30281
|
+
});
|
|
30282
|
+
}
|
|
30283
|
+
prevState.current = state;
|
|
30284
|
+
}, [props, state]);
|
|
30077
30285
|
React__namespace.useImperativeHandle(ref, () => ({
|
|
30078
30286
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
30079
30287
|
}));
|
|
30080
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
30288
|
+
return /*#__PURE__*/React__namespace.createElement(GraphStateContext.Provider, {
|
|
30289
|
+
value: {
|
|
30290
|
+
state,
|
|
30291
|
+
dispatch
|
|
30292
|
+
}
|
|
30293
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30081
30294
|
style: {
|
|
30082
30295
|
width,
|
|
30083
30296
|
height,
|
|
@@ -30108,7 +30321,7 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
|
30108
30321
|
}), renderGraph({
|
|
30109
30322
|
state,
|
|
30110
30323
|
dispatch
|
|
30111
|
-
}))));
|
|
30324
|
+
})))));
|
|
30112
30325
|
});
|
|
30113
30326
|
|
|
30114
30327
|
const {
|
|
@@ -31275,6 +31488,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
31275
31488
|
});
|
|
31276
31489
|
$__default["default"](this.angle).on("move", () => {
|
|
31277
31490
|
this.onChange({
|
|
31491
|
+
// @ts-expect-error Type '{ coords: any; type: "angle"; showAngles?: boolean | undefined; allowReflexAngles?: boolean | undefined; angleOffsetDeg?: number | undefined; snapDegrees?: number | undefined; match?: "congruent" | undefined; }' is not assignable to type 'InteractiveGraphState | undefined'.
|
|
31278
31492
|
graph: {
|
|
31279
31493
|
...graph,
|
|
31280
31494
|
coords: this.angle?.getClockwiseCoords()
|
|
@@ -31809,7 +32023,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
31809
32023
|
}
|
|
31810
32024
|
} else if (userInput.type === "point" && rubric.correct.type === "point" && userInput.coords != null) {
|
|
31811
32025
|
let correct = InteractiveGraph.getPointCoords(rubric.correct, component);
|
|
31812
|
-
const guess = userInput.coords
|
|
32026
|
+
const guess = userInput.coords.slice();
|
|
31813
32027
|
correct = correct.slice();
|
|
31814
32028
|
// Everything's already rounded so we shouldn't need to do an
|
|
31815
32029
|
// eq() comparison but _.isEqual(0, -0) is false, so we'll use
|
|
@@ -42115,7 +42329,7 @@ const init = function (options) {
|
|
|
42115
42329
|
|
|
42116
42330
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42117
42331
|
const libName = "@khanacademy/perseus";
|
|
42118
|
-
const libVersion = "21.
|
|
42332
|
+
const libVersion = "21.1.0";
|
|
42119
42333
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42120
42334
|
|
|
42121
42335
|
const apiVersion = {
|
|
@@ -44617,7 +44831,7 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44617
44831
|
// E.g. 'item 1\nitem 2\nitem 3'
|
|
44618
44832
|
const orderer = widget;
|
|
44619
44833
|
if (orderer.options?.correctOptions) {
|
|
44620
|
-
answers.push(orderer.options.correctOptions
|
|
44834
|
+
answers.push(joinOptionContents(orderer.options.correctOptions));
|
|
44621
44835
|
}
|
|
44622
44836
|
break;
|
|
44623
44837
|
case "sorter":
|
|
@@ -44676,6 +44890,31 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44676
44890
|
return answers;
|
|
44677
44891
|
}
|
|
44678
44892
|
|
|
44893
|
+
/**
|
|
44894
|
+
* Join the content of the options together.
|
|
44895
|
+
* @param {Array<{content: string}>} options
|
|
44896
|
+
* @returns {string}
|
|
44897
|
+
*/
|
|
44898
|
+
const joinOptionContents = options => options.map(_ref => {
|
|
44899
|
+
let {
|
|
44900
|
+
content
|
|
44901
|
+
} = _ref;
|
|
44902
|
+
return content;
|
|
44903
|
+
}).join("\n");
|
|
44904
|
+
|
|
44905
|
+
/**
|
|
44906
|
+
* Convert an index to an option letter.
|
|
44907
|
+
* @param {number} index
|
|
44908
|
+
* @returns {string}
|
|
44909
|
+
* @example
|
|
44910
|
+
* toOptionLetter(0) // 'A'
|
|
44911
|
+
* toOptionLetter(1) // 'B'
|
|
44912
|
+
* toOptionLetter(25) // 'Z'
|
|
44913
|
+
* // Once the index goes past 25, it will start returning special characters
|
|
44914
|
+
* toOptionLetter(26) // '['
|
|
44915
|
+
*/
|
|
44916
|
+
const toOptionLetter = index => String.fromCharCode("A".charCodeAt(0) + index);
|
|
44917
|
+
|
|
44679
44918
|
/**
|
|
44680
44919
|
* Inject a string equivalent of the widgets into the content.
|
|
44681
44920
|
*
|
|
@@ -44686,7 +44925,7 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44686
44925
|
* @param {PerseusRenderer["widgets"]} widgets
|
|
44687
44926
|
* @returns
|
|
44688
44927
|
*/
|
|
44689
|
-
function injectWidgets(content, widgets) {
|
|
44928
|
+
function injectWidgets(content, widgets, widgetProps) {
|
|
44690
44929
|
// The types for taskProgress.itemData are not well defined,
|
|
44691
44930
|
// so there is a chance that widgets or content could be undefined.
|
|
44692
44931
|
// In that scenario, simply exit early and return the content as is.
|
|
@@ -44705,11 +44944,22 @@ function injectWidgets(content, widgets) {
|
|
|
44705
44944
|
switch (widget.type) {
|
|
44706
44945
|
case "radio":
|
|
44707
44946
|
// Replace radio with the radio options
|
|
44708
|
-
// '[[☃ Radio 1]]' -> '
|
|
44947
|
+
// '[[☃ Radio 1]]' -> 'choice 1\nchoice 2\nchoice 3'
|
|
44948
|
+
// or if the current widget state is available with proper order,
|
|
44949
|
+
// '[[☃ Radio 1]]' ->
|
|
44950
|
+
// 'Option A: choice 1\nOption B: choice 2\nOption C: choice 3'
|
|
44709
44951
|
const radio = widget;
|
|
44952
|
+
const radioProps = widgetProps?.[widgetID];
|
|
44710
44953
|
if (radio.options?.choices?.length) {
|
|
44711
|
-
let radioContext =
|
|
44712
|
-
|
|
44954
|
+
let radioContext = joinOptionContents(radioProps ? radioProps.choices.map((_ref2, i) => {
|
|
44955
|
+
let {
|
|
44956
|
+
content
|
|
44957
|
+
} = _ref2;
|
|
44958
|
+
return {
|
|
44959
|
+
content: `Option ${toOptionLetter(i)}: ${content}`
|
|
44960
|
+
};
|
|
44961
|
+
}) : radio.options.choices);
|
|
44962
|
+
if (!radioProps && radio.options?.randomize) {
|
|
44713
44963
|
radioContext += "\nThose options are displayed in a different order to the user. If the user says the letter, number, or ordinal number, always ask them clarify which option they are referring to.\n";
|
|
44714
44964
|
}
|
|
44715
44965
|
context = context.replace(`[[☃ ${widgetID}]]`, radioContext);
|
|
@@ -44817,7 +45067,7 @@ function injectWidgets(content, widgets) {
|
|
|
44817
45067
|
// '[[☃ Orderer 1]]' -> 'option 1\noption 2\noption 3'
|
|
44818
45068
|
const orderer = widget;
|
|
44819
45069
|
if (orderer.options?.options) {
|
|
44820
|
-
context = context.replace(`[[☃ ${widgetID}]]`, orderer.options.options
|
|
45070
|
+
context = context.replace(`[[☃ ${widgetID}]]`, joinOptionContents(orderer.options.options));
|
|
44821
45071
|
}
|
|
44822
45072
|
break;
|
|
44823
45073
|
case "sorter":
|