@khanacademy/perseus 20.0.1 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as KAS from '@khanacademy/kas';
2
- import { keyTranslator, CursorContext, createMathField, convertDotToTimesByLocale, mathQuillInstance, getCursorContext, DesktopKeypad, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
2
+ import { keyTranslator, CursorContext, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
3
3
  import * as PerseusLinter from '@khanacademy/perseus-linter';
4
4
  import { linterContextDefault, Rule, linterContextProps } from '@khanacademy/perseus-linter';
5
5
  import { View, RenderStateRoot, useUniqueIdWithMock, Text as Text$1 } from '@khanacademy/wonder-blocks-core';
@@ -8,7 +8,7 @@ import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
8
8
  import classNames from 'classnames';
9
9
  import * as React from 'react';
10
10
  import React__default, { useState, useEffect, useRef } from 'react';
11
- import _, { debounce } from 'underscore';
11
+ import _, { debounce as debounce$1 } from 'underscore';
12
12
  import Clickable from '@khanacademy/wonder-blocks-clickable';
13
13
  import Color, { fade } from '@khanacademy/wonder-blocks-color';
14
14
  import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
@@ -23,16 +23,18 @@ import { entries, UnreachableCaseError, keys } from '@khanacademy/wonder-stuff-c
23
23
  import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
24
24
  import SimpleMarkdown from '@khanacademy/simple-markdown';
25
25
  import { pureMarkdownRules } from '@khanacademy/pure-markdown';
26
- import { TextField } from '@khanacademy/wonder-blocks-form';
26
+ import { TextField, Checkbox } from '@khanacademy/wonder-blocks-form';
27
27
  import Button from '@khanacademy/wonder-blocks-button';
28
28
  import { Strut } from '@khanacademy/wonder-blocks-layout';
29
29
  import Banner from '@khanacademy/wonder-blocks-banner';
30
30
  import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-blocks-dropdown';
31
- import debounce$1 from 'lodash.debounce';
32
- import { vec, Line as Line$3, MovablePoint as MovablePoint$5, Coordinates, Mafs } from 'mafs';
31
+ import debounce$2 from 'lodash.debounce';
32
+ import { vec, useMovable, useTransformContext, MovablePoint as MovablePoint$5, Coordinates, Mafs } from 'mafs';
33
+ import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
34
+ import questionIcon from '@phosphor-icons/core/regular/question.svg';
35
+ import { LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
33
36
  import createReactClass from 'create-react-class';
34
37
  import Switch from '@khanacademy/wonder-blocks-switch';
35
- import { LabelMedium } from '@khanacademy/wonder-blocks-typography';
36
38
  import Pill from '@khanacademy/wonder-blocks-pill';
37
39
  import { Popper } from 'react-popper';
38
40
  import Link from '@khanacademy/wonder-blocks-link';
@@ -42,12 +44,14 @@ function _extends() {
42
44
  _extends = Object.assign ? Object.assign.bind() : function (target) {
43
45
  for (var i = 1; i < arguments.length; i++) {
44
46
  var source = arguments[i];
47
+
45
48
  for (var key in source) {
46
49
  if (Object.prototype.hasOwnProperty.call(source, key)) {
47
50
  target[key] = source[key];
48
51
  }
49
52
  }
50
53
  }
54
+
51
55
  return target;
52
56
  };
53
57
  return _extends.apply(this, arguments);
@@ -58,14 +62,28 @@ function _objectWithoutPropertiesLoose(source, excluded) {
58
62
  var target = {};
59
63
  var sourceKeys = Object.keys(source);
60
64
  var key, i;
65
+
61
66
  for (i = 0; i < sourceKeys.length; i++) {
62
67
  key = sourceKeys[i];
63
68
  if (excluded.indexOf(key) >= 0) continue;
64
69
  target[key] = source[key];
65
70
  }
71
+
66
72
  return target;
67
73
  }
68
74
 
75
+ const debounce = (func, delay) => {
76
+ let timer = null;
77
+ return (...args) => {
78
+ if (timer) {
79
+ clearTimeout(timer);
80
+ }
81
+ timer = window.setTimeout(() => {
82
+ func(...args);
83
+ }, delay);
84
+ };
85
+ };
86
+
69
87
  const customKeyTranslator = _extends({}, keyTranslator, {
70
88
  // If there's something in the input that can become part of a
71
89
  // fraction, typing "/" puts it in the numerator. If not, typing
@@ -119,7 +137,7 @@ class MathInput extends React.Component {
119
137
  // Initialize MathQuill.MathField instance
120
138
  this.__mathField = createMathField(this.__mathFieldWrapperRef, baseConfig => _extends({}, baseConfig, {
121
139
  handlers: {
122
- edit: mathField => {
140
+ edit: debounce(mathField => {
123
141
  // This handler is guaranteed to be called on change, but
124
142
  // unlike React it sometimes generates false positives.
125
143
  // One of these is on initialization (with an empty string
@@ -155,7 +173,7 @@ class MathInput extends React.Component {
155
173
  this.setState({
156
174
  cursorContext: getCursorContext(mathField)
157
175
  });
158
- },
176
+ }, 100),
159
177
  enter: () => {
160
178
  // NOTE(kevinb): This isn't how answers to exercises are
161
179
  // submitted. The actual mechanism for this can be found
@@ -245,7 +263,7 @@ class MathInput extends React.Component {
245
263
  className = className + " " + this.props.className;
246
264
  }
247
265
  return /*#__PURE__*/React.createElement(View, {
248
- style: [styles$C.outerWrapper, this.state.focused && styles$C.wrapperFocused, this.props.hasError && styles$C.wrapperError]
266
+ style: [styles$D.outerWrapper, this.state.focused && styles$D.wrapperFocused, this.props.hasError && styles$D.wrapperError]
249
267
  }, /*#__PURE__*/React.createElement("div", {
250
268
  style: {
251
269
  display: "flex",
@@ -278,7 +296,7 @@ class MathInput extends React.Component {
278
296
  var _this$props$keypadBut, _this$props;
279
297
  return /*#__PURE__*/React.createElement(PopoverContentCore, {
280
298
  closeButtonVisible: true,
281
- style: styles$C.popoverContent
299
+ style: styles$D.popoverContent
282
300
  }, /*#__PURE__*/React.createElement(DesktopKeypad, _extends({
283
301
  onAnalyticsEvent: this.props.analytics.onAnalyticsEvent,
284
302
  extraKeys: this.props.extraKeys,
@@ -322,9 +340,9 @@ const MathInputIcon = ({
322
340
  color = Color.offBlack;
323
341
  break;
324
342
  }
325
- const dynamicClass = active || focused ? styles$C.iconActive : styles$C.iconInactive;
343
+ const dynamicClass = active || focused ? styles$D.iconActive : styles$D.iconInactive;
326
344
  return /*#__PURE__*/React.createElement(View, {
327
- style: [styles$C.iconContainer, dynamicClass]
345
+ style: [styles$D.iconContainer, dynamicClass]
328
346
  }, /*#__PURE__*/React.createElement("svg", {
329
347
  xmlns: "http://www.w3.org/2000/svg",
330
348
  width: "16",
@@ -369,7 +387,7 @@ const inputFocused = {
369
387
  borderColor: Color.blue,
370
388
  margin: -1
371
389
  };
372
- const styles$C = StyleSheet.create({
390
+ const styles$D = StyleSheet.create({
373
391
  iconContainer: {
374
392
  display: "flex",
375
393
  justifyContent: "center",
@@ -4223,6 +4241,7 @@ function _classPrivateFieldBase(receiver, privateKey) {
4223
4241
  if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
4224
4242
  throw new TypeError("attempted to use private field on non-instance");
4225
4243
  }
4244
+
4226
4245
  return receiver;
4227
4246
  }
4228
4247
 
@@ -17864,33 +17883,33 @@ class Lint extends React.Component {
17864
17883
  let warningText;
17865
17884
  let warningTextStyle;
17866
17885
  if (this.props.severity === Severity.Error) {
17867
- severityStyle = styles$B.indicatorError;
17886
+ severityStyle = styles$C.indicatorError;
17868
17887
  warningText = "Error";
17869
- warningTextStyle = styles$B.publishBlockingError;
17888
+ warningTextStyle = styles$C.publishBlockingError;
17870
17889
  } else if (this.props.severity === Severity.Warning) {
17871
- severityStyle = styles$B.indicatorWarning;
17890
+ severityStyle = styles$C.indicatorWarning;
17872
17891
  warningText = "Warning";
17873
- warningTextStyle = styles$B.warning;
17892
+ warningTextStyle = styles$C.warning;
17874
17893
  } else {
17875
- severityStyle = styles$B.indicatorGuideline;
17894
+ severityStyle = styles$C.indicatorGuideline;
17876
17895
  warningText = "Recommendation";
17877
- warningTextStyle = styles$B.warning;
17896
+ warningTextStyle = styles$C.warning;
17878
17897
  }
17879
17898
  return /*#__PURE__*/React.createElement("a", {
17880
17899
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
17881
17900
  target: "lint-help-window",
17882
17901
  className: css(style)
17883
17902
  }, /*#__PURE__*/React.createElement("span", {
17884
- className: css(styles$B.indicator, severityStyle)
17903
+ className: css(styles$C.indicator, severityStyle)
17885
17904
  }, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React.createElement("div", {
17886
- className: css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
17905
+ className: css(styles$C.tooltip, tooltipAbove && styles$C.tooltipAbove)
17887
17906
  }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
17888
17907
  key: i,
17889
- className: css(styles$B.tooltipParagraph)
17908
+ className: css(styles$C.tooltipParagraph)
17890
17909
  }, /*#__PURE__*/React.createElement("span", {
17891
17910
  className: css(warningTextStyle)
17892
17911
  }, warningText, ":", " "), m)), /*#__PURE__*/React.createElement("div", {
17893
- className: css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
17912
+ className: css(styles$C.tail, tooltipAbove && styles$C.tailAbove)
17894
17913
  })));
17895
17914
  };
17896
17915
  }
@@ -17928,20 +17947,20 @@ class Lint extends React.Component {
17928
17947
  }
17929
17948
  if (blockHighlight) {
17930
17949
  return /*#__PURE__*/React.createElement("span", {
17931
- className: css(styles$B.lintContainer, styles$B.lintContainerBlock)
17932
- }, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17950
+ className: css(styles$C.lintContainer, styles$C.lintContainerBlock)
17951
+ }, this.renderLink(styles$C.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17933
17952
  }
17934
17953
  if (inline) {
17935
17954
  return /*#__PURE__*/React.createElement("span", {
17936
- className: css(styles$B.lintContainer)
17937
- }, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17955
+ className: css(styles$C.lintContainer)
17956
+ }, this.renderLink(styles$C.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17938
17957
  }
17939
17958
  return /*#__PURE__*/React.createElement("div", {
17940
- className: css(styles$B.lintContainer)
17941
- }, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
17959
+ className: css(styles$C.lintContainer)
17960
+ }, this.renderLink(styles$C.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
17942
17961
  }
17943
17962
  }
17944
- const styles$B = StyleSheet.create({
17963
+ const styles$C = StyleSheet.create({
17945
17964
  // This is the class of the outermost element.
17946
17965
  // We use relative positioning so that the lint indicator can be
17947
17966
  // positioned absolutely relative to the position of the linty container.
@@ -18540,7 +18559,7 @@ class TranslationLinter {
18540
18559
  * Linting is relatively expensive -- so we debounce linting each instance
18541
18560
  * for some amount of time.
18542
18561
  */
18543
- this.runLinter = debounce((perseusStr, onLintErrorsGenerated) => {
18562
+ this.runLinter = debounce$1((perseusStr, onLintErrorsGenerated) => {
18544
18563
  // TODO(FEI-5003): Do we still need to check for 'KA'?
18545
18564
  if (typeof KA === "undefined") {
18546
18565
  return;
@@ -19866,7 +19885,7 @@ class Renderer extends React.Component {
19866
19885
  paddingLeft: margin,
19867
19886
  paddingRight: margin
19868
19887
  };
19869
- const mobileInnerStyle = _extends({}, innerStyle, styles$A.mobileZoomableParentFix);
19888
+ const mobileInnerStyle = _extends({}, innerStyle, styles$B.mobileZoomableParentFix);
19870
19889
  return /*#__PURE__*/React.createElement("div", {
19871
19890
  key: state.key,
19872
19891
  className: "perseus-block-math",
@@ -19987,7 +20006,7 @@ class Renderer extends React.Component {
19987
20006
  paddingLeft: 0,
19988
20007
  paddingRight: 0
19989
20008
  };
19990
- const mobileInnerStyle = _extends({}, innerStyle, styles$A.mobileZoomableParentFix);
20009
+ const mobileInnerStyle = _extends({}, innerStyle, styles$B.mobileZoomableParentFix);
19991
20010
  const wrappedOutput = /*#__PURE__*/React.createElement("div", {
19992
20011
  style: _extends({}, mobileInnerStyle, {
19993
20012
  overflowX: "auto"
@@ -20634,7 +20653,7 @@ Renderer.defaultProps = {
20634
20653
  onSerializedStateUpdated: () => {},
20635
20654
  linterContext: PerseusLinter.linterContextDefault
20636
20655
  };
20637
- const styles$A = {
20656
+ const styles$B = {
20638
20657
  mobileZoomableParentFix: {
20639
20658
  // NOTE(abdul): There is an issue where transform animations will
20640
20659
  // cause the Zoomable component to disappear when running on the
@@ -21642,10 +21661,10 @@ class InputNumber extends React.Component {
21642
21661
  // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21643
21662
  // you modify this, double-check if you also need to modify that
21644
21663
  // component.
21645
- const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
21664
+ const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
21646
21665
  // Unanswered
21647
21666
  if (rubric && !this.props.currentValue) {
21648
- inputStyles.push(styles$z.answerStateUnanswered);
21667
+ inputStyles.push(styles$A.answerStateUnanswered);
21649
21668
  }
21650
21669
  return /*#__PURE__*/React.createElement(InputWithExamples
21651
21670
  // eslint-disable-next-line react/no-string-refs
@@ -21730,7 +21749,7 @@ InputNumber.defaultProps = {
21730
21749
  apiOptions: ApiOptions.defaults,
21731
21750
  linterContext: linterContextDefault
21732
21751
  };
21733
- const styles$z = StyleSheet.create({
21752
+ const styles$A = StyleSheet.create({
21734
21753
  default: {
21735
21754
  width: 80,
21736
21755
  height: "auto"
@@ -22722,7 +22741,7 @@ const FocusRing = function FocusRing(props) {
22722
22741
  };
22723
22742
  return /*#__PURE__*/React.createElement("span", {
22724
22743
  "data-test-id": "focus-ring",
22725
- className: css(styles$y.ring),
22744
+ className: css(styles$z.ring),
22726
22745
  style: style
22727
22746
  }, children);
22728
22747
  };
@@ -22731,7 +22750,7 @@ FocusRing.defaultProps = {
22731
22750
  color: kaGreen$1,
22732
22751
  multipleSelect: false
22733
22752
  };
22734
- const styles$y = StyleSheet.create({
22753
+ const styles$z = StyleSheet.create({
22735
22754
  ring: {
22736
22755
  margin: "auto",
22737
22756
  display: "inline-block",
@@ -22768,7 +22787,7 @@ function getChoiceLetter(pos) {
22768
22787
  }
22769
22788
 
22770
22789
  const CHOICE_ICON_SIZE = 24;
22771
- const styles$x = StyleSheet.create({
22790
+ const styles$y = StyleSheet.create({
22772
22791
  iconWrapper: {
22773
22792
  display: "inline-block",
22774
22793
  position: "relative"
@@ -22791,7 +22810,7 @@ const CrossOutLine = function CrossOutLine(props) {
22791
22810
  width: CROSS_OUT_LINE_SIZE,
22792
22811
  height: CROSS_OUT_LINE_SIZE,
22793
22812
  viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
22794
- className: css(styles$w.crossOutLine),
22813
+ className: css(styles$x.crossOutLine),
22795
22814
  "data-test-id": "choice-icon__cross-out-line"
22796
22815
  }, /*#__PURE__*/React.createElement("line", {
22797
22816
  // The line stretches from the bottom-left to top-right.
@@ -22806,7 +22825,7 @@ const CrossOutLine = function CrossOutLine(props) {
22806
22825
  strokeLinecap: "round"
22807
22826
  }));
22808
22827
  };
22809
- const styles$w = StyleSheet.create({
22828
+ const styles$x = StyleSheet.create({
22810
22829
  crossOutLine: {
22811
22830
  // Center the icon within the container.
22812
22831
  position: "absolute",
@@ -22887,7 +22906,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
22887
22906
  } = props;
22888
22907
  const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
22889
22908
  return /*#__PURE__*/React.createElement("div", {
22890
- className: css(styles$x.iconWrapper)
22909
+ className: css(styles$y.iconWrapper)
22891
22910
  }, /*#__PURE__*/React.createElement(FocusRing, {
22892
22911
  color: Color.blue,
22893
22912
  visible: focused || hovered,
@@ -22896,13 +22915,13 @@ const ChoiceIcon = function ChoiceIcon(props) {
22896
22915
  // @ts-expect-error - TS2322 - Type '{ backgroundColor: string | null | undefined; borderColor: string; color: string; borderRadius: number; }' is not assignable to type 'Properties<string | number, string & {}>'.
22897
22916
  style: dynamicStyles,
22898
22917
  "data-test-id": "choice-icon__library-choice-icon",
22899
- className: css(styles$v.circle, showCorrectness && correct && styles$v.circleCorrect, showCorrectness && !correct && styles$v.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$v.circleIncorrectAnswered)
22918
+ className: css(styles$w.circle, showCorrectness && correct && styles$w.circleCorrect, showCorrectness && !correct && styles$w.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$w.circleIncorrectAnswered)
22900
22919
  // used in BaseRadio editMode to check
22901
22920
  // if we actually clicked on the radio icon
22902
22921
  ,
22903
22922
  "data-is-radio-icon": true
22904
22923
  }, /*#__PURE__*/React.createElement("div", {
22905
- className: css(styles$v.innerWrapper)
22924
+ className: css(styles$w.innerWrapper)
22906
22925
  }, /*#__PURE__*/React.createElement(ChoiceInner, {
22907
22926
  pos: pos,
22908
22927
  showCorrectness: showCorrectness,
@@ -22911,7 +22930,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
22911
22930
  color: dynamicStyles.borderColor
22912
22931
  }));
22913
22932
  };
22914
- const styles$v = StyleSheet.create({
22933
+ const styles$w = StyleSheet.create({
22915
22934
  innerWrapper: {
22916
22935
  width: CHOICE_ICON_SIZE,
22917
22936
  height: CHOICE_ICON_SIZE,
@@ -23003,19 +23022,19 @@ const OptionStatus = function OptionStatus(props) {
23003
23022
  }
23004
23023
  let textStyle;
23005
23024
  if (correct) {
23006
- textStyle = styles$u.correct;
23025
+ textStyle = styles$v.correct;
23007
23026
  } else {
23008
23027
  if (checked || previouslyAnswered) {
23009
- textStyle = styles$u.incorrectAnswered;
23028
+ textStyle = styles$v.incorrectAnswered;
23010
23029
  } else {
23011
- textStyle = styles$u.incorrect;
23030
+ textStyle = styles$v.incorrect;
23012
23031
  }
23013
23032
  }
23014
23033
  return /*#__PURE__*/React.createElement("div", {
23015
- className: css(styles$u.text, textStyle)
23034
+ className: css(styles$v.text, textStyle)
23016
23035
  }, renderText(checked, correct, crossedOut));
23017
23036
  };
23018
- const styles$u = StyleSheet.create({
23037
+ const styles$v = StyleSheet.create({
23019
23038
  text: {
23020
23039
  alignItems: "center",
23021
23040
  display: "flex",
@@ -23090,8 +23109,8 @@ const Choice = function Choice(props) {
23090
23109
  crossedOut: updatedCrossedOut
23091
23110
  });
23092
23111
  }
23093
- const descriptionClassName = classNames("description", css(styles$t.description));
23094
- const rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$t.rationale));
23112
+ const descriptionClassName = classNames("description", css(styles$u.description));
23113
+ const rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$u.rationale));
23095
23114
 
23096
23115
  // We want to show the choices as dimmed out when the choices are disabled.
23097
23116
  // However, we don't want to do this when we're in review mode in the
@@ -23255,7 +23274,7 @@ const Choice = function Choice(props) {
23255
23274
  "data-test-id": `perseus-radio-rationale-content-${pos}`
23256
23275
  }, rationale));
23257
23276
  };
23258
- const styles$t = StyleSheet.create({
23277
+ const styles$u = StyleSheet.create({
23259
23278
  description: {
23260
23279
  display: "inline-block",
23261
23280
  width: "100%"
@@ -23447,10 +23466,10 @@ const BaseRadio = function BaseRadio(props) {
23447
23466
  const isMobile = apiOptions.isMobile;
23448
23467
  const firstChoiceHighlighted = choices[0].highlighted;
23449
23468
  const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
23450
- const className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$s.radio, styles$s.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$s.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$s.radioContainerLastHighlighted));
23451
- const instructionsClassName = classNames("instructions", css(styles$s.instructions, isMobile && styles$s.instructionsMobile));
23469
+ 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));
23470
+ const instructionsClassName = classNames("instructions", css(styles$t.instructions, isMobile && styles$t.instructionsMobile));
23452
23471
  const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
23453
- const responsiveClassName = css(styles$s.responsiveFieldset);
23472
+ const responsiveClassName = css(styles$t.responsiveFieldset);
23454
23473
  const fieldset = /*#__PURE__*/React.createElement("fieldset", {
23455
23474
  className: `perseus-widget-radio-fieldset ${responsiveClassName}`
23456
23475
  }, /*#__PURE__*/React.createElement("legend", {
@@ -23501,7 +23520,7 @@ const BaseRadio = function BaseRadio(props) {
23501
23520
  const aphroditeClassName = checked => {
23502
23521
  // Whether or not to show correctness borders
23503
23522
  // for this choice and the next choice.
23504
- return css(sharedStyles.aboveScratchpad, styles$s.item, styles$s.responsiveItem, checked && styles$s.selectedItem, checked && choice.highlighted && styles$s.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$s.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$s.nextHighlighted);
23523
+ 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);
23505
23524
  };
23506
23525
 
23507
23526
  // HACK(abdulrahman): Preloads the selection-state
@@ -23575,14 +23594,14 @@ const BaseRadio = function BaseRadio(props) {
23575
23594
  // Allow for horizontal scrolling if content is too wide, which may be
23576
23595
  // an issue especially on phones.
23577
23596
  return /*#__PURE__*/React.createElement("div", {
23578
- className: css(styles$s.responsiveContainer)
23597
+ className: css(styles$t.responsiveContainer)
23579
23598
  }, fieldset);
23580
23599
  };
23581
23600
  BaseRadio.defaultProps = {
23582
23601
  editMode: false,
23583
23602
  multipleSelect: false
23584
23603
  };
23585
- const styles$s = StyleSheet.create({
23604
+ const styles$t = StyleSheet.create({
23586
23605
  instructions: {
23587
23606
  display: "block",
23588
23607
  color: gray17,
@@ -24223,9 +24242,9 @@ class Categorizer extends React.Component {
24223
24242
  indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
24224
24243
  }
24225
24244
  const table = /*#__PURE__*/React.createElement("table", {
24226
- className: "categorizer-table " + css(styles$r.mobileTable)
24245
+ className: "categorizer-table " + css(styles$s.mobileTable)
24227
24246
  }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
24228
- className: css(styles$r.emptyHeaderCell)
24247
+ className: css(styles$s.emptyHeaderCell)
24229
24248
  }), this.props.categories.map((category, i) => {
24230
24249
  // Array index is the correct key here, as that's
24231
24250
  // how category grading actually works -- no way
@@ -24233,7 +24252,7 @@ class Categorizer extends React.Component {
24233
24252
  // middle. (If we later add that, this should be
24234
24253
  // fixed.)
24235
24254
  return /*#__PURE__*/React.createElement("th", {
24236
- className: css(styles$r.header),
24255
+ className: css(styles$s.header),
24237
24256
  key: i
24238
24257
  }, /*#__PURE__*/React.createElement(Renderer, {
24239
24258
  content: category,
@@ -24253,7 +24272,7 @@ class Categorizer extends React.Component {
24253
24272
  })), self.props.categories.map((catName, catNum) => {
24254
24273
  const selected = self.props.values[itemNum] === catNum;
24255
24274
  return /*#__PURE__*/React.createElement("td", {
24256
- className: "category " + css(styles$r.cell),
24275
+ className: "category " + css(styles$s.cell),
24257
24276
  key: catNum
24258
24277
  }, /*#__PURE__*/React.createElement("div", {
24259
24278
  className: ClassNames.INTERACTIVE,
@@ -24268,7 +24287,7 @@ class Categorizer extends React.Component {
24268
24287
  onChange: () => this.onChange(itemNum, catNum),
24269
24288
  onClick: e => e.stopPropagation()
24270
24289
  }), !isMobile && /*#__PURE__*/React.createElement("span", {
24271
- className: css(styles$r.radioSpan, selected && styles$r.checkedRadioSpan, this.props.static && selected && styles$r.staticCheckedRadioSpan)
24290
+ className: css(styles$s.radioSpan, selected && styles$s.checkedRadioSpan, this.props.static && selected && styles$s.staticCheckedRadioSpan)
24272
24291
  }, selected ? /*#__PURE__*/React.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React.createElement(InlineIcon, iconCircleThin))));
24273
24292
  }));
24274
24293
  /* eslint-enable max-len */
@@ -24280,7 +24299,7 @@ class Categorizer extends React.Component {
24280
24299
  "categorizer-container": true,
24281
24300
  "static-mode": this.props.static
24282
24301
  });
24283
- const inlineStyles = this.props.apiOptions.isMobile ? [styles$r.fullBleedContainer] : [];
24302
+ const inlineStyles = this.props.apiOptions.isMobile ? [styles$s.fullBleedContainer] : [];
24284
24303
  return /*#__PURE__*/React.createElement("div", {
24285
24304
  className: extraClassNames + " " + css(...inlineStyles)
24286
24305
  }, table);
@@ -24332,7 +24351,7 @@ const pageMargin = 16;
24332
24351
 
24333
24352
  // Stylesheets aren't directly testable
24334
24353
  /* c8 ignore next */
24335
- const styles$r = StyleSheet.create({
24354
+ const styles$s = StyleSheet.create({
24336
24355
  mobileTable: {
24337
24356
  [mediaQueries.smOrSmaller]: {
24338
24357
  minWidth: "auto"
@@ -24568,7 +24587,7 @@ class CSProgram extends React.Component {
24568
24587
  // creator "went wild".
24569
24588
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
24570
24589
  return /*#__PURE__*/React.createElement("div", {
24571
- className: css(styles$q.widthOverride, styleContainer && styles$q.container)
24590
+ className: css(styles$r.widthOverride, styleContainer && styles$r.container)
24572
24591
  }, /*#__PURE__*/React.createElement("iframe", {
24573
24592
  sandbox: sandboxOptions,
24574
24593
  src: url,
@@ -24597,7 +24616,7 @@ CSProgram.defaultProps = {
24597
24616
  // optional message
24598
24617
  message: null
24599
24618
  };
24600
- const styles$q = StyleSheet.create({
24619
+ const styles$r = StyleSheet.create({
24601
24620
  // Override the inherited width from the perseus paragraph class
24602
24621
  // 820 is minimum width for 420px editor and 400px canvas
24603
24622
  widthOverride: {
@@ -24642,7 +24661,7 @@ class Definition extends React.Component {
24642
24661
  }) => /*#__PURE__*/React.createElement(Popover, {
24643
24662
  content: /*#__PURE__*/React.createElement(PopoverContentCore, {
24644
24663
  color: "white",
24645
- style: styles$p.tooltipBody,
24664
+ style: styles$q.tooltipBody,
24646
24665
  closeButtonVisible: true
24647
24666
  }, /*#__PURE__*/React.createElement(Renderer, {
24648
24667
  apiOptions: this.props.apiOptions,
@@ -24673,7 +24692,7 @@ Definition.defaultProps = {
24673
24692
  togglePrompt: "define me",
24674
24693
  definition: "definition goes here"
24675
24694
  };
24676
- const styles$p = {
24695
+ const styles$q = {
24677
24696
  tooltipBody: {
24678
24697
  color: Color.offBlack,
24679
24698
  fontSize: 20,
@@ -24876,15 +24895,15 @@ class Explanation extends React.Component {
24876
24895
  const onClick = this._onClick;
24877
24896
  if (isMobile) {
24878
24897
  promptContainer = /*#__PURE__*/React.createElement("div", {
24879
- className: css(styles$o.linkContainer)
24898
+ className: css(styles$p.linkContainer)
24880
24899
  }, /*#__PURE__*/React.createElement("a", {
24881
- className: css(styles$o.mobileExplanationLink),
24900
+ className: css(styles$p.mobileExplanationLink),
24882
24901
  href: href,
24883
24902
  onClick: onClick,
24884
24903
  role: "button",
24885
24904
  "aria-expanded": this.state.expanded
24886
24905
  }, promptText), this.state.expanded && /*#__PURE__*/React.createElement("svg", {
24887
- className: css(styles$o.disclosureArrow)
24906
+ className: css(styles$p.disclosureArrow)
24888
24907
  }, /*#__PURE__*/React.createElement("polygon", {
24889
24908
  style: {
24890
24909
  fill: backgroundColor
@@ -24892,7 +24911,7 @@ class Explanation extends React.Component {
24892
24911
  points: `0,${arrowHeight} ` + `${arrowWidth},${arrowHeight} ` + `${arrowWidth / 2},0`
24893
24912
  })));
24894
24913
  } else {
24895
- const viewStyling = isArticle ? [styles$o.explanationLink, styles$o.articleLink] : [styles$o.explanationLink, styles$o.exerciseLink];
24914
+ const viewStyling = isArticle ? [styles$p.explanationLink, styles$p.articleLink] : [styles$p.explanationLink, styles$p.exerciseLink];
24896
24915
  promptContainer = /*#__PURE__*/React.createElement(Clickable, {
24897
24916
  onClick: onClick,
24898
24917
  "aria-expanded": this.state.expanded
@@ -24900,11 +24919,11 @@ class Explanation extends React.Component {
24900
24919
  style: viewStyling
24901
24920
  }, `[${promptText}]`));
24902
24921
  }
24903
- const expandedStyle = isMobile ? styles$o.contentExpandedMobile : styles$o.contentExpanded;
24922
+ const expandedStyle = isMobile ? styles$p.contentExpandedMobile : styles$p.contentExpanded;
24904
24923
  return /*#__PURE__*/React.createElement("div", {
24905
- className: css(styles$o.container)
24924
+ className: css(styles$p.container)
24906
24925
  }, promptContainer, this.state.expanded && /*#__PURE__*/React.createElement("div", {
24907
- className: css(styles$o.content, isMobile && styles$o.contentMobile, this.state.expanded && expandedStyle)
24926
+ className: css(styles$p.content, isMobile && styles$p.contentMobile, this.state.expanded && expandedStyle)
24908
24927
  // eslint-disable-next-line react/no-string-refs
24909
24928
  ,
24910
24929
  ref: "content"
@@ -24928,7 +24947,7 @@ const verticalContentPadding = 10;
24928
24947
  const arrowWidth = 30;
24929
24948
  const arrowHeight = 14;
24930
24949
  const backgroundColor = gray95;
24931
- const styles$o = StyleSheet.create({
24950
+ const styles$p = StyleSheet.create({
24932
24951
  container: {
24933
24952
  display: "inline",
24934
24953
  position: "relative"
@@ -25033,15 +25052,15 @@ class GradedGroupAnswerBar extends React.Component {
25033
25052
  onCheckAnswer,
25034
25053
  onNextQuestion
25035
25054
  } = this.props;
25036
- const answerBarStyle = _extends({}, styles$n.answerBar, {
25055
+ const answerBarStyle = _extends({}, styles$o.answerBar, {
25037
25056
  backgroundColor: answerBarState === "CORRECT" ? Color.offWhite : "white",
25038
25057
  // Center the "Correct!" message only when there's no next question
25039
25058
  justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
25040
25059
  });
25041
25060
  const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React.createElement("span", {
25042
- style: styles$n.text
25061
+ style: styles$o.text
25043
25062
  }, /*#__PURE__*/React.createElement("span", {
25044
- style: styles$n.tryAgainIcon
25063
+ style: styles$o.tryAgainIcon
25045
25064
  }, /*#__PURE__*/React.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React.createElement("span", {
25046
25065
  style: {
25047
25066
  marginLeft: 8
@@ -25060,7 +25079,7 @@ class GradedGroupAnswerBar extends React.Component {
25060
25079
  return /*#__PURE__*/React.createElement("div", {
25061
25080
  style: answerBarStyle
25062
25081
  }, /*#__PURE__*/React.createElement("span", {
25063
- style: styles$n.text
25082
+ style: styles$o.text
25064
25083
  }, /*#__PURE__*/React.createElement("span", {
25065
25084
  style: {
25066
25085
  fontSize: 28,
@@ -25082,7 +25101,7 @@ class GradedGroupAnswerBar extends React.Component {
25082
25101
  }
25083
25102
  }
25084
25103
  const fontSize = 17;
25085
- const styles$n = {
25104
+ const styles$o = {
25086
25105
  answerBar: {
25087
25106
  display: "flex",
25088
25107
  alignItems: "center",
@@ -25268,7 +25287,7 @@ class GradedGroup extends React.Component {
25268
25287
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
25269
25288
  gradeStatus = i18n._("Incorrect");
25270
25289
  }
25271
- const mobileClass = this.props.inGradedGroupSet ? css(styles$m.gradedGroupInSet) : css(styles$m.gradedGroup);
25290
+ const mobileClass = this.props.inGradedGroupSet ? css(styles$n.gradedGroupInSet) : css(styles$n.gradedGroup);
25272
25291
  const classes = classNames({
25273
25292
  [mobileClass]: apiOptions.isMobile,
25274
25293
  "perseus-graded-group": true,
@@ -25287,7 +25306,7 @@ class GradedGroup extends React.Component {
25287
25306
  return /*#__PURE__*/React.createElement("div", {
25288
25307
  className: classes
25289
25308
  }, !!this.props.title && /*#__PURE__*/React.createElement("div", {
25290
- className: css(styles$m.title)
25309
+ className: css(styles$n.title)
25291
25310
  }, this.props.title), /*#__PURE__*/React.createElement(Renderer, _extends({}, this.props, {
25292
25311
  // eslint-disable-next-line react/no-string-refs
25293
25312
  ref: "renderer",
@@ -25319,7 +25338,7 @@ class GradedGroup extends React.Component {
25319
25338
  }, i18n._("Next question")), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
25320
25339
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
25321
25340
  tabIndex: "0",
25322
- className: css(styles$m.explanationTitle),
25341
+ className: css(styles$n.explanationTitle),
25323
25342
  onClick: () => this.setState({
25324
25343
  showHint: false
25325
25344
  }),
@@ -25351,7 +25370,7 @@ class GradedGroup extends React.Component {
25351
25370
  showHint: true
25352
25371
  });
25353
25372
  },
25354
- className: css(styles$m.showHintLink)
25373
+ className: css(styles$n.showHintLink)
25355
25374
  }, i18n._("Explain"))), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React.createElement(GradedGroupAnswerBar, {
25356
25375
  apiOptions: apiOptions,
25357
25376
  answerBarState: answerBarState,
@@ -25372,7 +25391,7 @@ GradedGroup.defaultProps = {
25372
25391
  const traverseChildWidgets$2 = function traverseChildWidgets(props, traverseRenderer) {
25373
25392
  return _.extend({}, props, traverseRenderer(props));
25374
25393
  };
25375
- const styles$m = StyleSheet.create({
25394
+ const styles$n = StyleSheet.create({
25376
25395
  gradedGroupInSet: {
25377
25396
  // Reset a few desktop-only styles that come from graded-group.less
25378
25397
  marginLeft: 0,
@@ -25445,18 +25464,18 @@ class Indicators extends React.Component {
25445
25464
  return /*#__PURE__*/React.createElement("ul", {
25446
25465
  // reduntantly add class name for use in .less files--
25447
25466
  // the styles object key gets hashed
25448
- className: classNames(css(styles$l.indicatorContainer), "indicatorContainer")
25467
+ className: classNames(css(styles$m.indicatorContainer), "indicatorContainer")
25449
25468
  }, this.props.gradedGroups.map(({
25450
25469
  title
25451
25470
  }, i) => /*#__PURE__*/React.createElement("li", {
25452
- className: css(styles$l.indicator),
25471
+ className: css(styles$m.indicator),
25453
25472
  key: title
25454
25473
  }, /*#__PURE__*/React.createElement(Clickable, {
25455
25474
  role: "button",
25456
25475
  "aria-label": i18n._("Skip to %(title)s", {
25457
25476
  title
25458
25477
  }),
25459
- style: styles$l.indicatorButton,
25478
+ style: styles$m.indicatorButton,
25460
25479
  onClick: () => this.props.onChangeCurrentGroup(i),
25461
25480
  onKeyDown: e => this.handleKeyDown(e, i)
25462
25481
  }, ({
@@ -25464,9 +25483,9 @@ class Indicators extends React.Component {
25464
25483
  focused,
25465
25484
  pressed
25466
25485
  }) => /*#__PURE__*/React.createElement(View, {
25467
- style: [styles$l.indicatorDot, (hovered || focused || pressed) && styles$l.indicatorDotFocused]
25486
+ style: [styles$m.indicatorDot, (hovered || focused || pressed) && styles$m.indicatorDotFocused]
25468
25487
  }, i === this.props.currentGroup && /*#__PURE__*/React.createElement(View, {
25469
- style: styles$l.indicatorDotActive
25488
+ style: styles$m.indicatorDotActive
25470
25489
  }, /*#__PURE__*/React.createElement("span", {
25471
25490
  className: css(a11y.srOnly)
25472
25491
  }, i18n._("Current"))))))));
@@ -25532,7 +25551,7 @@ class GradedGroupSet extends React.Component {
25532
25551
  } = getDependencies();
25533
25552
  if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
25534
25553
  return /*#__PURE__*/React.createElement("div", {
25535
- className: css(styles$l.container)
25554
+ className: css(styles$m.container)
25536
25555
  }, this.props.gradedGroups.map((gradedGroup, i) => {
25537
25556
  return (
25538
25557
  /*#__PURE__*/
@@ -25555,13 +25574,13 @@ class GradedGroupSet extends React.Component {
25555
25574
  const numGroups = this.props.gradedGroups.length;
25556
25575
  const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
25557
25576
  return /*#__PURE__*/React.createElement("div", {
25558
- className: css(styles$l.container)
25577
+ className: css(styles$m.container)
25559
25578
  }, /*#__PURE__*/React.createElement("div", {
25560
- className: css(styles$l.top)
25579
+ className: css(styles$m.top)
25561
25580
  }, /*#__PURE__*/React.createElement("div", {
25562
- className: css(styles$l.title)
25581
+ className: css(styles$m.title)
25563
25582
  }, currentGroup.title), /*#__PURE__*/React.createElement("div", {
25564
- className: css(styles$l.spacer)
25583
+ className: css(styles$m.spacer)
25565
25584
  }), /*#__PURE__*/React.createElement(Indicators, {
25566
25585
  currentGroup: this.state.currentGroup,
25567
25586
  gradedGroups: this.props.gradedGroups,
@@ -25603,7 +25622,7 @@ var GradedGroupSet$1 = {
25603
25622
  tracking: "all",
25604
25623
  isLintable: true
25605
25624
  };
25606
- const styles$l = StyleSheet.create({
25625
+ const styles$m = StyleSheet.create({
25607
25626
  top: {
25608
25627
  display: "flex",
25609
25628
  flexDirection: "row"
@@ -25708,7 +25727,7 @@ class ButtonGroup extends React.Component {
25708
25727
  id: "" + i,
25709
25728
  ref: "button" + i,
25710
25729
  key: "" + i,
25711
- className: css(styles$k.buttonStyle, button.value === value && styles$k.selectedStyle),
25730
+ className: css(styles$l.buttonStyle, button.value === value && styles$l.selectedStyle),
25712
25731
  onClick: () => this.toggleSelect(button.value)
25713
25732
  }, button.content || "" + button.value);
25714
25733
  });
@@ -25725,7 +25744,7 @@ ButtonGroup.defaultProps = {
25725
25744
  value: null,
25726
25745
  allowEmpty: true
25727
25746
  };
25728
- const styles$k = StyleSheet.create({
25747
+ const styles$l = StyleSheet.create({
25729
25748
  buttonStyle: {
25730
25749
  backgroundColor: "white",
25731
25750
  border: "1px solid #ccc",
@@ -28227,18 +28246,51 @@ const SegmentGraph = props => {
28227
28246
  })));
28228
28247
  };
28229
28248
  const SegmentView = props => {
28230
- const [pt1, pt2] = props.segment;
28249
+ const {
28250
+ onMoveSegment,
28251
+ segment: [pt1, pt2]
28252
+ } = props;
28231
28253
  const midpoint = vec.midpoint(pt1, pt2);
28232
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Line$3.Segment, {
28233
- point1: pt1,
28234
- point2: pt2
28235
- }), /*#__PURE__*/React.createElement(MovablePoint$5, {
28254
+ const segment = useRef(null);
28255
+ const {
28256
+ dragging: isDraggingSegment
28257
+ } = useMovable({
28258
+ gestureTarget: segment,
28236
28259
  point: midpoint,
28237
- color: Color.blue,
28238
28260
  onMove: newPoint => {
28239
- props.onMoveSegment(vec.sub(newPoint, midpoint));
28261
+ onMoveSegment(vec.sub(newPoint, midpoint));
28262
+ },
28263
+ constrain: p => p
28264
+ });
28265
+ const {
28266
+ viewTransform,
28267
+ userTransform
28268
+ } = useTransformContext();
28269
+ const transform = vec.matrixMult(viewTransform, userTransform);
28270
+ const scaledPoint1 = vec.transform(pt1, transform);
28271
+ const scaledPoint2 = vec.transform(pt2, transform);
28272
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("g", {
28273
+ ref: segment,
28274
+ tabIndex: 0,
28275
+ className: "movable-segment",
28276
+ style: {
28277
+ cursor: isDraggingSegment ? "grabbing" : "grab"
28240
28278
  }
28241
- }), /*#__PURE__*/React.createElement(MovablePoint$5, {
28279
+ }, /*#__PURE__*/React.createElement(SVGLine, {
28280
+ start: scaledPoint1,
28281
+ end: scaledPoint2,
28282
+ style: {
28283
+ stroke: "transparent",
28284
+ strokeWidth: 30
28285
+ }
28286
+ }), /*#__PURE__*/React.createElement(SVGLine, {
28287
+ start: scaledPoint1,
28288
+ end: scaledPoint2,
28289
+ style: {
28290
+ stroke: "var(--mafs-segment-stroke-color)",
28291
+ strokeWidth: "var(--mafs-segment-stroke-weight)"
28292
+ }
28293
+ })), /*#__PURE__*/React.createElement(MovablePoint$5, {
28242
28294
  point: pt1,
28243
28295
  color: Color.blue,
28244
28296
  onMove: newPoint => {
@@ -28252,6 +28304,20 @@ const SegmentView = props => {
28252
28304
  }
28253
28305
  }));
28254
28306
  };
28307
+ function SVGLine(props) {
28308
+ const {
28309
+ start,
28310
+ end,
28311
+ style
28312
+ } = props;
28313
+ return /*#__PURE__*/React.createElement("line", {
28314
+ x1: start[0],
28315
+ y1: start[1],
28316
+ x2: end[0],
28317
+ y2: end[1],
28318
+ style: style
28319
+ });
28320
+ }
28255
28321
 
28256
28322
  const renderLineLabel = (n, [min, max]) => n !== -1 && n !== min && n !== max;
28257
28323
  const axisOptions = (props, index) => ({
@@ -28421,7 +28487,7 @@ const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
28421
28487
  width: "24",
28422
28488
  height: "24",
28423
28489
  viewBox: "0 0 24 24",
28424
- className: css(styles$j.icon)
28490
+ className: css(styles$k.icon)
28425
28491
  }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
28426
28492
  id: "a",
28427
28493
  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"
@@ -28452,7 +28518,7 @@ const HiddenIcon = () => /*#__PURE__*/React.createElement("svg", {
28452
28518
  width: "24",
28453
28519
  height: "24",
28454
28520
  viewBox: "0 0 24 24",
28455
- className: css(styles$j.icon)
28521
+ className: css(styles$k.icon)
28456
28522
  }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
28457
28523
  id: "a",
28458
28524
  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"
@@ -28486,20 +28552,20 @@ const HUD = ({
28486
28552
  let state;
28487
28553
  let icon;
28488
28554
  if (enabled) {
28489
- state = styles$j.enabled;
28555
+ state = styles$k.enabled;
28490
28556
  icon = /*#__PURE__*/React.createElement(VisibleIcon, null);
28491
28557
  } else {
28492
- state = styles$j.disabled;
28558
+ state = styles$k.disabled;
28493
28559
  icon = /*#__PURE__*/React.createElement(HiddenIcon, null);
28494
28560
  }
28495
28561
  return /*#__PURE__*/React.createElement("button", {
28496
- className: css(styles$j.hud, _fixedPosition && styles$j.hudFixedPosition, state),
28562
+ className: css(styles$k.hud, _fixedPosition && styles$k.hudFixedPosition, state),
28497
28563
  onClick: e => {
28498
28564
  onClick();
28499
28565
  }
28500
28566
  }, icon, message);
28501
28567
  };
28502
- const styles$j = StyleSheet.create({
28568
+ const styles$k = StyleSheet.create({
28503
28569
  hud: {
28504
28570
  boxSizing: "border-box",
28505
28571
  height: 36,
@@ -28563,7 +28629,7 @@ const triangleBeforeAfter = {
28563
28629
  top: "0",
28564
28630
  width: "0"
28565
28631
  };
28566
- const styles$i = StyleSheet.create({
28632
+ const styles$j = StyleSheet.create({
28567
28633
  infoTip: {
28568
28634
  display: "inline-block",
28569
28635
  marginLeft: "5px",
@@ -28602,7 +28668,6 @@ const styles$i = StyleSheet.create({
28602
28668
  width: "240px"
28603
28669
  }
28604
28670
  });
28605
- const questionMark = "data:image/png;base64," + "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBB" + "ZG9iZSBJbWFnZVJlYWR5ccllPAAAA3NpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/" + "eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+" + "IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2Jl" + "IFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAg" + "ICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5" + "LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9" + "IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHht" + "bG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3Vy" + "Y2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHht" + "cE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2N2M3NTAxYS04YmVlLTQ0M2Mt" + "YmRiNS04OGM2N2IxN2NhYzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUJCRTk4" + "Qjc4NjAwMTFFMzg3QUJDNEI4Mzk2QTRGQkQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5p" + "aWQ6OUJCRTk4QjY4NjAwMTFFMzg3QUJDNEI4Mzk2QTRGQkQiIHhtcDpDcmVhdG9yVG9v" + "bD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRG" + "cm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NGE5ZDI0OTMtODk1NC00OGFkLTlh" + "MTgtZDAwM2MwYWNjNDJlIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY3Yzc1MDFh" + "LThiZWUtNDQzYy1iZGI1LTg4YzY3YjE3Y2FjMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4g" + "PC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pqm89uYAAADM" + "SURBVHjaXJA9DoJAEIUH1M4TUHIFsCMGen9OwCGw1YRGW2ntKel0exsojHIBC0ouQAyU" + "viFDstmXfNmZeS+zm7XSNCXRFiRgJf0bXIHixpbhGdxBBJYC1w/xaA424MhNEATkui71" + "fU9KqfEU78UbD9PdbJRlOdae55GmhIP+1NV1TcMwkOM41DSNHvRtMhTHMRVFQW3b6mOL" + "gx99kue5GRp/gIOZuZGvNpTNwjD8oliANU+qqqKu6/TQBdymN57AHjzBT+B6Jx79BRgA" + "vc49kQA4yxgAAAAASUVORK5CYII=";
28606
28671
  class InfoTip$1 extends React.Component {
28607
28672
  constructor(...args) {
28608
28673
  super(...args);
@@ -28622,23 +28687,22 @@ class InfoTip$1 extends React.Component {
28622
28687
  }
28623
28688
  render() {
28624
28689
  return /*#__PURE__*/React.createElement("div", {
28625
- className: css(styles$i.infoTip)
28626
- }, /*#__PURE__*/React.createElement("img", {
28627
- alt: "",
28628
- width: 10,
28629
- height: 10,
28630
- src: questionMark,
28690
+ className: css(styles$j.infoTip)
28691
+ }, /*#__PURE__*/React.createElement(View, {
28631
28692
  onMouseEnter: this.handleMouseEnter,
28632
28693
  onMouseLeave: this.handleMouseLeave
28633
- }), /*#__PURE__*/React.createElement("div", {
28634
- className: css(styles$i.infoTipContainer),
28694
+ }, /*#__PURE__*/React.createElement(PhosphorIcon, {
28695
+ size: "small",
28696
+ icon: questionIcon
28697
+ })), /*#__PURE__*/React.createElement("div", {
28698
+ className: css(styles$j.infoTipContainer),
28635
28699
  style: {
28636
28700
  display: this.state.hover ? "block" : "none"
28637
28701
  }
28638
28702
  }, /*#__PURE__*/React.createElement("div", {
28639
- className: css(styles$i.infoTipTriangle)
28703
+ className: css(styles$j.infoTipTriangle)
28640
28704
  }), /*#__PURE__*/React.createElement("div", {
28641
- className: css(styles$i.verticalShadow, styles$i.infoTipContentContainer)
28705
+ className: css(styles$j.verticalShadow, styles$j.infoTipContentContainer)
28642
28706
  }, this.props.children)));
28643
28707
  }
28644
28708
  }
@@ -28713,7 +28777,7 @@ class MultiButtonGroup extends React.Component {
28713
28777
  id: "" + i,
28714
28778
  key: "" + i,
28715
28779
  ref: "button" + i,
28716
- className: css(styles$h.buttonStyle, selected && styles$h.selectedStyle),
28780
+ className: css(styles$i.buttonStyle, selected && styles$i.selectedStyle),
28717
28781
  onClick: () => this.toggleSelect(button.value)
28718
28782
  }, button.content || "" + button.value);
28719
28783
  });
@@ -28729,7 +28793,7 @@ MultiButtonGroup.defaultProps = {
28729
28793
  values: [],
28730
28794
  allowEmpty: true
28731
28795
  };
28732
- const styles$h = StyleSheet.create({
28796
+ const styles$i = StyleSheet.create({
28733
28797
  buttonStyle: {
28734
28798
  backgroundColor: "white",
28735
28799
  border: "1px solid #ccc",
@@ -28987,11 +29051,12 @@ const PropCheckBox = createReactClass({
28987
29051
  },
28988
29052
  render: function () {
28989
29053
  const propName = this.propName();
28990
- return /*#__PURE__*/React.createElement("label", null, this._labelAlignLeft() && this.props.label, /*#__PURE__*/React.createElement("input", {
28991
- type: "checkbox",
29054
+ return /*#__PURE__*/React.createElement("label", {
29055
+ className: css(styles$h.labeledCheckbox)
29056
+ }, this._labelAlignLeft() && /*#__PURE__*/React.createElement(LabelSmall, null, this.props.label), /*#__PURE__*/React.createElement(Checkbox, {
28992
29057
  checked: this.props[propName],
28993
29058
  onChange: this.toggle
28994
- }), !this._labelAlignLeft() && this.props.label);
29059
+ }), !this._labelAlignLeft() && /*#__PURE__*/React.createElement(LabelSmall, null, this.props.label));
28995
29060
  },
28996
29061
  toggle: function () {
28997
29062
  const propName = this.propName();
@@ -29000,6 +29065,13 @@ const PropCheckBox = createReactClass({
29000
29065
  this.props.onChange(changes);
29001
29066
  }
29002
29067
  });
29068
+ const styles$h = StyleSheet.create({
29069
+ labeledCheckbox: {
29070
+ display: "flex",
29071
+ flexDirection: "row",
29072
+ alignItems: "center"
29073
+ }
29074
+ });
29003
29075
 
29004
29076
  const truth = () => true;
29005
29077
 
@@ -29815,7 +29887,7 @@ class InteractiveGraph extends React.Component {
29815
29887
  // eslint-disable-next-line no-restricted-syntax
29816
29888
  setTimeout(point$1.remove.bind(point$1), 0);
29817
29889
  };
29818
- const setInitialMove = debounce$1((point, bool) => {
29890
+ const setInitialMove = debounce$2((point, bool) => {
29819
29891
  point.state.isInitialMove = bool;
29820
29892
  }, 1000);
29821
29893
  const onMoveEndHandler = coord => {
@@ -41167,7 +41239,7 @@ const init = function init(options) {
41167
41239
 
41168
41240
  // This file is processed by a Rollup plugin (replace) to inject the production
41169
41241
  const libName = "@khanacademy/perseus";
41170
- const libVersion = "20.0.1";
41242
+ const libVersion = "20.1.0";
41171
41243
  addLibraryVersionToPerseusDebug(libName, libVersion);
41172
41244
 
41173
41245
  const apiVersion = {