@khanacademy/perseus 21.0.0 → 21.2.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 +519 -117
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +532 -119
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -1
- package/dist/perseus-types.d.ts +6 -2
- package/dist/server-item-renderer.d.ts +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/util/extract-perseus-data.d.ts +2 -2
- package/dist/util.d.ts +3 -0
- package/dist/widgets/expression.d.ts +6 -6
- package/dist/widgets/interactive-graph.d.ts +6 -3
- package/dist/widgets/interactive-graphs/axis-arrows.d.ts +2 -0
- package/dist/widgets/interactive-graphs/axis-ticks.d.ts +8 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +6 -4
- package/dist/widgets/interactive-graphs/graphs/point.d.ts +5 -0
- package/dist/widgets/interactive-graphs/grid.d.ts +14 -3
- 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 +23 -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 +4 -2
- package/dist/widgets/label-image.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3281,6 +3281,15 @@ const textarea = {
|
|
|
3281
3281
|
*/
|
|
3282
3282
|
const unescapeMathMode$1 = label => label.startsWith("$") && label.endsWith("$") ? label.slice(1, -1) : label;
|
|
3283
3283
|
const random$1 = seededRNG$1(new Date().getTime() & 0xffffffff);
|
|
3284
|
+
|
|
3285
|
+
// TODO(benchristel): in the future, we may want to make deepClone work for
|
|
3286
|
+
// Record<string, Cloneable> as well. Currently, it only does arrays.
|
|
3287
|
+
function deepClone(obj) {
|
|
3288
|
+
if (Array.isArray(obj)) {
|
|
3289
|
+
return obj.map(deepClone);
|
|
3290
|
+
}
|
|
3291
|
+
return obj;
|
|
3292
|
+
}
|
|
3284
3293
|
const Util = {
|
|
3285
3294
|
inputPathsEqual,
|
|
3286
3295
|
nestedMap: nestedMap$2,
|
|
@@ -3326,7 +3335,8 @@ const Util = {
|
|
|
3326
3335
|
getDataUrl: getDataUrl,
|
|
3327
3336
|
textarea,
|
|
3328
3337
|
unescapeMathMode: unescapeMathMode$1,
|
|
3329
|
-
random: random$1
|
|
3338
|
+
random: random$1,
|
|
3339
|
+
deepClone
|
|
3330
3340
|
};
|
|
3331
3341
|
|
|
3332
3342
|
// Derived from the MIT-licensed:
|
|
@@ -25026,9 +25036,22 @@ class Explanation extends React__namespace.Component {
|
|
|
25026
25036
|
// Special styling is needed to fit the button in a block of text without throwing off the line spacing.
|
|
25027
25037
|
// While the button is not normally included in a block of text, it needs to be able to accommodate such a case.
|
|
25028
25038
|
const buttonStyleOverrides = {
|
|
25029
|
-
height: "
|
|
25039
|
+
height: "auto",
|
|
25030
25040
|
marginLeft: "-2px",
|
|
25031
|
-
|
|
25041
|
+
// transfer space on the left side to the padding
|
|
25042
|
+
marginRight: "2px",
|
|
25043
|
+
// adds space between the right border and any text that follows
|
|
25044
|
+
paddingLeft: "2px" // adds space between the left border and the button text
|
|
25045
|
+
};
|
|
25046
|
+
|
|
25047
|
+
const labelStyle = {
|
|
25048
|
+
fontSize: "18px",
|
|
25049
|
+
lineHeight: "20px",
|
|
25050
|
+
// The following property adjusts the large space between the button text and the caret icon.
|
|
25051
|
+
// Since we are unable to adjust the styling of the icon (where the extra space exists),
|
|
25052
|
+
// we are adjusting it on the text label by using a negative margin.
|
|
25053
|
+
marginRight: "-6px",
|
|
25054
|
+
"white-space": "normal"
|
|
25032
25055
|
};
|
|
25033
25056
|
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
25057
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
|
|
@@ -25039,8 +25062,9 @@ class Explanation extends React__namespace.Component {
|
|
|
25039
25062
|
"aria-controls": ids.get("content"),
|
|
25040
25063
|
endIcon: caretIcon,
|
|
25041
25064
|
kind: "tertiary",
|
|
25065
|
+
labelStyle: labelStyle,
|
|
25042
25066
|
onClick: this._onClick,
|
|
25043
|
-
size: "
|
|
25067
|
+
size: "small",
|
|
25044
25068
|
style: buttonStyleOverrides
|
|
25045
25069
|
}, promptText), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
25046
25070
|
id: ids.get("content"),
|
|
@@ -28342,6 +28366,36 @@ const moveAll = delta => ({
|
|
|
28342
28366
|
type: MOVE_ALL,
|
|
28343
28367
|
delta
|
|
28344
28368
|
});
|
|
28369
|
+
const MOVE_POINT = "move-point";
|
|
28370
|
+
function movePoint(index, destination) {
|
|
28371
|
+
return {
|
|
28372
|
+
type: MOVE_POINT,
|
|
28373
|
+
index,
|
|
28374
|
+
destination
|
|
28375
|
+
};
|
|
28376
|
+
}
|
|
28377
|
+
const CHANGE_SNAP_STEP = "change-snap-step";
|
|
28378
|
+
function changeSnapStep(snapStep) {
|
|
28379
|
+
return {
|
|
28380
|
+
type: CHANGE_SNAP_STEP,
|
|
28381
|
+
snapStep
|
|
28382
|
+
};
|
|
28383
|
+
}
|
|
28384
|
+
const CHANGE_RANGE = "change-range";
|
|
28385
|
+
function changeRange(range) {
|
|
28386
|
+
return {
|
|
28387
|
+
type: CHANGE_RANGE,
|
|
28388
|
+
range
|
|
28389
|
+
};
|
|
28390
|
+
}
|
|
28391
|
+
|
|
28392
|
+
const GraphStateContext = /*#__PURE__*/React.createContext({
|
|
28393
|
+
state: {},
|
|
28394
|
+
dispatch: () => {}
|
|
28395
|
+
});
|
|
28396
|
+
function useGraphState() {
|
|
28397
|
+
return React__default["default"].useContext(GraphStateContext);
|
|
28398
|
+
}
|
|
28345
28399
|
|
|
28346
28400
|
/**
|
|
28347
28401
|
* 44 is touch best practice and AAA compliant for WCAG
|
|
@@ -28368,6 +28422,11 @@ const normalizeCoords = (coordsList, ranges) => coordsList.map(coords => coords.
|
|
|
28368
28422
|
const extent = ranges[i][1] - ranges[i][0];
|
|
28369
28423
|
return (coord + ranges[i][1]) / extent;
|
|
28370
28424
|
}));
|
|
28425
|
+
function snap(snapStep, point) {
|
|
28426
|
+
const [requestedX, requestedY] = point;
|
|
28427
|
+
const [snapX, snapY] = snapStep;
|
|
28428
|
+
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
28429
|
+
}
|
|
28371
28430
|
|
|
28372
28431
|
const useTransform = function () {
|
|
28373
28432
|
const {
|
|
@@ -28426,6 +28485,9 @@ const getLines = points => points.map((point, i) => {
|
|
|
28426
28485
|
|
|
28427
28486
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
28428
28487
|
const MovableLine = props => {
|
|
28488
|
+
const {
|
|
28489
|
+
state
|
|
28490
|
+
} = useGraphState();
|
|
28429
28491
|
const {
|
|
28430
28492
|
start,
|
|
28431
28493
|
end,
|
|
@@ -28450,7 +28512,7 @@ const MovableLine = props => {
|
|
|
28450
28512
|
onMove: newPoint => {
|
|
28451
28513
|
onMove(mafs.vec.sub(newPoint, midpoint));
|
|
28452
28514
|
},
|
|
28453
|
-
constrain: p => p
|
|
28515
|
+
constrain: p => snap(state.snapStep, p)
|
|
28454
28516
|
});
|
|
28455
28517
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("g", {
|
|
28456
28518
|
ref: line,
|
|
@@ -28501,7 +28563,13 @@ function SVGLine(props) {
|
|
|
28501
28563
|
});
|
|
28502
28564
|
}
|
|
28503
28565
|
|
|
28566
|
+
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
28567
|
+
// graph.
|
|
28568
|
+
const hitboxSizePx = 48;
|
|
28504
28569
|
const StyledMovablePoint = props => {
|
|
28570
|
+
const {
|
|
28571
|
+
state
|
|
28572
|
+
} = useGraphState();
|
|
28505
28573
|
const hitboxRef = React.useRef(null);
|
|
28506
28574
|
const {
|
|
28507
28575
|
point,
|
|
@@ -28514,7 +28582,7 @@ const StyledMovablePoint = props => {
|
|
|
28514
28582
|
gestureTarget: hitboxRef,
|
|
28515
28583
|
point,
|
|
28516
28584
|
onMove,
|
|
28517
|
-
constrain: p => p
|
|
28585
|
+
constrain: p => snap(state.snapStep, p)
|
|
28518
28586
|
});
|
|
28519
28587
|
const [[x, y]] = useTransform(point);
|
|
28520
28588
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -28529,7 +28597,7 @@ const StyledMovablePoint = props => {
|
|
|
28529
28597
|
}
|
|
28530
28598
|
}, /*#__PURE__*/React__namespace.createElement("circle", {
|
|
28531
28599
|
className: "movable-point-hitbox",
|
|
28532
|
-
r:
|
|
28600
|
+
r: hitboxSizePx / 2,
|
|
28533
28601
|
cx: x,
|
|
28534
28602
|
cy: y
|
|
28535
28603
|
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
@@ -28567,7 +28635,9 @@ const SegmentGraph = props => {
|
|
|
28567
28635
|
onMoveLine: delta => {
|
|
28568
28636
|
dispatch(moveLine(i, delta));
|
|
28569
28637
|
},
|
|
28570
|
-
onMovePoint: (endpointIndex, destination) =>
|
|
28638
|
+
onMovePoint: (endpointIndex, destination) => {
|
|
28639
|
+
dispatch(moveControlPoint(endpointIndex, destination, i));
|
|
28640
|
+
},
|
|
28571
28641
|
"data-testid": "segment" + i
|
|
28572
28642
|
})));
|
|
28573
28643
|
};
|
|
@@ -28863,7 +28933,8 @@ const PolygonGraph = props => {
|
|
|
28863
28933
|
type,
|
|
28864
28934
|
showAngles,
|
|
28865
28935
|
showSides,
|
|
28866
|
-
range
|
|
28936
|
+
range,
|
|
28937
|
+
snapStep
|
|
28867
28938
|
} = props.graphState;
|
|
28868
28939
|
const points = coords ?? [[0, 0]];
|
|
28869
28940
|
const pointsSum = points.reduce((acc, point) => mafs.vec.add(acc, point), [0, 0]);
|
|
@@ -28878,7 +28949,7 @@ const PolygonGraph = props => {
|
|
|
28878
28949
|
const delta = mafs.vec.sub(newPoint, midpoint);
|
|
28879
28950
|
dispatch(moveAll(delta));
|
|
28880
28951
|
},
|
|
28881
|
-
constrain: p => p
|
|
28952
|
+
constrain: p => snap(snapStep, p)
|
|
28882
28953
|
});
|
|
28883
28954
|
const active = hovered || focused || dragging;
|
|
28884
28955
|
const lines = getLines(points);
|
|
@@ -28931,25 +29002,181 @@ const PolygonGraph = props => {
|
|
|
28931
29002
|
}), points.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
28932
29003
|
key: "point-" + i,
|
|
28933
29004
|
point: point,
|
|
28934
|
-
onMove: destination => dispatch(
|
|
29005
|
+
onMove: destination => dispatch(movePoint(i, destination)),
|
|
28935
29006
|
"data-testid": type + i
|
|
28936
29007
|
})));
|
|
28937
29008
|
};
|
|
28938
29009
|
|
|
28939
|
-
|
|
28940
|
-
|
|
28941
|
-
|
|
29010
|
+
function PointGraph(props) {
|
|
29011
|
+
const {
|
|
29012
|
+
dispatch
|
|
29013
|
+
} = props;
|
|
29014
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.graphState.coords.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
29015
|
+
key: i,
|
|
29016
|
+
point: point,
|
|
29017
|
+
onMove: destination => dispatch(movePoint(i, destination))
|
|
29018
|
+
})));
|
|
29019
|
+
}
|
|
29020
|
+
|
|
29021
|
+
function Arrow(props) {
|
|
29022
|
+
const {
|
|
29023
|
+
userTransform,
|
|
29024
|
+
viewTransform
|
|
29025
|
+
} = mafs.useTransformContext();
|
|
29026
|
+
const point = [props.x, props.y];
|
|
29027
|
+
const userTransformedPoint = mafs.vec.transform(point, userTransform);
|
|
29028
|
+
const viewTransformedPoint = mafs.vec.transform(userTransformedPoint, viewTransform);
|
|
29029
|
+
return /*#__PURE__*/React__default["default"].createElement("g", {
|
|
29030
|
+
transform: `translate(${viewTransformedPoint[0]} ${viewTransformedPoint[1]}) rotate(${props.rotate}) scale(1.25)`
|
|
29031
|
+
}, /*#__PURE__*/React__default["default"].createElement("g", {
|
|
29032
|
+
transform: "translate(-1)"
|
|
29033
|
+
}, /*#__PURE__*/React__default["default"].createElement("path", {
|
|
29034
|
+
d: "M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4",
|
|
29035
|
+
fill: "none"
|
|
29036
|
+
})));
|
|
29037
|
+
}
|
|
29038
|
+
function AxisArrows() {
|
|
29039
|
+
const {
|
|
29040
|
+
state
|
|
29041
|
+
} = useGraphState();
|
|
29042
|
+
const range = state.range;
|
|
29043
|
+
const [xMin, xMax] = range[0];
|
|
29044
|
+
const [yMin, yMax] = range[1];
|
|
29045
|
+
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29046
|
+
x: xMax,
|
|
29047
|
+
y: 0,
|
|
29048
|
+
rotate: 0
|
|
29049
|
+
}), /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29050
|
+
x: 0,
|
|
29051
|
+
y: yMin,
|
|
29052
|
+
rotate: 90
|
|
29053
|
+
}), /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29054
|
+
x: xMin,
|
|
29055
|
+
y: 0,
|
|
29056
|
+
rotate: 180
|
|
29057
|
+
}), /*#__PURE__*/React__default["default"].createElement(Arrow, {
|
|
29058
|
+
x: 0,
|
|
29059
|
+
y: yMax,
|
|
29060
|
+
rotate: 270
|
|
29061
|
+
}));
|
|
29062
|
+
}
|
|
29063
|
+
|
|
29064
|
+
const tickSize = 10;
|
|
29065
|
+
const tickStyle = {
|
|
29066
|
+
stroke: "black",
|
|
29067
|
+
strokeWidth: 1
|
|
29068
|
+
};
|
|
29069
|
+
const YGridTick = _ref => {
|
|
29070
|
+
let {
|
|
29071
|
+
y
|
|
29072
|
+
} = _ref;
|
|
29073
|
+
const pointOnAxis = [0, y];
|
|
29074
|
+
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
29075
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29076
|
+
className: "y-axis-ticks"
|
|
29077
|
+
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29078
|
+
x1: xPosition - tickSize / 2,
|
|
29079
|
+
y1: yPosition,
|
|
29080
|
+
x2: xPosition + tickSize / 2,
|
|
29081
|
+
y2: yPosition,
|
|
29082
|
+
style: tickStyle
|
|
29083
|
+
}));
|
|
29084
|
+
};
|
|
29085
|
+
const XGridTick = _ref2 => {
|
|
29086
|
+
let {
|
|
29087
|
+
x
|
|
29088
|
+
} = _ref2;
|
|
29089
|
+
const pointOnAxis = [x, 0];
|
|
29090
|
+
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
29091
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29092
|
+
className: "x-axis-ticks"
|
|
29093
|
+
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29094
|
+
x1: xPosition,
|
|
29095
|
+
y1: yPosition + tickSize / 2,
|
|
29096
|
+
x2: xPosition,
|
|
29097
|
+
y2: yPosition - tickSize / 2,
|
|
29098
|
+
style: tickStyle
|
|
29099
|
+
}));
|
|
29100
|
+
};
|
|
29101
|
+
function generateTickLocations(tickStep, min, max) {
|
|
29102
|
+
const ticks = [];
|
|
29103
|
+
for (let i = 0 + tickStep; i < max; i += tickStep) {
|
|
29104
|
+
ticks.push(i);
|
|
29105
|
+
}
|
|
29106
|
+
for (let i = 0 - tickStep; i > min; i -= tickStep) {
|
|
29107
|
+
ticks.push(i);
|
|
29108
|
+
}
|
|
29109
|
+
return ticks;
|
|
29110
|
+
}
|
|
29111
|
+
const AxisTicks = props => {
|
|
29112
|
+
const range = props.range;
|
|
29113
|
+
const [xMin, xMax] = range[0];
|
|
29114
|
+
const [yMin, yMax] = range[1];
|
|
29115
|
+
const yTickStep = props.tickStep[1];
|
|
29116
|
+
const xTickStep = props.tickStep[0];
|
|
29117
|
+
const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
|
|
29118
|
+
const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
|
|
29119
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29120
|
+
className: "axis-ticks"
|
|
29121
|
+
}, yGridTicks.map(y => {
|
|
29122
|
+
return /*#__PURE__*/React__namespace.createElement(YGridTick, {
|
|
29123
|
+
y: y,
|
|
29124
|
+
key: `y-grid-tick-${y}`
|
|
29125
|
+
});
|
|
29126
|
+
}), xGridTicks.map(x => {
|
|
29127
|
+
return /*#__PURE__*/React__namespace.createElement(XGridTick, {
|
|
29128
|
+
x: x,
|
|
29129
|
+
key: `x-grid-tick-${x}`
|
|
29130
|
+
});
|
|
29131
|
+
}));
|
|
29132
|
+
};
|
|
29133
|
+
|
|
29134
|
+
/**
|
|
29135
|
+
* lineLabelText get the text that should
|
|
29136
|
+
* be displayed for a specific tick place
|
|
29137
|
+
*
|
|
29138
|
+
* @param {number} n the tick number
|
|
29139
|
+
* @param {number} tickStep how frequently a label should appear
|
|
29140
|
+
* @param {vec.Vector2} range the min/max range on the axis
|
|
29141
|
+
*/
|
|
29142
|
+
const lineLabelText = (n, tickStep, range) => {
|
|
29143
|
+
const [min, max] = range;
|
|
29144
|
+
const isOnStep = n % tickStep === 0;
|
|
29145
|
+
const isNegativeOne = n === -1;
|
|
29146
|
+
const isMin = n === min;
|
|
29147
|
+
const isMax = n === max;
|
|
29148
|
+
const shouldRender = isOnStep && !isNegativeOne && !isMin && !isMax;
|
|
29149
|
+
return shouldRender ? `${n}` : "";
|
|
29150
|
+
};
|
|
29151
|
+
|
|
29152
|
+
/**
|
|
29153
|
+
* axisOptions determine axis options for Mafs
|
|
29154
|
+
*
|
|
29155
|
+
* axisIndex is for grabbing data in an array that contains
|
|
29156
|
+
* data for multiple axes. For example range: [[-10, 10], [-10, 10]]
|
|
29157
|
+
* range[0] is data for the x axis and range[1] is data for the y axis
|
|
29158
|
+
*
|
|
29159
|
+
* @param {GridProps} props
|
|
29160
|
+
* @param {number} axisIndex which axis we're getting options for
|
|
29161
|
+
*/
|
|
29162
|
+
const axisOptions = (props, axisIndex) => {
|
|
29163
|
+
const axisStep = props.tickStep[axisIndex];
|
|
29164
|
+
const axisRange = props.range[axisIndex];
|
|
29165
|
+
return {
|
|
29166
|
+
axis: props.markings === "graph",
|
|
29167
|
+
lines: props.gridStep[axisIndex],
|
|
29168
|
+
labels: n => lineLabelText(n, axisStep, axisRange)
|
|
29169
|
+
};
|
|
29170
|
+
};
|
|
29171
|
+
const Grid = props => {
|
|
29172
|
+
return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
29173
|
+
xAxis: axisOptions(props, 0),
|
|
29174
|
+
yAxis: axisOptions(props, 1)
|
|
29175
|
+
}), /*#__PURE__*/React__namespace.createElement(AxisTicks, {
|
|
29176
|
+
range: props.range,
|
|
29177
|
+
tickStep: props.tickStep
|
|
29178
|
+
}), props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisArrows, null));
|
|
28942
29179
|
};
|
|
28943
|
-
const axisOptions = (props, index) => ({
|
|
28944
|
-
axis: props.markings === "graph",
|
|
28945
|
-
lines: props.step[index],
|
|
28946
|
-
subdivisions: props.step[index] / props.gridStep[index],
|
|
28947
|
-
labels: n => renderLineLabel(n, props.range[index]) ? n : ""
|
|
28948
|
-
});
|
|
28949
|
-
const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
28950
|
-
xAxis: axisOptions(props, 0),
|
|
28951
|
-
yAxis: axisOptions(props, 1)
|
|
28952
|
-
});
|
|
28953
29180
|
|
|
28954
29181
|
// Displays a stylized open eye: lint warnings are visible
|
|
28955
29182
|
const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
|
|
@@ -29647,53 +29874,50 @@ const LegacyGrid = _ref => {
|
|
|
29647
29874
|
return null;
|
|
29648
29875
|
};
|
|
29649
29876
|
|
|
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
29877
|
function interactiveGraphReducer(state, action) {
|
|
29878
|
+
switch (action.type) {
|
|
29879
|
+
case MOVE_CONTROL_POINT:
|
|
29880
|
+
return doMoveControlPoint(state, action);
|
|
29881
|
+
case MOVE_LINE:
|
|
29882
|
+
return doMoveLine(state, action);
|
|
29883
|
+
case MOVE_ALL:
|
|
29884
|
+
return doMoveAll(state, action);
|
|
29885
|
+
case MOVE_POINT:
|
|
29886
|
+
return doMovePoint(state, action);
|
|
29887
|
+
case CHANGE_SNAP_STEP:
|
|
29888
|
+
return doChangeSnapStep(state, action);
|
|
29889
|
+
case CHANGE_RANGE:
|
|
29890
|
+
return doChangeRange(state, action);
|
|
29891
|
+
default:
|
|
29892
|
+
throw new wonderStuffCore.UnreachableCaseError(action);
|
|
29893
|
+
}
|
|
29894
|
+
}
|
|
29895
|
+
function doMoveControlPoint(state, action) {
|
|
29655
29896
|
const {
|
|
29656
29897
|
snapStep,
|
|
29657
29898
|
range
|
|
29658
29899
|
} = state;
|
|
29659
|
-
|
|
29660
|
-
|
|
29661
|
-
|
|
29662
|
-
|
|
29663
|
-
case
|
|
29900
|
+
switch (state.type) {
|
|
29901
|
+
case "segment":
|
|
29902
|
+
case "linear":
|
|
29903
|
+
case "linear-system":
|
|
29904
|
+
case "ray":
|
|
29664
29905
|
{
|
|
29665
|
-
const newCoords =
|
|
29906
|
+
const newCoords = updateAtIndex({
|
|
29666
29907
|
array: state.coords,
|
|
29667
29908
|
index: action.itemIndex,
|
|
29668
29909
|
update: tuple => setAtIndex({
|
|
29669
29910
|
array: tuple,
|
|
29670
29911
|
index: action.pointIndex,
|
|
29671
|
-
newValue: snap({
|
|
29672
|
-
snapStep,
|
|
29673
|
-
point: bound$1({
|
|
29674
|
-
snapStep,
|
|
29675
|
-
range,
|
|
29676
|
-
point: action.destination
|
|
29677
|
-
})
|
|
29678
|
-
})
|
|
29679
|
-
})
|
|
29680
|
-
}) : setAtIndex({
|
|
29681
|
-
array: state.coords,
|
|
29682
|
-
index: action.pointIndex,
|
|
29683
|
-
newValue: snap({
|
|
29684
|
-
snapStep,
|
|
29685
|
-
point: bound$1({
|
|
29912
|
+
newValue: snap(snapStep, bound$1({
|
|
29686
29913
|
snapStep,
|
|
29687
29914
|
range,
|
|
29688
29915
|
point: action.destination
|
|
29689
|
-
})
|
|
29916
|
+
}))
|
|
29690
29917
|
})
|
|
29691
29918
|
});
|
|
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)) {
|
|
29919
|
+
const coordsToCheck = newCoords[action.itemIndex];
|
|
29920
|
+
if (coordsOverlap(coordsToCheck)) {
|
|
29697
29921
|
return state;
|
|
29698
29922
|
}
|
|
29699
29923
|
return {
|
|
@@ -29702,15 +29926,30 @@ function interactiveGraphReducer(state, action) {
|
|
|
29702
29926
|
coords: newCoords
|
|
29703
29927
|
};
|
|
29704
29928
|
}
|
|
29705
|
-
case
|
|
29929
|
+
case "circle":
|
|
29930
|
+
throw new Error("FIXME implement circle reducer");
|
|
29931
|
+
case "point":
|
|
29932
|
+
case "polygon":
|
|
29933
|
+
throw new Error(`Don't use moveControlPoint for ${state.type} graphs. Use movePoint instead!`);
|
|
29934
|
+
default:
|
|
29935
|
+
throw new wonderStuffCore.UnreachableCaseError(state);
|
|
29936
|
+
}
|
|
29937
|
+
}
|
|
29938
|
+
function doMoveLine(state, action) {
|
|
29939
|
+
const {
|
|
29940
|
+
snapStep,
|
|
29941
|
+
range
|
|
29942
|
+
} = state;
|
|
29943
|
+
switch (state.type) {
|
|
29944
|
+
case "segment":
|
|
29945
|
+
case "linear":
|
|
29946
|
+
case "linear-system":
|
|
29947
|
+
case "ray":
|
|
29706
29948
|
{
|
|
29707
|
-
if (!isCollinearTuples(state.coords)) {
|
|
29708
|
-
throw new Error("Cannot call this action unless coords is array of CollinearTuple.");
|
|
29709
|
-
}
|
|
29710
29949
|
if (action.itemIndex === undefined) {
|
|
29711
29950
|
throw new Error("Please provide index of line to move");
|
|
29712
29951
|
}
|
|
29713
|
-
const currentLine = state.coords
|
|
29952
|
+
const currentLine = state.coords[action.itemIndex];
|
|
29714
29953
|
if (!currentLine) {
|
|
29715
29954
|
throw new Error("No line to move");
|
|
29716
29955
|
}
|
|
@@ -29718,13 +29957,7 @@ function interactiveGraphReducer(state, action) {
|
|
|
29718
29957
|
snapStep,
|
|
29719
29958
|
range
|
|
29720
29959
|
});
|
|
29721
|
-
const newLine = [snap(
|
|
29722
|
-
snapStep,
|
|
29723
|
-
point: mafs.vec.add(currentLine[0], change)
|
|
29724
|
-
}), snap({
|
|
29725
|
-
snapStep,
|
|
29726
|
-
point: mafs.vec.add(currentLine[1], change)
|
|
29727
|
-
})];
|
|
29960
|
+
const newLine = [snap(snapStep, mafs.vec.add(currentLine[0], change)), snap(snapStep, mafs.vec.add(currentLine[1], change))];
|
|
29728
29961
|
const newCoords = setAtIndex({
|
|
29729
29962
|
array: state.coords,
|
|
29730
29963
|
index: action.itemIndex,
|
|
@@ -29732,23 +29965,30 @@ function interactiveGraphReducer(state, action) {
|
|
|
29732
29965
|
});
|
|
29733
29966
|
return {
|
|
29734
29967
|
...state,
|
|
29968
|
+
type: state.type,
|
|
29735
29969
|
hasBeenInteractedWith: true,
|
|
29736
29970
|
coords: newCoords
|
|
29737
29971
|
};
|
|
29738
29972
|
}
|
|
29739
|
-
|
|
29973
|
+
default:
|
|
29974
|
+
// The MoveLine action doesn't make sense for other graph types;
|
|
29975
|
+
// ignore it if it somehow happens
|
|
29976
|
+
return state;
|
|
29977
|
+
}
|
|
29978
|
+
}
|
|
29979
|
+
function doMoveAll(state, action) {
|
|
29980
|
+
const {
|
|
29981
|
+
snapStep,
|
|
29982
|
+
range
|
|
29983
|
+
} = state;
|
|
29984
|
+
switch (state.type) {
|
|
29985
|
+
case "polygon":
|
|
29740
29986
|
{
|
|
29741
|
-
if (isCollinearTuples(state.coords)) {
|
|
29742
|
-
throw new Error("Cannot call this action unless coords is array of vectors.");
|
|
29743
|
-
}
|
|
29744
29987
|
const change = getChange(state.coords, action.delta, {
|
|
29745
29988
|
snapStep,
|
|
29746
29989
|
range
|
|
29747
29990
|
});
|
|
29748
|
-
const newCoords = state.coords.map(point => snap(
|
|
29749
|
-
snapStep,
|
|
29750
|
-
point: mafs.vec.add(point, change)
|
|
29751
|
-
}));
|
|
29991
|
+
const newCoords = state.coords.map(point => snap(snapStep, mafs.vec.add(point, change)));
|
|
29752
29992
|
return {
|
|
29753
29993
|
...state,
|
|
29754
29994
|
hasBeenInteractedWith: true,
|
|
@@ -29756,8 +29996,54 @@ function interactiveGraphReducer(state, action) {
|
|
|
29756
29996
|
};
|
|
29757
29997
|
}
|
|
29758
29998
|
default:
|
|
29759
|
-
|
|
29999
|
+
// MoveAll is not supported for other state types; just ignore it.
|
|
30000
|
+
return state;
|
|
30001
|
+
}
|
|
30002
|
+
}
|
|
30003
|
+
function doMovePoint(state, action) {
|
|
30004
|
+
switch (state.type) {
|
|
30005
|
+
case "point":
|
|
30006
|
+
case "polygon":
|
|
30007
|
+
{
|
|
30008
|
+
return {
|
|
30009
|
+
...state,
|
|
30010
|
+
hasBeenInteractedWith: true,
|
|
30011
|
+
coords: setAtIndex({
|
|
30012
|
+
array: state.coords,
|
|
30013
|
+
index: action.index,
|
|
30014
|
+
newValue: snap(state.snapStep, bound$1({
|
|
30015
|
+
snapStep: state.snapStep,
|
|
30016
|
+
range: state.range,
|
|
30017
|
+
point: action.destination
|
|
30018
|
+
}))
|
|
30019
|
+
})
|
|
30020
|
+
};
|
|
30021
|
+
}
|
|
30022
|
+
default:
|
|
30023
|
+
throw new Error("The movePoint action is only for point and polygon graphs");
|
|
30024
|
+
}
|
|
30025
|
+
}
|
|
30026
|
+
function doChangeSnapStep(state, action) {
|
|
30027
|
+
if (
|
|
30028
|
+
// Deep equality check since these are arrays
|
|
30029
|
+
___default["default"].isEqual(state.snapStep, action.snapStep)) {
|
|
30030
|
+
return state;
|
|
30031
|
+
}
|
|
30032
|
+
return {
|
|
30033
|
+
...state,
|
|
30034
|
+
snapStep: action.snapStep
|
|
30035
|
+
};
|
|
30036
|
+
}
|
|
30037
|
+
function doChangeRange(state, action) {
|
|
30038
|
+
if (
|
|
30039
|
+
// Deep equality check since these are arrays
|
|
30040
|
+
___default["default"].isEqual(state.range, action.range)) {
|
|
30041
|
+
return state;
|
|
29760
30042
|
}
|
|
30043
|
+
return {
|
|
30044
|
+
...state,
|
|
30045
|
+
range: action.range
|
|
30046
|
+
};
|
|
29761
30047
|
}
|
|
29762
30048
|
const getChange = (coords, delta, constraintOpts) => {
|
|
29763
30049
|
const [deltaX, deltaY] = delta;
|
|
@@ -29777,24 +30063,14 @@ const getChange = (coords, delta, constraintOpts) => {
|
|
|
29777
30063
|
const dy = clamp(deltaY, minYMove, maxYMove);
|
|
29778
30064
|
return [dx, dy];
|
|
29779
30065
|
};
|
|
29780
|
-
function snap(_ref) {
|
|
29781
|
-
let {
|
|
29782
|
-
snapStep,
|
|
29783
|
-
point
|
|
29784
|
-
} = _ref;
|
|
29785
|
-
const [requestedX, requestedY] = point;
|
|
29786
|
-
const [snapX, snapY] = snapStep;
|
|
29787
|
-
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
29788
|
-
}
|
|
29789
|
-
|
|
29790
30066
|
// Returns the closest point to the given `point` that is within the graph
|
|
29791
30067
|
// bounds given in `state`.
|
|
29792
|
-
function bound$1(
|
|
30068
|
+
function bound$1(_ref) {
|
|
29793
30069
|
let {
|
|
29794
30070
|
snapStep,
|
|
29795
30071
|
range,
|
|
29796
30072
|
point
|
|
29797
|
-
} =
|
|
30073
|
+
} = _ref;
|
|
29798
30074
|
const [requestedX, requestedY] = point;
|
|
29799
30075
|
const [snapX, snapY] = snapStep;
|
|
29800
30076
|
const [[minX, maxX], [minY, maxY]] = range;
|
|
@@ -29802,12 +30078,12 @@ function bound$1(_ref2) {
|
|
|
29802
30078
|
}
|
|
29803
30079
|
|
|
29804
30080
|
// Returns the vector from the given point to the top-right corner of the graph
|
|
29805
|
-
function maxMove(
|
|
30081
|
+
function maxMove(_ref2) {
|
|
29806
30082
|
let {
|
|
29807
30083
|
snapStep,
|
|
29808
30084
|
range,
|
|
29809
30085
|
point
|
|
29810
|
-
} =
|
|
30086
|
+
} = _ref2;
|
|
29811
30087
|
const topRight = bound$1({
|
|
29812
30088
|
snapStep,
|
|
29813
30089
|
range,
|
|
@@ -29818,12 +30094,12 @@ function maxMove(_ref3) {
|
|
|
29818
30094
|
|
|
29819
30095
|
// Returns the vector from the given point to the bottom-left corner of the
|
|
29820
30096
|
// graph
|
|
29821
|
-
function minMove(
|
|
30097
|
+
function minMove(_ref3) {
|
|
29822
30098
|
let {
|
|
29823
30099
|
snapStep,
|
|
29824
30100
|
range,
|
|
29825
30101
|
point
|
|
29826
|
-
} =
|
|
30102
|
+
} = _ref3;
|
|
29827
30103
|
const bottomLeft = bound$1({
|
|
29828
30104
|
snapStep,
|
|
29829
30105
|
range,
|
|
@@ -29843,7 +30119,7 @@ function clamp(value, min, max) {
|
|
|
29843
30119
|
const coordsOverlap = coords => coords.some((coord, i) => coords.some((c, j) => i !== j && kmath.vector.equal(coord, c)));
|
|
29844
30120
|
function updateAtIndex(args) {
|
|
29845
30121
|
const {
|
|
29846
|
-
array
|
|
30122
|
+
array,
|
|
29847
30123
|
index,
|
|
29848
30124
|
update
|
|
29849
30125
|
} = args;
|
|
@@ -29856,13 +30132,12 @@ function updateAtIndex(args) {
|
|
|
29856
30132
|
}
|
|
29857
30133
|
function setAtIndex(args) {
|
|
29858
30134
|
const {
|
|
29859
|
-
array
|
|
30135
|
+
array,
|
|
29860
30136
|
index,
|
|
29861
30137
|
newValue
|
|
29862
30138
|
} = args;
|
|
29863
30139
|
const copy = [...array];
|
|
29864
30140
|
copy[index] = newValue;
|
|
29865
|
-
// restoring readonly to array
|
|
29866
30141
|
return copy;
|
|
29867
30142
|
}
|
|
29868
30143
|
|
|
@@ -29904,18 +30179,31 @@ function initializeGraphState(params) {
|
|
|
29904
30179
|
};
|
|
29905
30180
|
case "polygon":
|
|
29906
30181
|
return {
|
|
30182
|
+
type: "polygon",
|
|
29907
30183
|
hasBeenInteractedWith: false,
|
|
29908
30184
|
range,
|
|
29909
30185
|
snapStep,
|
|
29910
|
-
|
|
30186
|
+
showAngles: Boolean(graph.showAngles),
|
|
30187
|
+
showSides: Boolean(graph.showSides),
|
|
29911
30188
|
coords: getPolygonCoords({
|
|
29912
30189
|
graph,
|
|
29913
30190
|
range,
|
|
29914
30191
|
step
|
|
29915
30192
|
})
|
|
29916
30193
|
};
|
|
29917
|
-
case "angle":
|
|
29918
30194
|
case "point":
|
|
30195
|
+
return {
|
|
30196
|
+
type: graph.type,
|
|
30197
|
+
hasBeenInteractedWith: false,
|
|
30198
|
+
range,
|
|
30199
|
+
snapStep,
|
|
30200
|
+
coords: getDefaultPoints({
|
|
30201
|
+
graph,
|
|
30202
|
+
step,
|
|
30203
|
+
range
|
|
30204
|
+
})
|
|
30205
|
+
};
|
|
30206
|
+
case "angle":
|
|
29919
30207
|
case "circle":
|
|
29920
30208
|
case "sinusoid":
|
|
29921
30209
|
case "quadratic":
|
|
@@ -29924,6 +30212,46 @@ function initializeGraphState(params) {
|
|
|
29924
30212
|
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
29925
30213
|
}
|
|
29926
30214
|
}
|
|
30215
|
+
const getDefaultPoints = _ref => {
|
|
30216
|
+
let {
|
|
30217
|
+
graph,
|
|
30218
|
+
range,
|
|
30219
|
+
step
|
|
30220
|
+
} = _ref;
|
|
30221
|
+
const numPoints = graph.numPoints || 1;
|
|
30222
|
+
let coords = graph.coords?.slice();
|
|
30223
|
+
if (coords) {
|
|
30224
|
+
return coords;
|
|
30225
|
+
}
|
|
30226
|
+
switch (numPoints) {
|
|
30227
|
+
case 1:
|
|
30228
|
+
// Back in the day, one point's coords were in graph.coord
|
|
30229
|
+
coords = [graph.coord || [0, 0]];
|
|
30230
|
+
break;
|
|
30231
|
+
case 2:
|
|
30232
|
+
coords = [[-5, 0], [5, 0]];
|
|
30233
|
+
break;
|
|
30234
|
+
case 3:
|
|
30235
|
+
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
30236
|
+
break;
|
|
30237
|
+
case 4:
|
|
30238
|
+
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
30239
|
+
break;
|
|
30240
|
+
case 5:
|
|
30241
|
+
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
30242
|
+
break;
|
|
30243
|
+
case 6:
|
|
30244
|
+
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
30245
|
+
break;
|
|
30246
|
+
default:
|
|
30247
|
+
coords = [];
|
|
30248
|
+
break;
|
|
30249
|
+
}
|
|
30250
|
+
// Transform coords from their -10 to 10 space to 0 to 1
|
|
30251
|
+
// because of the old graph.coord, and also it's easier.
|
|
30252
|
+
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
30253
|
+
return normalizePoints(range, step, newCoords);
|
|
30254
|
+
};
|
|
29927
30255
|
|
|
29928
30256
|
// TS v4 doesn't narrow return types, while v5 does.
|
|
29929
30257
|
// Instead of updating to v5, using generic type to relate input and output types.
|
|
@@ -29948,13 +30276,13 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29948
30276
|
if (state.type === "linear" && initialGraph.type === "linear") {
|
|
29949
30277
|
return {
|
|
29950
30278
|
...initialGraph,
|
|
29951
|
-
coords: state.coords
|
|
30279
|
+
coords: state.coords[0]
|
|
29952
30280
|
};
|
|
29953
30281
|
}
|
|
29954
30282
|
if (state.type === "ray" && initialGraph.type === "ray") {
|
|
29955
30283
|
return {
|
|
29956
30284
|
...initialGraph,
|
|
29957
|
-
coords: state.coords
|
|
30285
|
+
coords: state.coords[0]
|
|
29958
30286
|
};
|
|
29959
30287
|
}
|
|
29960
30288
|
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
@@ -29963,14 +30291,20 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29963
30291
|
coords: state.coords
|
|
29964
30292
|
};
|
|
29965
30293
|
}
|
|
30294
|
+
if (state.type === "point" && initialGraph.type === "point") {
|
|
30295
|
+
return {
|
|
30296
|
+
...initialGraph,
|
|
30297
|
+
coords: state.coords
|
|
30298
|
+
};
|
|
30299
|
+
}
|
|
29966
30300
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
29967
30301
|
}
|
|
29968
|
-
const getDefaultSegments =
|
|
30302
|
+
const getDefaultSegments = _ref2 => {
|
|
29969
30303
|
let {
|
|
29970
30304
|
graph,
|
|
29971
30305
|
range,
|
|
29972
30306
|
step
|
|
29973
|
-
} =
|
|
30307
|
+
} = _ref2;
|
|
29974
30308
|
const ys = n => {
|
|
29975
30309
|
switch (n) {
|
|
29976
30310
|
case 2:
|
|
@@ -29996,24 +30330,24 @@ const getDefaultSegments = _ref => {
|
|
|
29996
30330
|
});
|
|
29997
30331
|
};
|
|
29998
30332
|
const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
|
|
29999
|
-
const getLineCoords =
|
|
30333
|
+
const getLineCoords = _ref3 => {
|
|
30000
30334
|
let {
|
|
30001
30335
|
graph,
|
|
30002
30336
|
range,
|
|
30003
30337
|
step
|
|
30004
|
-
} =
|
|
30338
|
+
} = _ref3;
|
|
30005
30339
|
return (
|
|
30006
30340
|
// Return two lines for a linear system, one for a ray or linear
|
|
30007
30341
|
graph.coords ?? graph.type === "linear-system" ? defaultLinearCoords.map(collinear => normalizePoints(range, step, collinear)) : [normalizePoints(range, step, defaultLinearCoords[0])]
|
|
30008
30342
|
);
|
|
30009
30343
|
};
|
|
30010
|
-
const getPolygonCoords =
|
|
30344
|
+
const getPolygonCoords = _ref4 => {
|
|
30011
30345
|
let {
|
|
30012
30346
|
graph,
|
|
30013
30347
|
range,
|
|
30014
30348
|
step
|
|
30015
|
-
} =
|
|
30016
|
-
let coords = graph.coords;
|
|
30349
|
+
} = _ref4;
|
|
30350
|
+
let coords = graph.coords?.slice();
|
|
30017
30351
|
if (coords) {
|
|
30018
30352
|
return coords;
|
|
30019
30353
|
}
|
|
@@ -30067,6 +30401,13 @@ const renderGraph = props => {
|
|
|
30067
30401
|
graphState: state,
|
|
30068
30402
|
dispatch: dispatch
|
|
30069
30403
|
});
|
|
30404
|
+
case "point":
|
|
30405
|
+
return /*#__PURE__*/React__namespace.createElement(PointGraph, {
|
|
30406
|
+
graphState: state,
|
|
30407
|
+
dispatch: dispatch
|
|
30408
|
+
});
|
|
30409
|
+
case "circle":
|
|
30410
|
+
throw new Error("the circle graph type is not yet implemented");
|
|
30070
30411
|
default:
|
|
30071
30412
|
return new wonderStuffCore.UnreachableCaseError(type);
|
|
30072
30413
|
}
|
|
@@ -30074,10 +30415,36 @@ const renderGraph = props => {
|
|
|
30074
30415
|
const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
30075
30416
|
const [width, height] = props.box;
|
|
30076
30417
|
const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
30418
|
+
const prevState = React.useRef(state);
|
|
30419
|
+
React.useEffect(() => {
|
|
30420
|
+
if (prevState.current !== state) {
|
|
30421
|
+
props.onChange({
|
|
30422
|
+
graph: state
|
|
30423
|
+
});
|
|
30424
|
+
}
|
|
30425
|
+
prevState.current = state;
|
|
30426
|
+
}, [props, state]);
|
|
30427
|
+
|
|
30428
|
+
// Destructuring first to keep useEffect from making excess calls
|
|
30429
|
+
const [xSnap, ySnap] = props.snapStep;
|
|
30430
|
+
React.useEffect(() => {
|
|
30431
|
+
dispatch(changeSnapStep([xSnap, ySnap]));
|
|
30432
|
+
}, [xSnap, ySnap]);
|
|
30433
|
+
|
|
30434
|
+
// Destructuring first to keep useEffect from making excess calls
|
|
30435
|
+
const [[xMinRange, xMaxRange], [yMinRange, yMaxRange]] = props.range;
|
|
30436
|
+
React.useEffect(() => {
|
|
30437
|
+
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
30438
|
+
}, [xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
30077
30439
|
React__namespace.useImperativeHandle(ref, () => ({
|
|
30078
30440
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
30079
30441
|
}));
|
|
30080
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
30442
|
+
return /*#__PURE__*/React__namespace.createElement(GraphStateContext.Provider, {
|
|
30443
|
+
value: {
|
|
30444
|
+
state,
|
|
30445
|
+
dispatch
|
|
30446
|
+
}
|
|
30447
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30081
30448
|
style: {
|
|
30082
30449
|
width,
|
|
30083
30450
|
height,
|
|
@@ -30103,12 +30470,18 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
|
30103
30470
|
zoom: false,
|
|
30104
30471
|
width: width,
|
|
30105
30472
|
height: height
|
|
30106
|
-
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid,
|
|
30473
|
+
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
30474
|
+
tickStep: props.step,
|
|
30475
|
+
gridStep: props.gridStep,
|
|
30476
|
+
range: props.range,
|
|
30477
|
+
containerSizeClass: props.containerSizeClass,
|
|
30478
|
+
markings: props.markings
|
|
30479
|
+
}), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
30107
30480
|
lockedFigures: props.lockedFigures
|
|
30108
30481
|
}), renderGraph({
|
|
30109
30482
|
state,
|
|
30110
30483
|
dispatch
|
|
30111
|
-
}))));
|
|
30484
|
+
})))));
|
|
30112
30485
|
});
|
|
30113
30486
|
|
|
30114
30487
|
const {
|
|
@@ -31275,6 +31648,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
31275
31648
|
});
|
|
31276
31649
|
$__default["default"](this.angle).on("move", () => {
|
|
31277
31650
|
this.onChange({
|
|
31651
|
+
// @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
31652
|
graph: {
|
|
31279
31653
|
...graph,
|
|
31280
31654
|
coords: this.angle?.getClockwiseCoords()
|
|
@@ -31809,7 +32183,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
31809
32183
|
}
|
|
31810
32184
|
} else if (userInput.type === "point" && rubric.correct.type === "point" && userInput.coords != null) {
|
|
31811
32185
|
let correct = InteractiveGraph.getPointCoords(rubric.correct, component);
|
|
31812
|
-
const guess = userInput.coords
|
|
32186
|
+
const guess = userInput.coords.slice();
|
|
31813
32187
|
correct = correct.slice();
|
|
31814
32188
|
// Everything's already rounded so we shouldn't need to do an
|
|
31815
32189
|
// eq() comparison but _.isEqual(0, -0) is false, so we'll use
|
|
@@ -31852,8 +32226,8 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
31852
32226
|
};
|
|
31853
32227
|
}
|
|
31854
32228
|
} else if (userInput.type === "segment" && rubric.correct.type === "segment" && userInput.coords != null) {
|
|
31855
|
-
let guess = userInput.coords
|
|
31856
|
-
let correct = rubric.correct
|
|
32229
|
+
let guess = Util.deepClone(userInput.coords);
|
|
32230
|
+
let correct = Util.deepClone(rubric.correct?.coords);
|
|
31857
32231
|
guess = ___default["default"].invoke(guess, "sort").sort();
|
|
31858
32232
|
// @ts-expect-error - TS2345 - Argument of type '(readonly Coord[])[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
31859
32233
|
correct = ___default["default"].invoke(correct, "sort").sort();
|
|
@@ -42115,7 +42489,7 @@ const init = function (options) {
|
|
|
42115
42489
|
|
|
42116
42490
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42117
42491
|
const libName = "@khanacademy/perseus";
|
|
42118
|
-
const libVersion = "21.
|
|
42492
|
+
const libVersion = "21.2.0";
|
|
42119
42493
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42120
42494
|
|
|
42121
42495
|
const apiVersion = {
|
|
@@ -43244,6 +43618,9 @@ const ItemExtras = [
|
|
|
43244
43618
|
// A background image applied to various widgets.
|
|
43245
43619
|
|
|
43246
43620
|
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
43621
|
+
|
|
43622
|
+
// 2D range: xMin, xMax, yMin, yMax
|
|
43623
|
+
|
|
43247
43624
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
43248
43625
|
|
|
43249
43626
|
/**
|
|
@@ -44617,7 +44994,7 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44617
44994
|
// E.g. 'item 1\nitem 2\nitem 3'
|
|
44618
44995
|
const orderer = widget;
|
|
44619
44996
|
if (orderer.options?.correctOptions) {
|
|
44620
|
-
answers.push(orderer.options.correctOptions
|
|
44997
|
+
answers.push(joinOptionContents(orderer.options.correctOptions));
|
|
44621
44998
|
}
|
|
44622
44999
|
break;
|
|
44623
45000
|
case "sorter":
|
|
@@ -44676,6 +45053,31 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44676
45053
|
return answers;
|
|
44677
45054
|
}
|
|
44678
45055
|
|
|
45056
|
+
/**
|
|
45057
|
+
* Join the content of the options together.
|
|
45058
|
+
* @param {Array<{content: string}>} options
|
|
45059
|
+
* @returns {string}
|
|
45060
|
+
*/
|
|
45061
|
+
const joinOptionContents = options => options.map(_ref => {
|
|
45062
|
+
let {
|
|
45063
|
+
content
|
|
45064
|
+
} = _ref;
|
|
45065
|
+
return content;
|
|
45066
|
+
}).join("\n");
|
|
45067
|
+
|
|
45068
|
+
/**
|
|
45069
|
+
* Convert an index to an option letter.
|
|
45070
|
+
* @param {number} index
|
|
45071
|
+
* @returns {string}
|
|
45072
|
+
* @example
|
|
45073
|
+
* toOptionLetter(0) // 'A'
|
|
45074
|
+
* toOptionLetter(1) // 'B'
|
|
45075
|
+
* toOptionLetter(25) // 'Z'
|
|
45076
|
+
* // Once the index goes past 25, it will start returning special characters
|
|
45077
|
+
* toOptionLetter(26) // '['
|
|
45078
|
+
*/
|
|
45079
|
+
const toOptionLetter = index => String.fromCharCode("A".charCodeAt(0) + index);
|
|
45080
|
+
|
|
44679
45081
|
/**
|
|
44680
45082
|
* Inject a string equivalent of the widgets into the content.
|
|
44681
45083
|
*
|
|
@@ -44686,7 +45088,7 @@ function getAnswersFromWidgets(widgets) {
|
|
|
44686
45088
|
* @param {PerseusRenderer["widgets"]} widgets
|
|
44687
45089
|
* @returns
|
|
44688
45090
|
*/
|
|
44689
|
-
function injectWidgets(content, widgets) {
|
|
45091
|
+
function injectWidgets(content, widgets, widgetProps) {
|
|
44690
45092
|
// The types for taskProgress.itemData are not well defined,
|
|
44691
45093
|
// so there is a chance that widgets or content could be undefined.
|
|
44692
45094
|
// In that scenario, simply exit early and return the content as is.
|
|
@@ -44705,11 +45107,22 @@ function injectWidgets(content, widgets) {
|
|
|
44705
45107
|
switch (widget.type) {
|
|
44706
45108
|
case "radio":
|
|
44707
45109
|
// Replace radio with the radio options
|
|
44708
|
-
// '[[☃ Radio 1]]' -> '
|
|
45110
|
+
// '[[☃ Radio 1]]' -> 'choice 1\nchoice 2\nchoice 3'
|
|
45111
|
+
// or if the current widget state is available with proper order,
|
|
45112
|
+
// '[[☃ Radio 1]]' ->
|
|
45113
|
+
// 'Option A: choice 1\nOption B: choice 2\nOption C: choice 3'
|
|
44709
45114
|
const radio = widget;
|
|
45115
|
+
const radioProps = widgetProps?.[widgetID];
|
|
44710
45116
|
if (radio.options?.choices?.length) {
|
|
44711
|
-
let radioContext =
|
|
44712
|
-
|
|
45117
|
+
let radioContext = joinOptionContents(radioProps ? radioProps.choices.map((_ref2, i) => {
|
|
45118
|
+
let {
|
|
45119
|
+
content
|
|
45120
|
+
} = _ref2;
|
|
45121
|
+
return {
|
|
45122
|
+
content: `Option ${toOptionLetter(i)}: ${content}`
|
|
45123
|
+
};
|
|
45124
|
+
}) : radio.options.choices);
|
|
45125
|
+
if (!radioProps && radio.options?.randomize) {
|
|
44713
45126
|
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
45127
|
}
|
|
44715
45128
|
context = context.replace(`[[☃ ${widgetID}]]`, radioContext);
|
|
@@ -44817,7 +45230,7 @@ function injectWidgets(content, widgets) {
|
|
|
44817
45230
|
// '[[☃ Orderer 1]]' -> 'option 1\noption 2\noption 3'
|
|
44818
45231
|
const orderer = widget;
|
|
44819
45232
|
if (orderer.options?.options) {
|
|
44820
|
-
context = context.replace(`[[☃ ${widgetID}]]`, orderer.options.options
|
|
45233
|
+
context = context.replace(`[[☃ ${widgetID}]]`, joinOptionContents(orderer.options.options));
|
|
44821
45234
|
}
|
|
44822
45235
|
break;
|
|
44823
45236
|
case "sorter":
|