@khanacademy/perseus 48.2.0 → 49.0.1
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
CHANGED
|
@@ -2,13 +2,13 @@ import * as KAS from '@khanacademy/kas';
|
|
|
2
2
|
import { MathInputI18nContext, CursorContext, getKeyTranslator, 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 } from '@khanacademy/perseus-linter';
|
|
5
|
-
import { View, RenderStateRoot,
|
|
5
|
+
import { View, RenderStateRoot, Id, useOnMountEffect, useLatestRef, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
6
6
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
7
7
|
import { HeadingMedium, LabelSmall, LabelLarge, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
8
8
|
import { StyleSheet, css } from 'aphrodite';
|
|
9
9
|
import classNames$1 from 'classnames';
|
|
10
10
|
import * as React from 'react';
|
|
11
|
-
import React__default, { useContext, useState, useEffect, useRef, createContext, forwardRef, useLayoutEffect, useImperativeHandle } from 'react';
|
|
11
|
+
import React__default, { useContext, useState, useEffect, useRef, createContext, forwardRef, useLayoutEffect, useImperativeHandle, useId } from 'react';
|
|
12
12
|
import * as ReactDOM from 'react-dom';
|
|
13
13
|
import ReactDOM__default from 'react-dom';
|
|
14
14
|
import _, { debounce as debounce$1 } from 'underscore';
|
|
@@ -44,13 +44,21 @@ import cornersOutIcon from '@phosphor-icons/core/regular/corners-out.svg';
|
|
|
44
44
|
import Link from '@khanacademy/wonder-blocks-link';
|
|
45
45
|
|
|
46
46
|
function _extends() {
|
|
47
|
-
|
|
48
|
-
for (var
|
|
49
|
-
var
|
|
50
|
-
|
|
47
|
+
_extends = Object.assign || function (target) {
|
|
48
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
49
|
+
var source = arguments[i];
|
|
50
|
+
|
|
51
|
+
for (var key in source) {
|
|
52
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
53
|
+
target[key] = source[key];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
|
|
58
|
+
return target;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return _extends.apply(this, arguments);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/**
|
|
@@ -4445,14 +4453,17 @@ const InteractiveUtil = {
|
|
|
4445
4453
|
}
|
|
4446
4454
|
};
|
|
4447
4455
|
|
|
4448
|
-
function _classPrivateFieldBase(
|
|
4449
|
-
if (!
|
|
4450
|
-
|
|
4456
|
+
function _classPrivateFieldBase(receiver, privateKey) {
|
|
4457
|
+
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
|
|
4458
|
+
throw new TypeError("attempted to use private field on non-instance");
|
|
4459
|
+
}
|
|
4460
|
+
|
|
4461
|
+
return receiver;
|
|
4451
4462
|
}
|
|
4452
4463
|
|
|
4453
4464
|
var id = 0;
|
|
4454
|
-
function _classPrivateFieldKey(
|
|
4455
|
-
return "__private_" + id++ + "_" +
|
|
4465
|
+
function _classPrivateFieldKey(name) {
|
|
4466
|
+
return "__private_" + id++ + "_" + name;
|
|
4456
4467
|
}
|
|
4457
4468
|
|
|
4458
4469
|
/*!
|
|
@@ -8859,13 +8870,10 @@ const reactRootCache = new WeakMap();
|
|
|
8859
8870
|
*/
|
|
8860
8871
|
function render(element, container) {
|
|
8861
8872
|
/**
|
|
8862
|
-
* `RenderStateRoot` is responsible for tracking whether it's
|
|
8863
|
-
*
|
|
8864
|
-
*
|
|
8865
|
-
*
|
|
8866
|
-
* high up in the render tree as possible to ensure that any
|
|
8867
|
-
* components using that hook or those components will function
|
|
8868
|
-
* correctly.
|
|
8873
|
+
* `RenderStateRoot` is responsible for tracking whether it's the initial
|
|
8874
|
+
* render or subsequent renders. It's used by `WithSSRPlaceholder`. We're
|
|
8875
|
+
* placing it as high up in the render tree as possible to ensure that any
|
|
8876
|
+
* components using that hook or those components will function correctly.
|
|
8869
8877
|
*/
|
|
8870
8878
|
const children = /*#__PURE__*/React.createElement(RenderStateRoot, {
|
|
8871
8879
|
throwIfNested: false
|
|
@@ -21081,14 +21089,19 @@ TextInput.defaultProps = {
|
|
|
21081
21089
|
disabled: false
|
|
21082
21090
|
};
|
|
21083
21091
|
|
|
21084
|
-
function _objectWithoutPropertiesLoose(
|
|
21085
|
-
if (
|
|
21086
|
-
var
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
|
|
21092
|
+
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
21093
|
+
if (source == null) return {};
|
|
21094
|
+
var target = {};
|
|
21095
|
+
var sourceKeys = Object.keys(source);
|
|
21096
|
+
var key, i;
|
|
21097
|
+
|
|
21098
|
+
for (i = 0; i < sourceKeys.length; i++) {
|
|
21099
|
+
key = sourceKeys[i];
|
|
21100
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
21101
|
+
target[key] = source[key];
|
|
21090
21102
|
}
|
|
21091
|
-
|
|
21103
|
+
|
|
21104
|
+
return target;
|
|
21092
21105
|
}
|
|
21093
21106
|
|
|
21094
21107
|
const _excluded$7 = ["position", "visibility", "left", "top"];
|
|
@@ -27369,10 +27382,7 @@ class Dropdown extends React.Component {
|
|
|
27369
27382
|
value: String(i + 1),
|
|
27370
27383
|
label: choice
|
|
27371
27384
|
}))];
|
|
27372
|
-
return /*#__PURE__*/React.createElement(
|
|
27373
|
-
scope: "dropdown-widget",
|
|
27374
|
-
mockOnFirstRender: true
|
|
27375
|
-
}, ids => /*#__PURE__*/React.createElement(View
|
|
27385
|
+
return /*#__PURE__*/React.createElement(Id, null, dropdownId => /*#__PURE__*/React.createElement(View
|
|
27376
27386
|
// NOTE(jared): These are required to prevent weird behavior
|
|
27377
27387
|
// When there's a dropdown in a zoomable table.
|
|
27378
27388
|
, {
|
|
@@ -27384,9 +27394,9 @@ class Dropdown extends React.Component {
|
|
|
27384
27394
|
}
|
|
27385
27395
|
}, this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelLarge, {
|
|
27386
27396
|
tag: "label",
|
|
27387
|
-
htmlFor:
|
|
27397
|
+
htmlFor: dropdownId
|
|
27388
27398
|
}, this.props.visibleLabel), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
27389
|
-
id:
|
|
27399
|
+
id: dropdownId,
|
|
27390
27400
|
placeholder: "",
|
|
27391
27401
|
onChange: value => this._handleChange(parseInt(value)),
|
|
27392
27402
|
selectedValue: String(this.props.selected),
|
|
@@ -27501,12 +27511,9 @@ class Explanation extends React.Component {
|
|
|
27501
27511
|
"white-space": "normal"
|
|
27502
27512
|
};
|
|
27503
27513
|
const contentStyling = [styles$k.content, this.state.expanded ? styles$k.contentExpanded : styles$k.contentCollapsed, allowTransition && (this.state.expanded ? styles$k.transitionExpanded : styles$k.transitionCollapsed)];
|
|
27504
|
-
return /*#__PURE__*/React.createElement(
|
|
27505
|
-
mockOnFirstRender: true,
|
|
27506
|
-
scope: "explanation-widget"
|
|
27507
|
-
}, ids => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
|
|
27514
|
+
return /*#__PURE__*/React.createElement(Id, null, contentId => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
|
|
27508
27515
|
"aria-expanded": this.state.expanded,
|
|
27509
|
-
"aria-controls":
|
|
27516
|
+
"aria-controls": contentId,
|
|
27510
27517
|
endIcon: caretIcon,
|
|
27511
27518
|
kind: "tertiary",
|
|
27512
27519
|
labelStyle: labelStyle,
|
|
@@ -27514,7 +27521,7 @@ class Explanation extends React.Component {
|
|
|
27514
27521
|
size: "small",
|
|
27515
27522
|
style: buttonStyleOverrides
|
|
27516
27523
|
}, promptText), /*#__PURE__*/React.createElement(View, {
|
|
27517
|
-
id:
|
|
27524
|
+
id: contentId,
|
|
27518
27525
|
style: contentStyling,
|
|
27519
27526
|
"aria-hidden": !this.state.expanded,
|
|
27520
27527
|
testId: "content-container"
|
|
@@ -32682,6 +32689,17 @@ const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
|
32682
32689
|
function isBetween(x, low, high) {
|
|
32683
32690
|
return x >= low && x <= high;
|
|
32684
32691
|
}
|
|
32692
|
+
function getArrayWithoutDuplicates(array) {
|
|
32693
|
+
const returnArray = [];
|
|
32694
|
+
for (const coordPair of array) {
|
|
32695
|
+
if (
|
|
32696
|
+
// Check if the coordPair is not already in the returnArray
|
|
32697
|
+
!returnArray.some(([x, y]) => x === coordPair[0] && y === coordPair[1])) {
|
|
32698
|
+
returnArray.push(coordPair);
|
|
32699
|
+
}
|
|
32700
|
+
}
|
|
32701
|
+
return returnArray;
|
|
32702
|
+
}
|
|
32685
32703
|
|
|
32686
32704
|
const LockedLine = props => {
|
|
32687
32705
|
var _flags$mafs;
|
|
@@ -34092,6 +34110,12 @@ function getGradableGraph(state, initialGraph) {
|
|
|
34092
34110
|
});
|
|
34093
34111
|
}
|
|
34094
34112
|
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
34113
|
+
// Unless the polygon is closed it is not considered score-able.
|
|
34114
|
+
if (state.numSides === "unlimited" && !state.closedPolygon) {
|
|
34115
|
+
return _extends({}, initialGraph, {
|
|
34116
|
+
coords: null
|
|
34117
|
+
});
|
|
34118
|
+
}
|
|
34095
34119
|
return _extends({}, initialGraph, {
|
|
34096
34120
|
coords: state.coords
|
|
34097
34121
|
});
|
|
@@ -34603,6 +34627,15 @@ const PolygonGraph = props => {
|
|
|
34603
34627
|
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
34604
34628
|
}
|
|
34605
34629
|
}, [props.graphState.focusedPointIndex, pointsRef]);
|
|
34630
|
+
|
|
34631
|
+
// If the unlimited polygon is rendered with 3 or more coordinates
|
|
34632
|
+
// Close the polygon, but only on first render.
|
|
34633
|
+
React.useEffect(() => {
|
|
34634
|
+
if (numSides === "unlimited" && props.graphState.coords.length > 2) {
|
|
34635
|
+
dispatch(actions.polygon.closePolygon());
|
|
34636
|
+
}
|
|
34637
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34638
|
+
}, []);
|
|
34606
34639
|
const statefulProps = _extends({}, props, {
|
|
34607
34640
|
graphConfig,
|
|
34608
34641
|
polygonRef,
|
|
@@ -34743,7 +34776,16 @@ const UnlimitedPolygonGraph = statefulProps => {
|
|
|
34743
34776
|
} = graphConfig;
|
|
34744
34777
|
const widthPx = graphDimensionsInPixels[0];
|
|
34745
34778
|
const heightPx = graphDimensionsInPixels[1];
|
|
34746
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(
|
|
34779
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Polyline, {
|
|
34780
|
+
points: [...points],
|
|
34781
|
+
color: "var(--movable-line-stroke-color)",
|
|
34782
|
+
svgPolylineProps: {
|
|
34783
|
+
strokeWidth: "var(--movable-line-stroke-weight)",
|
|
34784
|
+
style: {
|
|
34785
|
+
fill: "transparent"
|
|
34786
|
+
}
|
|
34787
|
+
}
|
|
34788
|
+
}), /*#__PURE__*/React.createElement("rect", {
|
|
34747
34789
|
style: {
|
|
34748
34790
|
fill: "rgba(0,0,0,0)",
|
|
34749
34791
|
cursor: "crosshair"
|
|
@@ -34759,15 +34801,6 @@ const UnlimitedPolygonGraph = statefulProps => {
|
|
|
34759
34801
|
const graphCoordinates = pixelsToVectors([[x, y]], graphConfig);
|
|
34760
34802
|
dispatch(actions.polygon.addPoint(graphCoordinates[0]));
|
|
34761
34803
|
}
|
|
34762
|
-
}), /*#__PURE__*/React.createElement(Polyline, {
|
|
34763
|
-
points: [...points],
|
|
34764
|
-
color: "var(--movable-line-stroke-color)",
|
|
34765
|
-
svgPolylineProps: {
|
|
34766
|
-
strokeWidth: "var(--movable-line-stroke-weight)",
|
|
34767
|
-
style: {
|
|
34768
|
-
fill: "transparent"
|
|
34769
|
-
}
|
|
34770
|
-
}
|
|
34771
34804
|
}), coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
34772
34805
|
key: i,
|
|
34773
34806
|
point: point,
|
|
@@ -34781,9 +34814,10 @@ const UnlimitedPolygonGraph = statefulProps => {
|
|
|
34781
34814
|
},
|
|
34782
34815
|
onClick: () => {
|
|
34783
34816
|
// If the point being clicked is the first point and
|
|
34784
|
-
// there's enough points to form
|
|
34785
|
-
//
|
|
34786
|
-
|
|
34817
|
+
// there's enough non-duplicated points to form
|
|
34818
|
+
// a polygon (3 or more), close the shape before
|
|
34819
|
+
// setting focus.
|
|
34820
|
+
if (i === 0 && getArrayWithoutDuplicates(coords).length >= 3) {
|
|
34787
34821
|
dispatch(actions.polygon.closePolygon());
|
|
34788
34822
|
}
|
|
34789
34823
|
dispatch(actions.polygon.clickPoint(i));
|
|
@@ -35406,7 +35440,7 @@ const renderPolygonGraphControls = props => {
|
|
|
35406
35440
|
|
|
35407
35441
|
// We want to disable the closePolygon button when
|
|
35408
35442
|
// there are not enough coords to make a polygon
|
|
35409
|
-
const disableCloseButton = coords.length < 3;
|
|
35443
|
+
const disableCloseButton = getArrayWithoutDuplicates(coords).length < 3;
|
|
35410
35444
|
|
|
35411
35445
|
// If polygon is closed, show open button.
|
|
35412
35446
|
// If polygon is open, show close button.
|
|
@@ -36106,7 +36140,13 @@ function doClickPoint(state, action) {
|
|
|
36106
36140
|
}
|
|
36107
36141
|
function doClosePolygon(state) {
|
|
36108
36142
|
if (isUnlimitedGraphState(state) && state.type === "polygon") {
|
|
36143
|
+
// We want to remove any duplicate points when closing the polygon to
|
|
36144
|
+
// (1) prevent the polygon from sides with length zero, and
|
|
36145
|
+
// (2) make sure the question is can be marked correct if the polygon
|
|
36146
|
+
// LOOKS correct, even if two of the points are at the same coords.
|
|
36147
|
+
const noDupedPoints = getArrayWithoutDuplicates(state.coords);
|
|
36109
36148
|
return _extends({}, state, {
|
|
36149
|
+
coords: noDupedPoints,
|
|
36110
36150
|
closedPolygon: true
|
|
36111
36151
|
});
|
|
36112
36152
|
}
|
|
@@ -38888,9 +38928,8 @@ const AnswerChoices = props => {
|
|
|
38888
38928
|
};
|
|
38889
38929
|
|
|
38890
38930
|
const HideAnswersToggle = props => {
|
|
38891
|
-
const
|
|
38892
|
-
const
|
|
38893
|
-
const labelId = idFactory.get("hide-answers-label");
|
|
38931
|
+
const switchId = useId();
|
|
38932
|
+
const labelId = useId();
|
|
38894
38933
|
const {
|
|
38895
38934
|
strings
|
|
38896
38935
|
} = usePerseusI18n();
|
|
@@ -38933,7 +38972,7 @@ const AnswerPill = props => {
|
|
|
38933
38972
|
focused,
|
|
38934
38973
|
hovered
|
|
38935
38974
|
} = props;
|
|
38936
|
-
const
|
|
38975
|
+
const pillId = useId();
|
|
38937
38976
|
const {
|
|
38938
38977
|
strings
|
|
38939
38978
|
} = usePerseusI18n();
|
|
@@ -38960,7 +38999,7 @@ const AnswerPill = props => {
|
|
|
38960
38999
|
}) => /*#__PURE__*/React.createElement(Pill, {
|
|
38961
39000
|
size: "large",
|
|
38962
39001
|
kind: "accent",
|
|
38963
|
-
id:
|
|
39002
|
+
id: pillId,
|
|
38964
39003
|
onClick: correct ? undefined : onClick,
|
|
38965
39004
|
ref: ref,
|
|
38966
39005
|
style: [style, popperStyle, styles$b.pill, correct && styles$b.correct, incorrect && styles$b.incorrect, (focused || hovered) && BringToFront]
|
|
@@ -45276,7 +45315,7 @@ const init = function init() {
|
|
|
45276
45315
|
|
|
45277
45316
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45278
45317
|
const libName = "@khanacademy/perseus";
|
|
45279
|
-
const libVersion = "
|
|
45318
|
+
const libVersion = "49.0.1";
|
|
45280
45319
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45281
45320
|
|
|
45282
45321
|
const apiVersion = {
|