@khanacademy/perseus 23.4.0 → 23.6.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/components/input-with-examples.d.ts +0 -4
- package/dist/es/index.css +0 -17
- package/dist/es/index.js +276 -338
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +0 -17
- package/dist/index.d.ts +2 -2
- package/dist/index.js +274 -333
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +2 -1
- package/dist/perseus-types.d.ts +16 -8
- package/dist/server-item-renderer.d.ts +2 -1
- package/dist/types.d.ts +1 -1
- package/dist/widgets/expression.d.ts +12 -6
- package/dist/widgets/interactive-graphs/graphs/sinusoid.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/use-draggable.d.ts +13 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +9 -3
- package/dist/widgets/interactive-graphs/{locked-ellipse.d.ts → locked-figures/locked-ellipse.d.ts} +1 -1
- package/dist/widgets/interactive-graphs/{locked-line.d.ts → locked-figures/locked-line.d.ts} +1 -1
- package/dist/widgets/interactive-graphs/{locked-point.d.ts → locked-figures/locked-point.d.ts} +1 -1
- package/dist/widgets/interactive-graphs/locked-figures/locked-polygon.d.ts +4 -0
- package/dist/widgets/interactive-graphs/{locked-vector.d.ts → locked-figures/locked-vector.d.ts} +1 -1
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +2 -1
- package/dist/widgets/interactive-graphs/reducer/initialize-graph-state.d.ts +3 -2
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +8 -1
- package/dist/widgets/label-image.d.ts +4 -2
- package/package.json +1 -1
- package/dist/components/math-output.d.ts +0 -27
package/dist/es/index.js
CHANGED
|
@@ -2,7 +2,7 @@ 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, linterContextProps } from '@khanacademy/perseus-linter';
|
|
5
|
-
import { View, RenderStateRoot, UniqueIDProvider, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
5
|
+
import { View, RenderStateRoot, UniqueIDProvider, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
6
6
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
7
7
|
import classNames from 'classnames';
|
|
8
8
|
import * as React from 'react';
|
|
@@ -29,7 +29,7 @@ import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-block
|
|
|
29
29
|
import caretDown from '@phosphor-icons/core/regular/caret-down.svg';
|
|
30
30
|
import caretUp from '@phosphor-icons/core/regular/caret-up.svg';
|
|
31
31
|
import debounce$2 from 'lodash.debounce';
|
|
32
|
-
import { vec, Ellipse, Line as Line$4, Point as Point$2, useMovable, Text as Text$1,
|
|
32
|
+
import { vec, Ellipse, Line as Line$4, Point as Point$2, Polygon, useMovable, Text as Text$1, Plot as Plot$3, Coordinates, Mafs } from 'mafs';
|
|
33
33
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
34
34
|
import { Body, LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
35
35
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
@@ -20964,254 +20964,6 @@ const styles$B = {
|
|
|
20964
20964
|
}
|
|
20965
20965
|
};
|
|
20966
20966
|
|
|
20967
|
-
/*
|
|
20968
|
-
* In this file, an `expression` is some portion of valid TeX enclosed in
|
|
20969
|
-
* curly brackets.
|
|
20970
|
-
*/
|
|
20971
|
-
|
|
20972
|
-
/*
|
|
20973
|
-
* Find the index at which an expression ends, i.e., has an unmatched
|
|
20974
|
-
* closing curly bracket. This method assumes that we start with a non-open
|
|
20975
|
-
* bracket character and end when we've seen more left than right brackets
|
|
20976
|
-
* (rather than assuming that we start with a bracket character and wait for
|
|
20977
|
-
* bracket equality).
|
|
20978
|
-
*/
|
|
20979
|
-
function findEndpoint(tex, currentIndex) {
|
|
20980
|
-
let bracketDepth = 0;
|
|
20981
|
-
for (let i = currentIndex, len = tex.length; i < len; i++) {
|
|
20982
|
-
const c = tex[i];
|
|
20983
|
-
if (c === "{") {
|
|
20984
|
-
bracketDepth++;
|
|
20985
|
-
} else if (c === "}") {
|
|
20986
|
-
bracketDepth--;
|
|
20987
|
-
}
|
|
20988
|
-
if (bracketDepth < 0) {
|
|
20989
|
-
return i;
|
|
20990
|
-
}
|
|
20991
|
-
}
|
|
20992
|
-
// If we never see unbalanced curly brackets, default to the
|
|
20993
|
-
// entire string
|
|
20994
|
-
return tex.length;
|
|
20995
|
-
}
|
|
20996
|
-
|
|
20997
|
-
/*
|
|
20998
|
-
* Parses an individual set of curly brackets into TeX.
|
|
20999
|
-
*/
|
|
21000
|
-
function parseNextExpression(tex, currentIndex, handler) {
|
|
21001
|
-
// Find the first '{' and grab subsequent TeX
|
|
21002
|
-
// Ex) tex: '{3}{7}', and we want the '3'
|
|
21003
|
-
const openBracketIndex = tex.indexOf("{", currentIndex);
|
|
21004
|
-
const nextExpIndex = openBracketIndex + 1;
|
|
21005
|
-
|
|
21006
|
-
// Truncate to only contain remaining TeX
|
|
21007
|
-
const endpoint = findEndpoint(tex, nextExpIndex);
|
|
21008
|
-
const expressionTeX = tex.substring(nextExpIndex, endpoint);
|
|
21009
|
-
const parsedExp = walkTex(expressionTeX, handler);
|
|
21010
|
-
return {
|
|
21011
|
-
endpoint: endpoint,
|
|
21012
|
-
expression: parsedExp
|
|
21013
|
-
};
|
|
21014
|
-
}
|
|
21015
|
-
function getNextFracIndex(tex, currentIndex) {
|
|
21016
|
-
const dfrac = "\\dfrac";
|
|
21017
|
-
const frac = "\\frac";
|
|
21018
|
-
const nextFrac = tex.indexOf(frac, currentIndex);
|
|
21019
|
-
const nextDFrac = tex.indexOf(dfrac, currentIndex);
|
|
21020
|
-
if (nextFrac > -1 && nextDFrac > -1) {
|
|
21021
|
-
return Math.min(nextFrac, nextDFrac);
|
|
21022
|
-
}
|
|
21023
|
-
if (nextFrac > -1) {
|
|
21024
|
-
return nextFrac;
|
|
21025
|
-
}
|
|
21026
|
-
if (nextDFrac > -1) {
|
|
21027
|
-
return nextDFrac;
|
|
21028
|
-
}
|
|
21029
|
-
return -1;
|
|
21030
|
-
}
|
|
21031
|
-
function walkTex(tex, handler) {
|
|
21032
|
-
if (!tex) {
|
|
21033
|
-
return "";
|
|
21034
|
-
}
|
|
21035
|
-
|
|
21036
|
-
// Ex) tex: '2 \dfrac {3}{7}'
|
|
21037
|
-
let parsedString = "";
|
|
21038
|
-
let currentIndex = 0;
|
|
21039
|
-
let nextFrac = getNextFracIndex(tex, currentIndex);
|
|
21040
|
-
|
|
21041
|
-
// For each \dfrac, find the two expressions (wrapped in {}) and recur
|
|
21042
|
-
while (nextFrac > -1) {
|
|
21043
|
-
// Gather first fragment, preceding \dfrac
|
|
21044
|
-
// Ex) parsedString: '2 '
|
|
21045
|
-
parsedString += tex.substring(currentIndex, nextFrac);
|
|
21046
|
-
|
|
21047
|
-
// Remove everything preceding \dfrac, which has been parsed
|
|
21048
|
-
currentIndex = nextFrac;
|
|
21049
|
-
|
|
21050
|
-
// Parse first expression and move index past it
|
|
21051
|
-
// Ex) firstParsedExpression.expression: '3'
|
|
21052
|
-
const firstParsedExpression = parseNextExpression(tex, currentIndex, handler);
|
|
21053
|
-
currentIndex = firstParsedExpression.endpoint + 1;
|
|
21054
|
-
|
|
21055
|
-
// Parse second expression
|
|
21056
|
-
// Ex) secondParsedExpression.expression: '7'
|
|
21057
|
-
const secondParsedExpression = parseNextExpression(tex, currentIndex, handler);
|
|
21058
|
-
currentIndex = secondParsedExpression.endpoint + 1;
|
|
21059
|
-
|
|
21060
|
-
// Add expressions to running total of parsed expressions
|
|
21061
|
-
if (parsedString.length) {
|
|
21062
|
-
parsedString += " ";
|
|
21063
|
-
}
|
|
21064
|
-
|
|
21065
|
-
// Apply a custom handler based on the parsed subexpressions
|
|
21066
|
-
parsedString += handler(firstParsedExpression.expression, secondParsedExpression.expression);
|
|
21067
|
-
|
|
21068
|
-
// Find next DFrac, relative to currentIndex
|
|
21069
|
-
nextFrac = getNextFracIndex(tex, currentIndex);
|
|
21070
|
-
}
|
|
21071
|
-
|
|
21072
|
-
// Add remaining TeX, which is \dfrac-free
|
|
21073
|
-
parsedString += tex.slice(currentIndex);
|
|
21074
|
-
return parsedString;
|
|
21075
|
-
}
|
|
21076
|
-
|
|
21077
|
-
/*
|
|
21078
|
-
* Modify a TeX expression, returning another TeX expression. The resulting
|
|
21079
|
-
* expression will have its innermost fractions stubbed out with \fracs
|
|
21080
|
-
* (as opposed to \dfracs). All other content will remain untouched.
|
|
21081
|
-
*/
|
|
21082
|
-
function modifyTex(tex) {
|
|
21083
|
-
function isNestedFraction(tex) {
|
|
21084
|
-
return tex.indexOf("\\frac") > -1 || tex.indexOf("\\dfrac") > -1;
|
|
21085
|
-
}
|
|
21086
|
-
const handler = function handler(exp1, exp2) {
|
|
21087
|
-
let prefix;
|
|
21088
|
-
if (isNestedFraction(exp1) || isNestedFraction(exp2)) {
|
|
21089
|
-
prefix = "\\dfrac";
|
|
21090
|
-
} else {
|
|
21091
|
-
prefix = "\\frac";
|
|
21092
|
-
}
|
|
21093
|
-
return prefix + " {" + exp1 + "}{" + exp2 + "}";
|
|
21094
|
-
};
|
|
21095
|
-
return walkTex(tex, handler);
|
|
21096
|
-
}
|
|
21097
|
-
|
|
21098
|
-
/*
|
|
21099
|
-
* Parse a TeX expression into something interpretable by input-number.
|
|
21100
|
-
* The process is concerned with: (1) parsing fractions, i.e., \dfracs; and
|
|
21101
|
-
* (2) removing backslash-escaping from certain characters (right now, only
|
|
21102
|
-
* percent signs).
|
|
21103
|
-
*
|
|
21104
|
-
* The basic algorithm for handling \dfracs splits on \dfracs and then recurs
|
|
21105
|
-
* on the subsequent "expressions", i.e., the {} pairs that follow \dfrac. The
|
|
21106
|
-
* recursion is to allow for nested \dfrac elements.
|
|
21107
|
-
*
|
|
21108
|
-
* Backslash-escapes are removed with a simple search-and-replace.
|
|
21109
|
-
*/
|
|
21110
|
-
function parseTex(tex) {
|
|
21111
|
-
const handler = function handler(exp1, exp2) {
|
|
21112
|
-
return exp1 + "/" + exp2;
|
|
21113
|
-
};
|
|
21114
|
-
const texWithoutFracs = walkTex(tex, handler);
|
|
21115
|
-
return texWithoutFracs.replace("\\%", "%");
|
|
21116
|
-
}
|
|
21117
|
-
var TexWrangler = {
|
|
21118
|
-
parseTex,
|
|
21119
|
-
modifyTex
|
|
21120
|
-
};
|
|
21121
|
-
|
|
21122
|
-
/* eslint-disable react/sort-comp */
|
|
21123
|
-
const ModifyTex = TexWrangler.modifyTex;
|
|
21124
|
-
class MathOutput extends React.Component {
|
|
21125
|
-
constructor(...args) {
|
|
21126
|
-
super(...args);
|
|
21127
|
-
this.state = {
|
|
21128
|
-
focused: false,
|
|
21129
|
-
selectorNamespace: _.uniqueId("math-output")
|
|
21130
|
-
};
|
|
21131
|
-
this._getInputClassName = () => {
|
|
21132
|
-
let className = "math-output " + ClassNames.INPUT + " " + ClassNames.INTERACTIVE;
|
|
21133
|
-
if (this.state.focused) {
|
|
21134
|
-
className += " " + ClassNames.FOCUSED;
|
|
21135
|
-
}
|
|
21136
|
-
if (this.props.className) {
|
|
21137
|
-
className += " " + this.props.className;
|
|
21138
|
-
}
|
|
21139
|
-
return className;
|
|
21140
|
-
};
|
|
21141
|
-
this._getDisplayValue = value => {
|
|
21142
|
-
// Cast from (potentially a) number to string
|
|
21143
|
-
let displayText;
|
|
21144
|
-
if (value != null) {
|
|
21145
|
-
displayText = "" + value;
|
|
21146
|
-
} else {
|
|
21147
|
-
displayText = "";
|
|
21148
|
-
}
|
|
21149
|
-
return ModifyTex(displayText);
|
|
21150
|
-
};
|
|
21151
|
-
this.getValue = () => {
|
|
21152
|
-
return this.props.value;
|
|
21153
|
-
};
|
|
21154
|
-
this.focus = () => {
|
|
21155
|
-
if (!this.state.focused) {
|
|
21156
|
-
this.props.onFocus();
|
|
21157
|
-
this._bindBlurHandler();
|
|
21158
|
-
this.setState({
|
|
21159
|
-
focused: true
|
|
21160
|
-
});
|
|
21161
|
-
}
|
|
21162
|
-
};
|
|
21163
|
-
this.blur = () => {
|
|
21164
|
-
if (this.state.focused) {
|
|
21165
|
-
this.props.onBlur();
|
|
21166
|
-
this._unbindBlurHandler();
|
|
21167
|
-
this.setState({
|
|
21168
|
-
focused: false
|
|
21169
|
-
});
|
|
21170
|
-
}
|
|
21171
|
-
};
|
|
21172
|
-
this._bindBlurHandler = () => {
|
|
21173
|
-
$(document).bind("vclick." + this.state.selectorNamespace, e => {
|
|
21174
|
-
// Detect whether the target has our React DOM node as a parent
|
|
21175
|
-
const $closestWidget = $(e.target).closest(
|
|
21176
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
21177
|
-
ReactDOM__default.findDOMNode(this));
|
|
21178
|
-
if (!$closestWidget.length) {
|
|
21179
|
-
this.blur();
|
|
21180
|
-
}
|
|
21181
|
-
});
|
|
21182
|
-
};
|
|
21183
|
-
this._unbindBlurHandler = () => {
|
|
21184
|
-
$(document).unbind("." + this.state.selectorNamespace);
|
|
21185
|
-
};
|
|
21186
|
-
}
|
|
21187
|
-
render() {
|
|
21188
|
-
const divStyle = {
|
|
21189
|
-
textAlign: "center"
|
|
21190
|
-
};
|
|
21191
|
-
const {
|
|
21192
|
-
TeX
|
|
21193
|
-
} = getDependencies();
|
|
21194
|
-
return /*#__PURE__*/React.createElement("span", {
|
|
21195
|
-
// eslint-disable-next-line react/no-string-refs
|
|
21196
|
-
ref: "input",
|
|
21197
|
-
className: this._getInputClassName(),
|
|
21198
|
-
"aria-label": this.props.labelText,
|
|
21199
|
-
onMouseDown: this.focus,
|
|
21200
|
-
onTouchStart: this.focus
|
|
21201
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
21202
|
-
style: divStyle
|
|
21203
|
-
}, /*#__PURE__*/React.createElement(TeX, null, this._getDisplayValue(this.props.value))));
|
|
21204
|
-
}
|
|
21205
|
-
componentWillUnmount() {
|
|
21206
|
-
this._unbindBlurHandler();
|
|
21207
|
-
}
|
|
21208
|
-
}
|
|
21209
|
-
MathOutput.defaultProps = {
|
|
21210
|
-
value: "",
|
|
21211
|
-
onFocus: function () {},
|
|
21212
|
-
onBlur: function () {}
|
|
21213
|
-
};
|
|
21214
|
-
|
|
21215
20967
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
21216
20968
|
let lastId = 0;
|
|
21217
20969
|
function uniqueIdForInput(prefix = "input-") {
|
|
@@ -21566,12 +21318,6 @@ class InputWithExamples extends React.Component {
|
|
|
21566
21318
|
return `input-with-examples-${btoa(this.props.id).replace(/=/g, "")}`;
|
|
21567
21319
|
};
|
|
21568
21320
|
this._getInputClassName = () => {
|
|
21569
|
-
// <MathOutput> is a special component that manages its own class and
|
|
21570
|
-
// state, as it's a <span> that wants to act like an <input>.
|
|
21571
|
-
if (this.props.type === "tex") {
|
|
21572
|
-
return this.props.className;
|
|
21573
|
-
}
|
|
21574
|
-
|
|
21575
21321
|
// Otherwise, we need to add these INPUT and FOCUSED tags here.
|
|
21576
21322
|
let className = ClassNames.INPUT + " " + ClassNames.INTERACTIVE;
|
|
21577
21323
|
if (this.state.focused) {
|
|
@@ -21582,8 +21328,7 @@ class InputWithExamples extends React.Component {
|
|
|
21582
21328
|
}
|
|
21583
21329
|
return className;
|
|
21584
21330
|
};
|
|
21585
|
-
this.
|
|
21586
|
-
// Minimal set of props, used by each input type
|
|
21331
|
+
this._renderInput = () => {
|
|
21587
21332
|
const id = this._getUniqueId();
|
|
21588
21333
|
const inputProps = {
|
|
21589
21334
|
id: id,
|
|
@@ -21595,52 +21340,15 @@ class InputWithExamples extends React.Component {
|
|
|
21595
21340
|
onFocus: this._handleFocus,
|
|
21596
21341
|
onBlur: this._handleBlur,
|
|
21597
21342
|
disabled: this.props.disabled,
|
|
21598
|
-
style: this.props.style
|
|
21599
|
-
};
|
|
21600
|
-
if (this.props.type === "tex") {
|
|
21601
|
-
return inputProps;
|
|
21602
|
-
}
|
|
21603
|
-
|
|
21604
|
-
// Add useful props required for MATH and TEXT modes
|
|
21605
|
-
_.extend(inputProps, {
|
|
21343
|
+
style: this.props.style,
|
|
21606
21344
|
onChange: this.props.onChange,
|
|
21607
|
-
onTouchStart: captureScratchpadTouchStart$2
|
|
21608
|
-
|
|
21609
|
-
|
|
21610
|
-
|
|
21611
|
-
|
|
21612
|
-
|
|
21613
|
-
|
|
21614
|
-
buttonsVisible: this.props.buttonsVisible,
|
|
21615
|
-
convertDotToTimes: this.props.convertDotToTimes
|
|
21616
|
-
}, inputProps);
|
|
21617
|
-
}
|
|
21618
|
-
if (this.props.type === "text") {
|
|
21619
|
-
return _.extend({
|
|
21620
|
-
autoCapitalize: "off",
|
|
21621
|
-
autoComplete: "off",
|
|
21622
|
-
autoCorrect: "off",
|
|
21623
|
-
spellCheck: "false"
|
|
21624
|
-
}, inputProps);
|
|
21625
|
-
}
|
|
21626
|
-
};
|
|
21627
|
-
this._getComponentForInputType = () => {
|
|
21628
|
-
switch (this.props.type) {
|
|
21629
|
-
case "tex":
|
|
21630
|
-
return MathOutput;
|
|
21631
|
-
case "math":
|
|
21632
|
-
return MathInput;
|
|
21633
|
-
case "text":
|
|
21634
|
-
return TextInput;
|
|
21635
|
-
default:
|
|
21636
|
-
this.props.type;
|
|
21637
|
-
return null;
|
|
21638
|
-
}
|
|
21639
|
-
};
|
|
21640
|
-
this._renderInput = () => {
|
|
21641
|
-
const inputProps = this._getPropsForInputType();
|
|
21642
|
-
const InputComponent = this._getComponentForInputType();
|
|
21643
|
-
return /*#__PURE__*/React.createElement(InputComponent, inputProps);
|
|
21345
|
+
onTouchStart: captureScratchpadTouchStart$2,
|
|
21346
|
+
autoCapitalize: "off",
|
|
21347
|
+
autoComplete: "off",
|
|
21348
|
+
autoCorrect: "off",
|
|
21349
|
+
spellCheck: "false"
|
|
21350
|
+
};
|
|
21351
|
+
return /*#__PURE__*/React.createElement(TextInput, inputProps);
|
|
21644
21352
|
};
|
|
21645
21353
|
this._handleFocus = () => {
|
|
21646
21354
|
this.props.onFocus();
|
|
@@ -21682,14 +21390,6 @@ class InputWithExamples extends React.Component {
|
|
|
21682
21390
|
}
|
|
21683
21391
|
render() {
|
|
21684
21392
|
const input = this._renderInput();
|
|
21685
|
-
|
|
21686
|
-
// Static rendering, which doesn't include the 'tooltip' logic that the
|
|
21687
|
-
// other types require, and is hence handled separately.
|
|
21688
|
-
if (this.props.type === "tex") {
|
|
21689
|
-
return input;
|
|
21690
|
-
}
|
|
21691
|
-
|
|
21692
|
-
// Else, we need to be able to show examples
|
|
21693
21393
|
const examplesContent = _.map(this.props.examples, example => {
|
|
21694
21394
|
return "- " + example;
|
|
21695
21395
|
}).join("\n");
|
|
@@ -21716,7 +21416,6 @@ class InputWithExamples extends React.Component {
|
|
|
21716
21416
|
}
|
|
21717
21417
|
InputWithExamples.contextType = PerseusI18nContext;
|
|
21718
21418
|
InputWithExamples.defaultProps = {
|
|
21719
|
-
type: "text",
|
|
21720
21419
|
shouldShowExamples: true,
|
|
21721
21420
|
onFocus: function () {},
|
|
21722
21421
|
onBlur: function () {},
|
|
@@ -21805,6 +21504,161 @@ SimpleKeypadInput.propTypes = {
|
|
|
21805
21504
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
21806
21505
|
};
|
|
21807
21506
|
|
|
21507
|
+
/*
|
|
21508
|
+
* In this file, an `expression` is some portion of valid TeX enclosed in
|
|
21509
|
+
* curly brackets.
|
|
21510
|
+
*/
|
|
21511
|
+
|
|
21512
|
+
/*
|
|
21513
|
+
* Find the index at which an expression ends, i.e., has an unmatched
|
|
21514
|
+
* closing curly bracket. This method assumes that we start with a non-open
|
|
21515
|
+
* bracket character and end when we've seen more left than right brackets
|
|
21516
|
+
* (rather than assuming that we start with a bracket character and wait for
|
|
21517
|
+
* bracket equality).
|
|
21518
|
+
*/
|
|
21519
|
+
function findEndpoint(tex, currentIndex) {
|
|
21520
|
+
let bracketDepth = 0;
|
|
21521
|
+
for (let i = currentIndex, len = tex.length; i < len; i++) {
|
|
21522
|
+
const c = tex[i];
|
|
21523
|
+
if (c === "{") {
|
|
21524
|
+
bracketDepth++;
|
|
21525
|
+
} else if (c === "}") {
|
|
21526
|
+
bracketDepth--;
|
|
21527
|
+
}
|
|
21528
|
+
if (bracketDepth < 0) {
|
|
21529
|
+
return i;
|
|
21530
|
+
}
|
|
21531
|
+
}
|
|
21532
|
+
// If we never see unbalanced curly brackets, default to the
|
|
21533
|
+
// entire string
|
|
21534
|
+
return tex.length;
|
|
21535
|
+
}
|
|
21536
|
+
|
|
21537
|
+
/*
|
|
21538
|
+
* Parses an individual set of curly brackets into TeX.
|
|
21539
|
+
*/
|
|
21540
|
+
function parseNextExpression(tex, currentIndex, handler) {
|
|
21541
|
+
// Find the first '{' and grab subsequent TeX
|
|
21542
|
+
// Ex) tex: '{3}{7}', and we want the '3'
|
|
21543
|
+
const openBracketIndex = tex.indexOf("{", currentIndex);
|
|
21544
|
+
const nextExpIndex = openBracketIndex + 1;
|
|
21545
|
+
|
|
21546
|
+
// Truncate to only contain remaining TeX
|
|
21547
|
+
const endpoint = findEndpoint(tex, nextExpIndex);
|
|
21548
|
+
const expressionTeX = tex.substring(nextExpIndex, endpoint);
|
|
21549
|
+
const parsedExp = walkTex(expressionTeX, handler);
|
|
21550
|
+
return {
|
|
21551
|
+
endpoint: endpoint,
|
|
21552
|
+
expression: parsedExp
|
|
21553
|
+
};
|
|
21554
|
+
}
|
|
21555
|
+
function getNextFracIndex(tex, currentIndex) {
|
|
21556
|
+
const dfrac = "\\dfrac";
|
|
21557
|
+
const frac = "\\frac";
|
|
21558
|
+
const nextFrac = tex.indexOf(frac, currentIndex);
|
|
21559
|
+
const nextDFrac = tex.indexOf(dfrac, currentIndex);
|
|
21560
|
+
if (nextFrac > -1 && nextDFrac > -1) {
|
|
21561
|
+
return Math.min(nextFrac, nextDFrac);
|
|
21562
|
+
}
|
|
21563
|
+
if (nextFrac > -1) {
|
|
21564
|
+
return nextFrac;
|
|
21565
|
+
}
|
|
21566
|
+
if (nextDFrac > -1) {
|
|
21567
|
+
return nextDFrac;
|
|
21568
|
+
}
|
|
21569
|
+
return -1;
|
|
21570
|
+
}
|
|
21571
|
+
function walkTex(tex, handler) {
|
|
21572
|
+
if (!tex) {
|
|
21573
|
+
return "";
|
|
21574
|
+
}
|
|
21575
|
+
|
|
21576
|
+
// Ex) tex: '2 \dfrac {3}{7}'
|
|
21577
|
+
let parsedString = "";
|
|
21578
|
+
let currentIndex = 0;
|
|
21579
|
+
let nextFrac = getNextFracIndex(tex, currentIndex);
|
|
21580
|
+
|
|
21581
|
+
// For each \dfrac, find the two expressions (wrapped in {}) and recur
|
|
21582
|
+
while (nextFrac > -1) {
|
|
21583
|
+
// Gather first fragment, preceding \dfrac
|
|
21584
|
+
// Ex) parsedString: '2 '
|
|
21585
|
+
parsedString += tex.substring(currentIndex, nextFrac);
|
|
21586
|
+
|
|
21587
|
+
// Remove everything preceding \dfrac, which has been parsed
|
|
21588
|
+
currentIndex = nextFrac;
|
|
21589
|
+
|
|
21590
|
+
// Parse first expression and move index past it
|
|
21591
|
+
// Ex) firstParsedExpression.expression: '3'
|
|
21592
|
+
const firstParsedExpression = parseNextExpression(tex, currentIndex, handler);
|
|
21593
|
+
currentIndex = firstParsedExpression.endpoint + 1;
|
|
21594
|
+
|
|
21595
|
+
// Parse second expression
|
|
21596
|
+
// Ex) secondParsedExpression.expression: '7'
|
|
21597
|
+
const secondParsedExpression = parseNextExpression(tex, currentIndex, handler);
|
|
21598
|
+
currentIndex = secondParsedExpression.endpoint + 1;
|
|
21599
|
+
|
|
21600
|
+
// Add expressions to running total of parsed expressions
|
|
21601
|
+
if (parsedString.length) {
|
|
21602
|
+
parsedString += " ";
|
|
21603
|
+
}
|
|
21604
|
+
|
|
21605
|
+
// Apply a custom handler based on the parsed subexpressions
|
|
21606
|
+
parsedString += handler(firstParsedExpression.expression, secondParsedExpression.expression);
|
|
21607
|
+
|
|
21608
|
+
// Find next DFrac, relative to currentIndex
|
|
21609
|
+
nextFrac = getNextFracIndex(tex, currentIndex);
|
|
21610
|
+
}
|
|
21611
|
+
|
|
21612
|
+
// Add remaining TeX, which is \dfrac-free
|
|
21613
|
+
parsedString += tex.slice(currentIndex);
|
|
21614
|
+
return parsedString;
|
|
21615
|
+
}
|
|
21616
|
+
|
|
21617
|
+
/*
|
|
21618
|
+
* Modify a TeX expression, returning another TeX expression. The resulting
|
|
21619
|
+
* expression will have its innermost fractions stubbed out with \fracs
|
|
21620
|
+
* (as opposed to \dfracs). All other content will remain untouched.
|
|
21621
|
+
*/
|
|
21622
|
+
function modifyTex(tex) {
|
|
21623
|
+
function isNestedFraction(tex) {
|
|
21624
|
+
return tex.indexOf("\\frac") > -1 || tex.indexOf("\\dfrac") > -1;
|
|
21625
|
+
}
|
|
21626
|
+
const handler = function handler(exp1, exp2) {
|
|
21627
|
+
let prefix;
|
|
21628
|
+
if (isNestedFraction(exp1) || isNestedFraction(exp2)) {
|
|
21629
|
+
prefix = "\\dfrac";
|
|
21630
|
+
} else {
|
|
21631
|
+
prefix = "\\frac";
|
|
21632
|
+
}
|
|
21633
|
+
return prefix + " {" + exp1 + "}{" + exp2 + "}";
|
|
21634
|
+
};
|
|
21635
|
+
return walkTex(tex, handler);
|
|
21636
|
+
}
|
|
21637
|
+
|
|
21638
|
+
/*
|
|
21639
|
+
* Parse a TeX expression into something interpretable by input-number.
|
|
21640
|
+
* The process is concerned with: (1) parsing fractions, i.e., \dfracs; and
|
|
21641
|
+
* (2) removing backslash-escaping from certain characters (right now, only
|
|
21642
|
+
* percent signs).
|
|
21643
|
+
*
|
|
21644
|
+
* The basic algorithm for handling \dfracs splits on \dfracs and then recurs
|
|
21645
|
+
* on the subsequent "expressions", i.e., the {} pairs that follow \dfrac. The
|
|
21646
|
+
* recursion is to allow for nested \dfrac elements.
|
|
21647
|
+
*
|
|
21648
|
+
* Backslash-escapes are removed with a simple search-and-replace.
|
|
21649
|
+
*/
|
|
21650
|
+
function parseTex(tex) {
|
|
21651
|
+
const handler = function handler(exp1, exp2) {
|
|
21652
|
+
return exp1 + "/" + exp2;
|
|
21653
|
+
};
|
|
21654
|
+
const texWithoutFracs = walkTex(tex, handler);
|
|
21655
|
+
return texWithoutFracs.replace("\\%", "%");
|
|
21656
|
+
}
|
|
21657
|
+
var TexWrangler = {
|
|
21658
|
+
parseTex,
|
|
21659
|
+
modifyTex
|
|
21660
|
+
};
|
|
21661
|
+
|
|
21808
21662
|
/* eslint-disable react/sort-comp */
|
|
21809
21663
|
const ParseTex$1 = TexWrangler.parseTex;
|
|
21810
21664
|
const answerTypes = {
|
|
@@ -21983,7 +21837,6 @@ class InputNumber extends React.Component {
|
|
|
21983
21837
|
value: this.props.currentValue,
|
|
21984
21838
|
onChange: this.handleChange,
|
|
21985
21839
|
style: inputStyles,
|
|
21986
|
-
type: "text",
|
|
21987
21840
|
examples: this.examples(),
|
|
21988
21841
|
shouldShowExamples: this.shouldShowExamples(),
|
|
21989
21842
|
onFocus: this._handleFocus,
|
|
@@ -22392,7 +22245,6 @@ class NumericInput extends React.Component {
|
|
|
22392
22245
|
value: this.props.currentValue,
|
|
22393
22246
|
onChange: this.handleChange,
|
|
22394
22247
|
labelText: labelText,
|
|
22395
|
-
type: "text",
|
|
22396
22248
|
examples: this.examples(),
|
|
22397
22249
|
shouldShowExamples: this.shouldShowExamples(),
|
|
22398
22250
|
onFocus: this._handleFocus,
|
|
@@ -28656,13 +28508,15 @@ const ItemExtras = [
|
|
|
28656
28508
|
|
|
28657
28509
|
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
28658
28510
|
const lockedFigureColors = {
|
|
28511
|
+
blue: "#3D7586",
|
|
28659
28512
|
green: "#447A53",
|
|
28660
28513
|
grayH: "#3B3D45",
|
|
28661
28514
|
purple: "#594094",
|
|
28662
28515
|
pink: "#B25071",
|
|
28663
|
-
red: "#D92916"
|
|
28516
|
+
red: "#D92916",
|
|
28517
|
+
orange: "#946700"
|
|
28664
28518
|
};
|
|
28665
|
-
const
|
|
28519
|
+
const lockedFigureFillStyles = {
|
|
28666
28520
|
none: 0,
|
|
28667
28521
|
solid: 1,
|
|
28668
28522
|
translucent: 0.4
|
|
@@ -28682,7 +28536,7 @@ const LockedEllipse = props => {
|
|
|
28682
28536
|
center: center,
|
|
28683
28537
|
radius: radius,
|
|
28684
28538
|
angle: angle,
|
|
28685
|
-
fillOpacity:
|
|
28539
|
+
fillOpacity: lockedFigureFillStyles[fillStyle],
|
|
28686
28540
|
strokeStyle: strokeStyle,
|
|
28687
28541
|
color: lockedFigureColors[color]
|
|
28688
28542
|
});
|
|
@@ -28942,6 +28796,29 @@ const LockedPoint = props => {
|
|
|
28942
28796
|
});
|
|
28943
28797
|
};
|
|
28944
28798
|
|
|
28799
|
+
const LockedPolygon = props => {
|
|
28800
|
+
const {
|
|
28801
|
+
points,
|
|
28802
|
+
color,
|
|
28803
|
+
showVertices,
|
|
28804
|
+
fillStyle,
|
|
28805
|
+
strokeStyle
|
|
28806
|
+
} = props;
|
|
28807
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28808
|
+
className: "locked-polygon"
|
|
28809
|
+
}, /*#__PURE__*/React.createElement(Polygon, {
|
|
28810
|
+
points: [...points],
|
|
28811
|
+
fillOpacity: lockedFigureFillStyles[fillStyle],
|
|
28812
|
+
strokeStyle: strokeStyle,
|
|
28813
|
+
color: lockedFigureColors[color]
|
|
28814
|
+
}), showVertices && points.map((point, index) => /*#__PURE__*/React.createElement(Point$2, {
|
|
28815
|
+
key: `locked-polygon-point-${index}`,
|
|
28816
|
+
x: point[0],
|
|
28817
|
+
y: point[1],
|
|
28818
|
+
color: lockedFigureColors[color]
|
|
28819
|
+
})));
|
|
28820
|
+
};
|
|
28821
|
+
|
|
28945
28822
|
const LockedVector = props => {
|
|
28946
28823
|
const {
|
|
28947
28824
|
color,
|
|
@@ -28972,13 +28849,17 @@ const GraphLockedLayer = props => {
|
|
|
28972
28849
|
key: `line-${index}`,
|
|
28973
28850
|
range: props.range
|
|
28974
28851
|
}, figure));
|
|
28852
|
+
case "vector":
|
|
28853
|
+
return /*#__PURE__*/React.createElement(LockedVector, _extends({
|
|
28854
|
+
key: `vector-${index}`
|
|
28855
|
+
}, figure));
|
|
28975
28856
|
case "ellipse":
|
|
28976
28857
|
return /*#__PURE__*/React.createElement(LockedEllipse, _extends({
|
|
28977
28858
|
key: `ellipse-${index}`
|
|
28978
28859
|
}, figure));
|
|
28979
|
-
case "
|
|
28980
|
-
return /*#__PURE__*/React.createElement(
|
|
28981
|
-
key: `
|
|
28860
|
+
case "polygon":
|
|
28861
|
+
return /*#__PURE__*/React.createElement(LockedPolygon, _extends({
|
|
28862
|
+
key: `polygon-${index}`
|
|
28982
28863
|
}, figure));
|
|
28983
28864
|
default:
|
|
28984
28865
|
/**
|
|
@@ -28992,6 +28873,13 @@ const GraphLockedLayer = props => {
|
|
|
28992
28873
|
}));
|
|
28993
28874
|
};
|
|
28994
28875
|
|
|
28876
|
+
const REINITIALIZE = "reinitialize";
|
|
28877
|
+
function reinitialize(params) {
|
|
28878
|
+
return {
|
|
28879
|
+
type: REINITIALIZE,
|
|
28880
|
+
params
|
|
28881
|
+
};
|
|
28882
|
+
}
|
|
28995
28883
|
const MOVE_CONTROL_POINT = "move-control-point";
|
|
28996
28884
|
function moveControlPoint(pointIndex, destination, itemIndex) {
|
|
28997
28885
|
return {
|
|
@@ -29084,6 +28972,10 @@ function snap(snapStep, point) {
|
|
|
29084
28972
|
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
29085
28973
|
}
|
|
29086
28974
|
|
|
28975
|
+
function useDraggable(params) {
|
|
28976
|
+
return useMovable(params);
|
|
28977
|
+
}
|
|
28978
|
+
|
|
29087
28979
|
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
29088
28980
|
// graph.
|
|
29089
28981
|
const hitboxSizePx = 48;
|
|
@@ -29237,7 +29129,7 @@ function useControlPoint(point, color, onMovePoint) {
|
|
|
29237
29129
|
} = useGraphConfig();
|
|
29238
29130
|
const [focused, setFocused] = useState(false);
|
|
29239
29131
|
const keyboardHandleRef = useRef(null);
|
|
29240
|
-
|
|
29132
|
+
useDraggable({
|
|
29241
29133
|
gestureTarget: keyboardHandleRef,
|
|
29242
29134
|
point,
|
|
29243
29135
|
onMove: onMovePoint,
|
|
@@ -29246,7 +29138,7 @@ function useControlPoint(point, color, onMovePoint) {
|
|
|
29246
29138
|
const visiblePointRef = useRef(null);
|
|
29247
29139
|
const {
|
|
29248
29140
|
dragging
|
|
29249
|
-
} =
|
|
29141
|
+
} = useDraggable({
|
|
29250
29142
|
gestureTarget: visiblePointRef,
|
|
29251
29143
|
point,
|
|
29252
29144
|
onMove: onMovePoint,
|
|
@@ -29300,7 +29192,7 @@ const Line$1 = props => {
|
|
|
29300
29192
|
const line = useRef(null);
|
|
29301
29193
|
const {
|
|
29302
29194
|
dragging
|
|
29303
|
-
} =
|
|
29195
|
+
} = useDraggable({
|
|
29304
29196
|
gestureTarget: line,
|
|
29305
29197
|
point: start,
|
|
29306
29198
|
onMove: newPoint => {
|
|
@@ -29640,7 +29532,7 @@ const StyledMovablePoint = props => {
|
|
|
29640
29532
|
const snapToValue = snapTo != null ? snapTo : "grid";
|
|
29641
29533
|
const {
|
|
29642
29534
|
dragging
|
|
29643
|
-
} =
|
|
29535
|
+
} = useDraggable({
|
|
29644
29536
|
gestureTarget: elementRef,
|
|
29645
29537
|
point,
|
|
29646
29538
|
onMove,
|
|
@@ -29682,7 +29574,7 @@ const PolygonGraph = props => {
|
|
|
29682
29574
|
const snapToValue = snapTo != null ? snapTo : "grid";
|
|
29683
29575
|
const {
|
|
29684
29576
|
dragging
|
|
29685
|
-
} =
|
|
29577
|
+
} = useDraggable({
|
|
29686
29578
|
gestureTarget: ref,
|
|
29687
29579
|
point: dragReferencePoint,
|
|
29688
29580
|
onMove: newPoint => {
|
|
@@ -29845,7 +29737,7 @@ function MovableCircle(props) {
|
|
|
29845
29737
|
const draggableRef = useRef(null);
|
|
29846
29738
|
const {
|
|
29847
29739
|
dragging
|
|
29848
|
-
} =
|
|
29740
|
+
} = useDraggable({
|
|
29849
29741
|
gestureTarget: draggableRef,
|
|
29850
29742
|
point: center,
|
|
29851
29743
|
onMove,
|
|
@@ -29976,10 +29868,24 @@ function SinusoidGraph(props) {
|
|
|
29976
29868
|
coords
|
|
29977
29869
|
} = graphState;
|
|
29978
29870
|
|
|
29979
|
-
//
|
|
29871
|
+
// The coefficients are used to calculate the sinusoid equation, plot the graph, and to indicate
|
|
29872
|
+
// to content creators the currently selected "correct answer" in the Content Editor.
|
|
29873
|
+
// While we should technically never have invalid coordinates, we want to ensure that
|
|
29874
|
+
// we have a fallback so that the graph can still be plotted without crashing.
|
|
29875
|
+
const coeffRef = React.useRef({
|
|
29876
|
+
amplitude: 1,
|
|
29877
|
+
angularFrequency: 1,
|
|
29878
|
+
phase: 1,
|
|
29879
|
+
verticalOffset: 0
|
|
29880
|
+
});
|
|
29980
29881
|
const coeffs = getSinusoidCoefficients(coords);
|
|
29882
|
+
|
|
29883
|
+
// If the coefficients are valid, update the reference
|
|
29884
|
+
if (coeffs !== undefined) {
|
|
29885
|
+
coeffRef.current = coeffs;
|
|
29886
|
+
}
|
|
29981
29887
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Plot$3.OfX, {
|
|
29982
|
-
y: x => computeSine(x,
|
|
29888
|
+
y: x => computeSine(x, coeffRef.current),
|
|
29983
29889
|
color: color.blue
|
|
29984
29890
|
}), coords.map((coord, i) => /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
29985
29891
|
key: "point-" + i,
|
|
@@ -30006,6 +29912,11 @@ const getSinusoidCoefficients = coords => {
|
|
|
30006
29912
|
const p1 = coords[0];
|
|
30007
29913
|
const p2 = coords[1];
|
|
30008
29914
|
|
|
29915
|
+
// If the x-coordinates are the same, we are unable to calculate the coefficients
|
|
29916
|
+
if (p2[0] === p1[0]) {
|
|
29917
|
+
return;
|
|
29918
|
+
}
|
|
29919
|
+
|
|
30009
29920
|
// Resulting coefficients are canonical for this sine curve
|
|
30010
29921
|
const amplitude = p2[1] - p1[1];
|
|
30011
29922
|
const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
|
|
@@ -31284,6 +31195,8 @@ function getCircleCoords(graph) {
|
|
|
31284
31195
|
|
|
31285
31196
|
function interactiveGraphReducer(state, action) {
|
|
31286
31197
|
switch (action.type) {
|
|
31198
|
+
case REINITIALIZE:
|
|
31199
|
+
return initializeGraphState(action.params);
|
|
31287
31200
|
case MOVE_CONTROL_POINT:
|
|
31288
31201
|
return doMoveControlPoint(state, action);
|
|
31289
31202
|
case MOVE_LINE:
|
|
@@ -31477,11 +31390,14 @@ function doMovePoint(state, action) {
|
|
|
31477
31390
|
}
|
|
31478
31391
|
case "sinusoid":
|
|
31479
31392
|
{
|
|
31480
|
-
// First, we need to
|
|
31481
|
-
// If they are, we don't want to move the point
|
|
31393
|
+
// First, we need to make sure to bound the new coordinates to the graph range
|
|
31482
31394
|
const destination = action.destination;
|
|
31395
|
+
const boundDestination = boundAndSnapToGrid(destination, state);
|
|
31396
|
+
|
|
31397
|
+
// Then, we need to verify that the new coordinates are not on the same
|
|
31398
|
+
// vertical line. If they are, then we don't want to move the point
|
|
31483
31399
|
const _newCoords = [...state.coords];
|
|
31484
|
-
_newCoords[action.index] =
|
|
31400
|
+
_newCoords[action.index] = boundDestination;
|
|
31485
31401
|
if (_newCoords[0][0] === _newCoords[1][0]) {
|
|
31486
31402
|
return state;
|
|
31487
31403
|
}
|
|
@@ -31490,7 +31406,7 @@ function doMovePoint(state, action) {
|
|
|
31490
31406
|
coords: setAtIndex({
|
|
31491
31407
|
array: state.coords,
|
|
31492
31408
|
index: action.index,
|
|
31493
|
-
newValue:
|
|
31409
|
+
newValue: boundDestination
|
|
31494
31410
|
})
|
|
31495
31411
|
});
|
|
31496
31412
|
}
|
|
@@ -31498,7 +31414,10 @@ function doMovePoint(state, action) {
|
|
|
31498
31414
|
{
|
|
31499
31415
|
// Set up the new coords and check if the quadratic coefficients are valid
|
|
31500
31416
|
const _newCoords2 = [...state.coords];
|
|
31501
|
-
|
|
31417
|
+
|
|
31418
|
+
// Bind the new destination to the graph range/snapStep and then get the quadratic coefficients
|
|
31419
|
+
const boundDestination = boundAndSnapToGrid(action.destination, state);
|
|
31420
|
+
_newCoords2[action.index] = boundDestination;
|
|
31502
31421
|
const QuadraticCoefficients = getQuadraticCoefficients(_newCoords2);
|
|
31503
31422
|
|
|
31504
31423
|
// If the new destination results in an invalid quadratic equation, we don't want to move the point
|
|
@@ -31510,7 +31429,7 @@ function doMovePoint(state, action) {
|
|
|
31510
31429
|
coords: setAtIndex({
|
|
31511
31430
|
array: state.coords,
|
|
31512
31431
|
index: action.index,
|
|
31513
|
-
newValue:
|
|
31432
|
+
newValue: boundDestination
|
|
31514
31433
|
})
|
|
31515
31434
|
});
|
|
31516
31435
|
}
|
|
@@ -31908,11 +31827,12 @@ function mafsStateToInteractiveGraph(state) {
|
|
|
31908
31827
|
}
|
|
31909
31828
|
const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
31910
31829
|
const {
|
|
31911
|
-
onChange
|
|
31830
|
+
onChange,
|
|
31831
|
+
graph
|
|
31912
31832
|
} = props;
|
|
31913
31833
|
const [state, dispatch] = React.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
31914
31834
|
useImperativeHandle(ref, () => ({
|
|
31915
|
-
getUserInput: () => getGradableGraph(state,
|
|
31835
|
+
getUserInput: () => getGradableGraph(state, graph)
|
|
31916
31836
|
}));
|
|
31917
31837
|
const prevState = useRef(state);
|
|
31918
31838
|
useEffect(() => {
|
|
@@ -31935,6 +31855,18 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
31935
31855
|
useEffect(() => {
|
|
31936
31856
|
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
31937
31857
|
}, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
31858
|
+
const numSegments = graph.type === "segment" ? graph.numSegments : null;
|
|
31859
|
+
const originalPropsRef = useRef(props);
|
|
31860
|
+
const latestPropsRef = useLatestRef(props);
|
|
31861
|
+
useEffect(() => {
|
|
31862
|
+
// This conditional prevents the state from being "reinitialized" right
|
|
31863
|
+
// after the first render. This is an optimization, but also prevents
|
|
31864
|
+
// a bug where the graph would be marked "incorrect" during grading
|
|
31865
|
+
// even if the user never interacted with it.
|
|
31866
|
+
if (latestPropsRef.current !== originalPropsRef.current) {
|
|
31867
|
+
dispatch(reinitialize(latestPropsRef.current));
|
|
31868
|
+
}
|
|
31869
|
+
}, [graph.type, numSegments, latestPropsRef]);
|
|
31938
31870
|
return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, props, {
|
|
31939
31871
|
state: state,
|
|
31940
31872
|
dispatch: dispatch
|
|
@@ -33309,6 +33241,12 @@ class InteractiveGraph extends React.Component {
|
|
|
33309
33241
|
}
|
|
33310
33242
|
render() {
|
|
33311
33243
|
var _this$props$apiOption;
|
|
33244
|
+
if (this.props.graph.type === "polygon" && this.props.graph.numSides === "unlimited") {
|
|
33245
|
+
return /*#__PURE__*/React.createElement(LegacyInteractiveGraph, _extends({
|
|
33246
|
+
ref: this.legacyGraphRef
|
|
33247
|
+
}, this.props));
|
|
33248
|
+
}
|
|
33249
|
+
|
|
33312
33250
|
// Mafs shim
|
|
33313
33251
|
if ((_this$props$apiOption = this.props.apiOptions) != null && (_this$props$apiOption = _this$props$apiOption.flags) != null && (_this$props$apiOption = _this$props$apiOption["mafs"]) != null && _this$props$apiOption[this.props.graph.type]) {
|
|
33314
33252
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
@@ -44101,7 +44039,7 @@ const init = function init(options) {
|
|
|
44101
44039
|
|
|
44102
44040
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44103
44041
|
const libName = "@khanacademy/perseus";
|
|
44104
|
-
const libVersion = "23.
|
|
44042
|
+
const libVersion = "23.6.0";
|
|
44105
44043
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44106
44044
|
|
|
44107
44045
|
const apiVersion = {
|
|
@@ -47102,5 +47040,5 @@ const EditorJsonify = {
|
|
|
47102
47040
|
}
|
|
47103
47041
|
};
|
|
47104
47042
|
|
|
47105
|
-
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion,
|
|
47043
|
+
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
47106
47044
|
//# sourceMappingURL=index.js.map
|