@khanacademy/perseus 47.0.1 → 48.0.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 +221 -180
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +211 -180
- package/dist/index.js.map +1 -1
- package/dist/renderer.d.ts +0 -4
- package/dist/server-item-renderer.d.ts +0 -6
- package/dist/util/test-utils.d.ts +7 -1
- package/package.json +9 -9
package/dist/es/index.js
CHANGED
|
@@ -2287,9 +2287,6 @@ function scoreExpression(userInput, rubric, strings, locale) {
|
|
|
2287
2287
|
// We matched a graded answer form, so we can now tell the user
|
|
2288
2288
|
// whether their input was correct or incorrect, and hand out
|
|
2289
2289
|
// points accordingly
|
|
2290
|
-
// TODO(eater): Seems silly to translate result to this
|
|
2291
|
-
// invalid/points thing and immediately translate it back in
|
|
2292
|
-
// ItemRenderer.scoreInput()
|
|
2293
2290
|
return {
|
|
2294
2291
|
type: "points",
|
|
2295
2292
|
earned: matchingAnswerForm.considered === "correct" ? 1 : 0,
|
|
@@ -3240,7 +3237,7 @@ const supportsPassiveEvents = () => {
|
|
|
3240
3237
|
window.addEventListener("testPassive", null, opts);
|
|
3241
3238
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
3242
3239
|
window.removeEventListener("testPassive", null, opts);
|
|
3243
|
-
} catch (
|
|
3240
|
+
} catch (_unused) {
|
|
3244
3241
|
// Intentionally left empty!
|
|
3245
3242
|
}
|
|
3246
3243
|
return supportsPassive;
|
|
@@ -3483,7 +3480,9 @@ function changeViewportTag(contentString, callback) {
|
|
|
3483
3480
|
// finished resetting.
|
|
3484
3481
|
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
3485
3482
|
// eslint-disable-next-line no-restricted-syntax
|
|
3486
|
-
|
|
3483
|
+
if (callback != null) {
|
|
3484
|
+
setTimeout(callback, 0);
|
|
3485
|
+
}
|
|
3487
3486
|
}, 0);
|
|
3488
3487
|
}
|
|
3489
3488
|
|
|
@@ -16768,7 +16767,7 @@ class ImageLoader extends React.Component {
|
|
|
16768
16767
|
onKeyUp = e => {
|
|
16769
16768
|
// 13 is enter key, 32 is space key
|
|
16770
16769
|
if (e.keyCode === 13 || e.keyCode === 32) {
|
|
16771
|
-
imgProps.onClick
|
|
16770
|
+
imgProps.onClick == null || imgProps.onClick(e);
|
|
16772
16771
|
}
|
|
16773
16772
|
};
|
|
16774
16773
|
onKeyDown = e => {
|
|
@@ -16849,6 +16848,7 @@ const labelDataCache = {};
|
|
|
16849
16848
|
// Write our own JSONP handler because all the other ones don't do things we
|
|
16850
16849
|
// need.
|
|
16851
16850
|
const doJSONP = function doJSONP(url, options) {
|
|
16851
|
+
var _document$head2;
|
|
16852
16852
|
options = _extends({
|
|
16853
16853
|
callbackName: "callback",
|
|
16854
16854
|
success: $.noop,
|
|
@@ -16862,7 +16862,8 @@ const doJSONP = function doJSONP(url, options) {
|
|
|
16862
16862
|
|
|
16863
16863
|
// A cleanup function to run when we're done.
|
|
16864
16864
|
function cleanup() {
|
|
16865
|
-
|
|
16865
|
+
var _document$head;
|
|
16866
|
+
(_document$head = document.head) == null || _document$head.removeChild(script);
|
|
16866
16867
|
delete window[options.callbackName];
|
|
16867
16868
|
}
|
|
16868
16869
|
|
|
@@ -16880,7 +16881,7 @@ const doJSONP = function doJSONP(url, options) {
|
|
|
16880
16881
|
});
|
|
16881
16882
|
|
|
16882
16883
|
// Insert the script to start the download.
|
|
16883
|
-
document.head
|
|
16884
|
+
(_document$head2 = document.head) == null || _document$head2.appendChild(script);
|
|
16884
16885
|
};
|
|
16885
16886
|
|
|
16886
16887
|
// For offline exercises in the mobile app, we download the graphie data
|
|
@@ -17050,6 +17051,7 @@ class SvgImage extends React.Component {
|
|
|
17050
17051
|
});
|
|
17051
17052
|
};
|
|
17052
17053
|
this._handleZoomClick = e => {
|
|
17054
|
+
var _this$props$trackInte, _this$props;
|
|
17053
17055
|
const $image = $(e.target);
|
|
17054
17056
|
|
|
17055
17057
|
// It's possible that the image is already displayed at its
|
|
@@ -17066,7 +17068,7 @@ class SvgImage extends React.Component {
|
|
|
17066
17068
|
$image.width() < this.props.width || this.props.zoomToFullSizeOnMobile) {
|
|
17067
17069
|
ZoomService.handleZoomClick(e, this.props.zoomToFullSizeOnMobile);
|
|
17068
17070
|
}
|
|
17069
|
-
this.props.trackInteraction
|
|
17071
|
+
(_this$props$trackInte = (_this$props = this.props).trackInteraction) == null || _this$props$trackInte.call(_this$props);
|
|
17070
17072
|
};
|
|
17071
17073
|
this.handleUpdate = status => {
|
|
17072
17074
|
this.props.onUpdate();
|
|
@@ -19602,8 +19604,8 @@ class WidgetContainer extends React.Component {
|
|
|
19602
19604
|
});
|
|
19603
19605
|
|
|
19604
19606
|
// Note: if you add more props here, please consider whether or not
|
|
19605
|
-
// it should be auto-serialized
|
|
19606
|
-
// widget-jsonify-deprecated.jsx and widget-prop-denylist.jsx
|
|
19607
|
+
// it should be auto-serialized.
|
|
19608
|
+
// See widget-jsonify-deprecated.jsx and widget-prop-denylist.jsx
|
|
19607
19609
|
|
|
19608
19610
|
// We default to an empty object for style instead of null
|
|
19609
19611
|
// because of a strange bug where the static styles aren't applied
|
|
@@ -20582,14 +20584,6 @@ class Renderer extends React.Component {
|
|
|
20582
20584
|
this.getWidgetIds = () => {
|
|
20583
20585
|
return this.widgetIds;
|
|
20584
20586
|
};
|
|
20585
|
-
/**
|
|
20586
|
-
* @deprecated use scorePerseusItem
|
|
20587
|
-
*/
|
|
20588
|
-
this.guessAndScore = () => {
|
|
20589
|
-
const totalGuess = this.getUserInput();
|
|
20590
|
-
const totalScore = this.score();
|
|
20591
|
-
return [totalGuess, totalScore];
|
|
20592
|
-
};
|
|
20593
20587
|
// TranslationLinter callback
|
|
20594
20588
|
this.handletranslationLintErrors = lintErrors => {
|
|
20595
20589
|
if (!this._isMounted) {
|
|
@@ -21556,11 +21550,11 @@ class SimpleKeypadInput extends React.Component {
|
|
|
21556
21550
|
keypadType: KeypadType.FRACTION
|
|
21557
21551
|
}, () => {
|
|
21558
21552
|
if (_this._isMounted) {
|
|
21559
|
-
onFocus
|
|
21553
|
+
onFocus == null || onFocus();
|
|
21560
21554
|
}
|
|
21561
21555
|
});
|
|
21562
21556
|
} else {
|
|
21563
|
-
onFocus
|
|
21557
|
+
onFocus == null || onFocus();
|
|
21564
21558
|
}
|
|
21565
21559
|
},
|
|
21566
21560
|
value: value == null ? "" : "" + value
|
|
@@ -21799,9 +21793,6 @@ function scoreInputNumber(userInput, rubric, strings) {
|
|
|
21799
21793
|
// If `currentValue` is not TeX, this should be a no-op.
|
|
21800
21794
|
const currentValue = ParseTex$1(userInput.currentValue);
|
|
21801
21795
|
const result = val(currentValue);
|
|
21802
|
-
|
|
21803
|
-
// TODO(eater): Seems silly to translate result to this invalid/points
|
|
21804
|
-
// thing and immediately translate it back in ItemRenderer.scoreInput()
|
|
21805
21796
|
if (result.empty) {
|
|
21806
21797
|
return {
|
|
21807
21798
|
type: "invalid",
|
|
@@ -22168,10 +22159,6 @@ function scoreNumericInput(userInput, rubric, strings) {
|
|
|
22168
22159
|
message: (_matchedAnswer$messag = matchedAnswer == null ? void 0 : matchedAnswer.message) != null ? _matchedAnswer$messag : null,
|
|
22169
22160
|
guess: localValue
|
|
22170
22161
|
};
|
|
22171
|
-
|
|
22172
|
-
// TODO(eater): Seems silly to translate result to this
|
|
22173
|
-
// invalid/points thing and immediately translate it
|
|
22174
|
-
// back in ItemRenderer.scoreInput()
|
|
22175
22162
|
if (result.empty) {
|
|
22176
22163
|
return {
|
|
22177
22164
|
type: "invalid",
|
|
@@ -25024,7 +25011,7 @@ const scrollElementToOffset = (elementOrWindow, offset, duration = 0, callback)
|
|
|
25024
25011
|
// TODO(jeff, WEB-1378): Use Wonder Blocks Timing API
|
|
25025
25012
|
// eslint-disable-next-line no-restricted-syntax
|
|
25026
25013
|
clearInterval(scrollInterval);
|
|
25027
|
-
callback
|
|
25014
|
+
callback == null || callback();
|
|
25028
25015
|
}
|
|
25029
25016
|
}, tickLength);
|
|
25030
25017
|
};
|
|
@@ -27048,7 +27035,7 @@ class CSProgram extends React.Component {
|
|
|
27048
27035
|
let data = {};
|
|
27049
27036
|
try {
|
|
27050
27037
|
data = JSON.parse(e.originalEvent.data);
|
|
27051
|
-
} catch (
|
|
27038
|
+
} catch (_unused) {
|
|
27052
27039
|
return;
|
|
27053
27040
|
}
|
|
27054
27041
|
if (_.isUndefined(data.testsPassed)) {
|
|
@@ -28104,7 +28091,6 @@ class GradedGroupSet extends React.Component {
|
|
|
28104
28091
|
};
|
|
28105
28092
|
}
|
|
28106
28093
|
shouldComponentUpdate(nextProps, nextState) {
|
|
28107
|
-
nextProps.gradedGroups;
|
|
28108
28094
|
return nextProps !== this.props || nextState !== this.state;
|
|
28109
28095
|
}
|
|
28110
28096
|
getPromptJSON() {
|
|
@@ -29573,7 +29559,7 @@ class Iframe extends React.Component {
|
|
|
29573
29559
|
let data = {};
|
|
29574
29560
|
try {
|
|
29575
29561
|
data = JSON.parse(e.originalEvent.data);
|
|
29576
|
-
} catch (
|
|
29562
|
+
} catch (_unused) {
|
|
29577
29563
|
return;
|
|
29578
29564
|
}
|
|
29579
29565
|
if (_.isUndefined(data.testsPassed)) {
|
|
@@ -30638,10 +30624,12 @@ class Graph extends React.Component {
|
|
|
30638
30624
|
this.props.onMouseDown(coord);
|
|
30639
30625
|
}, this) : undefined;
|
|
30640
30626
|
const onMouseOver = $instructionsWrapper ? function () {
|
|
30641
|
-
|
|
30627
|
+
var _$instructionsWrapper;
|
|
30628
|
+
(_$instructionsWrapper = $instructionsWrapper) == null || _$instructionsWrapper.css("opacity", invisible);
|
|
30642
30629
|
} : undefined;
|
|
30643
30630
|
const onMouseOut = $instructionsWrapper ? function () {
|
|
30644
|
-
|
|
30631
|
+
var _$instructionsWrapper2;
|
|
30632
|
+
(_$instructionsWrapper2 = $instructionsWrapper) == null || _$instructionsWrapper2.css("opacity", visible);
|
|
30645
30633
|
} : undefined;
|
|
30646
30634
|
/* eslint-enable indent */
|
|
30647
30635
|
|
|
@@ -31373,6 +31361,7 @@ function replaceOutsideTeX(mathString) {
|
|
|
31373
31361
|
const parsed = mathOnlyParser(mathString);
|
|
31374
31362
|
let result = "";
|
|
31375
31363
|
for (const piece of parsed) {
|
|
31364
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
31376
31365
|
piece.type === "math" ? result += "$" + piece.content + "$" : piece.type === "specialCharacter" ? result += escapeIfUnescaped(piece.content) : result += piece.content;
|
|
31377
31366
|
}
|
|
31378
31367
|
return `\\text{${result}}`;
|
|
@@ -34323,43 +34312,64 @@ function renderPointGraph(state, dispatch) {
|
|
|
34323
34312
|
};
|
|
34324
34313
|
}
|
|
34325
34314
|
function PointGraph(props) {
|
|
34326
|
-
const
|
|
34315
|
+
const {
|
|
34316
|
+
numPoints
|
|
34317
|
+
} = props.graphState;
|
|
34318
|
+
const graphConfig = useGraphConfig();
|
|
34319
|
+
const pointsRef = React.useRef([]);
|
|
34320
|
+
|
|
34321
|
+
// Dimensions to build the graph overlay for Unlimited Point.
|
|
34322
|
+
const {
|
|
34323
|
+
range: [x, y]
|
|
34324
|
+
} = graphConfig;
|
|
34325
|
+
const [[left, top]] = useTransformVectorsToPixels([x[0], y[1]]);
|
|
34326
|
+
|
|
34327
|
+
// This useEffect is to handle the focus snapping for Unlimited Point.
|
|
34328
|
+
React.useEffect(() => {
|
|
34329
|
+
const focusedIndex = props.graphState.focusedPointIndex;
|
|
34330
|
+
if (focusedIndex != null) {
|
|
34331
|
+
var _pointsRef$current$fo;
|
|
34332
|
+
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
34333
|
+
}
|
|
34334
|
+
}, [props.graphState.focusedPointIndex, pointsRef]);
|
|
34335
|
+
const statefulProps = _extends({}, props, {
|
|
34336
|
+
graphConfig,
|
|
34337
|
+
pointsRef,
|
|
34338
|
+
top,
|
|
34339
|
+
left
|
|
34340
|
+
});
|
|
34327
34341
|
if (numPoints === "unlimited") {
|
|
34328
|
-
return UnlimitedPointGraph(
|
|
34342
|
+
return UnlimitedPointGraph(statefulProps);
|
|
34329
34343
|
}
|
|
34330
|
-
return LimitedPointGraph(
|
|
34344
|
+
return LimitedPointGraph(statefulProps);
|
|
34331
34345
|
}
|
|
34332
|
-
function LimitedPointGraph(
|
|
34346
|
+
function LimitedPointGraph(statefulProps) {
|
|
34333
34347
|
const {
|
|
34334
34348
|
dispatch
|
|
34335
|
-
} =
|
|
34336
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null,
|
|
34349
|
+
} = statefulProps;
|
|
34350
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, statefulProps.graphState.coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
34337
34351
|
key: i,
|
|
34338
34352
|
point: point,
|
|
34339
34353
|
sequenceNumber: i + 1,
|
|
34340
34354
|
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination))
|
|
34341
34355
|
})));
|
|
34342
34356
|
}
|
|
34343
|
-
function UnlimitedPointGraph(
|
|
34357
|
+
function UnlimitedPointGraph(statefulProps) {
|
|
34344
34358
|
const {
|
|
34345
|
-
dispatch
|
|
34346
|
-
|
|
34347
|
-
|
|
34359
|
+
dispatch,
|
|
34360
|
+
graphConfig,
|
|
34361
|
+
pointsRef,
|
|
34362
|
+
top,
|
|
34363
|
+
left
|
|
34364
|
+
} = statefulProps;
|
|
34365
|
+
const {
|
|
34366
|
+
coords
|
|
34367
|
+
} = statefulProps.graphState;
|
|
34348
34368
|
const {
|
|
34349
|
-
|
|
34369
|
+
graphDimensionsInPixels
|
|
34350
34370
|
} = graphConfig;
|
|
34351
|
-
const
|
|
34352
|
-
const
|
|
34353
|
-
const [[widthPx, heightPx]] = useTransformDimensionsToPixels([width, height]);
|
|
34354
|
-
const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
|
|
34355
|
-
const itemsRef = React.useRef([]);
|
|
34356
|
-
React.useEffect(() => {
|
|
34357
|
-
const focusedIndex = props.graphState.focusedPointIndex;
|
|
34358
|
-
if (focusedIndex != null) {
|
|
34359
|
-
var _itemsRef$current$foc;
|
|
34360
|
-
(_itemsRef$current$foc = itemsRef.current[focusedIndex]) == null || _itemsRef$current$foc.focus();
|
|
34361
|
-
}
|
|
34362
|
-
}, [props.graphState.focusedPointIndex, itemsRef]);
|
|
34371
|
+
const widthPx = graphDimensionsInPixels[0];
|
|
34372
|
+
const heightPx = graphDimensionsInPixels[1];
|
|
34363
34373
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
|
|
34364
34374
|
style: {
|
|
34365
34375
|
fill: "rgba(0,0,0,0)",
|
|
@@ -34376,13 +34386,13 @@ function UnlimitedPointGraph(props) {
|
|
|
34376
34386
|
const graphCoordinates = pixelsToVectors([[x, y]], graphConfig);
|
|
34377
34387
|
dispatch(actions.pointGraph.addPoint(graphCoordinates[0]));
|
|
34378
34388
|
}
|
|
34379
|
-
}),
|
|
34389
|
+
}), coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
34380
34390
|
key: i,
|
|
34381
34391
|
point: point,
|
|
34382
34392
|
sequenceNumber: i + 1,
|
|
34383
34393
|
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
|
|
34384
34394
|
ref: ref => {
|
|
34385
|
-
|
|
34395
|
+
pointsRef.current[i] = ref;
|
|
34386
34396
|
},
|
|
34387
34397
|
onFocus: () => {
|
|
34388
34398
|
dispatch(actions.pointGraph.focusPoint(i));
|
|
@@ -34429,36 +34439,42 @@ function renderPolygonGraph(state, dispatch) {
|
|
|
34429
34439
|
interactiveElementsDescription: null
|
|
34430
34440
|
};
|
|
34431
34441
|
}
|
|
34432
|
-
const
|
|
34433
|
-
const [hovered, setHovered] = React.useState(false);
|
|
34434
|
-
// This is more so required for the re-rendering that occurs when state
|
|
34435
|
-
// updates; specifically with regard to line weighting and polygon focus.
|
|
34436
|
-
const [focusVisible, setFocusVisible] = React.useState(false);
|
|
34442
|
+
const PolygonGraph = props => {
|
|
34437
34443
|
const {
|
|
34438
34444
|
dispatch
|
|
34439
34445
|
} = props;
|
|
34440
34446
|
const {
|
|
34447
|
+
numSides,
|
|
34441
34448
|
coords,
|
|
34442
|
-
showAngles,
|
|
34443
|
-
showSides,
|
|
34444
|
-
range,
|
|
34445
34449
|
snapStep,
|
|
34446
34450
|
snapTo = "grid"
|
|
34447
34451
|
} = props.graphState;
|
|
34452
|
+
const graphConfig = useGraphConfig();
|
|
34453
|
+
|
|
34454
|
+
// Ref to implement the dragging behavior on a Limited/Closed Polygon.
|
|
34455
|
+
const polygonRef = React.useRef(null);
|
|
34456
|
+
// Ref to manage dynamic focus for the points in Unlimited Polygon
|
|
34457
|
+
const pointsRef = React.useRef([]);
|
|
34458
|
+
// Ref to manage the last move time for a Limited Polygon.
|
|
34459
|
+
const lastMoveTimeRef = React.useRef(0);
|
|
34460
|
+
|
|
34461
|
+
// Dimensions to build the graph overlay for Unlimited Polgyon.
|
|
34448
34462
|
const {
|
|
34449
|
-
|
|
34450
|
-
} =
|
|
34463
|
+
range: [x, y]
|
|
34464
|
+
} = graphConfig;
|
|
34465
|
+
const [[left, top]] = useTransformVectorsToPixels([x[0], y[1]]);
|
|
34451
34466
|
|
|
34452
34467
|
// TODO(benchristel): can the default set of points be removed here? I don't
|
|
34453
34468
|
// think coords can be null.
|
|
34454
34469
|
const points = coords != null ? coords : [[0, 0]];
|
|
34455
|
-
|
|
34470
|
+
|
|
34471
|
+
// Logic to build the dragging experience. Primarily used by Limited Polygon.
|
|
34456
34472
|
const dragReferencePoint = points[0];
|
|
34457
34473
|
const constrain = ["angles", "sides"].includes(snapTo) ? p => p : p => snap(snapStep, p);
|
|
34458
34474
|
const {
|
|
34459
34475
|
dragging
|
|
34460
34476
|
} = useDraggable({
|
|
34461
|
-
gestureTarget:
|
|
34477
|
+
gestureTarget: polygonRef,
|
|
34462
34478
|
point: dragReferencePoint,
|
|
34463
34479
|
onMove: newPoint => {
|
|
34464
34480
|
const delta = vec.sub(newPoint, dragReferencePoint);
|
|
@@ -34466,7 +34482,61 @@ const LimitedPolygonGraph = props => {
|
|
|
34466
34482
|
},
|
|
34467
34483
|
constrainKeyboardMovement: constrain
|
|
34468
34484
|
});
|
|
34469
|
-
|
|
34485
|
+
|
|
34486
|
+
// Hover/focus state for Limited Polgyon effects.
|
|
34487
|
+
const [hovered, setHovered] = React.useState(false);
|
|
34488
|
+
// This is more so required for the re-rendering that occurs when state
|
|
34489
|
+
// updates; specifically with regard to line weighting and polygon focus.
|
|
34490
|
+
const [focusVisible, setFocusVisible] = React.useState(false);
|
|
34491
|
+
|
|
34492
|
+
// This useEffect is to handle the focus snapping for Unlimited Polygon.
|
|
34493
|
+
React.useEffect(() => {
|
|
34494
|
+
const focusedIndex = props.graphState.focusedPointIndex;
|
|
34495
|
+
if (focusedIndex != null) {
|
|
34496
|
+
var _pointsRef$current$fo;
|
|
34497
|
+
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
34498
|
+
}
|
|
34499
|
+
}, [props.graphState.focusedPointIndex, pointsRef]);
|
|
34500
|
+
const statefulProps = _extends({}, props, {
|
|
34501
|
+
graphConfig,
|
|
34502
|
+
polygonRef,
|
|
34503
|
+
pointsRef,
|
|
34504
|
+
lastMoveTimeRef,
|
|
34505
|
+
left,
|
|
34506
|
+
top,
|
|
34507
|
+
dragging,
|
|
34508
|
+
points,
|
|
34509
|
+
constrain,
|
|
34510
|
+
hovered,
|
|
34511
|
+
setHovered,
|
|
34512
|
+
focusVisible,
|
|
34513
|
+
setFocusVisible
|
|
34514
|
+
});
|
|
34515
|
+
return numSides === "unlimited" ? UnlimitedPolygonGraph(statefulProps) : LimitedPolygonGraph(statefulProps);
|
|
34516
|
+
};
|
|
34517
|
+
const LimitedPolygonGraph = statefulProps => {
|
|
34518
|
+
const {
|
|
34519
|
+
dispatch,
|
|
34520
|
+
hovered,
|
|
34521
|
+
setHovered,
|
|
34522
|
+
focusVisible,
|
|
34523
|
+
setFocusVisible,
|
|
34524
|
+
graphConfig,
|
|
34525
|
+
polygonRef,
|
|
34526
|
+
lastMoveTimeRef,
|
|
34527
|
+
dragging,
|
|
34528
|
+
points,
|
|
34529
|
+
constrain
|
|
34530
|
+
} = statefulProps;
|
|
34531
|
+
const {
|
|
34532
|
+
showAngles,
|
|
34533
|
+
showSides,
|
|
34534
|
+
range,
|
|
34535
|
+
snapTo = "grid"
|
|
34536
|
+
} = statefulProps.graphState;
|
|
34537
|
+
const {
|
|
34538
|
+
disableKeyboardInteraction
|
|
34539
|
+
} = graphConfig;
|
|
34470
34540
|
const lines = getLines(points);
|
|
34471
34541
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Polygon, {
|
|
34472
34542
|
points: [...points],
|
|
@@ -34504,7 +34574,7 @@ const LimitedPolygonGraph = props => {
|
|
|
34504
34574
|
points: [...points],
|
|
34505
34575
|
color: "transparent",
|
|
34506
34576
|
svgPolygonProps: {
|
|
34507
|
-
ref,
|
|
34577
|
+
ref: polygonRef,
|
|
34508
34578
|
tabIndex: disableKeyboardInteraction ? -1 : 0,
|
|
34509
34579
|
strokeWidth: TARGET_SIZE,
|
|
34510
34580
|
style: {
|
|
@@ -34516,13 +34586,13 @@ const LimitedPolygonGraph = props => {
|
|
|
34516
34586
|
// Required to remove line weighting when user clicks away
|
|
34517
34587
|
// from the focused polygon
|
|
34518
34588
|
onKeyDownCapture: () => {
|
|
34519
|
-
setFocusVisible(hasFocusVisible(
|
|
34589
|
+
setFocusVisible(hasFocusVisible(polygonRef.current));
|
|
34520
34590
|
},
|
|
34521
34591
|
// Required for lines to darken on focus
|
|
34522
|
-
onFocus: () => setFocusVisible(hasFocusVisible(
|
|
34592
|
+
onFocus: () => setFocusVisible(hasFocusVisible(polygonRef.current)),
|
|
34523
34593
|
// Required for line weighting to update on blur. Without this,
|
|
34524
34594
|
// the user has to hover over the shape for it to update
|
|
34525
|
-
onBlur: () => setFocusVisible(hasFocusVisible(
|
|
34595
|
+
onBlur: () => setFocusVisible(hasFocusVisible(polygonRef.current)),
|
|
34526
34596
|
className: "movable-polygon"
|
|
34527
34597
|
}
|
|
34528
34598
|
}), points.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
@@ -34534,94 +34604,85 @@ const LimitedPolygonGraph = props => {
|
|
|
34534
34604
|
const now = Date.now();
|
|
34535
34605
|
const targetFPS = 40;
|
|
34536
34606
|
const moveThresholdTime = 1000 / targetFPS;
|
|
34537
|
-
if (now -
|
|
34607
|
+
if (now - lastMoveTimeRef.current > moveThresholdTime) {
|
|
34538
34608
|
dispatch(actions.polygon.movePoint(i, destination));
|
|
34539
|
-
|
|
34609
|
+
lastMoveTimeRef.current = now;
|
|
34540
34610
|
}
|
|
34541
34611
|
}
|
|
34542
34612
|
})));
|
|
34543
34613
|
};
|
|
34544
|
-
const UnlimitedPolygonGraph =
|
|
34614
|
+
const UnlimitedPolygonGraph = statefulProps => {
|
|
34545
34615
|
const {
|
|
34546
|
-
dispatch
|
|
34547
|
-
|
|
34616
|
+
dispatch,
|
|
34617
|
+
graphConfig,
|
|
34618
|
+
left,
|
|
34619
|
+
top,
|
|
34620
|
+
pointsRef,
|
|
34621
|
+
points
|
|
34622
|
+
} = statefulProps;
|
|
34548
34623
|
const {
|
|
34549
34624
|
coords,
|
|
34550
34625
|
closedPolygon
|
|
34551
|
-
} =
|
|
34552
|
-
|
|
34626
|
+
} = statefulProps.graphState;
|
|
34627
|
+
|
|
34628
|
+
// If the polygon is closed, return a LimitedPolygon component.
|
|
34629
|
+
if (closedPolygon) {
|
|
34630
|
+
const closedPolygonProps = _extends({}, statefulProps, {
|
|
34631
|
+
numSides: coords.length
|
|
34632
|
+
});
|
|
34633
|
+
return /*#__PURE__*/React.createElement(LimitedPolygonGraph, closedPolygonProps);
|
|
34634
|
+
}
|
|
34553
34635
|
const {
|
|
34554
|
-
range: [x, y],
|
|
34555
34636
|
graphDimensionsInPixels
|
|
34556
34637
|
} = graphConfig;
|
|
34557
34638
|
const widthPx = graphDimensionsInPixels[0];
|
|
34558
34639
|
const heightPx = graphDimensionsInPixels[1];
|
|
34559
|
-
|
|
34560
|
-
|
|
34561
|
-
|
|
34562
|
-
|
|
34563
|
-
|
|
34564
|
-
|
|
34565
|
-
|
|
34566
|
-
|
|
34567
|
-
|
|
34568
|
-
|
|
34569
|
-
|
|
34640
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
|
|
34641
|
+
style: {
|
|
34642
|
+
fill: "rgba(0,0,0,0)",
|
|
34643
|
+
cursor: "crosshair"
|
|
34644
|
+
},
|
|
34645
|
+
width: widthPx,
|
|
34646
|
+
height: heightPx,
|
|
34647
|
+
x: left,
|
|
34648
|
+
y: top,
|
|
34649
|
+
onClick: event => {
|
|
34650
|
+
const elementRect = event.currentTarget.getBoundingClientRect();
|
|
34651
|
+
const x = event.clientX - elementRect.x;
|
|
34652
|
+
const y = event.clientY - elementRect.y;
|
|
34653
|
+
const graphCoordinates = pixelsToVectors([[x, y]], graphConfig);
|
|
34654
|
+
dispatch(actions.polygon.addPoint(graphCoordinates[0]));
|
|
34570
34655
|
}
|
|
34571
|
-
},
|
|
34572
|
-
|
|
34573
|
-
|
|
34574
|
-
|
|
34575
|
-
|
|
34576
|
-
return /*#__PURE__*/React.createElement(LimitedPolygonGraph, closedPolygonProps);
|
|
34577
|
-
} else {
|
|
34578
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
|
|
34656
|
+
}), /*#__PURE__*/React.createElement(Polyline, {
|
|
34657
|
+
points: [...points],
|
|
34658
|
+
color: "var(--movable-line-stroke-color)",
|
|
34659
|
+
svgPolylineProps: {
|
|
34660
|
+
strokeWidth: "var(--movable-line-stroke-weight)",
|
|
34579
34661
|
style: {
|
|
34580
|
-
fill: "
|
|
34581
|
-
cursor: "crosshair"
|
|
34582
|
-
},
|
|
34583
|
-
width: widthPx,
|
|
34584
|
-
height: heightPx,
|
|
34585
|
-
x: left,
|
|
34586
|
-
y: top,
|
|
34587
|
-
onClick: event => {
|
|
34588
|
-
const elementRect = event.currentTarget.getBoundingClientRect();
|
|
34589
|
-
const x = event.clientX - elementRect.x;
|
|
34590
|
-
const y = event.clientY - elementRect.y;
|
|
34591
|
-
const graphCoordinates = pixelsToVectors([[x, y]], graphConfig);
|
|
34592
|
-
dispatch(actions.polygon.addPoint(graphCoordinates[0]));
|
|
34593
|
-
}
|
|
34594
|
-
}), /*#__PURE__*/React.createElement(Polyline, {
|
|
34595
|
-
points: [...points],
|
|
34596
|
-
color: "var(--movable-line-stroke-color)",
|
|
34597
|
-
svgPolylineProps: {
|
|
34598
|
-
strokeWidth: "var(--movable-line-stroke-weight)",
|
|
34599
|
-
style: {
|
|
34600
|
-
fill: "transparent"
|
|
34601
|
-
}
|
|
34662
|
+
fill: "transparent"
|
|
34602
34663
|
}
|
|
34603
|
-
}
|
|
34604
|
-
|
|
34605
|
-
|
|
34606
|
-
|
|
34607
|
-
|
|
34608
|
-
|
|
34609
|
-
|
|
34610
|
-
|
|
34611
|
-
|
|
34612
|
-
|
|
34613
|
-
|
|
34614
|
-
|
|
34615
|
-
|
|
34616
|
-
|
|
34617
|
-
|
|
34618
|
-
|
|
34619
|
-
|
|
34620
|
-
|
|
34621
|
-
dispatch(actions.polygon.clickPoint(i));
|
|
34664
|
+
}
|
|
34665
|
+
}), coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
34666
|
+
key: i,
|
|
34667
|
+
point: point,
|
|
34668
|
+
sequenceNumber: i + 1,
|
|
34669
|
+
onMove: destination => dispatch(actions.polygon.movePoint(i, destination)),
|
|
34670
|
+
ref: ref => {
|
|
34671
|
+
pointsRef.current[i] = ref;
|
|
34672
|
+
},
|
|
34673
|
+
onFocus: () => {
|
|
34674
|
+
dispatch(actions.polygon.focusPoint(i));
|
|
34675
|
+
},
|
|
34676
|
+
onClick: () => {
|
|
34677
|
+
// If the point being clicked is the first point and
|
|
34678
|
+
// there's enough points to form a polygon (3 or more)
|
|
34679
|
+
// Close the shape before setting focus.
|
|
34680
|
+
if (i === 0 && coords.length >= 3) {
|
|
34681
|
+
dispatch(actions.polygon.closePolygon());
|
|
34622
34682
|
}
|
|
34623
|
-
|
|
34624
|
-
|
|
34683
|
+
dispatch(actions.polygon.clickPoint(i));
|
|
34684
|
+
}
|
|
34685
|
+
})));
|
|
34625
34686
|
};
|
|
34626
34687
|
function getLines(points) {
|
|
34627
34688
|
return points.map((point, i) => {
|
|
@@ -34636,17 +34697,13 @@ const hasFocusVisible = element => {
|
|
|
34636
34697
|
};
|
|
34637
34698
|
try {
|
|
34638
34699
|
return matches(":focus-visible");
|
|
34639
|
-
} catch (
|
|
34700
|
+
} catch (_unused) {
|
|
34640
34701
|
// jsdom doesn't support :focus-visible
|
|
34641
34702
|
// (see https://github.com/jsdom/jsdom/issues/3426),
|
|
34642
34703
|
// so the call to matches(":focus-visible") will fail in tests.
|
|
34643
34704
|
return matches(":focus");
|
|
34644
34705
|
}
|
|
34645
34706
|
};
|
|
34646
|
-
const PolygonGraph = props => {
|
|
34647
|
-
const numSides = props.graphState.numSides;
|
|
34648
|
-
return numSides === "unlimited" ? UnlimitedPolygonGraph(props) : LimitedPolygonGraph(props);
|
|
34649
|
-
};
|
|
34650
34707
|
|
|
34651
34708
|
function renderQuadraticGraph(state, dispatch) {
|
|
34652
34709
|
return {
|
|
@@ -40012,7 +40069,8 @@ class Sortable extends React.Component {
|
|
|
40012
40069
|
this.setState({
|
|
40013
40070
|
items
|
|
40014
40071
|
}, () => {
|
|
40015
|
-
|
|
40072
|
+
var _this$props$onMeasure, _this$props;
|
|
40073
|
+
(_this$props$onMeasure = (_this$props = this.props).onMeasure) == null || _this$props$onMeasure.call(_this$props, {
|
|
40016
40074
|
widths: widths,
|
|
40017
40075
|
heights: heights
|
|
40018
40076
|
});
|
|
@@ -40038,6 +40096,7 @@ class Sortable extends React.Component {
|
|
|
40038
40096
|
// for testing and other cases where dragging and dropping may
|
|
40039
40097
|
// not be available
|
|
40040
40098
|
moveOptionToIndex(option, index) {
|
|
40099
|
+
var _this$props$onChange, _this$props2;
|
|
40041
40100
|
const {
|
|
40042
40101
|
items
|
|
40043
40102
|
} = this.state;
|
|
@@ -40062,7 +40121,7 @@ class Sortable extends React.Component {
|
|
|
40062
40121
|
this.setState({
|
|
40063
40122
|
items: nextItems
|
|
40064
40123
|
});
|
|
40065
|
-
this.props.onChange
|
|
40124
|
+
(_this$props$onChange = (_this$props2 = this.props).onChange) == null || _this$props$onChange.call(_this$props2, {});
|
|
40066
40125
|
}
|
|
40067
40126
|
onMouseMove(key) {
|
|
40068
40127
|
// Dragging: Rearrange items based on draggable's position
|
|
@@ -40120,6 +40179,7 @@ class Sortable extends React.Component {
|
|
|
40120
40179
|
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
40121
40180
|
// eslint-disable-next-line no-restricted-syntax
|
|
40122
40181
|
const nextAnimationFrame = requestAnimationFrame(() => {
|
|
40182
|
+
var _this$props$onChange2, _this$props3;
|
|
40123
40183
|
const items = _.map(this.state.items, function (item) {
|
|
40124
40184
|
if (item.key === key) {
|
|
40125
40185
|
item.state = ItemState.ANIMATING;
|
|
@@ -40142,7 +40202,7 @@ class Sortable extends React.Component {
|
|
|
40142
40202
|
// HACK: We need to know *that* the widget changed, but currently it's
|
|
40143
40203
|
// not set up in a nice way to tell us *how* it changed, since the
|
|
40144
40204
|
// permutation of the items is stored in state.
|
|
40145
|
-
this.props.onChange
|
|
40205
|
+
(_this$props$onChange2 = (_this$props3 = this.props).onChange) == null || _this$props$onChange2.call(_this$props3, {});
|
|
40146
40206
|
});
|
|
40147
40207
|
|
|
40148
40208
|
// @ts-expect-error - TS2339 - Property 'animationFrameRequest' does not exist on type 'Sortable'.
|
|
@@ -42820,11 +42880,12 @@ class Card extends React.Component {
|
|
|
42820
42880
|
event.preventDefault();
|
|
42821
42881
|
const loc = Util.extractPointerLocation(event);
|
|
42822
42882
|
if (loc) {
|
|
42883
|
+
var _this$props$onMouseDo, _this$props;
|
|
42823
42884
|
this.setState({
|
|
42824
42885
|
dragging: true
|
|
42825
42886
|
});
|
|
42826
42887
|
this.bindMouseMoveUp();
|
|
42827
|
-
this.props.onMouseDown
|
|
42888
|
+
(_this$props$onMouseDo = (_this$props = this.props).onMouseDown) == null || _this$props$onMouseDo.call(_this$props, loc, this);
|
|
42828
42889
|
}
|
|
42829
42890
|
};
|
|
42830
42891
|
this.onMouseMove = event => {
|
|
@@ -42834,18 +42895,20 @@ class Card extends React.Component {
|
|
|
42834
42895
|
event.preventDefault();
|
|
42835
42896
|
const loc = Util.extractPointerLocation(event);
|
|
42836
42897
|
if (loc) {
|
|
42837
|
-
|
|
42898
|
+
var _this$props$onMouseMo, _this$props2;
|
|
42899
|
+
(_this$props$onMouseMo = (_this$props2 = this.props).onMouseMove) == null || _this$props$onMouseMo.call(_this$props2, loc);
|
|
42838
42900
|
}
|
|
42839
42901
|
};
|
|
42840
42902
|
this.onMouseUp = event => {
|
|
42841
42903
|
event.preventDefault();
|
|
42842
42904
|
const loc = Util.extractPointerLocation(event);
|
|
42843
42905
|
if (loc) {
|
|
42906
|
+
var _this$props$onMouseUp, _this$props3;
|
|
42844
42907
|
this.setState({
|
|
42845
42908
|
dragging: false
|
|
42846
42909
|
});
|
|
42847
42910
|
this.unbindMouseMoveUp();
|
|
42848
|
-
this.props.onMouseUp
|
|
42911
|
+
(_this$props$onMouseUp = (_this$props3 = this.props).onMouseUp) == null || _this$props$onMouseUp.call(_this$props3, loc);
|
|
42849
42912
|
}
|
|
42850
42913
|
};
|
|
42851
42914
|
}
|
|
@@ -45107,7 +45170,7 @@ const init = function init() {
|
|
|
45107
45170
|
|
|
45108
45171
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45109
45172
|
const libName = "@khanacademy/perseus";
|
|
45110
|
-
const libVersion = "
|
|
45173
|
+
const libVersion = "48.0.0";
|
|
45111
45174
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45112
45175
|
|
|
45113
45176
|
const apiVersion = {
|
|
@@ -45869,28 +45932,6 @@ class ServerItemRenderer extends React.Component {
|
|
|
45869
45932
|
return this.questionRenderer.getUserInputMap();
|
|
45870
45933
|
}
|
|
45871
45934
|
|
|
45872
|
-
/**
|
|
45873
|
-
* Grades the item.
|
|
45874
|
-
*
|
|
45875
|
-
* @deprecated use scorePerseusItem
|
|
45876
|
-
*/
|
|
45877
|
-
scoreInput() {
|
|
45878
|
-
const guess = this.getUserInput();
|
|
45879
|
-
const score = scorePerseusItem(this.props.item.question, guess, this.context.strings, this.context.locale);
|
|
45880
|
-
|
|
45881
|
-
// Continue to include an empty guess for the now defunct answer area.
|
|
45882
|
-
// TODO(alex): Check whether we rely on the format here for
|
|
45883
|
-
// analyzing ProblemLogs. If not, remove this layer.
|
|
45884
|
-
const maxCompatGuess = [this.questionRenderer.getUserInput(), []];
|
|
45885
|
-
const keScore = keScoreFromPerseusScore(score, maxCompatGuess, this.questionRenderer.getSerializedState());
|
|
45886
|
-
const emptyQuestionAreaWidgets = this.questionRenderer.emptyWidgets();
|
|
45887
|
-
this.setState({
|
|
45888
|
-
questionCompleted: keScore.correct,
|
|
45889
|
-
questionHighlightedWidgets: emptyQuestionAreaWidgets
|
|
45890
|
-
});
|
|
45891
|
-
return keScore;
|
|
45892
|
-
}
|
|
45893
|
-
|
|
45894
45935
|
/**
|
|
45895
45936
|
* Returns an array of all widget IDs in the order they occur in
|
|
45896
45937
|
* the question content.
|