@khanacademy/perseus 21.3.0 → 21.4.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.css +17 -1
- package/dist/es/index.js +258 -139
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +17 -1
- package/dist/index.js +254 -128
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +9 -1
- package/dist/perseus-types.d.ts +1 -21
- package/dist/renderer.d.ts +19 -16
- package/dist/server-item-renderer.d.ts +9 -1
- package/dist/strings.js +0 -4
- package/dist/types.d.ts +11 -1
- package/dist/util/svg.d.ts +9 -0
- package/dist/widgets/expression.d.ts +54 -6
- 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/label-image.d.ts +18 -2
- 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/widgets/lights-puzzle.d.ts +0 -53
- package/dist/widgets/reaction-diagram.d.ts +0 -42
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,17 +28554,34 @@ 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
|
});
|
|
28559
|
+
const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""}`;
|
|
28447
28560
|
const [[x, y]] = useTransform(point);
|
|
28448
|
-
|
|
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", {
|
|
28449
28581
|
ref: hitboxRef,
|
|
28450
|
-
className:
|
|
28582
|
+
className: pointClasses,
|
|
28451
28583
|
tabIndex: 0,
|
|
28452
28584
|
style: {
|
|
28453
|
-
cursor: dragging ? "grabbing" : "grab",
|
|
28454
|
-
touchAction: "none",
|
|
28455
|
-
outline: "none",
|
|
28456
28585
|
"--movable-point-color": color$1
|
|
28457
28586
|
},
|
|
28458
28587
|
"data-test-id": "movable-point"
|
|
@@ -28481,7 +28610,7 @@ const StyledMovablePoint = props => {
|
|
|
28481
28610
|
fill: color$1
|
|
28482
28611
|
},
|
|
28483
28612
|
"data-test-id": "movable-point__center"
|
|
28484
|
-
}));
|
|
28613
|
+
})));
|
|
28485
28614
|
};
|
|
28486
28615
|
|
|
28487
28616
|
const SegmentGraph = props => {
|
|
@@ -28489,15 +28618,11 @@ const SegmentGraph = props => {
|
|
|
28489
28618
|
dispatch
|
|
28490
28619
|
} = props;
|
|
28491
28620
|
const {
|
|
28492
|
-
coords: segments
|
|
28493
|
-
snapStep,
|
|
28494
|
-
range
|
|
28621
|
+
coords: segments
|
|
28495
28622
|
} = props.graphState;
|
|
28496
28623
|
return /*#__PURE__*/React.createElement(React.Fragment, null, segments == null ? void 0 : segments.map((segment, i) => /*#__PURE__*/React.createElement(SegmentView, {
|
|
28497
28624
|
key: i,
|
|
28498
|
-
|
|
28499
|
-
snaps: snapStep,
|
|
28500
|
-
range: range,
|
|
28625
|
+
points: segment,
|
|
28501
28626
|
onMoveLine: delta => {
|
|
28502
28627
|
dispatch(moveLine(i, delta));
|
|
28503
28628
|
},
|
|
@@ -28510,7 +28635,7 @@ const SegmentGraph = props => {
|
|
|
28510
28635
|
const SegmentView = props => {
|
|
28511
28636
|
const {
|
|
28512
28637
|
onMoveLine: onMoveSegment,
|
|
28513
|
-
|
|
28638
|
+
points: [start, end]
|
|
28514
28639
|
} = props;
|
|
28515
28640
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MovableLine, {
|
|
28516
28641
|
start: start,
|
|
@@ -28535,16 +28660,12 @@ const LinearGraph = props => {
|
|
|
28535
28660
|
} = props;
|
|
28536
28661
|
const {
|
|
28537
28662
|
coords: lines,
|
|
28538
|
-
snapStep,
|
|
28539
|
-
range,
|
|
28540
28663
|
type
|
|
28541
28664
|
} = props.graphState;
|
|
28542
28665
|
const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
|
|
28543
28666
|
return /*#__PURE__*/React.createElement(React.Fragment, null, lines == null ? void 0 : lines.map((line, i) => /*#__PURE__*/React.createElement(LineView, {
|
|
28544
28667
|
key: i,
|
|
28545
|
-
|
|
28546
|
-
snaps: snapStep,
|
|
28547
|
-
range: range,
|
|
28668
|
+
points: line,
|
|
28548
28669
|
onMoveLine: delta => {
|
|
28549
28670
|
dispatch(moveLine(i, delta));
|
|
28550
28671
|
},
|
|
@@ -28559,10 +28680,12 @@ const LineView = props => {
|
|
|
28559
28680
|
const {
|
|
28560
28681
|
onMoveLine,
|
|
28561
28682
|
onMovePoint,
|
|
28562
|
-
|
|
28563
|
-
range,
|
|
28683
|
+
points: [start, end],
|
|
28564
28684
|
stroke
|
|
28565
28685
|
} = props;
|
|
28686
|
+
const {
|
|
28687
|
+
range
|
|
28688
|
+
} = useGraphConfig();
|
|
28566
28689
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MovableLine, {
|
|
28567
28690
|
start: start,
|
|
28568
28691
|
end: end,
|
|
@@ -28876,46 +28999,26 @@ function PointGraph(props) {
|
|
|
28876
28999
|
})));
|
|
28877
29000
|
}
|
|
28878
29001
|
|
|
28879
|
-
function Arrow(props) {
|
|
28880
|
-
const {
|
|
28881
|
-
userTransform,
|
|
28882
|
-
viewTransform
|
|
28883
|
-
} = useTransformContext();
|
|
28884
|
-
const point = [props.x, props.y];
|
|
28885
|
-
const userTransformedPoint = vec.transform(point, userTransform);
|
|
28886
|
-
const viewTransformedPoint = vec.transform(userTransformedPoint, viewTransform);
|
|
28887
|
-
return /*#__PURE__*/React__default.createElement("g", {
|
|
28888
|
-
transform: `translate(${viewTransformedPoint[0]} ${viewTransformedPoint[1]}) rotate(${props.rotate}) scale(1.25)`
|
|
28889
|
-
}, /*#__PURE__*/React__default.createElement("g", {
|
|
28890
|
-
transform: "translate(-1)"
|
|
28891
|
-
}, /*#__PURE__*/React__default.createElement("path", {
|
|
28892
|
-
d: "M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4",
|
|
28893
|
-
fill: "none"
|
|
28894
|
-
})));
|
|
28895
|
-
}
|
|
28896
29002
|
function AxisArrows() {
|
|
28897
29003
|
const {
|
|
28898
|
-
|
|
28899
|
-
} =
|
|
28900
|
-
|
|
28901
|
-
const [xMin, xMax] = range[0];
|
|
28902
|
-
const [yMin, yMax] = range[1];
|
|
28903
|
-
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, {
|
|
28904
29007
|
x: xMax,
|
|
28905
29008
|
y: 0,
|
|
28906
|
-
|
|
28907
|
-
}), /*#__PURE__*/React__default.createElement(
|
|
29009
|
+
angle: 0
|
|
29010
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28908
29011
|
x: 0,
|
|
28909
29012
|
y: yMin,
|
|
28910
|
-
|
|
28911
|
-
}), /*#__PURE__*/React__default.createElement(
|
|
29013
|
+
angle: 90
|
|
29014
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28912
29015
|
x: xMin,
|
|
28913
29016
|
y: 0,
|
|
28914
|
-
|
|
28915
|
-
}), /*#__PURE__*/React__default.createElement(
|
|
29017
|
+
angle: 180
|
|
29018
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
28916
29019
|
x: 0,
|
|
28917
29020
|
y: yMax,
|
|
28918
|
-
|
|
29021
|
+
angle: 270
|
|
28919
29022
|
}));
|
|
28920
29023
|
}
|
|
28921
29024
|
|
|
@@ -28924,8 +29027,19 @@ const tickStyle = {
|
|
|
28924
29027
|
stroke: "black",
|
|
28925
29028
|
strokeWidth: 1
|
|
28926
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
|
+
};
|
|
28927
29039
|
const YGridTick = ({
|
|
28928
|
-
y
|
|
29040
|
+
y,
|
|
29041
|
+
gridStep,
|
|
29042
|
+
tickStep
|
|
28929
29043
|
}) => {
|
|
28930
29044
|
const pointOnAxis = [0, y];
|
|
28931
29045
|
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
@@ -28937,7 +29051,7 @@ const YGridTick = ({
|
|
|
28937
29051
|
x2: xPosition + tickSize / 2,
|
|
28938
29052
|
y2: yPosition,
|
|
28939
29053
|
style: tickStyle
|
|
28940
|
-
}),
|
|
29054
|
+
}), showTickLabel(gridStep, tickStep, y) && /*#__PURE__*/React.createElement("text", {
|
|
28941
29055
|
height: 20,
|
|
28942
29056
|
width: 50,
|
|
28943
29057
|
textAnchor: "end",
|
|
@@ -28946,7 +29060,9 @@ const YGridTick = ({
|
|
|
28946
29060
|
}, y.toString()));
|
|
28947
29061
|
};
|
|
28948
29062
|
const XGridTick = ({
|
|
28949
|
-
x
|
|
29063
|
+
x,
|
|
29064
|
+
gridStep,
|
|
29065
|
+
tickStep
|
|
28950
29066
|
}) => {
|
|
28951
29067
|
const pointOnAxis = [x, 0];
|
|
28952
29068
|
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
@@ -28958,7 +29074,7 @@ const XGridTick = ({
|
|
|
28958
29074
|
x2: xPosition,
|
|
28959
29075
|
y2: yPosition - tickSize / 2,
|
|
28960
29076
|
style: tickStyle
|
|
28961
|
-
}),
|
|
29077
|
+
}), showTickLabel(gridStep, tickStep, x) && /*#__PURE__*/React.createElement("text", {
|
|
28962
29078
|
height: 20,
|
|
28963
29079
|
width: 50,
|
|
28964
29080
|
textAnchor: "middle",
|
|
@@ -28993,12 +29109,16 @@ const AxisTicks = props => {
|
|
|
28993
29109
|
}, yGridTicks.map(y => {
|
|
28994
29110
|
return /*#__PURE__*/React.createElement(YGridTick, {
|
|
28995
29111
|
y: y,
|
|
28996
|
-
key: `y-grid-tick-${y}
|
|
29112
|
+
key: `y-grid-tick-${y}`,
|
|
29113
|
+
gridStep: props.gridStep[0],
|
|
29114
|
+
tickStep: yTickStep
|
|
28997
29115
|
});
|
|
28998
29116
|
}), xGridTicks.map(x => {
|
|
28999
29117
|
return /*#__PURE__*/React.createElement(XGridTick, {
|
|
29000
29118
|
x: x,
|
|
29001
|
-
key: `x-grid-tick-${x}
|
|
29119
|
+
key: `x-grid-tick-${x}`,
|
|
29120
|
+
gridStep: props.gridStep[1],
|
|
29121
|
+
tickStep: xTickStep
|
|
29002
29122
|
});
|
|
29003
29123
|
}));
|
|
29004
29124
|
};
|
|
@@ -29024,10 +29144,13 @@ const Grid = props => {
|
|
|
29024
29144
|
return props.markings === "none" ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
|
|
29025
29145
|
xAxis: axisOptions(props, 0),
|
|
29026
29146
|
yAxis: axisOptions(props, 1)
|
|
29027
|
-
}), /*#__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, {
|
|
29028
29150
|
range: props.range,
|
|
29029
|
-
tickStep: props.tickStep
|
|
29030
|
-
|
|
29151
|
+
tickStep: props.tickStep,
|
|
29152
|
+
gridStep: props.gridStep
|
|
29153
|
+
}), /*#__PURE__*/React.createElement(AxisArrows, null)));
|
|
29031
29154
|
};
|
|
29032
29155
|
|
|
29033
29156
|
// Displays a stylized open eye: lint warnings are visible
|
|
@@ -29986,29 +30109,30 @@ function initializeGraphState(params) {
|
|
|
29986
30109
|
graph,
|
|
29987
30110
|
step,
|
|
29988
30111
|
snapStep,
|
|
29989
|
-
range
|
|
30112
|
+
range,
|
|
30113
|
+
markings
|
|
29990
30114
|
} = params;
|
|
30115
|
+
const shared = {
|
|
30116
|
+
hasBeenInteractedWith: false,
|
|
30117
|
+
range,
|
|
30118
|
+
snapStep,
|
|
30119
|
+
markings
|
|
30120
|
+
};
|
|
29991
30121
|
switch (graph.type) {
|
|
29992
30122
|
case "segment":
|
|
29993
|
-
return {
|
|
30123
|
+
return _extends({}, shared, {
|
|
29994
30124
|
type: "segment",
|
|
29995
|
-
hasBeenInteractedWith: false,
|
|
29996
|
-
range,
|
|
29997
|
-
snapStep,
|
|
29998
30125
|
coords: getDefaultSegments({
|
|
29999
30126
|
graph,
|
|
30000
30127
|
step,
|
|
30001
30128
|
range
|
|
30002
30129
|
})
|
|
30003
|
-
};
|
|
30130
|
+
});
|
|
30004
30131
|
case "linear":
|
|
30005
30132
|
case "linear-system":
|
|
30006
30133
|
case "ray":
|
|
30007
|
-
return {
|
|
30134
|
+
return _extends({}, shared, {
|
|
30008
30135
|
type: graph.type,
|
|
30009
|
-
hasBeenInteractedWith: false,
|
|
30010
|
-
range,
|
|
30011
|
-
snapStep,
|
|
30012
30136
|
// Linear and ray graphs have a single tuple of points, while a
|
|
30013
30137
|
// linear system has two tuples of points.
|
|
30014
30138
|
coords: getLineCoords({
|
|
@@ -30016,13 +30140,10 @@ function initializeGraphState(params) {
|
|
|
30016
30140
|
range,
|
|
30017
30141
|
step
|
|
30018
30142
|
})
|
|
30019
|
-
};
|
|
30143
|
+
});
|
|
30020
30144
|
case "polygon":
|
|
30021
|
-
return {
|
|
30145
|
+
return _extends({}, shared, {
|
|
30022
30146
|
type: "polygon",
|
|
30023
|
-
hasBeenInteractedWith: false,
|
|
30024
|
-
range,
|
|
30025
|
-
snapStep,
|
|
30026
30147
|
showAngles: Boolean(graph.showAngles),
|
|
30027
30148
|
showSides: Boolean(graph.showSides),
|
|
30028
30149
|
coords: getPolygonCoords({
|
|
@@ -30030,19 +30151,16 @@ function initializeGraphState(params) {
|
|
|
30030
30151
|
range,
|
|
30031
30152
|
step
|
|
30032
30153
|
})
|
|
30033
|
-
};
|
|
30154
|
+
});
|
|
30034
30155
|
case "point":
|
|
30035
|
-
return {
|
|
30156
|
+
return _extends({}, shared, {
|
|
30036
30157
|
type: graph.type,
|
|
30037
|
-
hasBeenInteractedWith: false,
|
|
30038
|
-
range,
|
|
30039
|
-
snapStep,
|
|
30040
30158
|
coords: getDefaultPoints({
|
|
30041
30159
|
graph,
|
|
30042
30160
|
step,
|
|
30043
30161
|
range
|
|
30044
30162
|
})
|
|
30045
|
-
};
|
|
30163
|
+
});
|
|
30046
30164
|
case "angle":
|
|
30047
30165
|
case "circle":
|
|
30048
30166
|
case "sinusoid":
|
|
@@ -30282,10 +30400,11 @@ const MafsGraph = props => {
|
|
|
30282
30400
|
useEffect(() => {
|
|
30283
30401
|
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
30284
30402
|
}, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
30285
|
-
return /*#__PURE__*/React.createElement(
|
|
30403
|
+
return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
|
|
30286
30404
|
value: {
|
|
30287
|
-
state,
|
|
30288
|
-
|
|
30405
|
+
range: state.range,
|
|
30406
|
+
snapStep: state.snapStep,
|
|
30407
|
+
markings: props.markings
|
|
30289
30408
|
}
|
|
30290
30409
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30291
30410
|
style: {
|
|
@@ -42370,7 +42489,7 @@ const init = function init(options) {
|
|
|
42370
42489
|
|
|
42371
42490
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42372
42491
|
const libName = "@khanacademy/perseus";
|
|
42373
|
-
const libVersion = "21.
|
|
42492
|
+
const libVersion = "21.4.0";
|
|
42374
42493
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42375
42494
|
|
|
42376
42495
|
const apiVersion = {
|