@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/es/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import * as i18n from '@khanacademy/wonder-blocks-i18n';
|
|
|
7
7
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
8
8
|
import classNames from 'classnames';
|
|
9
9
|
import * as React from 'react';
|
|
10
|
-
import React__default, { useState, useEffect, useRef } from 'react';
|
|
10
|
+
import React__default, { useState, useEffect, useRef, createContext } from 'react';
|
|
11
11
|
import _, { debounce as debounce$1 } from 'underscore';
|
|
12
12
|
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
13
13
|
import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
|
|
@@ -24901,9 +24901,22 @@ class Explanation extends React.Component {
|
|
|
24901
24901
|
// Special styling is needed to fit the button in a block of text without throwing off the line spacing.
|
|
24902
24902
|
// While the button is not normally included in a block of text, it needs to be able to accommodate such a case.
|
|
24903
24903
|
const buttonStyleOverrides = {
|
|
24904
|
-
height: "
|
|
24904
|
+
height: "auto",
|
|
24905
24905
|
marginLeft: "-2px",
|
|
24906
|
-
|
|
24906
|
+
// transfer space on the left side to the padding
|
|
24907
|
+
marginRight: "2px",
|
|
24908
|
+
// adds space between the right border and any text that follows
|
|
24909
|
+
paddingLeft: "2px" // adds space between the left border and the button text
|
|
24910
|
+
};
|
|
24911
|
+
|
|
24912
|
+
const labelStyle = {
|
|
24913
|
+
fontSize: "18px",
|
|
24914
|
+
lineHeight: "20px",
|
|
24915
|
+
// The following property adjusts the large space between the button text and the caret icon.
|
|
24916
|
+
// Since we are unable to adjust the styling of the icon (where the extra space exists),
|
|
24917
|
+
// we are adjusting it on the text label by using a negative margin.
|
|
24918
|
+
marginRight: "-6px",
|
|
24919
|
+
"white-space": "normal"
|
|
24907
24920
|
};
|
|
24908
24921
|
const contentStyling = [styles$p.content, this.state.expanded ? styles$p.contentExpanded : styles$p.contentCollapsed, allowTransition && (this.state.expanded ? styles$p.transitionExpanded : styles$p.transitionCollapsed)];
|
|
24909
24922
|
return /*#__PURE__*/React.createElement(UniqueIDProvider, {
|
|
@@ -24914,8 +24927,9 @@ class Explanation extends React.Component {
|
|
|
24914
24927
|
"aria-controls": ids.get("content"),
|
|
24915
24928
|
endIcon: caretIcon,
|
|
24916
24929
|
kind: "tertiary",
|
|
24930
|
+
labelStyle: labelStyle,
|
|
24917
24931
|
onClick: this._onClick,
|
|
24918
|
-
size: "
|
|
24932
|
+
size: "small",
|
|
24919
24933
|
style: buttonStyleOverrides
|
|
24920
24934
|
}, promptText), /*#__PURE__*/React.createElement(View, {
|
|
24921
24935
|
id: ids.get("content"),
|
|
@@ -28190,6 +28204,14 @@ const moveAll = delta => ({
|
|
|
28190
28204
|
type: MOVE_ALL,
|
|
28191
28205
|
delta
|
|
28192
28206
|
});
|
|
28207
|
+
const MOVE_POINT = "move-point";
|
|
28208
|
+
function movePoint(index, destination) {
|
|
28209
|
+
return {
|
|
28210
|
+
type: MOVE_POINT,
|
|
28211
|
+
index,
|
|
28212
|
+
destination
|
|
28213
|
+
};
|
|
28214
|
+
}
|
|
28193
28215
|
|
|
28194
28216
|
/**
|
|
28195
28217
|
* 44 is touch best practice and AAA compliant for WCAG
|
|
@@ -28412,7 +28434,9 @@ const SegmentGraph = props => {
|
|
|
28412
28434
|
onMoveLine: delta => {
|
|
28413
28435
|
dispatch(moveLine(i, delta));
|
|
28414
28436
|
},
|
|
28415
|
-
onMovePoint: (endpointIndex, destination) =>
|
|
28437
|
+
onMovePoint: (endpointIndex, destination) => {
|
|
28438
|
+
dispatch(moveControlPoint(endpointIndex, destination, i));
|
|
28439
|
+
},
|
|
28416
28440
|
"data-testid": "segment" + i
|
|
28417
28441
|
})));
|
|
28418
28442
|
};
|
|
@@ -28768,11 +28792,73 @@ const PolygonGraph = props => {
|
|
|
28768
28792
|
}), points.map((point, i) => /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
28769
28793
|
key: "point-" + i,
|
|
28770
28794
|
point: point,
|
|
28771
|
-
onMove: destination => dispatch(
|
|
28795
|
+
onMove: destination => dispatch(movePoint(i, destination)),
|
|
28772
28796
|
"data-testid": type + i
|
|
28773
28797
|
})));
|
|
28774
28798
|
};
|
|
28775
28799
|
|
|
28800
|
+
function PointGraph(props) {
|
|
28801
|
+
const {
|
|
28802
|
+
dispatch
|
|
28803
|
+
} = props;
|
|
28804
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, props.graphState.coords.map((point, i) => /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
28805
|
+
key: i,
|
|
28806
|
+
point: point,
|
|
28807
|
+
onMove: destination => dispatch(movePoint(i, destination))
|
|
28808
|
+
})));
|
|
28809
|
+
}
|
|
28810
|
+
|
|
28811
|
+
const GraphStateContext = /*#__PURE__*/createContext({
|
|
28812
|
+
state: {},
|
|
28813
|
+
dispatch: () => {}
|
|
28814
|
+
});
|
|
28815
|
+
function useGraphState() {
|
|
28816
|
+
return React__default.useContext(GraphStateContext);
|
|
28817
|
+
}
|
|
28818
|
+
|
|
28819
|
+
function Arrow(props) {
|
|
28820
|
+
const {
|
|
28821
|
+
userTransform,
|
|
28822
|
+
viewTransform
|
|
28823
|
+
} = useTransformContext();
|
|
28824
|
+
const point = [props.x, props.y];
|
|
28825
|
+
const userTransformedPoint = vec.transform(point, userTransform);
|
|
28826
|
+
const viewTransformedPoint = vec.transform(userTransformedPoint, viewTransform);
|
|
28827
|
+
return /*#__PURE__*/React__default.createElement("g", {
|
|
28828
|
+
transform: `translate(${viewTransformedPoint[0]} ${viewTransformedPoint[1]}) rotate(${props.rotate}) scale(1.25)`
|
|
28829
|
+
}, /*#__PURE__*/React__default.createElement("g", {
|
|
28830
|
+
transform: "translate(-1)"
|
|
28831
|
+
}, /*#__PURE__*/React__default.createElement("path", {
|
|
28832
|
+
d: "M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4",
|
|
28833
|
+
fill: "none"
|
|
28834
|
+
})));
|
|
28835
|
+
}
|
|
28836
|
+
function AxisArrows() {
|
|
28837
|
+
const {
|
|
28838
|
+
state
|
|
28839
|
+
} = useGraphState();
|
|
28840
|
+
const range = state.range;
|
|
28841
|
+
const [xMin, xMax] = range[0];
|
|
28842
|
+
const [yMin, yMax] = range[1];
|
|
28843
|
+
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrow, {
|
|
28844
|
+
x: xMax,
|
|
28845
|
+
y: 0,
|
|
28846
|
+
rotate: 0
|
|
28847
|
+
}), /*#__PURE__*/React__default.createElement(Arrow, {
|
|
28848
|
+
x: 0,
|
|
28849
|
+
y: yMin,
|
|
28850
|
+
rotate: 90
|
|
28851
|
+
}), /*#__PURE__*/React__default.createElement(Arrow, {
|
|
28852
|
+
x: xMin,
|
|
28853
|
+
y: 0,
|
|
28854
|
+
rotate: 180
|
|
28855
|
+
}), /*#__PURE__*/React__default.createElement(Arrow, {
|
|
28856
|
+
x: 0,
|
|
28857
|
+
y: yMax,
|
|
28858
|
+
rotate: 270
|
|
28859
|
+
}));
|
|
28860
|
+
}
|
|
28861
|
+
|
|
28776
28862
|
const renderLineLabel = (n, [min, max]) => n !== -1 && n !== min && n !== max;
|
|
28777
28863
|
const axisOptions = (props, index) => ({
|
|
28778
28864
|
axis: props.markings === "graph",
|
|
@@ -28780,10 +28866,10 @@ const axisOptions = (props, index) => ({
|
|
|
28780
28866
|
subdivisions: props.step[index] / props.gridStep[index],
|
|
28781
28867
|
labels: n => renderLineLabel(n, props.range[index]) ? n : ""
|
|
28782
28868
|
});
|
|
28783
|
-
const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
|
|
28869
|
+
const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
|
|
28784
28870
|
xAxis: axisOptions(props, 0),
|
|
28785
28871
|
yAxis: axisOptions(props, 1)
|
|
28786
|
-
});
|
|
28872
|
+
}), props.markings === "graph" && /*#__PURE__*/React.createElement(AxisArrows, null));
|
|
28787
28873
|
|
|
28788
28874
|
// Displays a stylized open eye: lint warnings are visible
|
|
28789
28875
|
const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
|
|
@@ -29480,22 +29566,32 @@ const LegacyGrid = ({
|
|
|
29480
29566
|
return null;
|
|
29481
29567
|
};
|
|
29482
29568
|
|
|
29483
|
-
/** Determine if coords is type CollinearTuple[] */
|
|
29484
|
-
const isCollinearTuples = coords => Array.isArray(coords[0][0]);
|
|
29485
|
-
|
|
29486
|
-
// Generic type makes returned state match input state
|
|
29487
29569
|
function interactiveGraphReducer(state, action) {
|
|
29570
|
+
switch (action.type) {
|
|
29571
|
+
case MOVE_CONTROL_POINT:
|
|
29572
|
+
return doMoveControlPoint(state, action);
|
|
29573
|
+
case MOVE_LINE:
|
|
29574
|
+
return doMoveLine(state, action);
|
|
29575
|
+
case MOVE_ALL:
|
|
29576
|
+
return doMoveAll(state, action);
|
|
29577
|
+
case MOVE_POINT:
|
|
29578
|
+
return doMovePoint(state, action);
|
|
29579
|
+
default:
|
|
29580
|
+
throw new UnreachableCaseError(action);
|
|
29581
|
+
}
|
|
29582
|
+
}
|
|
29583
|
+
function doMoveControlPoint(state, action) {
|
|
29488
29584
|
const {
|
|
29489
29585
|
snapStep,
|
|
29490
29586
|
range
|
|
29491
29587
|
} = state;
|
|
29492
|
-
|
|
29493
|
-
|
|
29494
|
-
|
|
29495
|
-
|
|
29496
|
-
case
|
|
29588
|
+
switch (state.type) {
|
|
29589
|
+
case "segment":
|
|
29590
|
+
case "linear":
|
|
29591
|
+
case "linear-system":
|
|
29592
|
+
case "ray":
|
|
29497
29593
|
{
|
|
29498
|
-
const newCoords =
|
|
29594
|
+
const newCoords = updateAtIndex({
|
|
29499
29595
|
array: state.coords,
|
|
29500
29596
|
index: action.itemIndex,
|
|
29501
29597
|
update: tuple => setAtIndex({
|
|
@@ -29510,23 +29606,9 @@ function interactiveGraphReducer(state, action) {
|
|
|
29510
29606
|
})
|
|
29511
29607
|
})
|
|
29512
29608
|
})
|
|
29513
|
-
}) : setAtIndex({
|
|
29514
|
-
array: state.coords,
|
|
29515
|
-
index: action.pointIndex,
|
|
29516
|
-
newValue: snap({
|
|
29517
|
-
snapStep,
|
|
29518
|
-
point: bound$1({
|
|
29519
|
-
snapStep,
|
|
29520
|
-
range,
|
|
29521
|
-
point: action.destination
|
|
29522
|
-
})
|
|
29523
|
-
})
|
|
29524
29609
|
});
|
|
29525
|
-
|
|
29526
|
-
|
|
29527
|
-
// so this may seem redundant, but it's necessary for type safety.
|
|
29528
|
-
const coordsToCheck = isCollinearTuples(newCoords) && action.itemIndex !== undefined ? newCoords[action.itemIndex] : newCoords;
|
|
29529
|
-
if (!isCollinearTuples(coordsToCheck) && coordsOverlap(coordsToCheck)) {
|
|
29610
|
+
const coordsToCheck = newCoords[action.itemIndex];
|
|
29611
|
+
if (coordsOverlap(coordsToCheck)) {
|
|
29530
29612
|
return state;
|
|
29531
29613
|
}
|
|
29532
29614
|
return _extends({}, state, {
|
|
@@ -29534,16 +29616,30 @@ function interactiveGraphReducer(state, action) {
|
|
|
29534
29616
|
coords: newCoords
|
|
29535
29617
|
});
|
|
29536
29618
|
}
|
|
29537
|
-
case
|
|
29619
|
+
case "circle":
|
|
29620
|
+
throw new Error("FIXME implement circle reducer");
|
|
29621
|
+
case "point":
|
|
29622
|
+
case "polygon":
|
|
29623
|
+
throw new Error(`Don't use moveControlPoint for ${state.type} graphs. Use movePoint instead!`);
|
|
29624
|
+
default:
|
|
29625
|
+
throw new UnreachableCaseError(state);
|
|
29626
|
+
}
|
|
29627
|
+
}
|
|
29628
|
+
function doMoveLine(state, action) {
|
|
29629
|
+
const {
|
|
29630
|
+
snapStep,
|
|
29631
|
+
range
|
|
29632
|
+
} = state;
|
|
29633
|
+
switch (state.type) {
|
|
29634
|
+
case "segment":
|
|
29635
|
+
case "linear":
|
|
29636
|
+
case "linear-system":
|
|
29637
|
+
case "ray":
|
|
29538
29638
|
{
|
|
29539
|
-
var _state$coords;
|
|
29540
|
-
if (!isCollinearTuples(state.coords)) {
|
|
29541
|
-
throw new Error("Cannot call this action unless coords is array of CollinearTuple.");
|
|
29542
|
-
}
|
|
29543
29639
|
if (action.itemIndex === undefined) {
|
|
29544
29640
|
throw new Error("Please provide index of line to move");
|
|
29545
29641
|
}
|
|
29546
|
-
const currentLine =
|
|
29642
|
+
const currentLine = state.coords[action.itemIndex];
|
|
29547
29643
|
if (!currentLine) {
|
|
29548
29644
|
throw new Error("No line to move");
|
|
29549
29645
|
}
|
|
@@ -29564,15 +29660,25 @@ function interactiveGraphReducer(state, action) {
|
|
|
29564
29660
|
newValue: newLine
|
|
29565
29661
|
});
|
|
29566
29662
|
return _extends({}, state, {
|
|
29663
|
+
type: state.type,
|
|
29567
29664
|
hasBeenInteractedWith: true,
|
|
29568
29665
|
coords: newCoords
|
|
29569
29666
|
});
|
|
29570
29667
|
}
|
|
29571
|
-
|
|
29668
|
+
default:
|
|
29669
|
+
// The MoveLine action doesn't make sense for other graph types;
|
|
29670
|
+
// ignore it if it somehow happens
|
|
29671
|
+
return state;
|
|
29672
|
+
}
|
|
29673
|
+
}
|
|
29674
|
+
function doMoveAll(state, action) {
|
|
29675
|
+
const {
|
|
29676
|
+
snapStep,
|
|
29677
|
+
range
|
|
29678
|
+
} = state;
|
|
29679
|
+
switch (state.type) {
|
|
29680
|
+
case "polygon":
|
|
29572
29681
|
{
|
|
29573
|
-
if (isCollinearTuples(state.coords)) {
|
|
29574
|
-
throw new Error("Cannot call this action unless coords is array of vectors.");
|
|
29575
|
-
}
|
|
29576
29682
|
const change = getChange(state.coords, action.delta, {
|
|
29577
29683
|
snapStep,
|
|
29578
29684
|
range
|
|
@@ -29587,7 +29693,33 @@ function interactiveGraphReducer(state, action) {
|
|
|
29587
29693
|
});
|
|
29588
29694
|
}
|
|
29589
29695
|
default:
|
|
29590
|
-
|
|
29696
|
+
// MoveAll is not supported for other state types; just ignore it.
|
|
29697
|
+
return state;
|
|
29698
|
+
}
|
|
29699
|
+
}
|
|
29700
|
+
function doMovePoint(state, action) {
|
|
29701
|
+
switch (state.type) {
|
|
29702
|
+
case "point":
|
|
29703
|
+
case "polygon":
|
|
29704
|
+
{
|
|
29705
|
+
return _extends({}, state, {
|
|
29706
|
+
hasBeenInteractedWith: true,
|
|
29707
|
+
coords: setAtIndex({
|
|
29708
|
+
array: state.coords,
|
|
29709
|
+
index: action.index,
|
|
29710
|
+
newValue: snap({
|
|
29711
|
+
snapStep: state.snapStep,
|
|
29712
|
+
point: bound$1({
|
|
29713
|
+
snapStep: state.snapStep,
|
|
29714
|
+
range: state.range,
|
|
29715
|
+
point: action.destination
|
|
29716
|
+
})
|
|
29717
|
+
})
|
|
29718
|
+
})
|
|
29719
|
+
});
|
|
29720
|
+
}
|
|
29721
|
+
default:
|
|
29722
|
+
throw new Error("The movePoint action is only for point and polygon graphs");
|
|
29591
29723
|
}
|
|
29592
29724
|
}
|
|
29593
29725
|
const getChange = (coords, delta, constraintOpts) => {
|
|
@@ -29668,7 +29800,7 @@ function clamp(value, min, max) {
|
|
|
29668
29800
|
const coordsOverlap = coords => coords.some((coord, i) => coords.some((c, j) => i !== j && vector$1.equal(coord, c)));
|
|
29669
29801
|
function updateAtIndex(args) {
|
|
29670
29802
|
const {
|
|
29671
|
-
array
|
|
29803
|
+
array,
|
|
29672
29804
|
index,
|
|
29673
29805
|
update
|
|
29674
29806
|
} = args;
|
|
@@ -29681,13 +29813,12 @@ function updateAtIndex(args) {
|
|
|
29681
29813
|
}
|
|
29682
29814
|
function setAtIndex(args) {
|
|
29683
29815
|
const {
|
|
29684
|
-
array
|
|
29816
|
+
array,
|
|
29685
29817
|
index,
|
|
29686
29818
|
newValue
|
|
29687
29819
|
} = args;
|
|
29688
29820
|
const copy = [...array];
|
|
29689
29821
|
copy[index] = newValue;
|
|
29690
|
-
// restoring readonly to array
|
|
29691
29822
|
return copy;
|
|
29692
29823
|
}
|
|
29693
29824
|
|
|
@@ -29728,19 +29859,32 @@ function initializeGraphState(params) {
|
|
|
29728
29859
|
})
|
|
29729
29860
|
};
|
|
29730
29861
|
case "polygon":
|
|
29731
|
-
return
|
|
29862
|
+
return {
|
|
29863
|
+
type: "polygon",
|
|
29732
29864
|
hasBeenInteractedWith: false,
|
|
29733
29865
|
range,
|
|
29734
|
-
snapStep
|
|
29735
|
-
|
|
29866
|
+
snapStep,
|
|
29867
|
+
showAngles: Boolean(graph.showAngles),
|
|
29868
|
+
showSides: Boolean(graph.showSides),
|
|
29736
29869
|
coords: getPolygonCoords({
|
|
29737
29870
|
graph,
|
|
29738
29871
|
range,
|
|
29739
29872
|
step
|
|
29740
29873
|
})
|
|
29741
|
-
}
|
|
29742
|
-
case "angle":
|
|
29874
|
+
};
|
|
29743
29875
|
case "point":
|
|
29876
|
+
return {
|
|
29877
|
+
type: graph.type,
|
|
29878
|
+
hasBeenInteractedWith: false,
|
|
29879
|
+
range,
|
|
29880
|
+
snapStep,
|
|
29881
|
+
coords: getDefaultPoints({
|
|
29882
|
+
graph,
|
|
29883
|
+
step,
|
|
29884
|
+
range
|
|
29885
|
+
})
|
|
29886
|
+
};
|
|
29887
|
+
case "angle":
|
|
29744
29888
|
case "circle":
|
|
29745
29889
|
case "sinusoid":
|
|
29746
29890
|
case "quadratic":
|
|
@@ -29749,6 +29893,46 @@ function initializeGraphState(params) {
|
|
|
29749
29893
|
throw new UnreachableCaseError(graph);
|
|
29750
29894
|
}
|
|
29751
29895
|
}
|
|
29896
|
+
const getDefaultPoints = ({
|
|
29897
|
+
graph,
|
|
29898
|
+
range,
|
|
29899
|
+
step
|
|
29900
|
+
}) => {
|
|
29901
|
+
var _graph$coords;
|
|
29902
|
+
const numPoints = graph.numPoints || 1;
|
|
29903
|
+
let coords = (_graph$coords = graph.coords) == null ? void 0 : _graph$coords.slice();
|
|
29904
|
+
if (coords) {
|
|
29905
|
+
return coords;
|
|
29906
|
+
}
|
|
29907
|
+
switch (numPoints) {
|
|
29908
|
+
case 1:
|
|
29909
|
+
// Back in the day, one point's coords were in graph.coord
|
|
29910
|
+
coords = [graph.coord || [0, 0]];
|
|
29911
|
+
break;
|
|
29912
|
+
case 2:
|
|
29913
|
+
coords = [[-5, 0], [5, 0]];
|
|
29914
|
+
break;
|
|
29915
|
+
case 3:
|
|
29916
|
+
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
29917
|
+
break;
|
|
29918
|
+
case 4:
|
|
29919
|
+
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
29920
|
+
break;
|
|
29921
|
+
case 5:
|
|
29922
|
+
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
29923
|
+
break;
|
|
29924
|
+
case 6:
|
|
29925
|
+
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
29926
|
+
break;
|
|
29927
|
+
default:
|
|
29928
|
+
coords = [];
|
|
29929
|
+
break;
|
|
29930
|
+
}
|
|
29931
|
+
// Transform coords from their -10 to 10 space to 0 to 1
|
|
29932
|
+
// because of the old graph.coord, and also it's easier.
|
|
29933
|
+
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
29934
|
+
return normalizePoints(range, step, newCoords);
|
|
29935
|
+
};
|
|
29752
29936
|
|
|
29753
29937
|
// TS v4 doesn't narrow return types, while v5 does.
|
|
29754
29938
|
// Instead of updating to v5, using generic type to relate input and output types.
|
|
@@ -29769,15 +29953,13 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29769
29953
|
});
|
|
29770
29954
|
}
|
|
29771
29955
|
if (state.type === "linear" && initialGraph.type === "linear") {
|
|
29772
|
-
var _state$coords;
|
|
29773
29956
|
return _extends({}, initialGraph, {
|
|
29774
|
-
coords:
|
|
29957
|
+
coords: state.coords[0]
|
|
29775
29958
|
});
|
|
29776
29959
|
}
|
|
29777
29960
|
if (state.type === "ray" && initialGraph.type === "ray") {
|
|
29778
|
-
var _state$coords2;
|
|
29779
29961
|
return _extends({}, initialGraph, {
|
|
29780
|
-
coords:
|
|
29962
|
+
coords: state.coords[0]
|
|
29781
29963
|
});
|
|
29782
29964
|
}
|
|
29783
29965
|
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
@@ -29785,6 +29967,11 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29785
29967
|
coords: state.coords
|
|
29786
29968
|
});
|
|
29787
29969
|
}
|
|
29970
|
+
if (state.type === "point" && initialGraph.type === "point") {
|
|
29971
|
+
return _extends({}, initialGraph, {
|
|
29972
|
+
coords: state.coords
|
|
29973
|
+
});
|
|
29974
|
+
}
|
|
29788
29975
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
29789
29976
|
}
|
|
29790
29977
|
const getDefaultSegments = ({
|
|
@@ -29822,10 +30009,10 @@ const getLineCoords = ({
|
|
|
29822
30009
|
range,
|
|
29823
30010
|
step
|
|
29824
30011
|
}) => {
|
|
29825
|
-
var _graph$
|
|
30012
|
+
var _graph$coords2;
|
|
29826
30013
|
return (
|
|
29827
30014
|
// Return two lines for a linear system, one for a ray or linear
|
|
29828
|
-
((_graph$
|
|
30015
|
+
((_graph$coords2 = graph.coords) != null ? _graph$coords2 : graph.type === "linear-system") ? defaultLinearCoords.map(collinear => normalizePoints(range, step, collinear)) : [normalizePoints(range, step, defaultLinearCoords[0])]
|
|
29829
30016
|
);
|
|
29830
30017
|
};
|
|
29831
30018
|
const getPolygonCoords = ({
|
|
@@ -29833,7 +30020,8 @@ const getPolygonCoords = ({
|
|
|
29833
30020
|
range,
|
|
29834
30021
|
step
|
|
29835
30022
|
}) => {
|
|
29836
|
-
|
|
30023
|
+
var _graph$coords3;
|
|
30024
|
+
let coords = (_graph$coords3 = graph.coords) == null ? void 0 : _graph$coords3.slice();
|
|
29837
30025
|
if (coords) {
|
|
29838
30026
|
return coords;
|
|
29839
30027
|
}
|
|
@@ -29887,6 +30075,13 @@ const renderGraph = props => {
|
|
|
29887
30075
|
graphState: state,
|
|
29888
30076
|
dispatch: dispatch
|
|
29889
30077
|
});
|
|
30078
|
+
case "point":
|
|
30079
|
+
return /*#__PURE__*/React.createElement(PointGraph, {
|
|
30080
|
+
graphState: state,
|
|
30081
|
+
dispatch: dispatch
|
|
30082
|
+
});
|
|
30083
|
+
case "circle":
|
|
30084
|
+
throw new Error("the circle graph type is not yet implemented");
|
|
29890
30085
|
default:
|
|
29891
30086
|
return new UnreachableCaseError(type);
|
|
29892
30087
|
}
|
|
@@ -29894,10 +30089,24 @@ const renderGraph = props => {
|
|
|
29894
30089
|
const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
29895
30090
|
const [width, height] = props.box;
|
|
29896
30091
|
const [state, dispatch] = React.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
30092
|
+
const prevState = useRef(state);
|
|
30093
|
+
useEffect(() => {
|
|
30094
|
+
if (prevState.current !== state) {
|
|
30095
|
+
props.onChange({
|
|
30096
|
+
graph: state
|
|
30097
|
+
});
|
|
30098
|
+
}
|
|
30099
|
+
prevState.current = state;
|
|
30100
|
+
}, [props, state]);
|
|
29897
30101
|
React.useImperativeHandle(ref, () => ({
|
|
29898
30102
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
29899
30103
|
}));
|
|
29900
|
-
return /*#__PURE__*/React.createElement(
|
|
30104
|
+
return /*#__PURE__*/React.createElement(GraphStateContext.Provider, {
|
|
30105
|
+
value: {
|
|
30106
|
+
state,
|
|
30107
|
+
dispatch
|
|
30108
|
+
}
|
|
30109
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
29901
30110
|
style: {
|
|
29902
30111
|
width,
|
|
29903
30112
|
height,
|
|
@@ -29928,7 +30137,7 @@ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
29928
30137
|
}), renderGraph({
|
|
29929
30138
|
state,
|
|
29930
30139
|
dispatch
|
|
29931
|
-
}))));
|
|
30140
|
+
})))));
|
|
29932
30141
|
});
|
|
29933
30142
|
|
|
29934
30143
|
const {
|
|
@@ -31065,6 +31274,7 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
31065
31274
|
$(this.angle).on("move", () => {
|
|
31066
31275
|
var _this$angle;
|
|
31067
31276
|
this.onChange({
|
|
31277
|
+
// @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'.
|
|
31068
31278
|
graph: _extends({}, graph, {
|
|
31069
31279
|
coords: (_this$angle = this.angle) == null ? void 0 : _this$angle.getClockwiseCoords()
|
|
31070
31280
|
})
|
|
@@ -31656,9 +31866,8 @@ class InteractiveGraph extends React.Component {
|
|
|
31656
31866
|
};
|
|
31657
31867
|
}
|
|
31658
31868
|
} else if (userInput.type === "point" && rubric.correct.type === "point" && userInput.coords != null) {
|
|
31659
|
-
var _userInput$coords;
|
|
31660
31869
|
let correct = InteractiveGraph.getPointCoords(rubric.correct, component);
|
|
31661
|
-
const guess =
|
|
31870
|
+
const guess = userInput.coords.slice();
|
|
31662
31871
|
correct = correct.slice();
|
|
31663
31872
|
// Everything's already rounded so we shouldn't need to do an
|
|
31664
31873
|
// eq() comparison but _.isEqual(0, -0) is false, so we'll use
|
|
@@ -31676,8 +31885,8 @@ class InteractiveGraph extends React.Component {
|
|
|
31676
31885
|
};
|
|
31677
31886
|
}
|
|
31678
31887
|
} else if (userInput.type === "polygon" && rubric.correct.type === "polygon" && userInput.coords != null) {
|
|
31679
|
-
var _userInput$
|
|
31680
|
-
const guess = (_userInput$
|
|
31888
|
+
var _userInput$coords, _rubric$correct$coord;
|
|
31889
|
+
const guess = (_userInput$coords = userInput.coords) == null ? void 0 : _userInput$coords.slice();
|
|
31681
31890
|
// @ts-expect-error - TS2322 - Type 'Coord[] | undefined' is not assignable to type 'Coord[]'.
|
|
31682
31891
|
const correct = (_rubric$correct$coord = rubric.correct.coords) == null ? void 0 : _rubric$correct$coord.slice();
|
|
31683
31892
|
let match;
|
|
@@ -41972,7 +42181,7 @@ const init = function init(options) {
|
|
|
41972
42181
|
|
|
41973
42182
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
41974
42183
|
const libName = "@khanacademy/perseus";
|
|
41975
|
-
const libVersion = "21.
|
|
42184
|
+
const libVersion = "21.1.0";
|
|
41976
42185
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
41977
42186
|
|
|
41978
42187
|
const apiVersion = {
|
|
@@ -44482,7 +44691,7 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44482
44691
|
// E.g. 'item 1\nitem 2\nitem 3'
|
|
44483
44692
|
const orderer = widget;
|
|
44484
44693
|
if ((_orderer$options = orderer.options) != null && _orderer$options.correctOptions) {
|
|
44485
|
-
answers.push(orderer.options.correctOptions
|
|
44694
|
+
answers.push(joinOptionContents(orderer.options.correctOptions));
|
|
44486
44695
|
}
|
|
44487
44696
|
break;
|
|
44488
44697
|
case "sorter":
|
|
@@ -44541,6 +44750,28 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44541
44750
|
return answers;
|
|
44542
44751
|
}
|
|
44543
44752
|
|
|
44753
|
+
/**
|
|
44754
|
+
* Join the content of the options together.
|
|
44755
|
+
* @param {Array<{content: string}>} options
|
|
44756
|
+
* @returns {string}
|
|
44757
|
+
*/
|
|
44758
|
+
const joinOptionContents = options => options.map(({
|
|
44759
|
+
content
|
|
44760
|
+
}) => content).join("\n");
|
|
44761
|
+
|
|
44762
|
+
/**
|
|
44763
|
+
* Convert an index to an option letter.
|
|
44764
|
+
* @param {number} index
|
|
44765
|
+
* @returns {string}
|
|
44766
|
+
* @example
|
|
44767
|
+
* toOptionLetter(0) // 'A'
|
|
44768
|
+
* toOptionLetter(1) // 'B'
|
|
44769
|
+
* toOptionLetter(25) // 'Z'
|
|
44770
|
+
* // Once the index goes past 25, it will start returning special characters
|
|
44771
|
+
* toOptionLetter(26) // '['
|
|
44772
|
+
*/
|
|
44773
|
+
const toOptionLetter = index => String.fromCharCode("A".charCodeAt(0) + index);
|
|
44774
|
+
|
|
44544
44775
|
/**
|
|
44545
44776
|
* Inject a string equivalent of the widgets into the content.
|
|
44546
44777
|
*
|
|
@@ -44551,7 +44782,7 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44551
44782
|
* @param {PerseusRenderer["widgets"]} widgets
|
|
44552
44783
|
* @returns
|
|
44553
44784
|
*/
|
|
44554
|
-
function injectWidgets(content, widgets) {
|
|
44785
|
+
function injectWidgets(content, widgets, widgetProps) {
|
|
44555
44786
|
// The types for taskProgress.itemData are not well defined,
|
|
44556
44787
|
// so there is a chance that widgets or content could be undefined.
|
|
44557
44788
|
// In that scenario, simply exit early and return the content as is.
|
|
@@ -44571,12 +44802,20 @@ function injectWidgets(content, widgets) {
|
|
|
44571
44802
|
switch (widget.type) {
|
|
44572
44803
|
case "radio":
|
|
44573
44804
|
// Replace radio with the radio options
|
|
44574
|
-
// '[[☃ Radio 1]]' -> '
|
|
44805
|
+
// '[[☃ Radio 1]]' -> 'choice 1\nchoice 2\nchoice 3'
|
|
44806
|
+
// or if the current widget state is available with proper order,
|
|
44807
|
+
// '[[☃ Radio 1]]' ->
|
|
44808
|
+
// 'Option A: choice 1\nOption B: choice 2\nOption C: choice 3'
|
|
44575
44809
|
const radio = widget;
|
|
44810
|
+
const radioProps = widgetProps == null ? void 0 : widgetProps[widgetID];
|
|
44576
44811
|
if ((_radio$options = radio.options) != null && (_radio$options = _radio$options.choices) != null && _radio$options.length) {
|
|
44577
44812
|
var _radio$options2;
|
|
44578
|
-
let radioContext =
|
|
44579
|
-
|
|
44813
|
+
let radioContext = joinOptionContents(radioProps ? radioProps.choices.map(({
|
|
44814
|
+
content
|
|
44815
|
+
}, i) => ({
|
|
44816
|
+
content: `Option ${toOptionLetter(i)}: ${content}`
|
|
44817
|
+
})) : radio.options.choices);
|
|
44818
|
+
if (!radioProps && (_radio$options2 = radio.options) != null && _radio$options2.randomize) {
|
|
44580
44819
|
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";
|
|
44581
44820
|
}
|
|
44582
44821
|
context = context.replace(`[[☃ ${widgetID}]]`, radioContext);
|
|
@@ -44685,7 +44924,7 @@ function injectWidgets(content, widgets) {
|
|
|
44685
44924
|
// '[[☃ Orderer 1]]' -> 'option 1\noption 2\noption 3'
|
|
44686
44925
|
const orderer = widget;
|
|
44687
44926
|
if ((_orderer$options2 = orderer.options) != null && _orderer$options2.options) {
|
|
44688
|
-
context = context.replace(`[[☃ ${widgetID}]]`, orderer.options.options
|
|
44927
|
+
context = context.replace(`[[☃ ${widgetID}]]`, joinOptionContents(orderer.options.options));
|
|
44689
44928
|
}
|
|
44690
44929
|
break;
|
|
44691
44930
|
case "sorter":
|