@khanacademy/perseus 49.0.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 +108 -100
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +110 -98
- package/dist/index.js.map +1 -1
- package/dist/widgets/interactive-graphs/graphs/utils.d.ts +2 -0
- package/package.json +1 -1
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';
|
|
@@ -8870,13 +8870,10 @@ const reactRootCache = new WeakMap();
|
|
|
8870
8870
|
*/
|
|
8871
8871
|
function render(element, container) {
|
|
8872
8872
|
/**
|
|
8873
|
-
* `RenderStateRoot` is responsible for tracking whether it's
|
|
8874
|
-
*
|
|
8875
|
-
*
|
|
8876
|
-
*
|
|
8877
|
-
* high up in the render tree as possible to ensure that any
|
|
8878
|
-
* components using that hook or those components will function
|
|
8879
|
-
* 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.
|
|
8880
8877
|
*/
|
|
8881
8878
|
const children = /*#__PURE__*/React.createElement(RenderStateRoot, {
|
|
8882
8879
|
throwIfNested: false
|
|
@@ -27385,41 +27382,33 @@ class Dropdown extends React.Component {
|
|
|
27385
27382
|
value: String(i + 1),
|
|
27386
27383
|
label: choice
|
|
27387
27384
|
}))];
|
|
27388
|
-
return (
|
|
27389
|
-
|
|
27390
|
-
|
|
27391
|
-
|
|
27392
|
-
|
|
27393
|
-
|
|
27394
|
-
|
|
27395
|
-
|
|
27396
|
-
|
|
27397
|
-
|
|
27398
|
-
|
|
27399
|
-
|
|
27400
|
-
|
|
27401
|
-
|
|
27402
|
-
|
|
27403
|
-
|
|
27404
|
-
|
|
27405
|
-
|
|
27406
|
-
|
|
27407
|
-
|
|
27408
|
-
|
|
27409
|
-
|
|
27410
|
-
|
|
27411
|
-
|
|
27412
|
-
|
|
27413
|
-
|
|
27414
|
-
|
|
27415
|
-
// This is currently necessary for SRs to read the labels properly.
|
|
27416
|
-
// However, WB is working on a change to add the "combobox" role to
|
|
27417
|
-
// all dropdowns.
|
|
27418
|
-
// See https://khanacademy.atlassian.net/browse/WB-1671
|
|
27419
|
-
,
|
|
27420
|
-
role: "combobox"
|
|
27421
|
-
}, children)))
|
|
27422
|
-
);
|
|
27385
|
+
return /*#__PURE__*/React.createElement(Id, null, dropdownId => /*#__PURE__*/React.createElement(View
|
|
27386
|
+
// NOTE(jared): These are required to prevent weird behavior
|
|
27387
|
+
// When there's a dropdown in a zoomable table.
|
|
27388
|
+
, {
|
|
27389
|
+
onClick: e => {
|
|
27390
|
+
e.stopPropagation();
|
|
27391
|
+
},
|
|
27392
|
+
onTouchStart: e => {
|
|
27393
|
+
e.stopPropagation();
|
|
27394
|
+
}
|
|
27395
|
+
}, this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelLarge, {
|
|
27396
|
+
tag: "label",
|
|
27397
|
+
htmlFor: dropdownId
|
|
27398
|
+
}, this.props.visibleLabel), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
27399
|
+
id: dropdownId,
|
|
27400
|
+
placeholder: "",
|
|
27401
|
+
onChange: value => this._handleChange(parseInt(value)),
|
|
27402
|
+
selectedValue: String(this.props.selected),
|
|
27403
|
+
disabled: this.props.apiOptions.readOnly,
|
|
27404
|
+
"aria-label": this.props.ariaLabel || this.props.visibleLabel || this.context.strings.selectAnAnswer
|
|
27405
|
+
// This is currently necessary for SRs to read the labels properly.
|
|
27406
|
+
// However, WB is working on a change to add the "combobox" role to
|
|
27407
|
+
// all dropdowns.
|
|
27408
|
+
// See https://khanacademy.atlassian.net/browse/WB-1671
|
|
27409
|
+
,
|
|
27410
|
+
role: "combobox"
|
|
27411
|
+
}, children)));
|
|
27423
27412
|
}
|
|
27424
27413
|
}
|
|
27425
27414
|
Dropdown.contextType = PerseusI18nContext;
|
|
@@ -27522,37 +27511,29 @@ class Explanation extends React.Component {
|
|
|
27522
27511
|
"white-space": "normal"
|
|
27523
27512
|
};
|
|
27524
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)];
|
|
27525
|
-
return (
|
|
27526
|
-
|
|
27527
|
-
|
|
27528
|
-
|
|
27529
|
-
|
|
27530
|
-
|
|
27531
|
-
|
|
27532
|
-
|
|
27533
|
-
|
|
27534
|
-
|
|
27535
|
-
|
|
27536
|
-
|
|
27537
|
-
|
|
27538
|
-
|
|
27539
|
-
|
|
27540
|
-
|
|
27541
|
-
|
|
27542
|
-
|
|
27543
|
-
|
|
27544
|
-
|
|
27545
|
-
|
|
27546
|
-
|
|
27547
|
-
|
|
27548
|
-
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27549
|
-
apiOptions: this.props.apiOptions,
|
|
27550
|
-
content: this.props.explanation,
|
|
27551
|
-
widgets: this.props.widgets,
|
|
27552
|
-
linterContext: this.props.linterContext,
|
|
27553
|
-
strings: this.context.strings
|
|
27554
|
-
})))))
|
|
27555
|
-
);
|
|
27514
|
+
return /*#__PURE__*/React.createElement(Id, null, contentId => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
|
|
27515
|
+
"aria-expanded": this.state.expanded,
|
|
27516
|
+
"aria-controls": contentId,
|
|
27517
|
+
endIcon: caretIcon,
|
|
27518
|
+
kind: "tertiary",
|
|
27519
|
+
labelStyle: labelStyle,
|
|
27520
|
+
onClick: this._onClick,
|
|
27521
|
+
size: "small",
|
|
27522
|
+
style: buttonStyleOverrides
|
|
27523
|
+
}, promptText), /*#__PURE__*/React.createElement(View, {
|
|
27524
|
+
id: contentId,
|
|
27525
|
+
style: contentStyling,
|
|
27526
|
+
"aria-hidden": !this.state.expanded,
|
|
27527
|
+
testId: "content-container"
|
|
27528
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
27529
|
+
style: styles$k.contentWrapper
|
|
27530
|
+
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27531
|
+
apiOptions: this.props.apiOptions,
|
|
27532
|
+
content: this.props.explanation,
|
|
27533
|
+
widgets: this.props.widgets,
|
|
27534
|
+
linterContext: this.props.linterContext,
|
|
27535
|
+
strings: this.context.strings
|
|
27536
|
+
})))));
|
|
27556
27537
|
}
|
|
27557
27538
|
}
|
|
27558
27539
|
Explanation.contextType = PerseusI18nContext;
|
|
@@ -32708,6 +32689,17 @@ const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
|
32708
32689
|
function isBetween(x, low, high) {
|
|
32709
32690
|
return x >= low && x <= high;
|
|
32710
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
|
+
}
|
|
32711
32703
|
|
|
32712
32704
|
const LockedLine = props => {
|
|
32713
32705
|
var _flags$mafs;
|
|
@@ -34118,6 +34110,12 @@ function getGradableGraph(state, initialGraph) {
|
|
|
34118
34110
|
});
|
|
34119
34111
|
}
|
|
34120
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
|
+
}
|
|
34121
34119
|
return _extends({}, initialGraph, {
|
|
34122
34120
|
coords: state.coords
|
|
34123
34121
|
});
|
|
@@ -34629,6 +34627,15 @@ const PolygonGraph = props => {
|
|
|
34629
34627
|
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
34630
34628
|
}
|
|
34631
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
|
+
}, []);
|
|
34632
34639
|
const statefulProps = _extends({}, props, {
|
|
34633
34640
|
graphConfig,
|
|
34634
34641
|
polygonRef,
|
|
@@ -34769,7 +34776,16 @@ const UnlimitedPolygonGraph = statefulProps => {
|
|
|
34769
34776
|
} = graphConfig;
|
|
34770
34777
|
const widthPx = graphDimensionsInPixels[0];
|
|
34771
34778
|
const heightPx = graphDimensionsInPixels[1];
|
|
34772
|
-
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", {
|
|
34773
34789
|
style: {
|
|
34774
34790
|
fill: "rgba(0,0,0,0)",
|
|
34775
34791
|
cursor: "crosshair"
|
|
@@ -34785,15 +34801,6 @@ const UnlimitedPolygonGraph = statefulProps => {
|
|
|
34785
34801
|
const graphCoordinates = pixelsToVectors([[x, y]], graphConfig);
|
|
34786
34802
|
dispatch(actions.polygon.addPoint(graphCoordinates[0]));
|
|
34787
34803
|
}
|
|
34788
|
-
}), /*#__PURE__*/React.createElement(Polyline, {
|
|
34789
|
-
points: [...points],
|
|
34790
|
-
color: "var(--movable-line-stroke-color)",
|
|
34791
|
-
svgPolylineProps: {
|
|
34792
|
-
strokeWidth: "var(--movable-line-stroke-weight)",
|
|
34793
|
-
style: {
|
|
34794
|
-
fill: "transparent"
|
|
34795
|
-
}
|
|
34796
|
-
}
|
|
34797
34804
|
}), coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
34798
34805
|
key: i,
|
|
34799
34806
|
point: point,
|
|
@@ -34807,9 +34814,10 @@ const UnlimitedPolygonGraph = statefulProps => {
|
|
|
34807
34814
|
},
|
|
34808
34815
|
onClick: () => {
|
|
34809
34816
|
// If the point being clicked is the first point and
|
|
34810
|
-
// there's enough points to form
|
|
34811
|
-
//
|
|
34812
|
-
|
|
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) {
|
|
34813
34821
|
dispatch(actions.polygon.closePolygon());
|
|
34814
34822
|
}
|
|
34815
34823
|
dispatch(actions.polygon.clickPoint(i));
|
|
@@ -35432,7 +35440,7 @@ const renderPolygonGraphControls = props => {
|
|
|
35432
35440
|
|
|
35433
35441
|
// We want to disable the closePolygon button when
|
|
35434
35442
|
// there are not enough coords to make a polygon
|
|
35435
|
-
const disableCloseButton = coords.length < 3;
|
|
35443
|
+
const disableCloseButton = getArrayWithoutDuplicates(coords).length < 3;
|
|
35436
35444
|
|
|
35437
35445
|
// If polygon is closed, show open button.
|
|
35438
35446
|
// If polygon is open, show close button.
|
|
@@ -36132,7 +36140,13 @@ function doClickPoint(state, action) {
|
|
|
36132
36140
|
}
|
|
36133
36141
|
function doClosePolygon(state) {
|
|
36134
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);
|
|
36135
36148
|
return _extends({}, state, {
|
|
36149
|
+
coords: noDupedPoints,
|
|
36136
36150
|
closedPolygon: true
|
|
36137
36151
|
});
|
|
36138
36152
|
}
|
|
@@ -38914,11 +38928,8 @@ const AnswerChoices = props => {
|
|
|
38914
38928
|
};
|
|
38915
38929
|
|
|
38916
38930
|
const HideAnswersToggle = props => {
|
|
38917
|
-
|
|
38918
|
-
|
|
38919
|
-
const idFactory = useUniqueIdWithMock();
|
|
38920
|
-
const switchId = idFactory.get("hide-answers-toggle");
|
|
38921
|
-
const labelId = idFactory.get("hide-answers-label");
|
|
38931
|
+
const switchId = useId();
|
|
38932
|
+
const labelId = useId();
|
|
38922
38933
|
const {
|
|
38923
38934
|
strings
|
|
38924
38935
|
} = usePerseusI18n();
|
|
@@ -38961,10 +38972,7 @@ const AnswerPill = props => {
|
|
|
38961
38972
|
focused,
|
|
38962
38973
|
hovered
|
|
38963
38974
|
} = props;
|
|
38964
|
-
|
|
38965
|
-
// TODO(WB-1812, somewhatabstract): Migrate to Id or useId
|
|
38966
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
38967
|
-
const idFactory = useUniqueIdWithMock();
|
|
38975
|
+
const pillId = useId();
|
|
38968
38976
|
const {
|
|
38969
38977
|
strings
|
|
38970
38978
|
} = usePerseusI18n();
|
|
@@ -38991,7 +38999,7 @@ const AnswerPill = props => {
|
|
|
38991
38999
|
}) => /*#__PURE__*/React.createElement(Pill, {
|
|
38992
39000
|
size: "large",
|
|
38993
39001
|
kind: "accent",
|
|
38994
|
-
id:
|
|
39002
|
+
id: pillId,
|
|
38995
39003
|
onClick: correct ? undefined : onClick,
|
|
38996
39004
|
ref: ref,
|
|
38997
39005
|
style: [style, popperStyle, styles$b.pill, correct && styles$b.correct, incorrect && styles$b.incorrect, (focused || hovered) && BringToFront]
|
|
@@ -45307,7 +45315,7 @@ const init = function init() {
|
|
|
45307
45315
|
|
|
45308
45316
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45309
45317
|
const libName = "@khanacademy/perseus";
|
|
45310
|
-
const libVersion = "49.0.
|
|
45318
|
+
const libVersion = "49.0.1";
|
|
45311
45319
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45312
45320
|
|
|
45313
45321
|
const apiVersion = {
|