@khanacademy/perseus 21.3.1 → 21.5.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 +257 -135
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +253 -124
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +1 -0
- package/dist/renderer.d.ts +19 -16
- package/dist/server-item-renderer.d.ts +4 -7
- package/dist/util/svg.d.ts +9 -0
- package/dist/widgets/interactive-graphs/axis-ticks.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/components/arrowhead.d.ts +8 -0
- package/dist/widgets/interactive-graphs/graphs/components/svg-line.d.ts +10 -0
- package/dist/widgets/interactive-graphs/graphs/components/vector.d.ts +9 -0
- package/dist/widgets/interactive-graphs/graphs/types.d.ts +2 -5
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-state.d.ts +9 -8
- package/dist/widgets/interactive-graphs/reducer/use-graph-config.d.ts +10 -0
- package/dist/widgets/interactive-graphs/types.d.ts +1 -0
- package/dist/widgets/radio/radio.d.ts +5 -8
- package/package.json +1 -1
- package/dist/widgets/interactive-graphs/reducer/use-graph-state.d.ts +0 -11
package/dist/es/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as KAS from '@khanacademy/kas';
|
|
|
2
2
|
import { keyTranslator, CursorContext, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
|
|
3
3
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
4
4
|
import { linterContextDefault, Rule, linterContextProps } from '@khanacademy/perseus-linter';
|
|
5
|
-
import { View, RenderStateRoot,
|
|
5
|
+
import { View, RenderStateRoot, useUniqueIdWithMock, UniqueIDProvider, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
6
6
|
import * as i18n from '@khanacademy/wonder-blocks-i18n';
|
|
7
7
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
8
8
|
import classNames from 'classnames';
|
|
@@ -30,7 +30,7 @@ import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-block
|
|
|
30
30
|
import caretDown from '@phosphor-icons/core/assets/regular/caret-down.svg';
|
|
31
31
|
import caretUp from '@phosphor-icons/core/assets/regular/caret-up.svg';
|
|
32
32
|
import debounce$2 from 'lodash.debounce';
|
|
33
|
-
import { Point as Point$2, useTransformContext, vec, useMovable,
|
|
33
|
+
import { Point as Point$2, useTransformContext, vec, useMovable, Text as Text$1, Polygon, Coordinates, Mafs } from 'mafs';
|
|
34
34
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
35
35
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
36
36
|
import { LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
@@ -4259,9 +4259,9 @@ function _classPrivateFieldBase(receiver, privateKey) {
|
|
|
4259
4259
|
return receiver;
|
|
4260
4260
|
}
|
|
4261
4261
|
|
|
4262
|
-
var id
|
|
4262
|
+
var id = 0;
|
|
4263
4263
|
function _classPrivateFieldKey(name) {
|
|
4264
|
-
return "__private_" + id
|
|
4264
|
+
return "__private_" + id++ + "_" + name;
|
|
4265
4265
|
}
|
|
4266
4266
|
|
|
4267
4267
|
/*!
|
|
@@ -10366,14 +10366,14 @@ class WrappedPath extends WrappedDrawing {
|
|
|
10366
10366
|
}
|
|
10367
10367
|
}
|
|
10368
10368
|
|
|
10369
|
-
class Arrowhead extends WrappedPath {
|
|
10369
|
+
class Arrowhead$1 extends WrappedPath {
|
|
10370
10370
|
constructor(graphie, style) {
|
|
10371
10371
|
// Points that define the arrowhead
|
|
10372
10372
|
const center = [0.75, 0];
|
|
10373
10373
|
const points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]].map(point => {
|
|
10374
10374
|
// Scale points by `Arrowhead.scale` around `center`
|
|
10375
10375
|
const pv = vector$1.subtract(point, center);
|
|
10376
|
-
const pvScaled = vector$1.scale(pv, Arrowhead.scale);
|
|
10376
|
+
const pvScaled = vector$1.scale(pv, Arrowhead$1.scale);
|
|
10377
10377
|
return vector$1.add(center, pvScaled);
|
|
10378
10378
|
});
|
|
10379
10379
|
const unscaledPoints = points.map(graphie.unscalePoint);
|
|
@@ -10391,14 +10391,14 @@ class Arrowhead extends WrappedPath {
|
|
|
10391
10391
|
}
|
|
10392
10392
|
toCoordAtAngle(coord, angle) {
|
|
10393
10393
|
const clipPoint = this.graphie.scalePoint(getClipPoint(this.graphie, coord, angle));
|
|
10394
|
-
this.transform("translateX(" + (clipPoint[0] + Arrowhead.scale * this.center[0]) + "px) " + "translateY(" + (clipPoint[1] + Arrowhead.scale * this.center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
|
|
10394
|
+
this.transform("translateX(" + (clipPoint[0] + Arrowhead$1.scale * this.center[0]) + "px) " + "translateY(" + (clipPoint[1] + Arrowhead$1.scale * this.center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
|
|
10395
10395
|
}
|
|
10396
10396
|
}
|
|
10397
10397
|
|
|
10398
10398
|
// We can't just pass in a path to `graph.fixedPath` as we need to modify
|
|
10399
10399
|
// the points in some way, so instead we provide a function for creating
|
|
10400
10400
|
// the path once the points have been transformed
|
|
10401
|
-
Arrowhead.scale = 1.4;
|
|
10401
|
+
Arrowhead$1.scale = 1.4;
|
|
10402
10402
|
const createCubicPath = function createCubicPath(points) {
|
|
10403
10403
|
let path = "M" + points[0][0] + " " + points[0][1];
|
|
10404
10404
|
for (let i = 1; i < points.length; i += 3) {
|
|
@@ -11638,10 +11638,10 @@ _.extend(GraphUtils.Graphie.prototype, {
|
|
|
11638
11638
|
if (this._arrows == null) {
|
|
11639
11639
|
this._arrows = [];
|
|
11640
11640
|
if (this.extendLine) {
|
|
11641
|
-
this._arrows.push(new Arrowhead(graph, this.normalStyle));
|
|
11642
|
-
this._arrows.push(new Arrowhead(graph, this.normalStyle));
|
|
11641
|
+
this._arrows.push(new Arrowhead$1(graph, this.normalStyle));
|
|
11642
|
+
this._arrows.push(new Arrowhead$1(graph, this.normalStyle));
|
|
11643
11643
|
} else if (this.extendRay) {
|
|
11644
|
-
this._arrows.push(new Arrowhead(graph, this.normalStyle));
|
|
11644
|
+
this._arrows.push(new Arrowhead$1(graph, this.normalStyle));
|
|
11645
11645
|
}
|
|
11646
11646
|
}
|
|
11647
11647
|
const coordForArrow = [this.coordA, this.coordZ];
|
|
@@ -14146,16 +14146,16 @@ const draw$3 = {
|
|
|
14146
14146
|
// @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
|
|
14147
14147
|
this._arrows.push(
|
|
14148
14148
|
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
|
|
14149
|
-
new Arrowhead(this.graphie, this.normalStyle()));
|
|
14149
|
+
new Arrowhead$1(this.graphie, this.normalStyle()));
|
|
14150
14150
|
// @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
|
|
14151
14151
|
this._arrows.push(
|
|
14152
14152
|
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
|
|
14153
|
-
new Arrowhead(this.graphie, this.normalStyle()));
|
|
14153
|
+
new Arrowhead$1(this.graphie, this.normalStyle()));
|
|
14154
14154
|
} else if (state.extendRay) {
|
|
14155
14155
|
// @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
|
|
14156
14156
|
this._arrows.push(
|
|
14157
14157
|
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
|
|
14158
|
-
new Arrowhead(this.graphie, this.normalStyle()));
|
|
14158
|
+
new Arrowhead$1(this.graphie, this.normalStyle()));
|
|
14159
14159
|
}
|
|
14160
14160
|
}
|
|
14161
14161
|
|
|
@@ -19463,6 +19463,7 @@ class Renderer extends React.Component {
|
|
|
19463
19463
|
apiOptions: this.getApiOptions(),
|
|
19464
19464
|
keypadElement: this.props.keypadElement,
|
|
19465
19465
|
questionCompleted: this.props.questionCompleted,
|
|
19466
|
+
showSolutions: this.props.showSolutions,
|
|
19466
19467
|
onFocus: _.partial(this._onWidgetFocus, id),
|
|
19467
19468
|
onBlur: _.partial(this._onWidgetBlur, id),
|
|
19468
19469
|
findWidgets: this.findWidgets,
|
|
@@ -20657,6 +20658,7 @@ Renderer.defaultProps = {
|
|
|
20657
20658
|
images: {},
|
|
20658
20659
|
highlightedWidgets: [],
|
|
20659
20660
|
questionCompleted: false,
|
|
20661
|
+
showSolutions: "none",
|
|
20660
20662
|
// onRender may be called multiple times per render, for example
|
|
20661
20663
|
// if there are multiple images or TeX pieces within `content`.
|
|
20662
20664
|
// It is a good idea to debounce any functions passed here.
|
|
@@ -23076,14 +23078,6 @@ const ellipsisHorizontalIcon = {
|
|
|
23076
23078
|
width: 100,
|
|
23077
23079
|
height: 27.284
|
|
23078
23080
|
};
|
|
23079
|
-
// Note(TB): Received errors when using useUniqueIdWithMock
|
|
23080
|
-
// so created this workaround function. Will update when
|
|
23081
|
-
// useUniqueIdWithMock is available.
|
|
23082
|
-
// https://khanacademy.atlassian.net/browse/FEI-4861?atlOrigin=eyJpIjoiNDJlZWMwNjM1NWJhNDBkMWFjY2FmN2I0ZjcxZmQxOGUiLCJwIjoiaiJ9
|
|
23083
|
-
let id = 0;
|
|
23084
|
-
function uniqueId() {
|
|
23085
|
-
return `choice-${id++}`;
|
|
23086
|
-
}
|
|
23087
23081
|
const Choice = function Choice(props) {
|
|
23088
23082
|
const {
|
|
23089
23083
|
disabled = false,
|
|
@@ -23134,7 +23128,8 @@ const Choice = function Choice(props) {
|
|
|
23134
23128
|
const showDimmed = !reviewMode && apiOptions.readOnly || crossedOut;
|
|
23135
23129
|
const letter = getChoiceLetter(pos);
|
|
23136
23130
|
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness);
|
|
23137
|
-
const
|
|
23131
|
+
const idFactory = useUniqueIdWithMock(`choice`);
|
|
23132
|
+
const choiceId = idFactory.get(letter);
|
|
23138
23133
|
return /*#__PURE__*/React.createElement("div", {
|
|
23139
23134
|
style: {
|
|
23140
23135
|
// @ts-expect-error - TS2322 - Type '{ dispay: string; flexDirection: "column"; color: string; }' is not assignable to type 'Properties<string | number, string & {}>'.
|
|
@@ -23807,6 +23802,7 @@ class Radio$1 extends React.Component {
|
|
|
23807
23802
|
* Turn on rationale display for the currently selected choices. Note that
|
|
23808
23803
|
* this leaves rationales on for choices that are already showing
|
|
23809
23804
|
* rationales.
|
|
23805
|
+
* @deprecated Internal only. Use `showSolutions` prop instead.
|
|
23810
23806
|
*/
|
|
23811
23807
|
this.showRationalesForCurrentlySelectedChoices = rubric => {
|
|
23812
23808
|
const {
|
|
@@ -23827,7 +23823,7 @@ class Radio$1 extends React.Component {
|
|
|
23827
23823
|
// We use the same behavior for the readOnly flag as for
|
|
23828
23824
|
// rationaleShown, but we keep it separate in case other
|
|
23829
23825
|
// behaviors want to disable choices without showing rationales.
|
|
23830
|
-
readOnly: state.selected || state.readOnly || widgetCorrect,
|
|
23826
|
+
readOnly: state.selected || state.readOnly || widgetCorrect || this.props.showSolutions !== "none",
|
|
23831
23827
|
correctnessShown: state.selected || state.correctnessShown,
|
|
23832
23828
|
previouslyAnswered: state.previouslyAnswered || state.selected
|
|
23833
23829
|
}));
|
|
@@ -23969,6 +23965,11 @@ class Radio$1 extends React.Component {
|
|
|
23969
23965
|
choicesSelected: props.choices.map(() => false)
|
|
23970
23966
|
};
|
|
23971
23967
|
}
|
|
23968
|
+
componentDidUpdate(prevProps) {
|
|
23969
|
+
if (this.props.showSolutions === "selected" && prevProps.showSolutions !== "selected") {
|
|
23970
|
+
this.showRationalesForCurrentlySelectedChoices(this.props);
|
|
23971
|
+
}
|
|
23972
|
+
}
|
|
23972
23973
|
// TODO(LP-10672): I think this might be unused right now. I can't find anywhere
|
|
23973
23974
|
// that we pass a value to `.focus()` and it seems to have been used for
|
|
23974
23975
|
// adding hints when editing.
|
|
@@ -24000,6 +24001,20 @@ class Radio$1 extends React.Component {
|
|
|
24000
24001
|
correctnessShown: true,
|
|
24001
24002
|
previouslyAnswered: false
|
|
24002
24003
|
}));
|
|
24004
|
+
} else if (this.props.showSolutions === "all") {
|
|
24005
|
+
choiceStates = choices.map(({
|
|
24006
|
+
correct
|
|
24007
|
+
}) => ({
|
|
24008
|
+
selected: correct,
|
|
24009
|
+
// to draw the eye to the correct answer
|
|
24010
|
+
crossedOut: false,
|
|
24011
|
+
readOnly: true,
|
|
24012
|
+
highlighted: false,
|
|
24013
|
+
// has no effect in this mode
|
|
24014
|
+
rationaleShown: true,
|
|
24015
|
+
correctnessShown: true,
|
|
24016
|
+
previouslyAnswered: false
|
|
24017
|
+
}));
|
|
24003
24018
|
} else if (this.props.choiceStates) {
|
|
24004
24019
|
choiceStates = this.props.choiceStates;
|
|
24005
24020
|
} else if (this.props.values) {
|
|
@@ -24087,7 +24102,8 @@ Radio$1.defaultProps = {
|
|
|
24087
24102
|
multipleSelect: false,
|
|
24088
24103
|
countChoices: false,
|
|
24089
24104
|
deselectEnabled: false,
|
|
24090
|
-
linterContext: linterContextDefault
|
|
24105
|
+
linterContext: linterContextDefault,
|
|
24106
|
+
showSolutions: "none"
|
|
24091
24107
|
};
|
|
24092
24108
|
|
|
24093
24109
|
const {
|
|
@@ -28322,6 +28338,118 @@ const getLines = points => points.map((point, i) => {
|
|
|
28322
28338
|
return [point, next];
|
|
28323
28339
|
});
|
|
28324
28340
|
|
|
28341
|
+
function SVGLine(props) {
|
|
28342
|
+
const {
|
|
28343
|
+
start,
|
|
28344
|
+
end,
|
|
28345
|
+
style,
|
|
28346
|
+
className,
|
|
28347
|
+
testId
|
|
28348
|
+
} = props;
|
|
28349
|
+
return /*#__PURE__*/React.createElement("line", {
|
|
28350
|
+
x1: start[0],
|
|
28351
|
+
y1: start[1],
|
|
28352
|
+
x2: end[0],
|
|
28353
|
+
y2: end[1],
|
|
28354
|
+
style: style,
|
|
28355
|
+
className: `${className}`,
|
|
28356
|
+
"data-test-id": testId
|
|
28357
|
+
});
|
|
28358
|
+
}
|
|
28359
|
+
|
|
28360
|
+
function pathBuilder() {
|
|
28361
|
+
return new PathBuilder();
|
|
28362
|
+
}
|
|
28363
|
+
class PathBuilder {
|
|
28364
|
+
constructor() {
|
|
28365
|
+
this.path = [];
|
|
28366
|
+
this.scaleFactor = 1;
|
|
28367
|
+
}
|
|
28368
|
+
build() {
|
|
28369
|
+
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28370
|
+
}
|
|
28371
|
+
|
|
28372
|
+
// add a move (M) command to the path
|
|
28373
|
+
move(x, y) {
|
|
28374
|
+
this.path.push({
|
|
28375
|
+
action: "M",
|
|
28376
|
+
coords: [x, y]
|
|
28377
|
+
});
|
|
28378
|
+
return this;
|
|
28379
|
+
}
|
|
28380
|
+
|
|
28381
|
+
// add a curve (C) command to the path
|
|
28382
|
+
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28383
|
+
this.path.push({
|
|
28384
|
+
action: "C",
|
|
28385
|
+
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28386
|
+
});
|
|
28387
|
+
return this;
|
|
28388
|
+
}
|
|
28389
|
+
|
|
28390
|
+
// Scale all coordinates of the path by a factor
|
|
28391
|
+
scale(factor) {
|
|
28392
|
+
this.scaleFactor *= factor;
|
|
28393
|
+
return this;
|
|
28394
|
+
}
|
|
28395
|
+
}
|
|
28396
|
+
function commandToString(command) {
|
|
28397
|
+
return `${command.action}${command.coords.join(" ")}`;
|
|
28398
|
+
}
|
|
28399
|
+
function scaleCommandBy(scaleFactor) {
|
|
28400
|
+
return command => _extends({}, command, {
|
|
28401
|
+
coords: command.coords.map(c => c * scaleFactor)
|
|
28402
|
+
});
|
|
28403
|
+
}
|
|
28404
|
+
|
|
28405
|
+
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
28406
|
+
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
28407
|
+
// transform because a transform would also scale up the stroke weight, and we
|
|
28408
|
+
// don't want that.
|
|
28409
|
+
const arrowPath = pathBuilder().move(-3, 4).curve(-2.75, 2.5, 0, 0.25, 0.75, 0).curve(0, -0.25, -2.75, -2.5, -3, -4).scale(1.4).build();
|
|
28410
|
+
function Arrowhead(props) {
|
|
28411
|
+
const [point] = useTransform([props.x, props.y]);
|
|
28412
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28413
|
+
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
28414
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
28415
|
+
transform: "translate(-1.5)"
|
|
28416
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
28417
|
+
d: arrowPath,
|
|
28418
|
+
fill: "none",
|
|
28419
|
+
style: {
|
|
28420
|
+
stroke: "inherit"
|
|
28421
|
+
},
|
|
28422
|
+
strokeLinejoin: "round",
|
|
28423
|
+
strokeLinecap: "round"
|
|
28424
|
+
})));
|
|
28425
|
+
}
|
|
28426
|
+
|
|
28427
|
+
function Vector(props) {
|
|
28428
|
+
const {
|
|
28429
|
+
tail,
|
|
28430
|
+
tip,
|
|
28431
|
+
color
|
|
28432
|
+
} = props;
|
|
28433
|
+
const [tailPx, tipPx] = useTransform(tail, tip);
|
|
28434
|
+
const direction = vec.sub(tip, tail);
|
|
28435
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28436
|
+
style: {
|
|
28437
|
+
stroke: color,
|
|
28438
|
+
strokeWidth: 2
|
|
28439
|
+
}
|
|
28440
|
+
}, /*#__PURE__*/React.createElement(SVGLine, {
|
|
28441
|
+
start: tailPx,
|
|
28442
|
+
end: tipPx
|
|
28443
|
+
}), /*#__PURE__*/React.createElement(Arrowhead, {
|
|
28444
|
+
x: tip[0],
|
|
28445
|
+
y: tip[1],
|
|
28446
|
+
angle: angleDegrees(direction)
|
|
28447
|
+
}));
|
|
28448
|
+
}
|
|
28449
|
+
function angleDegrees([x, y]) {
|
|
28450
|
+
return Math.atan2(y, x) * 180 / Math.PI;
|
|
28451
|
+
}
|
|
28452
|
+
|
|
28325
28453
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
28326
28454
|
const MovableLine = props => {
|
|
28327
28455
|
const {
|
|
@@ -28382,7 +28510,7 @@ const MovableLine = props => {
|
|
|
28382
28510
|
stroke,
|
|
28383
28511
|
strokeWidth: "var(--movable-line-stroke-weight)"
|
|
28384
28512
|
},
|
|
28385
|
-
dragging:
|
|
28513
|
+
className: dragging ? "movable-dragging" : "",
|
|
28386
28514
|
testId: "movable-line__line"
|
|
28387
28515
|
})), startExtend && /*#__PURE__*/React.createElement(Vector, {
|
|
28388
28516
|
tail: start,
|
|
@@ -28394,33 +28522,15 @@ const MovableLine = props => {
|
|
|
28394
28522
|
color: stroke
|
|
28395
28523
|
}));
|
|
28396
28524
|
};
|
|
28397
|
-
function SVGLine(props) {
|
|
28398
|
-
const {
|
|
28399
|
-
start,
|
|
28400
|
-
end,
|
|
28401
|
-
style,
|
|
28402
|
-
dragging,
|
|
28403
|
-
className,
|
|
28404
|
-
testId
|
|
28405
|
-
} = props;
|
|
28406
|
-
const draggingClass = dragging ? "movable-dragging" : "";
|
|
28407
|
-
return /*#__PURE__*/React.createElement("line", {
|
|
28408
|
-
x1: start[0],
|
|
28409
|
-
y1: start[1],
|
|
28410
|
-
x2: end[0],
|
|
28411
|
-
y2: end[1],
|
|
28412
|
-
style: style,
|
|
28413
|
-
className: `${className} ${draggingClass}`,
|
|
28414
|
-
"data-test-id": testId
|
|
28415
|
-
});
|
|
28416
|
-
}
|
|
28417
28525
|
|
|
28418
|
-
const
|
|
28419
|
-
|
|
28420
|
-
|
|
28421
|
-
|
|
28422
|
-
|
|
28423
|
-
|
|
28526
|
+
const defaultGraphConfig = {
|
|
28527
|
+
range: [[0, 1], [0, 1]],
|
|
28528
|
+
snapStep: [1, 1],
|
|
28529
|
+
markings: "none"
|
|
28530
|
+
};
|
|
28531
|
+
const GraphConfigContext = /*#__PURE__*/createContext(defaultGraphConfig);
|
|
28532
|
+
function useGraphConfig() {
|
|
28533
|
+
return React__default.useContext(GraphConfigContext);
|
|
28424
28534
|
}
|
|
28425
28535
|
|
|
28426
28536
|
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
@@ -28428,8 +28538,10 @@ function useGraphState() {
|
|
|
28428
28538
|
const hitboxSizePx = 48;
|
|
28429
28539
|
const StyledMovablePoint = props => {
|
|
28430
28540
|
const {
|
|
28431
|
-
|
|
28432
|
-
|
|
28541
|
+
range,
|
|
28542
|
+
snapStep,
|
|
28543
|
+
markings
|
|
28544
|
+
} = useGraphConfig();
|
|
28433
28545
|
const hitboxRef = useRef(null);
|
|
28434
28546
|
const {
|
|
28435
28547
|
point,
|
|
@@ -28442,11 +28554,30 @@ const StyledMovablePoint = props => {
|
|
|
28442
28554
|
gestureTarget: hitboxRef,
|
|
28443
28555
|
point,
|
|
28444
28556
|
onMove,
|
|
28445
|
-
constrain: p => snap(
|
|
28557
|
+
constrain: p => snap(snapStep, p)
|
|
28446
28558
|
});
|
|
28447
28559
|
const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""}`;
|
|
28448
28560
|
const [[x, y]] = useTransform(point);
|
|
28449
|
-
|
|
28561
|
+
const [xMin, xMax] = range[0];
|
|
28562
|
+
const [yMin, yMax] = range[1];
|
|
28563
|
+
const [[verticalStartX]] = useTransform([xMin, 0]);
|
|
28564
|
+
const [[verticalEndX]] = useTransform([xMax, 0]);
|
|
28565
|
+
const [[_, horizontalStartY]] = useTransform([0, yMin]);
|
|
28566
|
+
const [[__, horizontalEndY]] = useTransform([0, yMax]);
|
|
28567
|
+
const showHairlines = dragging && markings !== "none";
|
|
28568
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
28569
|
+
x1: verticalStartX,
|
|
28570
|
+
y1: y,
|
|
28571
|
+
x2: verticalEndX,
|
|
28572
|
+
y2: y,
|
|
28573
|
+
stroke: color.green
|
|
28574
|
+
}), /*#__PURE__*/React.createElement("line", {
|
|
28575
|
+
x1: x,
|
|
28576
|
+
y1: horizontalStartY,
|
|
28577
|
+
x2: x,
|
|
28578
|
+
y2: horizontalEndY,
|
|
28579
|
+
stroke: color.green
|
|
28580
|
+
})), /*#__PURE__*/React.createElement("g", {
|
|
28450
28581
|
ref: hitboxRef,
|
|
28451
28582
|
className: pointClasses,
|
|
28452
28583
|
tabIndex: 0,
|
|
@@ -28479,7 +28610,7 @@ const StyledMovablePoint = props => {
|
|
|
28479
28610
|
fill: color$1
|
|
28480
28611
|
},
|
|
28481
28612
|
"data-test-id": "movable-point__center"
|
|
28482
|
-
}));
|
|
28613
|
+
})));
|
|
28483
28614
|
};
|
|
28484
28615
|
|
|
28485
28616
|
const SegmentGraph = props => {
|
|
@@ -28487,15 +28618,11 @@ const SegmentGraph = props => {
|
|
|
28487
28618
|
dispatch
|
|
28488
28619
|
} = props;
|
|
28489
28620
|
const {
|
|
28490
|
-
coords: segments
|
|
28491
|
-
snapStep,
|
|
28492
|
-
range
|
|
28621
|
+
coords: segments
|
|
28493
28622
|
} = props.graphState;
|
|
28494
28623
|
return /*#__PURE__*/React.createElement(React.Fragment, null, segments == null ? void 0 : segments.map((segment, i) => /*#__PURE__*/React.createElement(SegmentView, {
|
|
28495
28624
|
key: i,
|
|
28496
|
-
|
|
28497
|
-
snaps: snapStep,
|
|
28498
|
-
range: range,
|
|
28625
|
+
points: segment,
|
|
28499
28626
|
onMoveLine: delta => {
|
|
28500
28627
|
dispatch(moveLine(i, delta));
|
|
28501
28628
|
},
|
|
@@ -28508,7 +28635,7 @@ const SegmentGraph = props => {
|
|
|
28508
28635
|
const SegmentView = props => {
|
|
28509
28636
|
const {
|
|
28510
28637
|
onMoveLine: onMoveSegment,
|
|
28511
|
-
|
|
28638
|
+
points: [start, end]
|
|
28512
28639
|
} = props;
|
|
28513
28640
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MovableLine, {
|
|
28514
28641
|
start: start,
|
|
@@ -28533,16 +28660,12 @@ const LinearGraph = props => {
|
|
|
28533
28660
|
} = props;
|
|
28534
28661
|
const {
|
|
28535
28662
|
coords: lines,
|
|
28536
|
-
snapStep,
|
|
28537
|
-
range,
|
|
28538
28663
|
type
|
|
28539
28664
|
} = props.graphState;
|
|
28540
28665
|
const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
|
|
28541
28666
|
return /*#__PURE__*/React.createElement(React.Fragment, null, lines == null ? void 0 : lines.map((line, i) => /*#__PURE__*/React.createElement(LineView, {
|
|
28542
28667
|
key: i,
|
|
28543
|
-
|
|
28544
|
-
snaps: snapStep,
|
|
28545
|
-
range: range,
|
|
28668
|
+
points: line,
|
|
28546
28669
|
onMoveLine: delta => {
|
|
28547
28670
|
dispatch(moveLine(i, delta));
|
|
28548
28671
|
},
|
|
@@ -28557,10 +28680,12 @@ const LineView = props => {
|
|
|
28557
28680
|
const {
|
|
28558
28681
|
onMoveLine,
|
|
28559
28682
|
onMovePoint,
|
|
28560
|
-
|
|
28561
|
-
range,
|
|
28683
|
+
points: [start, end],
|
|
28562
28684
|
stroke
|
|
28563
28685
|
} = props;
|
|
28686
|
+
const {
|
|
28687
|
+
range
|
|
28688
|
+
} = useGraphConfig();
|
|
28564
28689
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MovableLine, {
|
|
28565
28690
|
start: start,
|
|
28566
28691
|
end: end,
|
|
@@ -28874,46 +28999,26 @@ function PointGraph(props) {
|
|
|
28874
28999
|
})));
|
|
28875
29000
|
}
|
|
28876
29001
|
|
|
28877
|
-
function Arrow(props) {
|
|
28878
|
-
const {
|
|
28879
|
-
userTransform,
|
|
28880
|
-
viewTransform
|
|
28881
|
-
} = useTransformContext();
|
|
28882
|
-
const point = [props.x, props.y];
|
|
28883
|
-
const userTransformedPoint = vec.transform(point, userTransform);
|
|
28884
|
-
const viewTransformedPoint = vec.transform(userTransformedPoint, viewTransform);
|
|
28885
|
-
return /*#__PURE__*/React__default.createElement("g", {
|
|
28886
|
-
transform: `translate(${viewTransformedPoint[0]} ${viewTransformedPoint[1]}) rotate(${props.rotate}) scale(1.25)`
|
|
28887
|
-
}, /*#__PURE__*/React__default.createElement("g", {
|
|
28888
|
-
transform: "translate(-1)"
|
|
28889
|
-
}, /*#__PURE__*/React__default.createElement("path", {
|
|
28890
|
-
d: "M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4",
|
|
28891
|
-
fill: "none"
|
|
28892
|
-
})));
|
|
28893
|
-
}
|
|
28894
29002
|
function AxisArrows() {
|
|
28895
29003
|
const {
|
|
28896
|
-
|
|
28897
|
-
} =
|
|
28898
|
-
|
|
28899
|
-
const [xMin, xMax] = range[0];
|
|
28900
|
-
const [yMin, yMax] = range[1];
|
|
28901
|
-
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrow, {
|
|
29004
|
+
range: [[xMin, xMax], [yMin, yMax]]
|
|
29005
|
+
} = useGraphConfig();
|
|
29006
|
+
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28902
29007
|
x: xMax,
|
|
28903
29008
|
y: 0,
|
|
28904
|
-
|
|
28905
|
-
}), /*#__PURE__*/React__default.createElement(
|
|
29009
|
+
angle: 0
|
|
29010
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28906
29011
|
x: 0,
|
|
28907
29012
|
y: yMin,
|
|
28908
|
-
|
|
28909
|
-
}), /*#__PURE__*/React__default.createElement(
|
|
29013
|
+
angle: 90
|
|
29014
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28910
29015
|
x: xMin,
|
|
28911
29016
|
y: 0,
|
|
28912
|
-
|
|
28913
|
-
}), /*#__PURE__*/React__default.createElement(
|
|
29017
|
+
angle: 180
|
|
29018
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28914
29019
|
x: 0,
|
|
28915
29020
|
y: yMax,
|
|
28916
|
-
|
|
29021
|
+
angle: 270
|
|
28917
29022
|
}));
|
|
28918
29023
|
}
|
|
28919
29024
|
|
|
@@ -28922,8 +29027,19 @@ const tickStyle = {
|
|
|
28922
29027
|
stroke: "black",
|
|
28923
29028
|
strokeWidth: 1
|
|
28924
29029
|
};
|
|
29030
|
+
|
|
29031
|
+
// We only want to show the initial negative tick labels (e.g. -1) on each
|
|
29032
|
+
// axis if the tickStep > gridStep, to ensure that these labels do not overlap.
|
|
29033
|
+
// e.g. If gridStep = 1 and tickStep = 2, there are 2 grid lines for every 1 tick,
|
|
29034
|
+
// which allows enough room for both these tick labels to render.
|
|
29035
|
+
const showTickLabel = (gridStep, tickStep, label) => {
|
|
29036
|
+
const showLabel = tickStep > gridStep ? true : label !== -tickStep;
|
|
29037
|
+
return showLabel;
|
|
29038
|
+
};
|
|
28925
29039
|
const YGridTick = ({
|
|
28926
|
-
y
|
|
29040
|
+
y,
|
|
29041
|
+
gridStep,
|
|
29042
|
+
tickStep
|
|
28927
29043
|
}) => {
|
|
28928
29044
|
const pointOnAxis = [0, y];
|
|
28929
29045
|
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
@@ -28935,7 +29051,7 @@ const YGridTick = ({
|
|
|
28935
29051
|
x2: xPosition + tickSize / 2,
|
|
28936
29052
|
y2: yPosition,
|
|
28937
29053
|
style: tickStyle
|
|
28938
|
-
}),
|
|
29054
|
+
}), showTickLabel(gridStep, tickStep, y) && /*#__PURE__*/React.createElement("text", {
|
|
28939
29055
|
height: 20,
|
|
28940
29056
|
width: 50,
|
|
28941
29057
|
textAnchor: "end",
|
|
@@ -28944,7 +29060,9 @@ const YGridTick = ({
|
|
|
28944
29060
|
}, y.toString()));
|
|
28945
29061
|
};
|
|
28946
29062
|
const XGridTick = ({
|
|
28947
|
-
x
|
|
29063
|
+
x,
|
|
29064
|
+
gridStep,
|
|
29065
|
+
tickStep
|
|
28948
29066
|
}) => {
|
|
28949
29067
|
const pointOnAxis = [x, 0];
|
|
28950
29068
|
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
@@ -28956,7 +29074,7 @@ const XGridTick = ({
|
|
|
28956
29074
|
x2: xPosition,
|
|
28957
29075
|
y2: yPosition - tickSize / 2,
|
|
28958
29076
|
style: tickStyle
|
|
28959
|
-
}),
|
|
29077
|
+
}), showTickLabel(gridStep, tickStep, x) && /*#__PURE__*/React.createElement("text", {
|
|
28960
29078
|
height: 20,
|
|
28961
29079
|
width: 50,
|
|
28962
29080
|
textAnchor: "middle",
|
|
@@ -28991,12 +29109,16 @@ const AxisTicks = props => {
|
|
|
28991
29109
|
}, yGridTicks.map(y => {
|
|
28992
29110
|
return /*#__PURE__*/React.createElement(YGridTick, {
|
|
28993
29111
|
y: y,
|
|
28994
|
-
key: `y-grid-tick-${y}
|
|
29112
|
+
key: `y-grid-tick-${y}`,
|
|
29113
|
+
gridStep: props.gridStep[0],
|
|
29114
|
+
tickStep: yTickStep
|
|
28995
29115
|
});
|
|
28996
29116
|
}), xGridTicks.map(x => {
|
|
28997
29117
|
return /*#__PURE__*/React.createElement(XGridTick, {
|
|
28998
29118
|
x: x,
|
|
28999
|
-
key: `x-grid-tick-${x}
|
|
29119
|
+
key: `x-grid-tick-${x}`,
|
|
29120
|
+
gridStep: props.gridStep[1],
|
|
29121
|
+
tickStep: xTickStep
|
|
29000
29122
|
});
|
|
29001
29123
|
}));
|
|
29002
29124
|
};
|
|
@@ -29022,10 +29144,13 @@ const Grid = props => {
|
|
|
29022
29144
|
return props.markings === "none" ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
|
|
29023
29145
|
xAxis: axisOptions(props, 0),
|
|
29024
29146
|
yAxis: axisOptions(props, 1)
|
|
29025
|
-
}), /*#__PURE__*/React.createElement(
|
|
29147
|
+
}), props.markings === "graph" && /*#__PURE__*/React.createElement(AxisArrows, null),
|
|
29148
|
+
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
29149
|
+
props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisTicks, {
|
|
29026
29150
|
range: props.range,
|
|
29027
|
-
tickStep: props.tickStep
|
|
29028
|
-
|
|
29151
|
+
tickStep: props.tickStep,
|
|
29152
|
+
gridStep: props.gridStep
|
|
29153
|
+
}), /*#__PURE__*/React.createElement(AxisArrows, null)));
|
|
29029
29154
|
};
|
|
29030
29155
|
|
|
29031
29156
|
// Displays a stylized open eye: lint warnings are visible
|
|
@@ -29984,29 +30109,30 @@ function initializeGraphState(params) {
|
|
|
29984
30109
|
graph,
|
|
29985
30110
|
step,
|
|
29986
30111
|
snapStep,
|
|
29987
|
-
range
|
|
30112
|
+
range,
|
|
30113
|
+
markings
|
|
29988
30114
|
} = params;
|
|
30115
|
+
const shared = {
|
|
30116
|
+
hasBeenInteractedWith: false,
|
|
30117
|
+
range,
|
|
30118
|
+
snapStep,
|
|
30119
|
+
markings
|
|
30120
|
+
};
|
|
29989
30121
|
switch (graph.type) {
|
|
29990
30122
|
case "segment":
|
|
29991
|
-
return {
|
|
30123
|
+
return _extends({}, shared, {
|
|
29992
30124
|
type: "segment",
|
|
29993
|
-
hasBeenInteractedWith: false,
|
|
29994
|
-
range,
|
|
29995
|
-
snapStep,
|
|
29996
30125
|
coords: getDefaultSegments({
|
|
29997
30126
|
graph,
|
|
29998
30127
|
step,
|
|
29999
30128
|
range
|
|
30000
30129
|
})
|
|
30001
|
-
};
|
|
30130
|
+
});
|
|
30002
30131
|
case "linear":
|
|
30003
30132
|
case "linear-system":
|
|
30004
30133
|
case "ray":
|
|
30005
|
-
return {
|
|
30134
|
+
return _extends({}, shared, {
|
|
30006
30135
|
type: graph.type,
|
|
30007
|
-
hasBeenInteractedWith: false,
|
|
30008
|
-
range,
|
|
30009
|
-
snapStep,
|
|
30010
30136
|
// Linear and ray graphs have a single tuple of points, while a
|
|
30011
30137
|
// linear system has two tuples of points.
|
|
30012
30138
|
coords: getLineCoords({
|
|
@@ -30014,13 +30140,10 @@ function initializeGraphState(params) {
|
|
|
30014
30140
|
range,
|
|
30015
30141
|
step
|
|
30016
30142
|
})
|
|
30017
|
-
};
|
|
30143
|
+
});
|
|
30018
30144
|
case "polygon":
|
|
30019
|
-
return {
|
|
30145
|
+
return _extends({}, shared, {
|
|
30020
30146
|
type: "polygon",
|
|
30021
|
-
hasBeenInteractedWith: false,
|
|
30022
|
-
range,
|
|
30023
|
-
snapStep,
|
|
30024
30147
|
showAngles: Boolean(graph.showAngles),
|
|
30025
30148
|
showSides: Boolean(graph.showSides),
|
|
30026
30149
|
coords: getPolygonCoords({
|
|
@@ -30028,19 +30151,16 @@ function initializeGraphState(params) {
|
|
|
30028
30151
|
range,
|
|
30029
30152
|
step
|
|
30030
30153
|
})
|
|
30031
|
-
};
|
|
30154
|
+
});
|
|
30032
30155
|
case "point":
|
|
30033
|
-
return {
|
|
30156
|
+
return _extends({}, shared, {
|
|
30034
30157
|
type: graph.type,
|
|
30035
|
-
hasBeenInteractedWith: false,
|
|
30036
|
-
range,
|
|
30037
|
-
snapStep,
|
|
30038
30158
|
coords: getDefaultPoints({
|
|
30039
30159
|
graph,
|
|
30040
30160
|
step,
|
|
30041
30161
|
range
|
|
30042
30162
|
})
|
|
30043
|
-
};
|
|
30163
|
+
});
|
|
30044
30164
|
case "angle":
|
|
30045
30165
|
case "circle":
|
|
30046
30166
|
case "sinusoid":
|
|
@@ -30280,10 +30400,11 @@ const MafsGraph = props => {
|
|
|
30280
30400
|
useEffect(() => {
|
|
30281
30401
|
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
30282
30402
|
}, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
30283
|
-
return /*#__PURE__*/React.createElement(
|
|
30403
|
+
return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
|
|
30284
30404
|
value: {
|
|
30285
|
-
state,
|
|
30286
|
-
|
|
30405
|
+
range: state.range,
|
|
30406
|
+
snapStep: state.snapStep,
|
|
30407
|
+
markings: props.markings
|
|
30287
30408
|
}
|
|
30288
30409
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30289
30410
|
style: {
|
|
@@ -42368,7 +42489,7 @@ const init = function init(options) {
|
|
|
42368
42489
|
|
|
42369
42490
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42370
42491
|
const libName = "@khanacademy/perseus";
|
|
42371
|
-
const libVersion = "21.
|
|
42492
|
+
const libVersion = "21.5.0";
|
|
42372
42493
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42373
42494
|
|
|
42374
42495
|
const apiVersion = {
|
|
@@ -43198,6 +43319,7 @@ class ServerItemRenderer extends React.Component {
|
|
|
43198
43319
|
apiOptions: apiOptions,
|
|
43199
43320
|
questionCompleted: this.state.questionCompleted,
|
|
43200
43321
|
reviewMode: this.props.reviewMode,
|
|
43322
|
+
showSolutions: this.props.showSolutions,
|
|
43201
43323
|
ref: elem => {
|
|
43202
43324
|
if (elem != null) {
|
|
43203
43325
|
this.questionRenderer = elem;
|