@khanacademy/perseus 30.0.1 → 31.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 +611 -231
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +6 -2
- package/dist/es/strings.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +623 -235
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +2 -0
- package/dist/perseus-types.d.ts +17 -3
- package/dist/server-item-renderer.d.ts +2 -0
- package/dist/strings.d.ts +2 -0
- package/dist/strings.js +6 -2
- package/dist/strings.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/util/widget-enum-utils.d.ts +1 -1
- package/dist/widgets/expression.d.ts +12 -0
- package/dist/widgets/interactive-graphs/graph-locked-labels-layer.d.ts +7 -0
- package/dist/widgets/interactive-graphs/graphs/point.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/use-transform.d.ts +2 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +4 -0
- package/dist/widgets/interactive-graphs/locked-figures/locked-label.d.ts +3 -0
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +8 -1
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/types.d.ts +1 -0
- package/dist/widgets/label-image.d.ts +4 -0
- package/dist/widgets/phet-simulation.d.ts +61 -0
- package/package.json +3 -1
package/dist/es/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import ReactDOM__default from 'react-dom';
|
|
|
15
15
|
import _, { debounce as debounce$1 } from 'underscore';
|
|
16
16
|
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
17
17
|
import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
|
|
18
|
-
import { color, spacing } from '@khanacademy/wonder-blocks-tokens';
|
|
18
|
+
import { color, spacing, font } from '@khanacademy/wonder-blocks-tokens';
|
|
19
19
|
import $ from 'jquery';
|
|
20
20
|
import { v4 } from 'uuid';
|
|
21
21
|
import PropTypes from 'prop-types';
|
|
@@ -40,6 +40,8 @@ import Switch from '@khanacademy/wonder-blocks-switch';
|
|
|
40
40
|
import Pill from '@khanacademy/wonder-blocks-pill';
|
|
41
41
|
import { Popper } from 'react-popper';
|
|
42
42
|
import createReactClass from 'create-react-class';
|
|
43
|
+
import IconButton from '@khanacademy/wonder-blocks-icon-button';
|
|
44
|
+
import cornersOutIcon from '@phosphor-icons/core/regular/corners-out.svg';
|
|
43
45
|
import Link from '@khanacademy/wonder-blocks-link';
|
|
44
46
|
|
|
45
47
|
function _extends() {
|
|
@@ -250,7 +252,9 @@ const mockStrings = {
|
|
|
250
252
|
mathInputDescription: "Use keyboard/mouse to interact with math-based input fields",
|
|
251
253
|
sin: "sin",
|
|
252
254
|
cos: "cos",
|
|
253
|
-
tan: "tan"
|
|
255
|
+
tan: "tan",
|
|
256
|
+
simulationLoadFail: "Sorry, this simulation cannot load.",
|
|
257
|
+
simulationLocaleWarning: "Sorry, this simulation isn't available in your language."
|
|
254
258
|
};
|
|
255
259
|
|
|
256
260
|
/**
|
|
@@ -503,7 +507,7 @@ class InnerMathInput extends React.Component {
|
|
|
503
507
|
className = className + " " + this.props.className;
|
|
504
508
|
}
|
|
505
509
|
return /*#__PURE__*/React.createElement(View, {
|
|
506
|
-
style: [styles$
|
|
510
|
+
style: [styles$E.outerWrapper, this.state.focused && styles$E.wrapperFocused, this.props.hasError && styles$E.wrapperError]
|
|
507
511
|
}, /*#__PURE__*/React.createElement("div", {
|
|
508
512
|
style: {
|
|
509
513
|
display: "flex",
|
|
@@ -540,7 +544,7 @@ class InnerMathInput extends React.Component {
|
|
|
540
544
|
style: a11y.srOnly
|
|
541
545
|
}, this.context.strings.mathInputDescription), /*#__PURE__*/React.createElement(PopoverContentCore, {
|
|
542
546
|
closeButtonVisible: true,
|
|
543
|
-
style: styles$
|
|
547
|
+
style: styles$E.popoverContent
|
|
544
548
|
}, /*#__PURE__*/React.createElement(DesktopKeypad, _extends({
|
|
545
549
|
onAnalyticsEvent: this.props.analytics.onAnalyticsEvent,
|
|
546
550
|
extraKeys: this.props.extraKeys,
|
|
@@ -616,9 +620,9 @@ const MathInputIcon = ({
|
|
|
616
620
|
fillColor = color.offBlack;
|
|
617
621
|
break;
|
|
618
622
|
}
|
|
619
|
-
const dynamicClass = active || focused ? styles$
|
|
623
|
+
const dynamicClass = active || focused ? styles$E.iconActive : styles$E.iconInactive;
|
|
620
624
|
return /*#__PURE__*/React.createElement(View, {
|
|
621
|
-
style: [styles$
|
|
625
|
+
style: [styles$E.iconContainer, dynamicClass]
|
|
622
626
|
}, /*#__PURE__*/React.createElement("svg", {
|
|
623
627
|
xmlns: "http://www.w3.org/2000/svg",
|
|
624
628
|
width: "16",
|
|
@@ -663,7 +667,7 @@ const inputFocused = {
|
|
|
663
667
|
borderColor: color.blue,
|
|
664
668
|
margin: -1
|
|
665
669
|
};
|
|
666
|
-
const styles$
|
|
670
|
+
const styles$E = StyleSheet.create({
|
|
667
671
|
iconContainer: {
|
|
668
672
|
display: "flex",
|
|
669
673
|
justifyContent: "center",
|
|
@@ -2489,7 +2493,7 @@ class Expression extends React.Component {
|
|
|
2489
2493
|
var _this$props$keypadCon, _this$props$analytics3;
|
|
2490
2494
|
if (this.props.apiOptions.customKeypad) {
|
|
2491
2495
|
return /*#__PURE__*/React.createElement(View, {
|
|
2492
|
-
className: css(styles$
|
|
2496
|
+
className: css(styles$D.mobileLabelInputWrapper)
|
|
2493
2497
|
}, !!this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelSmall, {
|
|
2494
2498
|
htmlFor: this._textareaId,
|
|
2495
2499
|
tag: "label"
|
|
@@ -2524,7 +2528,7 @@ class Expression extends React.Component {
|
|
|
2524
2528
|
ERROR_TITLE
|
|
2525
2529
|
} = this.context.strings;
|
|
2526
2530
|
return /*#__PURE__*/React.createElement(View, {
|
|
2527
|
-
className: css(styles$
|
|
2531
|
+
className: css(styles$D.desktopLabelInputWrapper)
|
|
2528
2532
|
}, !!this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelSmall, {
|
|
2529
2533
|
htmlFor: this._textareaId,
|
|
2530
2534
|
tag: "label"
|
|
@@ -2576,7 +2580,7 @@ Expression.defaultProps = {
|
|
|
2576
2580
|
apiOptions: ApiOptions.defaults,
|
|
2577
2581
|
linterContext: linterContextDefault
|
|
2578
2582
|
};
|
|
2579
|
-
const styles$
|
|
2583
|
+
const styles$D = StyleSheet.create({
|
|
2580
2584
|
mobileLabelInputWrapper: {
|
|
2581
2585
|
padding: "15px 4px 0"
|
|
2582
2586
|
},
|
|
@@ -18199,33 +18203,33 @@ class Lint extends React.Component {
|
|
|
18199
18203
|
let warningText;
|
|
18200
18204
|
let warningTextStyle;
|
|
18201
18205
|
if (this.props.severity === Severity.Error) {
|
|
18202
|
-
severityStyle = styles$
|
|
18206
|
+
severityStyle = styles$C.indicatorError;
|
|
18203
18207
|
warningText = "Error";
|
|
18204
|
-
warningTextStyle = styles$
|
|
18208
|
+
warningTextStyle = styles$C.publishBlockingError;
|
|
18205
18209
|
} else if (this.props.severity === Severity.Warning) {
|
|
18206
|
-
severityStyle = styles$
|
|
18210
|
+
severityStyle = styles$C.indicatorWarning;
|
|
18207
18211
|
warningText = "Warning";
|
|
18208
|
-
warningTextStyle = styles$
|
|
18212
|
+
warningTextStyle = styles$C.warning;
|
|
18209
18213
|
} else {
|
|
18210
|
-
severityStyle = styles$
|
|
18214
|
+
severityStyle = styles$C.indicatorGuideline;
|
|
18211
18215
|
warningText = "Recommendation";
|
|
18212
|
-
warningTextStyle = styles$
|
|
18216
|
+
warningTextStyle = styles$C.warning;
|
|
18213
18217
|
}
|
|
18214
18218
|
return /*#__PURE__*/React.createElement("a", {
|
|
18215
18219
|
href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
|
|
18216
18220
|
target: "lint-help-window",
|
|
18217
18221
|
className: css(style)
|
|
18218
18222
|
}, /*#__PURE__*/React.createElement("span", {
|
|
18219
|
-
className: css(styles$
|
|
18223
|
+
className: css(styles$C.indicator, severityStyle)
|
|
18220
18224
|
}, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React.createElement("div", {
|
|
18221
|
-
className: css(styles$
|
|
18225
|
+
className: css(styles$C.tooltip, tooltipAbove && styles$C.tooltipAbove)
|
|
18222
18226
|
}, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
|
|
18223
18227
|
key: i,
|
|
18224
|
-
className: css(styles$
|
|
18228
|
+
className: css(styles$C.tooltipParagraph)
|
|
18225
18229
|
}, /*#__PURE__*/React.createElement("span", {
|
|
18226
18230
|
className: css(warningTextStyle)
|
|
18227
18231
|
}, warningText, ":", " "), m)), /*#__PURE__*/React.createElement("div", {
|
|
18228
|
-
className: css(styles$
|
|
18232
|
+
className: css(styles$C.tail, tooltipAbove && styles$C.tailAbove)
|
|
18229
18233
|
})));
|
|
18230
18234
|
};
|
|
18231
18235
|
}
|
|
@@ -18263,20 +18267,20 @@ class Lint extends React.Component {
|
|
|
18263
18267
|
}
|
|
18264
18268
|
if (blockHighlight) {
|
|
18265
18269
|
return /*#__PURE__*/React.createElement("span", {
|
|
18266
|
-
className: css(styles$
|
|
18267
|
-
}, this.renderLink(styles$
|
|
18270
|
+
className: css(styles$C.lintContainer, styles$C.lintContainerBlock)
|
|
18271
|
+
}, this.renderLink(styles$C.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
|
|
18268
18272
|
}
|
|
18269
18273
|
if (inline) {
|
|
18270
18274
|
return /*#__PURE__*/React.createElement("span", {
|
|
18271
|
-
className: css(styles$
|
|
18272
|
-
}, this.renderLink(styles$
|
|
18275
|
+
className: css(styles$C.lintContainer)
|
|
18276
|
+
}, this.renderLink(styles$C.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
|
|
18273
18277
|
}
|
|
18274
18278
|
return /*#__PURE__*/React.createElement("div", {
|
|
18275
|
-
className: css(styles$
|
|
18276
|
-
}, this.renderLink(styles$
|
|
18279
|
+
className: css(styles$C.lintContainer)
|
|
18280
|
+
}, this.renderLink(styles$C.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
|
|
18277
18281
|
}
|
|
18278
18282
|
}
|
|
18279
|
-
const styles$
|
|
18283
|
+
const styles$C = StyleSheet.create({
|
|
18280
18284
|
// This is the class of the outermost element.
|
|
18281
18285
|
// We use relative positioning so that the lint indicator can be
|
|
18282
18286
|
// positioned absolutely relative to the position of the linty container.
|
|
@@ -20210,7 +20214,7 @@ class Renderer extends React.Component {
|
|
|
20210
20214
|
paddingLeft: margin,
|
|
20211
20215
|
paddingRight: margin
|
|
20212
20216
|
};
|
|
20213
|
-
const mobileInnerStyle = _extends({}, innerStyle, styles$
|
|
20217
|
+
const mobileInnerStyle = _extends({}, innerStyle, styles$B.mobileZoomableParentFix);
|
|
20214
20218
|
return /*#__PURE__*/React.createElement("div", {
|
|
20215
20219
|
key: state.key,
|
|
20216
20220
|
className: "perseus-block-math",
|
|
@@ -20334,7 +20338,7 @@ class Renderer extends React.Component {
|
|
|
20334
20338
|
paddingLeft: 0,
|
|
20335
20339
|
paddingRight: 0
|
|
20336
20340
|
};
|
|
20337
|
-
const mobileInnerStyle = _extends({}, innerStyle, styles$
|
|
20341
|
+
const mobileInnerStyle = _extends({}, innerStyle, styles$B.mobileZoomableParentFix);
|
|
20338
20342
|
const wrappedOutput = /*#__PURE__*/React.createElement("div", {
|
|
20339
20343
|
style: _extends({}, mobileInnerStyle, {
|
|
20340
20344
|
overflowX: "auto"
|
|
@@ -20982,7 +20986,7 @@ Renderer.defaultProps = {
|
|
|
20982
20986
|
onSerializedStateUpdated: () => {},
|
|
20983
20987
|
linterContext: PerseusLinter.linterContextDefault
|
|
20984
20988
|
};
|
|
20985
|
-
const styles$
|
|
20989
|
+
const styles$B = {
|
|
20986
20990
|
mobileZoomableParentFix: {
|
|
20987
20991
|
// NOTE(abdul): There is an issue where transform animations will
|
|
20988
20992
|
// cause the Zoomable component to disappear when running on the
|
|
@@ -21852,10 +21856,10 @@ class InputNumber extends React.Component {
|
|
|
21852
21856
|
// Note: This is _very_ similar to what `numeric-input.jsx` does. If
|
|
21853
21857
|
// you modify this, double-check if you also need to modify that
|
|
21854
21858
|
// component.
|
|
21855
|
-
const inputStyles = [styles$
|
|
21859
|
+
const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
|
|
21856
21860
|
// Unanswered
|
|
21857
21861
|
if (rubric && !this.props.currentValue) {
|
|
21858
|
-
inputStyles.push(styles$
|
|
21862
|
+
inputStyles.push(styles$A.answerStateUnanswered);
|
|
21859
21863
|
}
|
|
21860
21864
|
return /*#__PURE__*/React.createElement(InputWithExamples
|
|
21861
21865
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -21940,7 +21944,7 @@ InputNumber.defaultProps = {
|
|
|
21940
21944
|
apiOptions: ApiOptions.defaults,
|
|
21941
21945
|
linterContext: linterContextDefault
|
|
21942
21946
|
};
|
|
21943
|
-
const styles$
|
|
21947
|
+
const styles$A = StyleSheet.create({
|
|
21944
21948
|
default: {
|
|
21945
21949
|
width: 80,
|
|
21946
21950
|
height: "auto"
|
|
@@ -22935,7 +22939,7 @@ const FocusRing = function FocusRing(props) {
|
|
|
22935
22939
|
};
|
|
22936
22940
|
return /*#__PURE__*/React.createElement("span", {
|
|
22937
22941
|
"data-testid": "focus-ring",
|
|
22938
|
-
className: css(styles$
|
|
22942
|
+
className: css(styles$z.ring),
|
|
22939
22943
|
style: style
|
|
22940
22944
|
}, children);
|
|
22941
22945
|
};
|
|
@@ -22944,7 +22948,7 @@ FocusRing.defaultProps = {
|
|
|
22944
22948
|
color: kaGreen$1,
|
|
22945
22949
|
multipleSelect: false
|
|
22946
22950
|
};
|
|
22947
|
-
const styles$
|
|
22951
|
+
const styles$z = StyleSheet.create({
|
|
22948
22952
|
ring: {
|
|
22949
22953
|
margin: "auto",
|
|
22950
22954
|
display: "inline-block",
|
|
@@ -22971,7 +22975,7 @@ function getChoiceLetter(pos, strings) {
|
|
|
22971
22975
|
}
|
|
22972
22976
|
|
|
22973
22977
|
const CHOICE_ICON_SIZE = 24;
|
|
22974
|
-
const styles$
|
|
22978
|
+
const styles$y = StyleSheet.create({
|
|
22975
22979
|
iconWrapper: {
|
|
22976
22980
|
display: "inline-block",
|
|
22977
22981
|
position: "relative"
|
|
@@ -22994,7 +22998,7 @@ const CrossOutLine = function CrossOutLine(props) {
|
|
|
22994
22998
|
width: CROSS_OUT_LINE_SIZE,
|
|
22995
22999
|
height: CROSS_OUT_LINE_SIZE,
|
|
22996
23000
|
viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
|
|
22997
|
-
className: css(styles$
|
|
23001
|
+
className: css(styles$x.crossOutLine),
|
|
22998
23002
|
"data-testid": "choice-icon__cross-out-line"
|
|
22999
23003
|
}, /*#__PURE__*/React.createElement("line", {
|
|
23000
23004
|
// The line stretches from the bottom-left to top-right.
|
|
@@ -23009,7 +23013,7 @@ const CrossOutLine = function CrossOutLine(props) {
|
|
|
23009
23013
|
strokeLinecap: "round"
|
|
23010
23014
|
}));
|
|
23011
23015
|
};
|
|
23012
|
-
const styles$
|
|
23016
|
+
const styles$x = StyleSheet.create({
|
|
23013
23017
|
crossOutLine: {
|
|
23014
23018
|
// Center the icon within the container.
|
|
23015
23019
|
position: "absolute",
|
|
@@ -23093,7 +23097,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
|
|
|
23093
23097
|
} = props;
|
|
23094
23098
|
const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
|
|
23095
23099
|
return /*#__PURE__*/React.createElement("div", {
|
|
23096
|
-
className: css(styles$
|
|
23100
|
+
className: css(styles$y.iconWrapper)
|
|
23097
23101
|
}, /*#__PURE__*/React.createElement(FocusRing, {
|
|
23098
23102
|
color: color.blue,
|
|
23099
23103
|
visible: focused || hovered,
|
|
@@ -23102,13 +23106,13 @@ const ChoiceIcon = function ChoiceIcon(props) {
|
|
|
23102
23106
|
// @ts-expect-error - TS2322 - Type '{ backgroundColor: string | null | undefined; borderColor: string; color: string; borderRadius: number; }' is not assignable to type 'Properties<string | number, string & {}>'.
|
|
23103
23107
|
style: dynamicStyles,
|
|
23104
23108
|
"data-testid": "choice-icon__library-choice-icon",
|
|
23105
|
-
className: css(styles$
|
|
23109
|
+
className: css(styles$w.circle, showCorrectness && correct && styles$w.circleCorrect, showCorrectness && !correct && styles$w.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$w.circleIncorrectAnswered)
|
|
23106
23110
|
// used in BaseRadio editMode to check
|
|
23107
23111
|
// if we actually clicked on the radio icon
|
|
23108
23112
|
,
|
|
23109
23113
|
"data-is-radio-icon": true
|
|
23110
23114
|
}, /*#__PURE__*/React.createElement("div", {
|
|
23111
|
-
className: css(styles$
|
|
23115
|
+
className: css(styles$w.innerWrapper)
|
|
23112
23116
|
}, /*#__PURE__*/React.createElement(ChoiceInner, {
|
|
23113
23117
|
pos: pos,
|
|
23114
23118
|
showCorrectness: showCorrectness,
|
|
@@ -23117,7 +23121,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
|
|
|
23117
23121
|
color: dynamicStyles.borderColor
|
|
23118
23122
|
}));
|
|
23119
23123
|
};
|
|
23120
|
-
const styles$
|
|
23124
|
+
const styles$w = StyleSheet.create({
|
|
23121
23125
|
innerWrapper: {
|
|
23122
23126
|
width: CHOICE_ICON_SIZE,
|
|
23123
23127
|
height: CHOICE_ICON_SIZE,
|
|
@@ -23212,19 +23216,19 @@ const OptionStatus = function OptionStatus(props) {
|
|
|
23212
23216
|
}
|
|
23213
23217
|
let textStyle;
|
|
23214
23218
|
if (correct) {
|
|
23215
|
-
textStyle = styles$
|
|
23219
|
+
textStyle = styles$v.correct;
|
|
23216
23220
|
} else {
|
|
23217
23221
|
if (checked || previouslyAnswered) {
|
|
23218
|
-
textStyle = styles$
|
|
23222
|
+
textStyle = styles$v.incorrectAnswered;
|
|
23219
23223
|
} else {
|
|
23220
|
-
textStyle = styles$
|
|
23224
|
+
textStyle = styles$v.incorrect;
|
|
23221
23225
|
}
|
|
23222
23226
|
}
|
|
23223
23227
|
return /*#__PURE__*/React.createElement("div", {
|
|
23224
|
-
className: css(styles$
|
|
23228
|
+
className: css(styles$v.text, textStyle)
|
|
23225
23229
|
}, renderText(checked, correct, crossedOut, strings));
|
|
23226
23230
|
};
|
|
23227
|
-
const styles$
|
|
23231
|
+
const styles$v = StyleSheet.create({
|
|
23228
23232
|
text: {
|
|
23229
23233
|
alignItems: "center",
|
|
23230
23234
|
display: "flex",
|
|
@@ -23294,8 +23298,8 @@ const Choice = function Choice(props) {
|
|
|
23294
23298
|
crossedOut: updatedCrossedOut
|
|
23295
23299
|
});
|
|
23296
23300
|
}
|
|
23297
|
-
const descriptionClassName = classNames("description", css(styles$
|
|
23298
|
-
const rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$
|
|
23301
|
+
const descriptionClassName = classNames("description", css(styles$u.description));
|
|
23302
|
+
const rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$u.rationale));
|
|
23299
23303
|
|
|
23300
23304
|
// We want to show the choices as dimmed out when the choices are disabled.
|
|
23301
23305
|
// However, we don't want to do this when we're in review mode in the
|
|
@@ -23455,7 +23459,7 @@ const Choice = function Choice(props) {
|
|
|
23455
23459
|
"data-testid": `perseus-radio-rationale-content-${pos}`
|
|
23456
23460
|
}, rationale));
|
|
23457
23461
|
};
|
|
23458
|
-
const styles$
|
|
23462
|
+
const styles$u = StyleSheet.create({
|
|
23459
23463
|
description: {
|
|
23460
23464
|
display: "inline-block",
|
|
23461
23465
|
width: "100%"
|
|
@@ -23654,10 +23658,10 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23654
23658
|
const isMobile = apiOptions.isMobile;
|
|
23655
23659
|
const firstChoiceHighlighted = choices[0].highlighted;
|
|
23656
23660
|
const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
23657
|
-
const className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$
|
|
23658
|
-
const instructionsClassName = classNames("instructions", css(styles$
|
|
23661
|
+
const className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$t.radio, styles$t.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$t.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$t.radioContainerLastHighlighted));
|
|
23662
|
+
const instructionsClassName = classNames("instructions", css(styles$t.instructions, isMobile && styles$t.instructionsMobile));
|
|
23659
23663
|
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
|
|
23660
|
-
const responsiveClassName = css(styles$
|
|
23664
|
+
const responsiveClassName = css(styles$t.responsiveFieldset);
|
|
23661
23665
|
const fieldset = /*#__PURE__*/React.createElement("fieldset", {
|
|
23662
23666
|
className: `perseus-widget-radio-fieldset ${responsiveClassName}`
|
|
23663
23667
|
}, /*#__PURE__*/React.createElement("legend", {
|
|
@@ -23708,7 +23712,7 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23708
23712
|
const aphroditeClassName = checked => {
|
|
23709
23713
|
// Whether or not to show correctness borders
|
|
23710
23714
|
// for this choice and the next choice.
|
|
23711
|
-
return css(sharedStyles.aboveScratchpad, styles$
|
|
23715
|
+
return css(sharedStyles.aboveScratchpad, styles$t.item, styles$t.responsiveItem, checked && styles$t.selectedItem, checked && choice.highlighted && styles$t.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$t.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$t.nextHighlighted);
|
|
23712
23716
|
};
|
|
23713
23717
|
|
|
23714
23718
|
// HACK(abdulrahman): Preloads the selection-state
|
|
@@ -23782,14 +23786,14 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23782
23786
|
// Allow for horizontal scrolling if content is too wide, which may be
|
|
23783
23787
|
// an issue especially on phones.
|
|
23784
23788
|
return /*#__PURE__*/React.createElement("div", {
|
|
23785
|
-
className: css(styles$
|
|
23789
|
+
className: css(styles$t.responsiveContainer)
|
|
23786
23790
|
}, fieldset);
|
|
23787
23791
|
};
|
|
23788
23792
|
BaseRadio.defaultProps = {
|
|
23789
23793
|
editMode: false,
|
|
23790
23794
|
multipleSelect: false
|
|
23791
23795
|
};
|
|
23792
|
-
const styles$
|
|
23796
|
+
const styles$t = StyleSheet.create({
|
|
23793
23797
|
instructions: {
|
|
23794
23798
|
display: "block",
|
|
23795
23799
|
color: gray17,
|
|
@@ -24451,9 +24455,9 @@ class Categorizer extends React.Component {
|
|
|
24451
24455
|
indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
|
|
24452
24456
|
}
|
|
24453
24457
|
const table = /*#__PURE__*/React.createElement("table", {
|
|
24454
|
-
className: "categorizer-table " + css(styles$
|
|
24458
|
+
className: "categorizer-table " + css(styles$s.mobileTable)
|
|
24455
24459
|
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
|
|
24456
|
-
className: css(styles$
|
|
24460
|
+
className: css(styles$s.emptyHeaderCell)
|
|
24457
24461
|
}), this.props.categories.map((category, i) => {
|
|
24458
24462
|
// Array index is the correct key here, as that's
|
|
24459
24463
|
// how category grading actually works -- no way
|
|
@@ -24461,7 +24465,7 @@ class Categorizer extends React.Component {
|
|
|
24461
24465
|
// middle. (If we later add that, this should be
|
|
24462
24466
|
// fixed.)
|
|
24463
24467
|
return /*#__PURE__*/React.createElement("th", {
|
|
24464
|
-
className: css(styles$
|
|
24468
|
+
className: css(styles$s.header),
|
|
24465
24469
|
key: i
|
|
24466
24470
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
24467
24471
|
content: category,
|
|
@@ -24483,7 +24487,7 @@ class Categorizer extends React.Component {
|
|
|
24483
24487
|
})), self.props.categories.map((catName, catNum) => {
|
|
24484
24488
|
const selected = self.props.values[itemNum] === catNum;
|
|
24485
24489
|
return /*#__PURE__*/React.createElement("td", {
|
|
24486
|
-
className: "category " + css(styles$
|
|
24490
|
+
className: "category " + css(styles$s.cell),
|
|
24487
24491
|
key: catNum
|
|
24488
24492
|
}, /*#__PURE__*/React.createElement("div", {
|
|
24489
24493
|
className: ClassNames.INTERACTIVE,
|
|
@@ -24498,7 +24502,7 @@ class Categorizer extends React.Component {
|
|
|
24498
24502
|
onChange: () => this.onChange(itemNum, catNum),
|
|
24499
24503
|
onClick: e => e.stopPropagation()
|
|
24500
24504
|
}), !isMobile && /*#__PURE__*/React.createElement("span", {
|
|
24501
|
-
className: css(styles$
|
|
24505
|
+
className: css(styles$s.radioSpan, selected && styles$s.checkedRadioSpan, this.props.static && selected && styles$s.staticCheckedRadioSpan)
|
|
24502
24506
|
}, selected ? /*#__PURE__*/React.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React.createElement(InlineIcon, iconCircleThin))));
|
|
24503
24507
|
}));
|
|
24504
24508
|
/* eslint-enable max-len */
|
|
@@ -24510,7 +24514,7 @@ class Categorizer extends React.Component {
|
|
|
24510
24514
|
"categorizer-container": true,
|
|
24511
24515
|
"static-mode": this.props.static
|
|
24512
24516
|
});
|
|
24513
|
-
const inlineStyles = this.props.apiOptions.isMobile ? [styles$
|
|
24517
|
+
const inlineStyles = this.props.apiOptions.isMobile ? [styles$s.fullBleedContainer] : [];
|
|
24514
24518
|
return /*#__PURE__*/React.createElement("div", {
|
|
24515
24519
|
className: extraClassNames + " " + css(...inlineStyles)
|
|
24516
24520
|
}, table);
|
|
@@ -24563,7 +24567,7 @@ const pageMargin = 16;
|
|
|
24563
24567
|
|
|
24564
24568
|
// Stylesheets aren't directly testable
|
|
24565
24569
|
/* c8 ignore next */
|
|
24566
|
-
const styles$
|
|
24570
|
+
const styles$s = StyleSheet.create({
|
|
24567
24571
|
mobileTable: {
|
|
24568
24572
|
[mediaQueries.smOrSmaller]: {
|
|
24569
24573
|
minWidth: "auto"
|
|
@@ -24799,7 +24803,7 @@ class CSProgram extends React.Component {
|
|
|
24799
24803
|
// creator "went wild".
|
|
24800
24804
|
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
24801
24805
|
return /*#__PURE__*/React.createElement("div", {
|
|
24802
|
-
className: css(styles$
|
|
24806
|
+
className: css(styles$r.widthOverride, styleContainer && styles$r.container)
|
|
24803
24807
|
}, /*#__PURE__*/React.createElement("iframe", {
|
|
24804
24808
|
sandbox: sandboxOptions,
|
|
24805
24809
|
src: url,
|
|
@@ -24828,7 +24832,7 @@ CSProgram.defaultProps = {
|
|
|
24828
24832
|
// optional message
|
|
24829
24833
|
message: null
|
|
24830
24834
|
};
|
|
24831
|
-
const styles$
|
|
24835
|
+
const styles$r = StyleSheet.create({
|
|
24832
24836
|
// Override the inherited width from the perseus paragraph class
|
|
24833
24837
|
// 820 is minimum width for 420px editor and 400px canvas
|
|
24834
24838
|
widthOverride: {
|
|
@@ -24871,7 +24875,7 @@ class Definition extends React.Component {
|
|
|
24871
24875
|
}) => /*#__PURE__*/React.createElement(Popover, {
|
|
24872
24876
|
content: /*#__PURE__*/React.createElement(PopoverContentCore, {
|
|
24873
24877
|
color: "white",
|
|
24874
|
-
style: styles$
|
|
24878
|
+
style: styles$q.tooltipBody,
|
|
24875
24879
|
closeButtonVisible: true
|
|
24876
24880
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
24877
24881
|
apiOptions: this.props.apiOptions,
|
|
@@ -24904,7 +24908,7 @@ Definition.defaultProps = {
|
|
|
24904
24908
|
togglePrompt: "define me",
|
|
24905
24909
|
definition: "definition goes here"
|
|
24906
24910
|
};
|
|
24907
|
-
const styles$
|
|
24911
|
+
const styles$q = {
|
|
24908
24912
|
tooltipBody: {
|
|
24909
24913
|
color: color.offBlack,
|
|
24910
24914
|
fontSize: 20,
|
|
@@ -25132,7 +25136,7 @@ class Explanation extends React.Component {
|
|
|
25132
25136
|
marginRight: "-6px",
|
|
25133
25137
|
"white-space": "normal"
|
|
25134
25138
|
};
|
|
25135
|
-
const contentStyling = [styles$
|
|
25139
|
+
const contentStyling = [styles$p.content, this.state.expanded ? styles$p.contentExpanded : styles$p.contentCollapsed, allowTransition && (this.state.expanded ? styles$p.transitionExpanded : styles$p.transitionCollapsed)];
|
|
25136
25140
|
return /*#__PURE__*/React.createElement(UniqueIDProvider, {
|
|
25137
25141
|
mockOnFirstRender: true,
|
|
25138
25142
|
scope: "explanation-widget"
|
|
@@ -25151,7 +25155,7 @@ class Explanation extends React.Component {
|
|
|
25151
25155
|
"aria-hidden": !this.state.expanded,
|
|
25152
25156
|
testId: "content-container"
|
|
25153
25157
|
}, /*#__PURE__*/React.createElement(View, {
|
|
25154
|
-
style: styles$
|
|
25158
|
+
style: styles$p.contentWrapper
|
|
25155
25159
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
25156
25160
|
apiOptions: this.props.apiOptions,
|
|
25157
25161
|
content: this.props.explanation,
|
|
@@ -25172,7 +25176,7 @@ Explanation.defaultProps = {
|
|
|
25172
25176
|
const leftBorderSpacing = 23;
|
|
25173
25177
|
const verticalContentPadding = 10;
|
|
25174
25178
|
const arrowHeight = 14;
|
|
25175
|
-
const styles$
|
|
25179
|
+
const styles$p = StyleSheet.create({
|
|
25176
25180
|
content: {
|
|
25177
25181
|
borderLeft: "0px solid #ccc",
|
|
25178
25182
|
display: "inline-grid",
|
|
@@ -25236,15 +25240,15 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25236
25240
|
correctExcited,
|
|
25237
25241
|
nextQuestion
|
|
25238
25242
|
} = this.context.strings;
|
|
25239
|
-
const answerBarStyle = _extends({}, styles$
|
|
25243
|
+
const answerBarStyle = _extends({}, styles$o.answerBar, {
|
|
25240
25244
|
backgroundColor: answerBarState === "CORRECT" ? color.offWhite : "white",
|
|
25241
25245
|
// Center the "Correct!" message only when there's no next question
|
|
25242
25246
|
justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
|
|
25243
25247
|
});
|
|
25244
25248
|
const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React.createElement("span", {
|
|
25245
|
-
style: styles$
|
|
25249
|
+
style: styles$o.text
|
|
25246
25250
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25247
|
-
style: styles$
|
|
25251
|
+
style: styles$o.tryAgainIcon
|
|
25248
25252
|
}, /*#__PURE__*/React.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React.createElement("span", {
|
|
25249
25253
|
style: {
|
|
25250
25254
|
marginLeft: 8
|
|
@@ -25263,7 +25267,7 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25263
25267
|
return /*#__PURE__*/React.createElement("div", {
|
|
25264
25268
|
style: answerBarStyle
|
|
25265
25269
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25266
|
-
style: styles$
|
|
25270
|
+
style: styles$o.text
|
|
25267
25271
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25268
25272
|
style: {
|
|
25269
25273
|
fontSize: 28,
|
|
@@ -25286,7 +25290,7 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25286
25290
|
}
|
|
25287
25291
|
GradedGroupAnswerBar.contextType = PerseusI18nContext;
|
|
25288
25292
|
const fontSize = 17;
|
|
25289
|
-
const styles$
|
|
25293
|
+
const styles$o = {
|
|
25290
25294
|
answerBar: {
|
|
25291
25295
|
display: "flex",
|
|
25292
25296
|
alignItems: "center",
|
|
@@ -25471,7 +25475,7 @@ class GradedGroup extends React.Component {
|
|
|
25471
25475
|
}));
|
|
25472
25476
|
gradeStatus = this.context.strings.incorrect;
|
|
25473
25477
|
}
|
|
25474
|
-
const mobileClass = this.props.inGradedGroupSet ? css(styles$
|
|
25478
|
+
const mobileClass = this.props.inGradedGroupSet ? css(styles$n.gradedGroupInSet) : css(styles$n.gradedGroup);
|
|
25475
25479
|
const classes = classNames({
|
|
25476
25480
|
[mobileClass]: apiOptions.isMobile,
|
|
25477
25481
|
"perseus-graded-group": true,
|
|
@@ -25490,7 +25494,7 @@ class GradedGroup extends React.Component {
|
|
|
25490
25494
|
return /*#__PURE__*/React.createElement("div", {
|
|
25491
25495
|
className: classes
|
|
25492
25496
|
}, !!this.props.title && /*#__PURE__*/React.createElement("div", {
|
|
25493
|
-
className: css(styles$
|
|
25497
|
+
className: css(styles$n.title)
|
|
25494
25498
|
}, this.props.title), /*#__PURE__*/React.createElement(Renderer, _extends({}, this.props, {
|
|
25495
25499
|
// eslint-disable-next-line react/no-string-refs
|
|
25496
25500
|
ref: "renderer",
|
|
@@ -25523,7 +25527,7 @@ class GradedGroup extends React.Component {
|
|
|
25523
25527
|
}, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
|
|
25524
25528
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
|
|
25525
25529
|
tabIndex: "0",
|
|
25526
|
-
className: css(styles$
|
|
25530
|
+
className: css(styles$n.explanationTitle),
|
|
25527
25531
|
onClick: () => this.setState({
|
|
25528
25532
|
showHint: false
|
|
25529
25533
|
}),
|
|
@@ -25556,7 +25560,7 @@ class GradedGroup extends React.Component {
|
|
|
25556
25560
|
showHint: true
|
|
25557
25561
|
});
|
|
25558
25562
|
},
|
|
25559
|
-
className: css(styles$
|
|
25563
|
+
className: css(styles$n.showHintLink)
|
|
25560
25564
|
}, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React.createElement(GradedGroupAnswerBar, {
|
|
25561
25565
|
apiOptions: apiOptions,
|
|
25562
25566
|
answerBarState: answerBarState,
|
|
@@ -25578,7 +25582,7 @@ GradedGroup.defaultProps = {
|
|
|
25578
25582
|
const traverseChildWidgets$2 = function traverseChildWidgets(props, traverseRenderer) {
|
|
25579
25583
|
return _.extend({}, props, traverseRenderer(props));
|
|
25580
25584
|
};
|
|
25581
|
-
const styles$
|
|
25585
|
+
const styles$n = StyleSheet.create({
|
|
25582
25586
|
gradedGroupInSet: {
|
|
25583
25587
|
// Reset a few desktop-only styles that come from graded-group.less
|
|
25584
25588
|
marginLeft: 0,
|
|
@@ -25651,18 +25655,18 @@ class Indicators extends React.Component {
|
|
|
25651
25655
|
return /*#__PURE__*/React.createElement("ul", {
|
|
25652
25656
|
// reduntantly add class name for use in .less files--
|
|
25653
25657
|
// the styles object key gets hashed
|
|
25654
|
-
className: classNames(css(styles$
|
|
25658
|
+
className: classNames(css(styles$m.indicatorContainer), "indicatorContainer")
|
|
25655
25659
|
}, this.props.gradedGroups.map(({
|
|
25656
25660
|
title
|
|
25657
25661
|
}, i) => /*#__PURE__*/React.createElement("li", {
|
|
25658
|
-
className: css(styles$
|
|
25662
|
+
className: css(styles$m.indicator),
|
|
25659
25663
|
key: title
|
|
25660
25664
|
}, /*#__PURE__*/React.createElement(Clickable, {
|
|
25661
25665
|
role: "button",
|
|
25662
25666
|
"aria-label": this.context.strings.skipToTitle({
|
|
25663
25667
|
title
|
|
25664
25668
|
}),
|
|
25665
|
-
style: styles$
|
|
25669
|
+
style: styles$m.indicatorButton,
|
|
25666
25670
|
onClick: () => this.props.onChangeCurrentGroup(i),
|
|
25667
25671
|
onKeyDown: e => this.handleKeyDown(e, i)
|
|
25668
25672
|
}, ({
|
|
@@ -25670,9 +25674,9 @@ class Indicators extends React.Component {
|
|
|
25670
25674
|
focused,
|
|
25671
25675
|
pressed
|
|
25672
25676
|
}) => /*#__PURE__*/React.createElement(View, {
|
|
25673
|
-
style: [styles$
|
|
25677
|
+
style: [styles$m.indicatorDot, (hovered || focused || pressed) && styles$m.indicatorDotFocused]
|
|
25674
25678
|
}, i === this.props.currentGroup && /*#__PURE__*/React.createElement(View, {
|
|
25675
|
-
style: styles$
|
|
25679
|
+
style: styles$m.indicatorDotActive
|
|
25676
25680
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25677
25681
|
className: css(a11y.srOnly)
|
|
25678
25682
|
}, this.context.strings.current)))))));
|
|
@@ -25736,7 +25740,7 @@ class GradedGroupSet extends React.Component {
|
|
|
25736
25740
|
} = getDependencies();
|
|
25737
25741
|
if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
|
|
25738
25742
|
return /*#__PURE__*/React.createElement("div", {
|
|
25739
|
-
className: css(styles$
|
|
25743
|
+
className: css(styles$m.container)
|
|
25740
25744
|
}, this.props.gradedGroups.map((gradedGroup, i) => {
|
|
25741
25745
|
return (
|
|
25742
25746
|
/*#__PURE__*/
|
|
@@ -25759,13 +25763,13 @@ class GradedGroupSet extends React.Component {
|
|
|
25759
25763
|
const numGroups = this.props.gradedGroups.length;
|
|
25760
25764
|
const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
|
|
25761
25765
|
return /*#__PURE__*/React.createElement("div", {
|
|
25762
|
-
className: css(styles$
|
|
25766
|
+
className: css(styles$m.container)
|
|
25763
25767
|
}, /*#__PURE__*/React.createElement("div", {
|
|
25764
|
-
className: css(styles$
|
|
25768
|
+
className: css(styles$m.top)
|
|
25765
25769
|
}, /*#__PURE__*/React.createElement("div", {
|
|
25766
|
-
className: css(styles$
|
|
25770
|
+
className: css(styles$m.title)
|
|
25767
25771
|
}, currentGroup.title), /*#__PURE__*/React.createElement("div", {
|
|
25768
|
-
className: css(styles$
|
|
25772
|
+
className: css(styles$m.spacer)
|
|
25769
25773
|
}), /*#__PURE__*/React.createElement(Indicators, {
|
|
25770
25774
|
currentGroup: this.state.currentGroup,
|
|
25771
25775
|
gradedGroups: this.props.gradedGroups,
|
|
@@ -25807,7 +25811,7 @@ var GradedGroupSet$1 = {
|
|
|
25807
25811
|
tracking: "all",
|
|
25808
25812
|
isLintable: true
|
|
25809
25813
|
};
|
|
25810
|
-
const styles$
|
|
25814
|
+
const styles$m = StyleSheet.create({
|
|
25811
25815
|
top: {
|
|
25812
25816
|
display: "flex",
|
|
25813
25817
|
flexDirection: "row"
|
|
@@ -25912,7 +25916,7 @@ class ButtonGroup extends React.Component {
|
|
|
25912
25916
|
id: "" + i,
|
|
25913
25917
|
ref: "button" + i,
|
|
25914
25918
|
key: "" + i,
|
|
25915
|
-
className: css(styles$
|
|
25919
|
+
className: css(styles$l.buttonStyle, button.value === value && styles$l.selectedStyle),
|
|
25916
25920
|
onClick: () => this.toggleSelect(button.value)
|
|
25917
25921
|
}, button.content || "" + button.value);
|
|
25918
25922
|
});
|
|
@@ -25929,7 +25933,7 @@ ButtonGroup.defaultProps = {
|
|
|
25929
25933
|
value: null,
|
|
25930
25934
|
allowEmpty: true
|
|
25931
25935
|
};
|
|
25932
|
-
const styles$
|
|
25936
|
+
const styles$l = StyleSheet.create({
|
|
25933
25937
|
buttonStyle: {
|
|
25934
25938
|
backgroundColor: "white",
|
|
25935
25939
|
border: "1px solid #ccc",
|
|
@@ -28339,65 +28343,6 @@ Graph.defaultProps = {
|
|
|
28339
28343
|
isMobile: false
|
|
28340
28344
|
};
|
|
28341
28345
|
|
|
28342
|
-
const defaultGraphConfig = {
|
|
28343
|
-
range: [[0, 1], [0, 1]],
|
|
28344
|
-
tickStep: [1, 1],
|
|
28345
|
-
gridStep: [1, 1],
|
|
28346
|
-
snapStep: [1, 1],
|
|
28347
|
-
markings: "none",
|
|
28348
|
-
showTooltips: false,
|
|
28349
|
-
graphDimensionsInPixels: [1, 1],
|
|
28350
|
-
width: 0,
|
|
28351
|
-
height: 0,
|
|
28352
|
-
labels: [],
|
|
28353
|
-
disableKeyboardInteraction: false
|
|
28354
|
-
};
|
|
28355
|
-
const GraphConfigContext = /*#__PURE__*/createContext(defaultGraphConfig);
|
|
28356
|
-
function useGraphConfig() {
|
|
28357
|
-
return React__default.useContext(GraphConfigContext);
|
|
28358
|
-
}
|
|
28359
|
-
|
|
28360
|
-
const matrixBuilder = vec.matrixBuilder;
|
|
28361
|
-
|
|
28362
|
-
// When converting vectors, we don't need to translate because a vector
|
|
28363
|
-
// is like a pair of x and y distances, which are not bound to specific graph locations.
|
|
28364
|
-
function vectorsToPixels(vectors, graphState, translation = [0, 0]) {
|
|
28365
|
-
const {
|
|
28366
|
-
range,
|
|
28367
|
-
width,
|
|
28368
|
-
height
|
|
28369
|
-
} = graphState;
|
|
28370
|
-
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28371
|
-
const transformToPx = matrixBuilder().translate(...translation).scale(width / (xMax - xMin), -height / (yMax - yMin)).get();
|
|
28372
|
-
return vectors.map(p => vec.transform(p, transformToPx));
|
|
28373
|
-
}
|
|
28374
|
-
function dimensionsToPixels(dimens, graphState) {
|
|
28375
|
-
const {
|
|
28376
|
-
range,
|
|
28377
|
-
width,
|
|
28378
|
-
height
|
|
28379
|
-
} = graphState;
|
|
28380
|
-
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28381
|
-
const transformToPx = matrixBuilder().scale(width / (xMax - xMin), height / (yMax - yMin)).get();
|
|
28382
|
-
return dimens.map(d => vec.transform(d, transformToPx));
|
|
28383
|
-
}
|
|
28384
|
-
|
|
28385
|
-
// When converting points, we translate so the pixel point ends up in the right location.
|
|
28386
|
-
// This is because points are specific locations on graphs, unlike vectors.
|
|
28387
|
-
function pointToPixel(point, graphState) {
|
|
28388
|
-
const [[xMin], [, yMax]] = graphState.range;
|
|
28389
|
-
const [a, b] = [-xMin, -yMax];
|
|
28390
|
-
return vectorsToPixels([point], graphState, [a, b])[0];
|
|
28391
|
-
}
|
|
28392
|
-
const useTransformVectorsToPixels = (...vectors) => {
|
|
28393
|
-
const graphState = useGraphConfig();
|
|
28394
|
-
return vectorsToPixels(vectors, graphState);
|
|
28395
|
-
};
|
|
28396
|
-
const useTransformDimensionsToPixels = (...dimens) => {
|
|
28397
|
-
const graphState = useGraphConfig();
|
|
28398
|
-
return dimensionsToPixels(dimens, graphState);
|
|
28399
|
-
};
|
|
28400
|
-
|
|
28401
28346
|
// Restricts `value` to be between `min` and `max`.
|
|
28402
28347
|
function clamp(value, min, max) {
|
|
28403
28348
|
if (value < min) {
|
|
@@ -28541,6 +28486,79 @@ const findAngle = (point1, point2, vertex) => {
|
|
|
28541
28486
|
return findAngle(point1, vertex) - findAngle(point2, vertex);
|
|
28542
28487
|
};
|
|
28543
28488
|
|
|
28489
|
+
const defaultGraphConfig = {
|
|
28490
|
+
range: [[0, 1], [0, 1]],
|
|
28491
|
+
tickStep: [1, 1],
|
|
28492
|
+
gridStep: [1, 1],
|
|
28493
|
+
snapStep: [1, 1],
|
|
28494
|
+
markings: "none",
|
|
28495
|
+
showTooltips: false,
|
|
28496
|
+
graphDimensionsInPixels: [1, 1],
|
|
28497
|
+
width: 0,
|
|
28498
|
+
height: 0,
|
|
28499
|
+
labels: [],
|
|
28500
|
+
disableKeyboardInteraction: false
|
|
28501
|
+
};
|
|
28502
|
+
const GraphConfigContext = /*#__PURE__*/createContext(defaultGraphConfig);
|
|
28503
|
+
function useGraphConfig() {
|
|
28504
|
+
return React__default.useContext(GraphConfigContext);
|
|
28505
|
+
}
|
|
28506
|
+
|
|
28507
|
+
const matrixBuilder = vec.matrixBuilder;
|
|
28508
|
+
|
|
28509
|
+
// When converting vectors, we don't need to translate because a vector
|
|
28510
|
+
// is like a pair of x and y distances, which are not bound to specific graph locations.
|
|
28511
|
+
function vectorsToPixels(vectors, graphState, translation = [0, 0]) {
|
|
28512
|
+
const {
|
|
28513
|
+
range,
|
|
28514
|
+
width,
|
|
28515
|
+
height
|
|
28516
|
+
} = graphState;
|
|
28517
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28518
|
+
const transformToPx = matrixBuilder().translate(...translation).scale(width / (xMax - xMin), -height / (yMax - yMin)).get();
|
|
28519
|
+
return vectors.map(p => vec.transform(p, transformToPx));
|
|
28520
|
+
}
|
|
28521
|
+
function dimensionsToPixels(dimens, graphState) {
|
|
28522
|
+
const {
|
|
28523
|
+
range,
|
|
28524
|
+
width,
|
|
28525
|
+
height
|
|
28526
|
+
} = graphState;
|
|
28527
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28528
|
+
const transformToPx = matrixBuilder().scale(width / (xMax - xMin), height / (yMax - yMin)).get();
|
|
28529
|
+
return dimens.map(d => vec.transform(d, transformToPx));
|
|
28530
|
+
}
|
|
28531
|
+
|
|
28532
|
+
// When converting points, we translate so the pixel point ends up in the right location.
|
|
28533
|
+
// This is because points are specific locations on graphs, unlike vectors.
|
|
28534
|
+
function pointToPixel(point, graphState) {
|
|
28535
|
+
const [[xMin], [, yMax]] = graphState.range;
|
|
28536
|
+
const [a, b] = [-xMin, -yMax];
|
|
28537
|
+
return vectorsToPixels([point], graphState, [a, b])[0];
|
|
28538
|
+
}
|
|
28539
|
+
const useTransformVectorsToPixels = (...vectors) => {
|
|
28540
|
+
const graphState = useGraphConfig();
|
|
28541
|
+
return vectorsToPixels(vectors, graphState);
|
|
28542
|
+
};
|
|
28543
|
+
const useTransformDimensionsToPixels = (...dimens) => {
|
|
28544
|
+
const graphState = useGraphConfig();
|
|
28545
|
+
return dimensionsToPixels(dimens, graphState);
|
|
28546
|
+
};
|
|
28547
|
+
function pixelsToVectors(pixels, graphState) {
|
|
28548
|
+
const [[xMin, xMax], [yMin, yMax]] = graphState.range;
|
|
28549
|
+
const {
|
|
28550
|
+
width,
|
|
28551
|
+
height
|
|
28552
|
+
} = graphState;
|
|
28553
|
+
const xSpan = xMax - xMin;
|
|
28554
|
+
const ySpan = yMax - yMin;
|
|
28555
|
+
return pixels.map(pixel => {
|
|
28556
|
+
const x = pixel[X] / width * xSpan + xMin;
|
|
28557
|
+
const y = yMax - pixel[Y] / height * ySpan;
|
|
28558
|
+
return [x, y];
|
|
28559
|
+
});
|
|
28560
|
+
}
|
|
28561
|
+
|
|
28544
28562
|
function AxisLabels() {
|
|
28545
28563
|
const {
|
|
28546
28564
|
range,
|
|
@@ -29127,7 +29145,7 @@ const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
|
|
|
29127
29145
|
width: "24",
|
|
29128
29146
|
height: "24",
|
|
29129
29147
|
viewBox: "0 0 24 24",
|
|
29130
|
-
className: css(styles$
|
|
29148
|
+
className: css(styles$k.icon)
|
|
29131
29149
|
}, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
|
|
29132
29150
|
id: "a",
|
|
29133
29151
|
d: "M7.401 10.035c-1.424.748-2.599 1.905-3.544 " + "3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 " + "12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 " + "1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-" + "3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 " + "0 0 0 0 6z"
|
|
@@ -29158,7 +29176,7 @@ const HiddenIcon = () => /*#__PURE__*/React.createElement("svg", {
|
|
|
29158
29176
|
width: "24",
|
|
29159
29177
|
height: "24",
|
|
29160
29178
|
viewBox: "0 0 24 24",
|
|
29161
|
-
className: css(styles$
|
|
29179
|
+
className: css(styles$k.icon)
|
|
29162
29180
|
}, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
|
|
29163
29181
|
id: "a",
|
|
29164
29182
|
d: "M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 " + "7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 " + "1.028c-.945-1.574-2.12-2.73-3.544-3.48.258." + "604.401 1.268.401 1.966 0 1.02-.305 " + "1.967-.828 2.757l2.535 2.536a1 1 0 0 " + "1-1.414 1.414l-12-12a1 1 0 0 1 " + "1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 " + "0-4.001-4.001l4 4.001zM6.072 8.486l2.976 " + "2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 " + "0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 " + "3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 " + "2.363-3.085 3.929-4z"
|
|
@@ -29192,20 +29210,20 @@ const HUD = ({
|
|
|
29192
29210
|
let state;
|
|
29193
29211
|
let icon;
|
|
29194
29212
|
if (enabled) {
|
|
29195
|
-
state = styles$
|
|
29213
|
+
state = styles$k.enabled;
|
|
29196
29214
|
icon = /*#__PURE__*/React.createElement(VisibleIcon, null);
|
|
29197
29215
|
} else {
|
|
29198
|
-
state = styles$
|
|
29216
|
+
state = styles$k.disabled;
|
|
29199
29217
|
icon = /*#__PURE__*/React.createElement(HiddenIcon, null);
|
|
29200
29218
|
}
|
|
29201
29219
|
return /*#__PURE__*/React.createElement("button", {
|
|
29202
|
-
className: css(styles$
|
|
29220
|
+
className: css(styles$k.hud, _fixedPosition && styles$k.hudFixedPosition, state),
|
|
29203
29221
|
onClick: e => {
|
|
29204
29222
|
onClick();
|
|
29205
29223
|
}
|
|
29206
29224
|
}, icon, message);
|
|
29207
29225
|
};
|
|
29208
|
-
const styles$
|
|
29226
|
+
const styles$k = StyleSheet.create({
|
|
29209
29227
|
hud: {
|
|
29210
29228
|
boxSizing: "border-box",
|
|
29211
29229
|
height: 36,
|
|
@@ -29258,16 +29276,16 @@ const styles$j = StyleSheet.create({
|
|
|
29258
29276
|
const InfoTipBase = props => {
|
|
29259
29277
|
return /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
29260
29278
|
content: /*#__PURE__*/React.createElement(Body, {
|
|
29261
|
-
style: styles$
|
|
29279
|
+
style: styles$j.body
|
|
29262
29280
|
}, props.children),
|
|
29263
29281
|
placement: "right"
|
|
29264
29282
|
}, /*#__PURE__*/React.createElement(PhosphorIcon, {
|
|
29265
29283
|
size: "small",
|
|
29266
29284
|
icon: questionIcon,
|
|
29267
|
-
style: styles$
|
|
29285
|
+
style: styles$j.spacingLeft
|
|
29268
29286
|
}));
|
|
29269
29287
|
};
|
|
29270
|
-
const styles$
|
|
29288
|
+
const styles$j = StyleSheet.create({
|
|
29271
29289
|
spacingLeft: {
|
|
29272
29290
|
marginInlineStart: spacing.xxxSmall_4
|
|
29273
29291
|
},
|
|
@@ -29346,7 +29364,7 @@ class MultiButtonGroup extends React.Component {
|
|
|
29346
29364
|
id: "" + i,
|
|
29347
29365
|
key: "" + i,
|
|
29348
29366
|
ref: "button" + i,
|
|
29349
|
-
className: css(styles$
|
|
29367
|
+
className: css(styles$i.buttonStyle, selected && styles$i.selectedStyle),
|
|
29350
29368
|
onClick: () => this.toggleSelect(button.value)
|
|
29351
29369
|
}, button.content || "" + button.value);
|
|
29352
29370
|
});
|
|
@@ -29362,7 +29380,7 @@ MultiButtonGroup.defaultProps = {
|
|
|
29362
29380
|
values: [],
|
|
29363
29381
|
allowEmpty: true
|
|
29364
29382
|
};
|
|
29365
|
-
const styles$
|
|
29383
|
+
const styles$i = StyleSheet.create({
|
|
29366
29384
|
buttonStyle: {
|
|
29367
29385
|
backgroundColor: "white",
|
|
29368
29386
|
border: "1px solid #ccc",
|
|
@@ -29797,6 +29815,8 @@ const ItemExtras = [
|
|
|
29797
29815
|
|
|
29798
29816
|
// prettier-ignore
|
|
29799
29817
|
|
|
29818
|
+
// prettier-ignore
|
|
29819
|
+
|
|
29800
29820
|
//prettier-ignore
|
|
29801
29821
|
|
|
29802
29822
|
// A background image applied to various widgets.
|
|
@@ -29817,8 +29837,53 @@ const lockedFigureFillStyles = {
|
|
|
29817
29837
|
translucent: 0.4,
|
|
29818
29838
|
solid: 1
|
|
29819
29839
|
};
|
|
29840
|
+
|
|
29841
|
+
// Not associated with a specific figure
|
|
29842
|
+
|
|
29820
29843
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
29821
29844
|
|
|
29845
|
+
function LockedLabel(props) {
|
|
29846
|
+
const {
|
|
29847
|
+
coord,
|
|
29848
|
+
text,
|
|
29849
|
+
color,
|
|
29850
|
+
size
|
|
29851
|
+
} = props;
|
|
29852
|
+
const [x, y] = pointToPixel(coord, useGraphConfig());
|
|
29853
|
+
const {
|
|
29854
|
+
TeX
|
|
29855
|
+
} = getDependencies();
|
|
29856
|
+
|
|
29857
|
+
// Move this all outside the SVG element
|
|
29858
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
29859
|
+
className: "locked-label",
|
|
29860
|
+
style: {
|
|
29861
|
+
position: "absolute",
|
|
29862
|
+
left: x,
|
|
29863
|
+
top: y,
|
|
29864
|
+
color: lockedFigureColors[color],
|
|
29865
|
+
fontSize: font.size[size]
|
|
29866
|
+
}
|
|
29867
|
+
}, /*#__PURE__*/React.createElement(TeX, null, text));
|
|
29868
|
+
}
|
|
29869
|
+
|
|
29870
|
+
function GraphLockedLabelsLayer(props) {
|
|
29871
|
+
const {
|
|
29872
|
+
lockedFigures
|
|
29873
|
+
} = props;
|
|
29874
|
+
return lockedFigures.map((figure, i) => {
|
|
29875
|
+
if (figure.type === "label") {
|
|
29876
|
+
return /*#__PURE__*/React.createElement(LockedLabel, _extends({
|
|
29877
|
+
key: `label-${i}`
|
|
29878
|
+
}, figure));
|
|
29879
|
+
}
|
|
29880
|
+
|
|
29881
|
+
// TODO(LEMS-2271): Add support for labels within
|
|
29882
|
+
// other locked figure types
|
|
29883
|
+
return null;
|
|
29884
|
+
});
|
|
29885
|
+
}
|
|
29886
|
+
|
|
29822
29887
|
const LockedEllipse = props => {
|
|
29823
29888
|
const {
|
|
29824
29889
|
center,
|
|
@@ -30133,6 +30198,12 @@ const GraphLockedLayer = props => {
|
|
|
30133
30198
|
return /*#__PURE__*/React.createElement(LockedFunction, _extends({
|
|
30134
30199
|
key: `function-${index}`
|
|
30135
30200
|
}, figure));
|
|
30201
|
+
case "label":
|
|
30202
|
+
// This is rendered outside the SVG element, since
|
|
30203
|
+
// TeX cannot be rendered inside an SVG.
|
|
30204
|
+
// See graph-locked-labels-layer.tsx for
|
|
30205
|
+
// the component that renders these.
|
|
30206
|
+
return null;
|
|
30136
30207
|
default:
|
|
30137
30208
|
/**
|
|
30138
30209
|
* Devlopment-time future-proofing: This should
|
|
@@ -30162,7 +30233,8 @@ const actions = {
|
|
|
30162
30233
|
movePointInFigure
|
|
30163
30234
|
},
|
|
30164
30235
|
pointGraph: {
|
|
30165
|
-
movePoint
|
|
30236
|
+
movePoint,
|
|
30237
|
+
addPoint
|
|
30166
30238
|
},
|
|
30167
30239
|
polygon: {
|
|
30168
30240
|
movePoint,
|
|
@@ -30191,6 +30263,13 @@ function moveLine(itemIndex, delta) {
|
|
|
30191
30263
|
delta
|
|
30192
30264
|
};
|
|
30193
30265
|
}
|
|
30266
|
+
const ADD_POINT = "add-point";
|
|
30267
|
+
function addPoint(location) {
|
|
30268
|
+
return {
|
|
30269
|
+
type: ADD_POINT,
|
|
30270
|
+
location
|
|
30271
|
+
};
|
|
30272
|
+
}
|
|
30194
30273
|
const MOVE_ALL = "move-all";
|
|
30195
30274
|
function moveAll(delta) {
|
|
30196
30275
|
return {
|
|
@@ -31727,7 +31806,7 @@ function getAngleSideConstraint(sidePoint, vertex, snapDegrees) {
|
|
|
31727
31806
|
};
|
|
31728
31807
|
}
|
|
31729
31808
|
|
|
31730
|
-
function
|
|
31809
|
+
function LimitedPointGraph(props) {
|
|
31731
31810
|
const {
|
|
31732
31811
|
dispatch
|
|
31733
31812
|
} = props;
|
|
@@ -31737,6 +31816,46 @@ function PointGraph(props) {
|
|
|
31737
31816
|
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination))
|
|
31738
31817
|
})));
|
|
31739
31818
|
}
|
|
31819
|
+
function UnlimitedPointGraph(props) {
|
|
31820
|
+
const {
|
|
31821
|
+
dispatch
|
|
31822
|
+
} = props;
|
|
31823
|
+
const graphState = useGraphConfig();
|
|
31824
|
+
const {
|
|
31825
|
+
range: [[minX, maxX], [minY, maxY]]
|
|
31826
|
+
} = graphState;
|
|
31827
|
+
const width = maxX - minX;
|
|
31828
|
+
const height = maxY - minY;
|
|
31829
|
+
const [[widthPx, heightPx]] = useTransformDimensionsToPixels([width, height]);
|
|
31830
|
+
const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
|
|
31831
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
|
|
31832
|
+
style: {
|
|
31833
|
+
fill: "rgba(0,0,0,0)"
|
|
31834
|
+
},
|
|
31835
|
+
width: widthPx,
|
|
31836
|
+
height: heightPx,
|
|
31837
|
+
x: left,
|
|
31838
|
+
y: top,
|
|
31839
|
+
onClick: event => {
|
|
31840
|
+
const elementRect = event.currentTarget.getBoundingClientRect();
|
|
31841
|
+
const x = event.clientX - elementRect.x;
|
|
31842
|
+
const y = event.clientY - elementRect.y;
|
|
31843
|
+
const graphCoordinates = pixelsToVectors([[x, y]], graphState);
|
|
31844
|
+
dispatch(actions.pointGraph.addPoint(graphCoordinates[0]));
|
|
31845
|
+
}
|
|
31846
|
+
}), props.graphState.coords.map((point, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31847
|
+
key: i,
|
|
31848
|
+
point: point,
|
|
31849
|
+
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination))
|
|
31850
|
+
})));
|
|
31851
|
+
}
|
|
31852
|
+
function PointGraph(props) {
|
|
31853
|
+
const numPoints = props.graphState.numPoints;
|
|
31854
|
+
if (numPoints === "unlimited") {
|
|
31855
|
+
return UnlimitedPointGraph(props);
|
|
31856
|
+
}
|
|
31857
|
+
return LimitedPointGraph(props);
|
|
31858
|
+
}
|
|
31740
31859
|
|
|
31741
31860
|
const protractorImage = "https://ka-perseus-graphie.s3.amazonaws.com/e9d032f2ab8b95979f674fbfa67056442ba1ff6a.png";
|
|
31742
31861
|
|
|
@@ -31897,11 +32016,11 @@ const MafsGraph = props => {
|
|
|
31897
32016
|
labels,
|
|
31898
32017
|
disableKeyboardInteraction: readOnly || !!props.static
|
|
31899
32018
|
}
|
|
31900
|
-
}, /*#__PURE__*/React.createElement(View, {
|
|
32019
|
+
}, /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(View, {
|
|
31901
32020
|
className: "mafs-graph",
|
|
31902
32021
|
style: {
|
|
31903
|
-
width,
|
|
31904
32022
|
height,
|
|
32023
|
+
width: "intrinsic",
|
|
31905
32024
|
position: "relative",
|
|
31906
32025
|
padding: "25px 25px 0 0",
|
|
31907
32026
|
boxSizing: "content-box",
|
|
@@ -31913,6 +32032,8 @@ const MafsGraph = props => {
|
|
|
31913
32032
|
}, /*#__PURE__*/React.createElement(LegacyGrid, {
|
|
31914
32033
|
box: props.box,
|
|
31915
32034
|
backgroundImage: props.backgroundImage
|
|
32035
|
+
}), props.showLabelsFlag && props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLabelsLayer, {
|
|
32036
|
+
lockedFigures: props.lockedFigures
|
|
31916
32037
|
}), /*#__PURE__*/React.createElement(View, {
|
|
31917
32038
|
style: {
|
|
31918
32039
|
position: "absolute",
|
|
@@ -31942,7 +32063,41 @@ const MafsGraph = props => {
|
|
|
31942
32063
|
}), props.showProtractor && /*#__PURE__*/React.createElement(Protractor, null), renderGraph({
|
|
31943
32064
|
state,
|
|
31944
32065
|
dispatch
|
|
31945
|
-
}))))
|
|
32066
|
+
})))), renderGraphControls({
|
|
32067
|
+
state,
|
|
32068
|
+
dispatch
|
|
32069
|
+
})));
|
|
32070
|
+
};
|
|
32071
|
+
const renderPointGraphControls = props => /*#__PURE__*/React.createElement(Button, {
|
|
32072
|
+
kind: "secondary",
|
|
32073
|
+
style: {
|
|
32074
|
+
width: "100%",
|
|
32075
|
+
marginLeft: "20px"
|
|
32076
|
+
},
|
|
32077
|
+
onClick: () => {
|
|
32078
|
+
props.dispatch(actions.pointGraph.addPoint([0, 0]));
|
|
32079
|
+
}
|
|
32080
|
+
}, "Add Point");
|
|
32081
|
+
const renderGraphControls = props => {
|
|
32082
|
+
const {
|
|
32083
|
+
state,
|
|
32084
|
+
dispatch
|
|
32085
|
+
} = props;
|
|
32086
|
+
const {
|
|
32087
|
+
type
|
|
32088
|
+
} = state;
|
|
32089
|
+
switch (type) {
|
|
32090
|
+
case "point":
|
|
32091
|
+
if (state.numPoints === "unlimited") {
|
|
32092
|
+
return renderPointGraphControls({
|
|
32093
|
+
state,
|
|
32094
|
+
dispatch
|
|
32095
|
+
});
|
|
32096
|
+
}
|
|
32097
|
+
return null;
|
|
32098
|
+
default:
|
|
32099
|
+
return null;
|
|
32100
|
+
}
|
|
31946
32101
|
};
|
|
31947
32102
|
const renderGraph = props => {
|
|
31948
32103
|
const {
|
|
@@ -32053,7 +32208,8 @@ function initializeGraphState(params) {
|
|
|
32053
32208
|
case "point":
|
|
32054
32209
|
return _extends({}, shared, {
|
|
32055
32210
|
type: graph.type,
|
|
32056
|
-
coords: getPointCoords(graph, range, step)
|
|
32211
|
+
coords: getPointCoords(graph, range, step),
|
|
32212
|
+
numPoints: graph.numPoints || 0
|
|
32057
32213
|
});
|
|
32058
32214
|
case "circle":
|
|
32059
32215
|
return _extends({}, shared, {
|
|
@@ -32307,6 +32463,8 @@ function interactiveGraphReducer(state, action) {
|
|
|
32307
32463
|
return doChangeSnapStep(state, action);
|
|
32308
32464
|
case CHANGE_RANGE:
|
|
32309
32465
|
return doChangeRange(state, action);
|
|
32466
|
+
case ADD_POINT:
|
|
32467
|
+
return doAddPoint(state, action);
|
|
32310
32468
|
default:
|
|
32311
32469
|
throw new UnreachableCaseError(action);
|
|
32312
32470
|
}
|
|
@@ -32632,6 +32790,28 @@ function doChangeRange(state, action) {
|
|
|
32632
32790
|
range: action.range
|
|
32633
32791
|
});
|
|
32634
32792
|
}
|
|
32793
|
+
function doAddPoint(state, action) {
|
|
32794
|
+
if (state.type !== "point") {
|
|
32795
|
+
return state;
|
|
32796
|
+
}
|
|
32797
|
+
const {
|
|
32798
|
+
snapStep
|
|
32799
|
+
} = state;
|
|
32800
|
+
const snappedPoint = snap(snapStep, action.location);
|
|
32801
|
+
|
|
32802
|
+
// Check if there's already a point in that spot
|
|
32803
|
+
for (const point of state.coords) {
|
|
32804
|
+
if (point[X] === snappedPoint[X] && point[Y] === snappedPoint[Y]) {
|
|
32805
|
+
return state;
|
|
32806
|
+
}
|
|
32807
|
+
}
|
|
32808
|
+
|
|
32809
|
+
// If there's no point in spot where we want the new point to go we add it there
|
|
32810
|
+
return _extends({}, state, {
|
|
32811
|
+
hasBeenInteractedWith: true,
|
|
32812
|
+
coords: [...state.coords, snappedPoint]
|
|
32813
|
+
});
|
|
32814
|
+
}
|
|
32635
32815
|
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
32636
32816
|
const [deltaX, deltaY] = delta;
|
|
32637
32817
|
const maxXMove = Math.min(...maxMoves.map(move => move[X]));
|
|
@@ -34344,17 +34524,18 @@ class InteractiveGraph extends React.Component {
|
|
|
34344
34524
|
// Mafs shim
|
|
34345
34525
|
const mafsFlags = (_this$props$apiOption = this.props.apiOptions) == null || (_this$props$apiOption = _this$props$apiOption.flags) == null ? void 0 : _this$props$apiOption["mafs"];
|
|
34346
34526
|
if (shouldUseMafs(mafsFlags, this.props.graph)) {
|
|
34347
|
-
var _this$props$apiOption2;
|
|
34527
|
+
var _this$props$apiOption2, _this$props$apiOption3;
|
|
34348
34528
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
34349
34529
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
34350
34530
|
const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
|
|
34351
34531
|
return /*#__PURE__*/React.createElement(StatefulMafsGraph, _extends({}, this.props, {
|
|
34532
|
+
showLabelsFlag: (_this$props$apiOption2 = this.props.apiOptions) == null || (_this$props$apiOption2 = _this$props$apiOption2.flags) == null || (_this$props$apiOption2 = _this$props$apiOption2["mafs"]) == null ? void 0 : _this$props$apiOption2["interactive-graph-locked-features-labels"],
|
|
34352
34533
|
ref: this.mafsRef,
|
|
34353
34534
|
gridStep: gridStep,
|
|
34354
34535
|
snapStep: snapStep,
|
|
34355
34536
|
box: box,
|
|
34356
34537
|
showTooltips: !!this.props.showTooltips,
|
|
34357
|
-
readOnly: (_this$props$
|
|
34538
|
+
readOnly: (_this$props$apiOption3 = this.props.apiOptions) == null ? void 0 : _this$props$apiOption3.readOnly
|
|
34358
34539
|
}));
|
|
34359
34540
|
}
|
|
34360
34541
|
return /*#__PURE__*/React.createElement(LegacyInteractiveGraph, _extends({
|
|
@@ -34925,10 +35106,7 @@ function shouldUseMafs(mafsFlags, graph) {
|
|
|
34925
35106
|
switch (graph.type) {
|
|
34926
35107
|
case "point":
|
|
34927
35108
|
if (graph.numPoints === UNLIMITED) {
|
|
34928
|
-
|
|
34929
|
-
// case once we've implemented point graphs with unlimited
|
|
34930
|
-
// points
|
|
34931
|
-
return false;
|
|
35109
|
+
return Boolean(mafsFlags["unlimited-point"]);
|
|
34932
35110
|
}
|
|
34933
35111
|
return Boolean(mafsFlags["point"]);
|
|
34934
35112
|
case "polygon":
|
|
@@ -35979,7 +36157,7 @@ const HideAnswersToggle = props => {
|
|
|
35979
36157
|
strings
|
|
35980
36158
|
} = usePerseusI18n();
|
|
35981
36159
|
return /*#__PURE__*/React.createElement(View, {
|
|
35982
|
-
style: styles$
|
|
36160
|
+
style: styles$h.switchWrapper
|
|
35983
36161
|
}, /*#__PURE__*/React.createElement(Switch, {
|
|
35984
36162
|
id: switchId,
|
|
35985
36163
|
checked: props.areAnswersHidden,
|
|
@@ -35991,7 +36169,7 @@ const HideAnswersToggle = props => {
|
|
|
35991
36169
|
tag: "label"
|
|
35992
36170
|
}, strings.hideAnswersToggleLabel));
|
|
35993
36171
|
};
|
|
35994
|
-
const styles$
|
|
36172
|
+
const styles$h = StyleSheet.create({
|
|
35995
36173
|
switchWrapper: {
|
|
35996
36174
|
display: "flex",
|
|
35997
36175
|
flexDirection: "row",
|
|
@@ -36047,14 +36225,14 @@ const AnswerPill = props => {
|
|
|
36047
36225
|
id: idFactory.get("perseus-label-image-widget-answer-pill"),
|
|
36048
36226
|
onClick: correct ? undefined : onClick,
|
|
36049
36227
|
ref: ref,
|
|
36050
|
-
style: [style, popperStyle, styles$
|
|
36228
|
+
style: [style, popperStyle, styles$g.pill, correct && styles$g.correct, incorrect && styles$g.incorrect, (focused || hovered) && BringToFront]
|
|
36051
36229
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
36052
36230
|
content: answerString,
|
|
36053
36231
|
strings: strings,
|
|
36054
36232
|
inline: true
|
|
36055
36233
|
})));
|
|
36056
36234
|
};
|
|
36057
|
-
const styles$
|
|
36235
|
+
const styles$g = StyleSheet.create({
|
|
36058
36236
|
correct: {
|
|
36059
36237
|
// WB green darkened by 18%
|
|
36060
36238
|
backgroundColor: "#00880b"
|
|
@@ -36118,23 +36296,23 @@ class Marker extends React.Component {
|
|
|
36118
36296
|
icon: iconNull
|
|
36119
36297
|
};
|
|
36120
36298
|
if (showCorrectness) {
|
|
36121
|
-
iconStyles = [styles$
|
|
36299
|
+
iconStyles = [styles$f.markerGraded, showCorrectness === "correct" ? styles$f.markerCorrect : styles$f.markerIncorrect, isOpen && styles$f.markerSelected];
|
|
36122
36300
|
args = _extends({}, args, {
|
|
36123
36301
|
icon: showCorrectness === "correct" ? iconCheck : iconMinus
|
|
36124
36302
|
});
|
|
36125
36303
|
} else if (selectedAnswers && selectedAnswers.length > 0) {
|
|
36126
|
-
iconStyles = [styles$
|
|
36304
|
+
iconStyles = [styles$f.markerFilled, isOpen && styles$f.markerSelected];
|
|
36127
36305
|
} else if (isOpen) {
|
|
36128
|
-
iconStyles = [styles$
|
|
36306
|
+
iconStyles = [styles$f.markerSelected];
|
|
36129
36307
|
args = _extends({}, args, {
|
|
36130
36308
|
icon: iconChevronDown,
|
|
36131
36309
|
size: 8
|
|
36132
36310
|
});
|
|
36133
36311
|
} else if (showPulsate) {
|
|
36134
|
-
iconStyles = [styles$
|
|
36312
|
+
iconStyles = [styles$f.markerPulsateBase, this._mounted && shouldReduceMotion() ? showPulsate && styles$f.markerUnfilledPulsateOnce : showPulsate && styles$f.markerUnfilledPulsateInfinite];
|
|
36135
36313
|
}
|
|
36136
36314
|
return /*#__PURE__*/React.createElement(View, {
|
|
36137
|
-
style: [styles$
|
|
36315
|
+
style: [styles$f.markerIcon, iconStyles],
|
|
36138
36316
|
ref: node => this._icon = node
|
|
36139
36317
|
}, /*#__PURE__*/React.createElement(Icon, args));
|
|
36140
36318
|
}
|
|
@@ -36156,7 +36334,7 @@ class Marker extends React.Component {
|
|
|
36156
36334
|
const markerDisabled = showCorrectness === "correct";
|
|
36157
36335
|
const active = hovered || focused;
|
|
36158
36336
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
|
|
36159
|
-
style: [styles$
|
|
36337
|
+
style: [styles$f.marker, active && !markerDisabled && styles$f.markerActive],
|
|
36160
36338
|
"aria-label": markerDisabled ? this.context.strings.correctExcited : label
|
|
36161
36339
|
}, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React.createElement(AnswerPill, {
|
|
36162
36340
|
selectedAnswers: selected,
|
|
@@ -36173,7 +36351,7 @@ Marker.contextType = PerseusI18nContext;
|
|
|
36173
36351
|
Marker.defaultProps = {
|
|
36174
36352
|
selected: []
|
|
36175
36353
|
};
|
|
36176
|
-
const styles$
|
|
36354
|
+
const styles$f = StyleSheet.create({
|
|
36177
36355
|
marker: {
|
|
36178
36356
|
position: "absolute",
|
|
36179
36357
|
backgroundColor: color.white,
|
|
@@ -36755,13 +36933,13 @@ class LabelImage extends React.Component {
|
|
|
36755
36933
|
const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
|
|
36756
36934
|
const choicesString = strings.choices;
|
|
36757
36935
|
return /*#__PURE__*/React.createElement("div", {
|
|
36758
|
-
className: classNames("perseus-label-image-widget-instructions", css(styles$
|
|
36936
|
+
className: classNames("perseus-label-image-widget-instructions", css(styles$e.instructions))
|
|
36759
36937
|
}, /*#__PURE__*/React.createElement("div", {
|
|
36760
|
-
className: css(styles$
|
|
36938
|
+
className: css(styles$e.instructionsCaption)
|
|
36761
36939
|
}, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React.createElement("div", {
|
|
36762
|
-
className: css(styles$
|
|
36940
|
+
className: css(styles$e.instructionsChoices)
|
|
36763
36941
|
}, choices.map((choice, index) => /*#__PURE__*/React.createElement("div", {
|
|
36764
|
-
className: css(styles$
|
|
36942
|
+
className: css(styles$e.instructionsChoice),
|
|
36765
36943
|
key: index
|
|
36766
36944
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
36767
36945
|
content: choice,
|
|
@@ -36779,20 +36957,20 @@ class LabelImage extends React.Component {
|
|
|
36779
36957
|
activeMarkerIndex
|
|
36780
36958
|
} = this.state;
|
|
36781
36959
|
return /*#__PURE__*/React.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React.createElement("div", {
|
|
36782
|
-
className: css(styles$
|
|
36960
|
+
className: css(styles$e.markersCanvas),
|
|
36783
36961
|
style: {
|
|
36784
36962
|
maxWidth: imageWidth,
|
|
36785
36963
|
maxHeight: imageHeight
|
|
36786
36964
|
}
|
|
36787
36965
|
}, /*#__PURE__*/React.createElement("div", {
|
|
36788
|
-
className: css(styles$
|
|
36966
|
+
className: css(styles$e.imageContainer,
|
|
36789
36967
|
// Ensure image interaction is disabled while answer
|
|
36790
36968
|
// choices popup is visible. This addresses specific
|
|
36791
36969
|
// case where user may click on question image to
|
|
36792
36970
|
// dismiss the popup. If the image is larger in size
|
|
36793
36971
|
// than its rendered in the widget, this would
|
|
36794
36972
|
// result in a zoom of the image.
|
|
36795
|
-
activeMarkerIndex !== -1 && styles$
|
|
36973
|
+
activeMarkerIndex !== -1 && styles$e.imageInteractionDisabled)
|
|
36796
36974
|
}, /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
|
|
36797
36975
|
setAssetStatus
|
|
36798
36976
|
}) => /*#__PURE__*/React.createElement(SvgImage, {
|
|
@@ -36817,7 +36995,7 @@ class LabelImage extends React.Component {
|
|
|
36817
36995
|
}
|
|
36818
36996
|
}
|
|
36819
36997
|
LabelImage.contextType = PerseusI18nContext;
|
|
36820
|
-
const styles$
|
|
36998
|
+
const styles$e = StyleSheet.create({
|
|
36821
36999
|
instructions: {
|
|
36822
37000
|
paddingBottom: 16
|
|
36823
37001
|
},
|
|
@@ -36914,7 +37092,7 @@ class Placeholder extends React.Component {
|
|
|
36914
37092
|
const {
|
|
36915
37093
|
layout
|
|
36916
37094
|
} = this.props;
|
|
36917
|
-
const className = css(styles$
|
|
37095
|
+
const className = css(styles$d.card, styles$d.placeholder, layout === Layout.HORIZONTAL && styles$d.horizontalCard);
|
|
36918
37096
|
const style = {
|
|
36919
37097
|
width: this.props.width,
|
|
36920
37098
|
height: this.props.height
|
|
@@ -37097,7 +37275,7 @@ class Draggable extends React.Component {
|
|
|
37097
37275
|
// We need to keep backwards compatbility with rules specified directly
|
|
37098
37276
|
// in CSS. Hence the hacky tacking on of manual classNames.
|
|
37099
37277
|
// See sortable.less for details.
|
|
37100
|
-
let className = css(styles$
|
|
37278
|
+
let className = css(styles$d.card, styles$d.draggable, layout === Layout.HORIZONTAL && styles$d.horizontalCard, layout === Layout.VERTICAL && styles$d.verticalCard, type === ItemState.DRAGGING && styles$d.dragging, type === ItemState.DISABLED && styles$d.disabled, !includePadding && styles$d.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
|
|
37101
37279
|
if (!includePadding) {
|
|
37102
37280
|
className += " perseus-sortable-draggable-unpadded";
|
|
37103
37281
|
}
|
|
@@ -37306,7 +37484,7 @@ class Sortable extends React.Component {
|
|
|
37306
37484
|
} = this.props;
|
|
37307
37485
|
// We need to keep backwards compatbility with rules specified directly
|
|
37308
37486
|
// in CSS. See sortable.less for details.
|
|
37309
|
-
const className = css(styles$
|
|
37487
|
+
const className = css(styles$d.sortable) + " perseus-sortable";
|
|
37310
37488
|
const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
|
|
37311
37489
|
const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
|
|
37312
37490
|
_.each(this.state.items, function (item, i, items) {
|
|
@@ -37548,7 +37726,7 @@ Sortable.defaultProps = {
|
|
|
37548
37726
|
linterContext: PerseusLinter.linterContextDefault,
|
|
37549
37727
|
waitForTexRendererToLoad: true
|
|
37550
37728
|
};
|
|
37551
|
-
const styles$
|
|
37729
|
+
const styles$d = StyleSheet.create({
|
|
37552
37730
|
sortable: {
|
|
37553
37731
|
boxSizing: "border-box",
|
|
37554
37732
|
float: "left",
|
|
@@ -37710,25 +37888,25 @@ class Matcher extends React.Component {
|
|
|
37710
37888
|
};
|
|
37711
37889
|
const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
|
|
37712
37890
|
return /*#__PURE__*/React.createElement("table", {
|
|
37713
|
-
className: css(styles$
|
|
37891
|
+
className: css(styles$c.widget) + " " + HACKY_CSS_CLASSNAME
|
|
37714
37892
|
}, /*#__PURE__*/React.createElement("tbody", null, showLabels && /*#__PURE__*/React.createElement("tr", {
|
|
37715
|
-
className: css(styles$
|
|
37893
|
+
className: css(styles$c.row)
|
|
37716
37894
|
}, /*#__PURE__*/React.createElement("th", {
|
|
37717
|
-
className: css(styles$
|
|
37895
|
+
className: css(styles$c.column, styles$c.columnLabel)
|
|
37718
37896
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
37719
37897
|
content: this.props.labels[0] || "...",
|
|
37720
37898
|
linterContext: this.props.linterContext,
|
|
37721
37899
|
strings: this.context.strings
|
|
37722
37900
|
})), /*#__PURE__*/React.createElement("th", {
|
|
37723
|
-
className: css(styles$
|
|
37901
|
+
className: css(styles$c.column, styles$c.columnRight, styles$c.columnLabel)
|
|
37724
37902
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
37725
37903
|
content: this.props.labels[1] || "...",
|
|
37726
37904
|
linterContext: this.props.linterContext,
|
|
37727
37905
|
strings: this.context.strings
|
|
37728
37906
|
}))), /*#__PURE__*/React.createElement("tr", {
|
|
37729
|
-
className: css(styles$
|
|
37907
|
+
className: css(styles$c.row)
|
|
37730
37908
|
}, /*#__PURE__*/React.createElement("td", {
|
|
37731
|
-
className: css(styles$
|
|
37909
|
+
className: css(styles$c.column)
|
|
37732
37910
|
}, /*#__PURE__*/React.createElement(Sortable, {
|
|
37733
37911
|
options: left,
|
|
37734
37912
|
layout: Layout.VERTICAL,
|
|
@@ -37743,7 +37921,7 @@ class Matcher extends React.Component {
|
|
|
37743
37921
|
,
|
|
37744
37922
|
ref: "left"
|
|
37745
37923
|
})), /*#__PURE__*/React.createElement("td", {
|
|
37746
|
-
className: css(styles$
|
|
37924
|
+
className: css(styles$c.column, styles$c.columnRight)
|
|
37747
37925
|
}, /*#__PURE__*/React.createElement(Sortable
|
|
37748
37926
|
// @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
|
|
37749
37927
|
, {
|
|
@@ -37797,7 +37975,7 @@ _.extend(Matcher, {
|
|
|
37797
37975
|
});
|
|
37798
37976
|
const padding = 5;
|
|
37799
37977
|
const border = "1px solid #444";
|
|
37800
|
-
const styles$
|
|
37978
|
+
const styles$c = StyleSheet.create({
|
|
37801
37979
|
widget: {
|
|
37802
37980
|
paddingTop: padding,
|
|
37803
37981
|
maxWidth: "100%",
|
|
@@ -38473,9 +38651,9 @@ function drawText(ctx, item) {
|
|
|
38473
38651
|
if (item.value === null) {
|
|
38474
38652
|
return;
|
|
38475
38653
|
}
|
|
38476
|
-
ctx.fillStyle = styles$
|
|
38477
|
-
ctx.font = styles$
|
|
38478
|
-
ctx.fillText(item.value, item.pos[0] - styles$
|
|
38654
|
+
ctx.fillStyle = styles$b.fgColor;
|
|
38655
|
+
ctx.font = styles$b.font;
|
|
38656
|
+
ctx.fillText(item.value, item.pos[0] - styles$b.fontSizePx / 2 + 1, item.pos[1] + styles$b.fontSizePx / 2);
|
|
38479
38657
|
}
|
|
38480
38658
|
|
|
38481
38659
|
/**
|
|
@@ -38496,16 +38674,16 @@ function drawText(ctx, item) {
|
|
|
38496
38674
|
function drawDoubleLine(ctx, item) {
|
|
38497
38675
|
// Outer line that forms both of the bond lines.
|
|
38498
38676
|
let path = new Path2D();
|
|
38499
|
-
ctx.lineWidth = 5 * styles$
|
|
38500
|
-
ctx.strokeStyle = styles$
|
|
38677
|
+
ctx.lineWidth = 5 * styles$b.lineWidth;
|
|
38678
|
+
ctx.strokeStyle = styles$b.fgColor;
|
|
38501
38679
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
38502
38680
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
38503
38681
|
ctx.stroke(path);
|
|
38504
38682
|
|
|
38505
38683
|
// Inner white line that separates the two bond lines.
|
|
38506
38684
|
path = new Path2D();
|
|
38507
|
-
ctx.lineWidth = 3 * styles$
|
|
38508
|
-
ctx.strokeStyle = styles$
|
|
38685
|
+
ctx.lineWidth = 3 * styles$b.lineWidth;
|
|
38686
|
+
ctx.strokeStyle = styles$b.bgColor;
|
|
38509
38687
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
38510
38688
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
38511
38689
|
ctx.stroke(path);
|
|
@@ -38532,16 +38710,16 @@ function drawTripleLine(ctx, item) {
|
|
|
38532
38710
|
|
|
38533
38711
|
// Outer line that will form the two outer bond lines.
|
|
38534
38712
|
let path = new Path2D();
|
|
38535
|
-
ctx.lineWidth = 7 * styles$
|
|
38536
|
-
ctx.strokeStyle = styles$
|
|
38713
|
+
ctx.lineWidth = 7 * styles$b.lineWidth;
|
|
38714
|
+
ctx.strokeStyle = styles$b.fgColor;
|
|
38537
38715
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
38538
38716
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
38539
38717
|
ctx.stroke(path);
|
|
38540
38718
|
|
|
38541
38719
|
// Middle white line that separates the bonds
|
|
38542
38720
|
path = new Path2D();
|
|
38543
|
-
ctx.lineWidth = 5 * styles$
|
|
38544
|
-
ctx.strokeStyle = styles$
|
|
38721
|
+
ctx.lineWidth = 5 * styles$b.lineWidth;
|
|
38722
|
+
ctx.strokeStyle = styles$b.bgColor;
|
|
38545
38723
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
38546
38724
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
38547
38725
|
ctx.stroke(path);
|
|
@@ -38563,8 +38741,8 @@ function drawTripleLine(ctx, item) {
|
|
|
38563
38741
|
*/
|
|
38564
38742
|
function drawLine(ctx, item) {
|
|
38565
38743
|
const path = new Path2D();
|
|
38566
|
-
ctx.lineWidth = styles$
|
|
38567
|
-
ctx.strokeStyle = styles$
|
|
38744
|
+
ctx.lineWidth = styles$b.lineWidth;
|
|
38745
|
+
ctx.strokeStyle = styles$b.fgColor;
|
|
38568
38746
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
38569
38747
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
38570
38748
|
ctx.stroke(path);
|
|
@@ -38616,7 +38794,7 @@ function compareElements(item0, item1) {
|
|
|
38616
38794
|
function draw(ctx, items) {
|
|
38617
38795
|
items.sort(compareElements).forEach(drawItem(ctx));
|
|
38618
38796
|
}
|
|
38619
|
-
const styles$
|
|
38797
|
+
const styles$b = {
|
|
38620
38798
|
bgColor: "rgb(255, 255, 255)",
|
|
38621
38799
|
fgColor: "rgb(0, 0, 0)",
|
|
38622
38800
|
fontSizePx: 12,
|
|
@@ -41175,7 +41353,7 @@ class HighlightRenderer extends React.PureComponent {
|
|
|
41175
41353
|
const rects = this.state.cachedHighlightRects;
|
|
41176
41354
|
return /*#__PURE__*/React.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React.createElement("div", {
|
|
41177
41355
|
key: index,
|
|
41178
|
-
className: css(styles$
|
|
41356
|
+
className: css(styles$a.highlightRect),
|
|
41179
41357
|
style: {
|
|
41180
41358
|
// NOTE(mdr): We apply `position: absolute` here
|
|
41181
41359
|
// rather than in Aphrodite styles, because
|
|
@@ -41194,7 +41372,7 @@ class HighlightRenderer extends React.PureComponent {
|
|
|
41194
41372
|
})));
|
|
41195
41373
|
}
|
|
41196
41374
|
}
|
|
41197
|
-
const styles$
|
|
41375
|
+
const styles$a = StyleSheet.create({
|
|
41198
41376
|
highlightRect: {
|
|
41199
41377
|
background: "#fffabe" // highlighter yellow :)
|
|
41200
41378
|
}
|
|
@@ -41275,7 +41453,7 @@ class HighlightTooltip extends React.PureComponent {
|
|
|
41275
41453
|
// TooltipContent wouldn't let me overwrite
|
|
41276
41454
|
// user-select and onClick
|
|
41277
41455
|
const content = /*#__PURE__*/React.createElement("div", {
|
|
41278
|
-
className: css(styles$
|
|
41456
|
+
className: css(styles$9.tooltipLabel),
|
|
41279
41457
|
onClick: this.props.onClick
|
|
41280
41458
|
}, this.props.label);
|
|
41281
41459
|
const style = {
|
|
@@ -41295,7 +41473,7 @@ class HighlightTooltip extends React.PureComponent {
|
|
|
41295
41473
|
}, /*#__PURE__*/React.createElement("div", null)));
|
|
41296
41474
|
}
|
|
41297
41475
|
}
|
|
41298
|
-
const styles$
|
|
41476
|
+
const styles$9 = StyleSheet.create({
|
|
41299
41477
|
tooltipLabel: {
|
|
41300
41478
|
// Unlike most tooltip contents, we don't want this label to be
|
|
41301
41479
|
// selectable. Selecting it is not only unhelpful, but dangerous: if
|
|
@@ -41849,7 +42027,7 @@ class HighlightableContent extends React.PureComponent {
|
|
|
41849
42027
|
// starting point: https://phabricator.khanacademy.org/D35623?id=170698
|
|
41850
42028
|
const buildHighlight = r => this._buildHighlight(r);
|
|
41851
42029
|
return /*#__PURE__*/React.createElement("div", {
|
|
41852
|
-
className: css(styles$
|
|
42030
|
+
className: css(styles$8.container),
|
|
41853
42031
|
ref: container => this._container = container
|
|
41854
42032
|
}, /*#__PURE__*/React.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React.createElement(HighlightingUI, {
|
|
41855
42033
|
buildHighlight: buildHighlight,
|
|
@@ -41870,14 +42048,14 @@ class HighlightableContent extends React.PureComponent {
|
|
|
41870
42048
|
onAddHighlight: this._handleAddHighlight,
|
|
41871
42049
|
onRemoveHighlight: this._handleRemoveHighlight
|
|
41872
42050
|
})), /*#__PURE__*/React.createElement("div", {
|
|
41873
|
-
className: css(styles$
|
|
42051
|
+
className: css(styles$8.content),
|
|
41874
42052
|
ref: content => this._content = content
|
|
41875
42053
|
}, /*#__PURE__*/React.createElement(WordIndexer, {
|
|
41876
42054
|
onWordsUpdate: this._handleWordsUpdate
|
|
41877
42055
|
}, this.props.children)));
|
|
41878
42056
|
}
|
|
41879
42057
|
}
|
|
41880
|
-
const styles$
|
|
42058
|
+
const styles$8 = StyleSheet.create({
|
|
41881
42059
|
// We render content with z-index 1, and highlights with z-index 0, so that
|
|
41882
42060
|
// content will receive the browser's native pointer events. (Highlights
|
|
41883
42061
|
// have their own magic code to manage hover detection, despite being
|
|
@@ -42289,7 +42467,7 @@ class LineHeightMeasurer extends React.Component {
|
|
|
42289
42467
|
}
|
|
42290
42468
|
render() {
|
|
42291
42469
|
return /*#__PURE__*/React.createElement("div", {
|
|
42292
|
-
className: css(styles$
|
|
42470
|
+
className: css(styles$7.measurer),
|
|
42293
42471
|
"aria-hidden": "true"
|
|
42294
42472
|
}, /*#__PURE__*/React.createElement("div", {
|
|
42295
42473
|
ref: ref => this._line = ref,
|
|
@@ -42297,7 +42475,7 @@ class LineHeightMeasurer extends React.Component {
|
|
|
42297
42475
|
}, "Line Height Measurement"));
|
|
42298
42476
|
}
|
|
42299
42477
|
}
|
|
42300
|
-
const styles$
|
|
42478
|
+
const styles$7 = StyleSheet.create({
|
|
42301
42479
|
measurer: {
|
|
42302
42480
|
position: "absolute",
|
|
42303
42481
|
top: 0,
|
|
@@ -42772,6 +42950,207 @@ var PassageRefTarget$1 = {
|
|
|
42772
42950
|
isLintable: true
|
|
42773
42951
|
};
|
|
42774
42952
|
|
|
42953
|
+
/* eslint-disable react/forbid-prop-types, react/sort-comp */
|
|
42954
|
+
|
|
42955
|
+
// For returning user input, but currently the PhET widget
|
|
42956
|
+
// does not support accessing user input
|
|
42957
|
+
// This renders the PhET sim
|
|
42958
|
+
class PhetSimulation extends React.Component {
|
|
42959
|
+
constructor(props) {
|
|
42960
|
+
super(props);
|
|
42961
|
+
this.iframeRef = /*#__PURE__*/React.createRef();
|
|
42962
|
+
this.locale = void 0;
|
|
42963
|
+
this.state = {
|
|
42964
|
+
url: null,
|
|
42965
|
+
banner: null
|
|
42966
|
+
};
|
|
42967
|
+
this.change = (...args) => {
|
|
42968
|
+
// @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
|
|
42969
|
+
return change.apply(this, args);
|
|
42970
|
+
};
|
|
42971
|
+
this.simpleValidate = rubric => {
|
|
42972
|
+
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof PhetSimulation'.
|
|
42973
|
+
return PhetSimulation.validate(this.getUserInput(), rubric);
|
|
42974
|
+
};
|
|
42975
|
+
// kaLocales and PhET locales use different formats and abbreviations.
|
|
42976
|
+
// PhET accepts different formats, i.e. kaLocale's hyphens, but it does not accept
|
|
42977
|
+
// different abbreviations, so in points of divergence of abbreviations, we need to
|
|
42978
|
+
// convert kaLocale abbreviations into abbreviations recognized by PhET.
|
|
42979
|
+
this.getPhetCompatibleLocale = kaLocale => {
|
|
42980
|
+
switch (kaLocale) {
|
|
42981
|
+
case "pt-pt":
|
|
42982
|
+
return "pt";
|
|
42983
|
+
case "zh-hans":
|
|
42984
|
+
return "zh_CN";
|
|
42985
|
+
case "zh-hant":
|
|
42986
|
+
return "zh_TW";
|
|
42987
|
+
case "fa-af":
|
|
42988
|
+
return "fa_DA";
|
|
42989
|
+
default:
|
|
42990
|
+
return kaLocale;
|
|
42991
|
+
}
|
|
42992
|
+
};
|
|
42993
|
+
this.displayLoadFailure = () => {
|
|
42994
|
+
this.setState({
|
|
42995
|
+
url: null,
|
|
42996
|
+
banner: {
|
|
42997
|
+
message: this.context.strings.simulationLoadFail,
|
|
42998
|
+
kind: "critical"
|
|
42999
|
+
}
|
|
43000
|
+
});
|
|
43001
|
+
};
|
|
43002
|
+
this.locale = this.getPhetCompatibleLocale(getDependencies().kaLocale);
|
|
43003
|
+
}
|
|
43004
|
+
getUserInput() {
|
|
43005
|
+
return null;
|
|
43006
|
+
}
|
|
43007
|
+
async componentDidMount() {
|
|
43008
|
+
await this.updateSimState(this.props.url);
|
|
43009
|
+
}
|
|
43010
|
+
async componentDidUpdate(prevProps) {
|
|
43011
|
+
// If the URL has changed, update our state
|
|
43012
|
+
if (prevProps.url !== this.props.url) {
|
|
43013
|
+
await this.updateSimState(this.props.url);
|
|
43014
|
+
}
|
|
43015
|
+
}
|
|
43016
|
+
render() {
|
|
43017
|
+
var _this$state$url;
|
|
43018
|
+
// We sandbox the iframe so that we allowlist only the functionality
|
|
43019
|
+
// that we need. This makes it safer to present third-party content
|
|
43020
|
+
// from the PhET website.
|
|
43021
|
+
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
43022
|
+
const sandboxProperties = "allow-same-origin allow-scripts";
|
|
43023
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
43024
|
+
style: styles$6.container
|
|
43025
|
+
}, this.state.banner !== null &&
|
|
43026
|
+
/*#__PURE__*/
|
|
43027
|
+
// TODO(anna): Make this banner focusable
|
|
43028
|
+
React.createElement(View, {
|
|
43029
|
+
style: {
|
|
43030
|
+
marginBottom: phoneMargin
|
|
43031
|
+
}
|
|
43032
|
+
}, /*#__PURE__*/React.createElement(Banner, {
|
|
43033
|
+
layout: "floating",
|
|
43034
|
+
kind: this.state.banner.kind,
|
|
43035
|
+
text: this.state.banner.message
|
|
43036
|
+
})), /*#__PURE__*/React.createElement("iframe", {
|
|
43037
|
+
ref: this.iframeRef,
|
|
43038
|
+
title: this.props.description,
|
|
43039
|
+
sandbox: sandboxProperties,
|
|
43040
|
+
style: {
|
|
43041
|
+
minWidth: 400,
|
|
43042
|
+
height: 360,
|
|
43043
|
+
width: "100%",
|
|
43044
|
+
borderWidth: 0
|
|
43045
|
+
},
|
|
43046
|
+
src: (_this$state$url = this.state.url) == null ? void 0 : _this$state$url.toString(),
|
|
43047
|
+
allow: "fullscreen"
|
|
43048
|
+
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
43049
|
+
icon: cornersOutIcon,
|
|
43050
|
+
onClick: () => {
|
|
43051
|
+
var _this$iframeRef$curre;
|
|
43052
|
+
(_this$iframeRef$curre = this.iframeRef.current) == null || _this$iframeRef$curre.requestFullscreen();
|
|
43053
|
+
},
|
|
43054
|
+
kind: "secondary",
|
|
43055
|
+
"aria-label": "Fullscreen",
|
|
43056
|
+
style: {
|
|
43057
|
+
marginTop: 5,
|
|
43058
|
+
marginBottom: 5,
|
|
43059
|
+
alignSelf: "flex-end"
|
|
43060
|
+
},
|
|
43061
|
+
disabled: this.state.url === null
|
|
43062
|
+
}));
|
|
43063
|
+
}
|
|
43064
|
+
async updateSimState(urlString) {
|
|
43065
|
+
const url = makeSafeUrl(urlString, this.locale);
|
|
43066
|
+
if (url === null) {
|
|
43067
|
+
this.displayLoadFailure();
|
|
43068
|
+
return;
|
|
43069
|
+
}
|
|
43070
|
+
const response = await fetch(url);
|
|
43071
|
+
if (!response.ok) {
|
|
43072
|
+
this.displayLoadFailure();
|
|
43073
|
+
return;
|
|
43074
|
+
}
|
|
43075
|
+
const showLocaleWarning = await this.showLocaleWarning(url);
|
|
43076
|
+
this.setState({
|
|
43077
|
+
url: url,
|
|
43078
|
+
banner: showLocaleWarning ? {
|
|
43079
|
+
message: this.context.strings.simulationLocaleWarning,
|
|
43080
|
+
kind: "warning"
|
|
43081
|
+
} : null
|
|
43082
|
+
});
|
|
43083
|
+
}
|
|
43084
|
+
async showLocaleWarning(url) {
|
|
43085
|
+
// Do not show a locale warning on an invalid URL
|
|
43086
|
+
if (!url) {
|
|
43087
|
+
return false;
|
|
43088
|
+
}
|
|
43089
|
+
// Grab the simulation name
|
|
43090
|
+
const phetRegex = /https:\/\/phet\.colorado\.edu\/sims\/html\/([a-zA-Z0-9-]+)\/.*/g;
|
|
43091
|
+
const match = phetRegex.exec(url.toString());
|
|
43092
|
+
// Do not show a locale warning on a non-simulation URL
|
|
43093
|
+
if (match === null) {
|
|
43094
|
+
return false;
|
|
43095
|
+
}
|
|
43096
|
+
const simName = match[1];
|
|
43097
|
+
const response = await fetch(`https://phet.colorado.edu/sims/html/${simName}/latest/string-map.json`);
|
|
43098
|
+
if (!response.ok) {
|
|
43099
|
+
return false;
|
|
43100
|
+
}
|
|
43101
|
+
let responseJson;
|
|
43102
|
+
try {
|
|
43103
|
+
responseJson = await response.json();
|
|
43104
|
+
} catch (_unused) {
|
|
43105
|
+
// If the file exists but there is no content to parse into a JSON,
|
|
43106
|
+
// response.json() will throw an error that we want to catch.
|
|
43107
|
+
return false;
|
|
43108
|
+
}
|
|
43109
|
+
const locales = Object.keys(responseJson);
|
|
43110
|
+
|
|
43111
|
+
// Only display a locale warning if there is no fallback language
|
|
43112
|
+
const baseLocale = this.locale.split("_")[0];
|
|
43113
|
+
for (const l of locales) {
|
|
43114
|
+
if (baseLocale === l.split("_")[0]) {
|
|
43115
|
+
return false;
|
|
43116
|
+
}
|
|
43117
|
+
}
|
|
43118
|
+
return true;
|
|
43119
|
+
}
|
|
43120
|
+
}
|
|
43121
|
+
|
|
43122
|
+
// Setting URL to null will display an error message in the iframe
|
|
43123
|
+
PhetSimulation.contextType = PerseusI18nContext;
|
|
43124
|
+
const makeSafeUrl = (urlString, locale) => {
|
|
43125
|
+
if (!URL.canParse(urlString)) {
|
|
43126
|
+
return null;
|
|
43127
|
+
}
|
|
43128
|
+
const url = new URL(urlString);
|
|
43129
|
+
if (url.origin !== "https://phet.colorado.edu") {
|
|
43130
|
+
return null;
|
|
43131
|
+
}
|
|
43132
|
+
url.searchParams.set("locale", locale);
|
|
43133
|
+
return url;
|
|
43134
|
+
};
|
|
43135
|
+
var PhetSimulation$1 = {
|
|
43136
|
+
name: "phet-simulation",
|
|
43137
|
+
displayName: "PhET Simulation",
|
|
43138
|
+
widget: PhetSimulation,
|
|
43139
|
+
// Hides widget from content creators until full release
|
|
43140
|
+
hidden: true,
|
|
43141
|
+
isLintable: true
|
|
43142
|
+
};
|
|
43143
|
+
const styles$6 = StyleSheet.create({
|
|
43144
|
+
container: {
|
|
43145
|
+
borderRadius: borderRadiusLarge,
|
|
43146
|
+
borderWidth: 1,
|
|
43147
|
+
borderColor: basicBorderColor,
|
|
43148
|
+
padding: phoneMargin,
|
|
43149
|
+
paddingBottom: 0,
|
|
43150
|
+
width: 650
|
|
43151
|
+
}
|
|
43152
|
+
});
|
|
43153
|
+
|
|
42775
43154
|
/* eslint-disable react/no-unsafe */
|
|
42776
43155
|
const {
|
|
42777
43156
|
deepEq
|
|
@@ -44236,7 +44615,7 @@ var Video$1 = {
|
|
|
44236
44615
|
};
|
|
44237
44616
|
|
|
44238
44617
|
/* eslint-disable import/no-named-as-default */
|
|
44239
|
-
var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, PythonProgram$1, Sorter$1, Table$1, Video$1, DeprecatedStandin$1];
|
|
44618
|
+
var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, PhetSimulation$1, Plotter$1, PythonProgram$1, Sorter$1, Table$1, Video$1, DeprecatedStandin$1];
|
|
44240
44619
|
|
|
44241
44620
|
/**
|
|
44242
44621
|
* This should be called by all clients, specifying whether extra widgets are
|
|
@@ -44276,7 +44655,7 @@ const init = function init(options) {
|
|
|
44276
44655
|
|
|
44277
44656
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44278
44657
|
const libName = "@khanacademy/perseus";
|
|
44279
|
-
const libVersion = "
|
|
44658
|
+
const libVersion = "31.0.1";
|
|
44280
44659
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44281
44660
|
|
|
44282
44661
|
const apiVersion = {
|
|
@@ -47836,6 +48215,7 @@ const widgetNameToEnum = {
|
|
|
47836
48215
|
passage: "PASSAGE",
|
|
47837
48216
|
"passage-ref": "PASSAGE_REF",
|
|
47838
48217
|
"passage-ref-target": "PASSAGE_REF_TARGET",
|
|
48218
|
+
"phet-simulation": "PHET_SIMULATION",
|
|
47839
48219
|
plotter: "PLOTTER",
|
|
47840
48220
|
"python-program": "PYTHON_PROGRAM",
|
|
47841
48221
|
"reaction-diagram": "REACTION_DIAGRAM",
|