@khanacademy/perseus 5.0.0 → 6.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/dist/components/fixed-to-responsive.d.ts +27 -1
  3. package/dist/components/fixed-to-responsive.js.flow +27 -1
  4. package/dist/components/graph.d.ts +42 -26
  5. package/dist/components/graph.js.flow +42 -28
  6. package/dist/components/graphie.d.ts +34 -22
  7. package/dist/components/graphie.js.flow +37 -24
  8. package/dist/components/hud.d.ts +8 -14
  9. package/dist/components/hud.js.flow +7 -14
  10. package/dist/components/inline-icon.d.ts +9 -19
  11. package/dist/components/inline-icon.js.flow +26 -13
  12. package/dist/components/lint.d.ts +41 -13
  13. package/dist/components/lint.js.flow +42 -13
  14. package/dist/components/math-output.d.ts +15 -11
  15. package/dist/components/math-output.js.flow +15 -11
  16. package/dist/components/sortable.d.ts +17 -9
  17. package/dist/components/sortable.js.flow +22 -9
  18. package/dist/components/svg-image.d.ts +5 -3
  19. package/dist/components/svg-image.js.flow +5 -3
  20. package/dist/components/tooltip.d.ts +45 -4
  21. package/dist/components/tooltip.js.flow +44 -31
  22. package/dist/es/index.css +0 -3
  23. package/dist/es/index.js +478 -649
  24. package/dist/es/index.js.map +1 -1
  25. package/dist/index.css +0 -3
  26. package/dist/index.js +482 -646
  27. package/dist/index.js.map +1 -1
  28. package/dist/perseus-types.d.ts +11 -9
  29. package/dist/perseus-types.js.flow +11 -9
  30. package/dist/renderer.d.ts +2 -2
  31. package/dist/renderer.js.flow +1 -3
  32. package/dist/styles/shared.d.ts +0 -1
  33. package/dist/styles/shared.js.flow +0 -1
  34. package/dist/types.d.ts +0 -10
  35. package/dist/types.js.flow +0 -13
  36. package/dist/util/a11y.d.ts +0 -1
  37. package/dist/util/a11y.js.flow +0 -1
  38. package/dist/util/interactive.d.ts +2 -0
  39. package/dist/util/interactive.js.flow +2 -0
  40. package/dist/util.d.ts +3 -3
  41. package/dist/util.js.flow +4 -3
  42. package/dist/widgets/grapher.d.ts +1 -1
  43. package/dist/widgets/grapher.js.flow +12 -3
  44. package/dist/widgets/matcher.d.ts +7 -3
  45. package/dist/widgets/matcher.js.flow +7 -3
  46. package/dist/widgets/number-line.d.ts +1 -1
  47. package/dist/widgets/number-line.js.flow +1 -1
  48. package/package.json +2 -2
  49. package/src/__tests__/__snapshots__/item-renderer.test.tsx.snap +151 -159
  50. package/src/__tests__/__snapshots__/renderer.test.tsx.snap +358 -394
  51. package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +169 -189
  52. package/src/components/__stories__/lint.stories.tsx +56 -21
  53. package/src/components/__stories__/sortable.stories.tsx +5 -5
  54. package/src/components/__stories__/tooltip.stories.tsx +52 -0
  55. package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +114 -30
  56. package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +172 -204
  57. package/src/components/__tests__/sortable.test.tsx +54 -16
  58. package/src/components/__tests__/sorter.test.tsx +12 -9
  59. package/src/components/fixed-to-responsive.tsx +43 -38
  60. package/src/components/graph.tsx +95 -81
  61. package/src/components/graphie.tsx +62 -32
  62. package/src/components/hud.tsx +104 -115
  63. package/src/components/inline-icon.tsx +15 -32
  64. package/src/components/input-with-examples.tsx +4 -4
  65. package/src/components/lint.tsx +47 -41
  66. package/src/components/math-output.tsx +17 -11
  67. package/src/components/simple-keypad-input.tsx +2 -2
  68. package/src/components/sortable.tsx +134 -94
  69. package/src/components/svg-image.tsx +10 -11
  70. package/src/components/tooltip.tsx +189 -171
  71. package/src/interactive2/types.ts +2 -2
  72. package/src/mixins/provide-keypad.tsx +2 -2
  73. package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +708 -764
  74. package/src/perseus-types.ts +13 -9
  75. package/src/renderer.tsx +11 -22
  76. package/src/types.ts +0 -18
  77. package/src/util/interactive.ts +18 -5
  78. package/src/util/tex.ts +13 -77
  79. package/src/util.ts +3 -4
  80. package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +2 -2
  81. package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +717 -773
  82. package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +28 -36
  83. package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +52 -60
  84. package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +100 -108
  85. package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +212 -260
  86. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +613 -641
  87. package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +249 -261
  88. package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +671 -735
  89. package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +2676 -2684
  90. package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +938 -1002
  91. package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +28 -36
  92. package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +227 -255
  93. package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +353 -357
  94. package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +255 -259
  95. package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +2401 -2433
  96. package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +600 -756
  97. package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +420 -428
  98. package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +762 -770
  99. package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +373 -393
  100. package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +116 -148
  101. package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +289 -301
  102. package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +1679 -1711
  103. package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +2692 -2960
  104. package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +90 -98
  105. package/src/widgets/__tests__/matcher.test.tsx +33 -9
  106. package/src/widgets/expression.tsx +9 -6
  107. package/src/widgets/grapher.tsx +3 -3
  108. package/src/widgets/image.tsx +2 -2
  109. package/src/widgets/interactive-graph.tsx +5 -5
  110. package/src/widgets/matcher.tsx +43 -24
  111. package/src/widgets/number-line.tsx +1 -1
  112. package/src/widgets/simulator.tsx +4 -6
  113. package/{tsconfig.json → tsconfig-build.json} +6 -6
  114. package/tsconfig-build.tsbuildinfo +1 -0
  115. package/tsconfig.tsbuildinfo +0 -1
package/dist/es/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as KAS from '@khanacademy/kas';
2
- import { KeypadInput, KeypadTypes, keypadElementPropType, Keypad } from '@khanacademy/math-input';
2
+ import { KeypadInput, KeypadType, keypadElementPropType, LegacyKeypad } 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 * as i18n from '@khanacademy/wonder-blocks-i18n';
@@ -7,12 +7,11 @@ import classNames from 'classnames';
7
7
  import * as React from 'react';
8
8
  import { useState, useEffect, useRef } from 'react';
9
9
  import _, { debounce } from 'underscore';
10
- import PropTypes from 'prop-types';
11
10
  import $ from 'jquery';
12
11
  import MathQuill from 'mathquill';
13
12
  import * as ReactDOM from 'react-dom';
14
13
  import ReactDOM__default from 'react-dom';
15
- import createReactClass from 'create-react-class';
14
+ import PropTypes from 'prop-types';
16
15
  import { number, point, vector as vector$1, line, ray } from '@khanacademy/kmath';
17
16
  import Spacing from '@khanacademy/wonder-blocks-spacing';
18
17
  import { StyleSheet, css } from 'aphrodite';
@@ -28,6 +27,7 @@ import { Strut } from '@khanacademy/wonder-blocks-layout';
28
27
  import { Popover, PopoverContent, PopoverContentCore } from '@khanacademy/wonder-blocks-popover';
29
28
  import { OptionItem, SingleSelect } from '@khanacademy/wonder-blocks-dropdown';
30
29
  import debounce$1 from 'lodash.debounce';
30
+ import createReactClass from 'create-react-class';
31
31
  import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
32
32
  import Link from '@khanacademy/wonder-blocks-link';
33
33
 
@@ -60,6 +60,30 @@ function _extends() {
60
60
  return _extends.apply(this, arguments);
61
61
  }
62
62
 
63
+ /**
64
+ * A stripped version of Icon.jsx from webapp. Takes an SVG icon and renders it
65
+ * inline like Font Awesome did.
66
+ *
67
+ * If you are looking for an icon that we've used before you should look in
68
+ * webapp's `icon-paths.js` which is a reference file for all the SVG paths
69
+ * that we've used. You'll need to copy the object from that file into
70
+ * whichever file you're using the icon and explicitly pass it in to the
71
+ * <InlineIcon/> React component.
72
+ *
73
+ * We assume that the viewBox is cropped and aligned to (0, 0), but icons can
74
+ * be defined differently. At some point we might want to add these attributes
75
+ * to `icon-paths.js`, but for now this is a fairly safe assumption.
76
+ *
77
+ * Sample usage:
78
+ *
79
+ * const editIcon = {
80
+ * path: "M41.209 53.753l5.39 0l0 5.39l3.136 0l6.468-6.517-8.477-8.526-6.517 6.517l0 3.136zm33.173-34.937q-.882-.882-1.862.049l-19.6 19.6q-.931.98-.049 1.862t1.862-.049l19.6-19.6q.931-.98.049-1.862zm-38.563 45.668l0-16.121l37.632-37.632 16.17 16.121-37.632 37.632l-16.17 0zm43.022-12.397l0 10.633q-.049 6.713-4.753 11.417t-11.368 4.704l-46.599 0q-6.713 0-11.417-4.753t-4.704-11.368l0-46.599q0-6.664 4.753-11.417t11.368-4.704l46.599 0q3.528 0 6.566 1.372.833.392.98 1.323t-.49 1.617l-2.744 2.744q-.784.784-1.96.441t-2.352-.343l-46.599 0q-3.675 0-6.321 2.646t-2.646 6.321l0 46.599q0 3.675 2.646 6.321t6.321 2.646l46.599 0q3.675 0 6.321-2.646t2.646-6.321l0-7.056q0-.735.49-1.225l3.577-3.577q.833-.833 1.96-.392t1.127 1.617zm7.203-51.646q2.254 0 3.773 1.568l8.526 8.526q1.568 1.568 1.568 3.822t-1.568 3.773l-5.145 5.145-16.121-16.121 5.145-5.145q1.568-1.568 3.822-1.568z",
81
+ * width: 100,
82
+ * height: 78.912,
83
+ * };
84
+ * <InlineIcon {...editIcon} />
85
+ *
86
+ */
63
87
  const InlineIcon = ({
64
88
  path,
65
89
  width,
@@ -79,18 +103,6 @@ const InlineIcon = ({
79
103
  d: path,
80
104
  fill: "currentColor"
81
105
  }));
82
- InlineIcon.propTypes = {
83
- // An SVG path to render.
84
- path: PropTypes.string.isRequired,
85
- // The path's viewBox dimensions.
86
- // We set the viewport height to 1em and scale the width accordingly.
87
- height: PropTypes.number.isRequired,
88
- width: PropTypes.number.isRequired,
89
- style: PropTypes.object,
90
- // A11y description for this icon. If absent, icon is marked
91
- // aria-hidden=true
92
- title: PropTypes.string
93
- };
94
106
 
95
107
  let _dependencies = null;
96
108
  const setDependencies = dependencies => {
@@ -623,145 +635,96 @@ MathInput.defaultProps = {
623
635
  buttonsVisible: "focused"
624
636
  };
625
637
 
626
- /**
627
- * A generic tooltip library for React.js
628
- *
629
- * This should eventually end up in react-components
630
- *
631
- * Interface: ({a, b} means one of a or b)
632
- * import Tooltip from "./tooltip";
633
- * <Tooltip
634
- * className="class-for-tooltip-contents"
635
- * horizontalPosition="left" // one of "left", "right"
636
- * horizontalAlign="left" // one of "left", "right"
637
- * verticalPosition="bottom" // one of "top", "bottom"
638
- * arrowSize={10} // arrow size in pixels
639
- * borderColor="#ccc" // color of the border for the tooltip
640
- * show={true} // whether the tooltip should currently be visible
641
- * targetContainerStyle={targetContainerStyle}
642
- * >
643
- * <TargetElementOfTheTooltip />
644
- * <TooltipContents1 />
645
- * <TooltipContents2 />
646
- * </Tooltip>
647
- *
648
- * To show/hide the tooltip, the parent component should call the
649
- * .show() and .hide() methods of the tooltip when appropriate.
650
- * (These are usually set up as handlers of events on the target element.)
651
- *
652
- * Notes:
653
- * className should not specify a border; that is handled by borderColor
654
- * so that the arrow and tooltip match
655
- */
638
+ /* eslint-disable react/no-unsafe */
656
639
  const zIndex = 10;
657
- const Triangle = createReactClass({
658
- displayName: "Triangle",
659
- propTypes: {
660
- color: PropTypes.string.isRequired,
661
- left: PropTypes.number.isRequired,
662
- top: PropTypes.number.isRequired,
663
- width: PropTypes.number.isRequired,
664
- height: PropTypes.number.isRequired,
665
- horizontalDirection: PropTypes.oneOf(["left", "right"]).isRequired,
666
- verticalDirection: PropTypes.oneOf(["top", "bottom"]).isRequired
667
- },
668
- render: function () {
669
- let borderLeft;
670
- let borderRight;
671
- let borderTop;
672
- let borderBottom;
673
- const hBorder = `${this.props.width}px solid transparent`;
674
- if (this.props.horizontalDirection === "right") {
675
- borderLeft = hBorder;
676
- } else {
677
- borderRight = hBorder;
678
- }
679
- const vBorder = `${this.props.height}px solid ${this.props.color}`;
680
- if (this.props.verticalDirection === "top") {
681
- borderTop = vBorder;
682
- } else {
683
- borderBottom = vBorder;
684
- }
685
- return /*#__PURE__*/React.createElement("div", {
686
- style: {
687
- display: "block",
688
- height: 0,
689
- width: 0,
690
- position: "absolute",
691
- left: this.props.left,
692
- top: this.props["top"],
693
- borderLeft: borderLeft,
694
- borderRight: borderRight,
695
- borderTop: borderTop,
696
- borderBottom: borderBottom
697
- }
698
- });
640
+ let HorizontalDirection = /*#__PURE__*/function (HorizontalDirection) {
641
+ HorizontalDirection["Left"] = "left";
642
+ HorizontalDirection["Right"] = "right";
643
+ return HorizontalDirection;
644
+ }({});
645
+ let VerticalDirection = /*#__PURE__*/function (VerticalDirection) {
646
+ VerticalDirection["Top"] = "top";
647
+ VerticalDirection["Bottom"] = "bottom";
648
+ return VerticalDirection;
649
+ }({});
650
+ const Triangle = props => {
651
+ let borderLeft;
652
+ let borderRight;
653
+ let borderTop;
654
+ let borderBottom;
655
+ const hBorder = `${props.width}px solid transparent`;
656
+ if (props.horizontalDirection === "right") {
657
+ borderLeft = hBorder;
658
+ } else {
659
+ borderRight = hBorder;
699
660
  }
700
- });
701
- const TooltipArrow = createReactClass({
702
- displayName: "TooltipArrow",
703
- propTypes: {
704
- position: PropTypes.string,
705
- visibility: PropTypes.string,
706
- left: PropTypes.number,
707
- top: PropTypes.number,
708
- color: PropTypes.string.isRequired,
709
- // a css color
710
- border: PropTypes.string.isRequired,
711
- // a css color
712
- width: PropTypes.number.isRequired,
713
- height: PropTypes.number.isRequired,
714
- horizontalDirection: PropTypes.oneOf(["left", "right"]).isRequired,
715
- verticalDirection: PropTypes.oneOf(["top", "bottom"]).isRequired
716
- },
717
- getDefaultProps: function () {
718
- return {
719
- position: "relative",
720
- visibility: "visible",
721
- left: 0,
722
- top: 0
723
- };
724
- },
661
+ const vBorder = `${props.height}px solid ${props.color}`;
662
+ if (props.verticalDirection === "top") {
663
+ borderTop = vBorder;
664
+ } else {
665
+ borderBottom = vBorder;
666
+ }
667
+ return /*#__PURE__*/React.createElement("div", {
668
+ style: {
669
+ display: "block",
670
+ height: 0,
671
+ width: 0,
672
+ position: "absolute",
673
+ left: props.left,
674
+ top: props["top"],
675
+ borderLeft: borderLeft,
676
+ borderRight: borderRight,
677
+ borderTop: borderTop,
678
+ borderBottom: borderBottom
679
+ }
680
+ });
681
+ };
682
+ const TooltipArrow = props => {
725
683
  // TODO(aria): Think about adding a box-shadow to the triangle here
726
684
  // See http://css-tricks.com/triangle-with-shadow/
727
- render: function () {
728
- //const isRight = (this.props.horizontalDirection === "right");
729
- const isTop = this.props.verticalDirection === "top";
730
- const frontTopOffset = isTop ? 0 : 1;
731
- const borderTopOffset = isTop ? 0 : -1;
732
- return /*#__PURE__*/React.createElement("div", {
733
- style: {
734
- display: "block",
735
- position: this.props.position,
736
- visibility: this.props.visibility,
737
- left: this.props.left,
738
- top: this.props["top"],
739
- width: this.props.width + 2,
740
- height: this.props.height + 1,
741
- marginTop: -1,
742
- marginBottom: -2,
743
- zIndex: zIndex
744
- }
745
- }, /*#__PURE__*/React.createElement(Triangle, {
746
- horizontalDirection: this.props.horizontalDirection,
747
- verticalDirection: this.props.verticalDirection,
748
- color: this.props.border,
749
- left: 0,
750
- top: borderTopOffset,
751
- width: this.props.width + 2 // one extra for the diagonal
752
- ,
753
- height: this.props.height + 2
754
- }), /*#__PURE__*/React.createElement(Triangle, {
755
- horizontalDirection: this.props.horizontalDirection,
756
- verticalDirection: this.props.verticalDirection,
757
- color: this.props.color,
758
- left: 1,
759
- top: frontTopOffset,
760
- width: this.props.width,
761
- height: this.props.height
762
- }));
763
- }
764
- });
685
+
686
+ //const isRight = (this.props.horizontalDirection === "right");
687
+ const isTop = props.verticalDirection === "top";
688
+ const frontTopOffset = isTop ? 0 : 1;
689
+ const borderTopOffset = isTop ? 0 : -1;
690
+ return /*#__PURE__*/React.createElement("div", {
691
+ style: {
692
+ display: "block",
693
+ position: props.position,
694
+ visibility: props.visibility,
695
+ left: props.left,
696
+ top: props["top"],
697
+ width: props.width + 2,
698
+ height: props.height + 1,
699
+ marginTop: -1,
700
+ marginBottom: -2,
701
+ zIndex: zIndex
702
+ }
703
+ }, /*#__PURE__*/React.createElement(Triangle, {
704
+ horizontalDirection: props.horizontalDirection,
705
+ verticalDirection: props.verticalDirection,
706
+ color: props.border,
707
+ left: 0,
708
+ top: borderTopOffset,
709
+ width: props.width + 2 // one extra for the diagonal
710
+ ,
711
+ height: props.height + 2
712
+ }), /*#__PURE__*/React.createElement(Triangle, {
713
+ horizontalDirection: props.horizontalDirection,
714
+ verticalDirection: props.verticalDirection,
715
+ color: props.color,
716
+ left: 1,
717
+ top: frontTopOffset,
718
+ width: props.width,
719
+ height: props.height
720
+ }));
721
+ };
722
+ TooltipArrow.defaultProps = {
723
+ position: "relative",
724
+ visibility: "visible",
725
+ left: 0,
726
+ top: 0
727
+ };
765
728
  const VERTICAL_CORNERS = {
766
729
  top: {
767
730
  top: "-100%"
@@ -788,59 +751,34 @@ const HORIZONTAL_ALIGNMNENTS = {
788
751
  arrowLeft: arrowSize => -arrowSize - 2
789
752
  }
790
753
  };
791
-
792
- // eslint-disable-next-line react/no-unsafe
793
- const Tooltip = createReactClass({
794
- displayName: "Tooltip",
795
- propTypes: {
796
- show: PropTypes.bool.isRequired,
797
- className: PropTypes.string,
798
- arrowSize: PropTypes.number,
799
- borderColor: PropTypes.string,
800
- verticalPosition: PropTypes.oneOf(Object.keys(VERTICAL_CORNERS)),
801
- horizontalPosition: PropTypes.oneOf(Object.keys(HORIZONTAL_CORNERS)),
802
- horizontalAlign: PropTypes.oneOf(Object.keys(HORIZONTAL_ALIGNMNENTS)),
803
- children: PropTypes.arrayOf(PropTypes.element).isRequired,
804
- targetContainerStyle: PropTypes.any // style object
805
- },
806
-
807
- getDefaultProps: function () {
808
- return {
809
- className: "",
810
- arrowSize: 10,
811
- borderColor: "#ccc",
812
- verticalPosition: "bottom",
813
- horizontalPosition: "left",
814
- horizontalAlign: "left",
815
- targetContainerStyle: {}
816
- };
817
- },
818
- getInitialState: function () {
819
- return {
754
+ class Tooltip extends React.Component {
755
+ constructor(...args) {
756
+ super(...args);
757
+ this.state = {
820
758
  height: null // used for offsetting "top" positioned tooltips
821
759
  };
822
- },
760
+ }
823
761
 
824
- componentDidMount: function () {
762
+ componentDidMount() {
825
763
  this._updateHeight();
826
- },
827
- UNSAFE_componentWillReceiveProps: function () {
764
+ }
765
+ UNSAFE_componentWillReceiveProps() {
828
766
  // If the contents have changed, reset our measure of the height
829
767
  this.setState({
830
768
  height: null
831
769
  });
832
- },
833
- componentDidUpdate: function () {
770
+ }
771
+ componentDidUpdate() {
834
772
  this._updateHeight();
835
- },
836
- _renderToolTipDiv: function (isTooltipAbove) {
773
+ }
774
+ _renderToolTipDiv(isTooltipAbove) {
837
775
  const settings = Object.assign({}, HORIZONTAL_CORNERS[this.props.horizontalPosition], HORIZONTAL_ALIGNMNENTS[this.props.horizontalAlign], VERTICAL_CORNERS[this.props.verticalPosition]);
838
776
  let arrowAbove;
839
777
  let arrowBelow;
840
778
  if (isTooltipAbove) {
841
779
  // We put an absolutely positioned arrow in the correct place
842
780
  arrowAbove = /*#__PURE__*/React.createElement(TooltipArrow, {
843
- verticalDirection: "top",
781
+ verticalDirection: VerticalDirection.Top,
844
782
  horizontalDirection: this.props.horizontalAlign,
845
783
  position: "absolute",
846
784
  color: "white",
@@ -855,7 +793,7 @@ const Tooltip = createReactClass({
855
793
  // And we use a visibility: hidden arrow below to shift up the
856
794
  // content by the correct amount
857
795
  arrowBelow = /*#__PURE__*/React.createElement(TooltipArrow, {
858
- verticalDirection: "top",
796
+ verticalDirection: VerticalDirection.Top,
859
797
  horizontalDirection: this.props.horizontalAlign,
860
798
  visibility: "hidden",
861
799
  color: "white",
@@ -868,7 +806,7 @@ const Tooltip = createReactClass({
868
806
  });
869
807
  } else {
870
808
  arrowAbove = /*#__PURE__*/React.createElement(TooltipArrow, {
871
- verticalDirection: "bottom",
809
+ verticalDirection: VerticalDirection.Bottom,
872
810
  horizontalDirection: this.props.horizontalAlign,
873
811
  color: "white",
874
812
  border: this.props.borderColor,
@@ -916,8 +854,8 @@ const Tooltip = createReactClass({
916
854
  zIndex: zIndex - 1
917
855
  }
918
856
  }, this.props.children.slice(1)), arrowBelow));
919
- },
920
- _updateHeight: function () {
857
+ }
858
+ _updateHeight() {
921
859
  const tooltipContainer = ReactDOM__default.findDOMNode(
922
860
  // eslint-disable-next-line react/no-string-refs
923
861
  this.refs.tooltipContainer);
@@ -927,8 +865,8 @@ const Tooltip = createReactClass({
927
865
  height
928
866
  });
929
867
  }
930
- },
931
- render: function () {
868
+ }
869
+ render() {
932
870
  const isTooltipAbove = this.props.verticalPosition === "top";
933
871
 
934
872
  /* We wrap the entire output in a span so that it displays inline */
@@ -936,7 +874,18 @@ const Tooltip = createReactClass({
936
874
  style: this.props.targetContainerStyle
937
875
  }, this.props.children[0]), !isTooltipAbove && this._renderToolTipDiv());
938
876
  }
939
- });
877
+ }
878
+
879
+ // Sorry. // Apology-Oriented-Programming
880
+ Tooltip.defaultProps = {
881
+ className: "",
882
+ arrowSize: 10,
883
+ borderColor: "#ccc",
884
+ verticalPosition: VerticalDirection.Bottom,
885
+ horizontalPosition: HorizontalDirection.Left,
886
+ horizontalAlign: HorizontalDirection.Left,
887
+ targetContainerStyle: {}
888
+ };
940
889
 
941
890
  /**
942
891
  * Icon paths to be used with `inline-icon.jsx`.
@@ -2845,9 +2794,9 @@ class Expression extends React.Component {
2845
2794
  role: "tooltip"
2846
2795
  }, /*#__PURE__*/React.createElement(Tooltip, {
2847
2796
  className: "error-text-container",
2848
- horizontalPosition: "right",
2849
- horizontalAlign: "left",
2850
- verticalPosition: "top",
2797
+ horizontalPosition: HorizontalDirection.Right,
2798
+ horizontalAlign: HorizontalDirection.Left,
2799
+ verticalPosition: VerticalDirection.Top,
2851
2800
  arrowSize: 10,
2852
2801
  borderColor: "#fcc335",
2853
2802
  show: this.state.showErrorText
@@ -2919,7 +2868,7 @@ Expression.defaultProps = {
2919
2868
  const keypadConfigurationForProps = widgetOptions => {
2920
2869
  // Always use the Expression keypad, regardless of the button sets that have
2921
2870
  // been enabled.
2922
- const keypadType = KeypadTypes.EXPRESSION;
2871
+ const keypadType = KeypadType.EXPRESSION;
2923
2872
 
2924
2873
  // Extract any and all variables and constants from the answer forms.
2925
2874
  const uniqueExtraVariables = {};
@@ -3380,8 +3329,6 @@ function tickStepFromNumTicks(span, numTicks) {
3380
3329
  // Round start and stop values to step interval.
3381
3330
  return step;
3382
3331
  }
3383
- // [min, max]
3384
-
3385
3332
  const constrainTickStep = (step, range) => {
3386
3333
  const span = range[1] - range[0];
3387
3334
  const numTicks = span / step;
@@ -4422,31 +4369,40 @@ var constants$1 = /*#__PURE__*/Object.freeze({
4422
4369
  articleMaxWidthTableInPx: articleMaxWidthTableInPx
4423
4370
  });
4424
4371
 
4425
- /* eslint-disable react/prop-types */
4372
+ /**
4373
+ * A wrapper for a component that would otherwise have a fixed width and
4374
+ * height, that magically makes it reponsive while preserving its aspect ratio.
4375
+ * Specifically, the component will shrink dynamically when it needs to but
4376
+ * won't ever grow past its original dimensions.
4377
+ *
4378
+ * Can wrap multiple components with the same dimensions at the same time;
4379
+ * these will be overlaid on top of each other.
4380
+ *
4381
+ * Usage:
4382
+ * <FixedToResponsive width={400} height={400}>
4383
+ * <img src="bottom-layer.png" />
4384
+ * <img src="top-layer.png" />
4385
+ * </FixedToResponsive>
4386
+ */
4426
4387
  const MIN_VIEWPORT_HEIGHT = 480;
4427
- const FixedToResponsive = createReactClass({
4428
- displayName: "FixedToResponsive",
4429
- propTypes: {
4430
- width: PropTypes.number.isRequired,
4431
- height: PropTypes.number.isRequired,
4432
- className: PropTypes.string,
4433
- constrainHeight: PropTypes.bool,
4434
- allowFullBleed: PropTypes.bool
4435
- },
4436
- getDefaultProps: function () {
4437
- return {
4438
- className: "",
4439
- constrainHeight: false,
4440
- allowFullBleed: false
4441
- };
4442
- },
4443
- getInitialState: function () {
4444
- return {
4388
+ class FixedToResponsive extends React.Component {
4389
+ constructor(...args) {
4390
+ super(...args);
4391
+ this._isMounted = false;
4392
+ this.state = {
4445
4393
  viewportHeight: null,
4446
4394
  viewportWidth: null
4447
4395
  };
4448
- },
4449
- componentDidMount: function () {
4396
+ this._cacheViewportSize = () => {
4397
+ if (this._isMounted) {
4398
+ this.setState({
4399
+ viewportHeight: Math.max(MIN_VIEWPORT_HEIGHT, window.innerHeight),
4400
+ viewportWidth: window.innerWidth
4401
+ });
4402
+ }
4403
+ };
4404
+ }
4405
+ componentDidMount() {
4450
4406
  // TODO(scottgrant): This is a hack to remove the deprecated call to
4451
4407
  // this.isMounted() but is still considered an anti-pattern.
4452
4408
  this._isMounted = true;
@@ -4467,19 +4423,11 @@ const FixedToResponsive = createReactClass({
4467
4423
  } else {
4468
4424
  this._cacheViewportSize();
4469
4425
  }
4470
- },
4471
- componentWillUnmount: function () {
4426
+ }
4427
+ componentWillUnmount() {
4472
4428
  this._isMounted = false;
4473
- },
4474
- _cacheViewportSize: function () {
4475
- if (this._isMounted) {
4476
- this.setState({
4477
- viewportHeight: Math.max(MIN_VIEWPORT_HEIGHT, window.innerHeight),
4478
- viewportWidth: window.innerWidth
4479
- });
4480
- }
4481
- },
4482
- render: function () {
4429
+ }
4430
+ render() {
4483
4431
  // The ideal behavior for responsified, fixed size child components is
4484
4432
  // that they shrink when they need to (while preserving aspect ratio)
4485
4433
  // but never grow larger than their original dimensions. We accomplish
@@ -4535,7 +4483,12 @@ const FixedToResponsive = createReactClass({
4535
4483
  }
4536
4484
  return container;
4537
4485
  }
4538
- });
4486
+ }
4487
+ FixedToResponsive.defaultProps = {
4488
+ className: "",
4489
+ constrainHeight: false,
4490
+ allowFullBleed: false
4491
+ };
4539
4492
 
4540
4493
  /* Local helper methods. */
4541
4494
 
@@ -9061,6 +9014,26 @@ const KhanColors = {
9061
9014
  DYNAMIC: "#6495ED" // BLUE
9062
9015
  };
9063
9016
 
9017
+ function render(element, container, callback) {
9018
+ // TODO(LP-11406): Replace this, or callers, with React Portal
9019
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'void' is not assignable to type 'ElementRef<ElementType>'.
9020
+ // eslint-disable-next-line no-restricted-syntax
9021
+ return ReactDOM__default.render(
9022
+ /*#__PURE__*/
9023
+ /**
9024
+ * `RenderStateRoot` is responsible for tracking whether it's
9025
+ * the initial render or subsequent renders. It's used by
9026
+ * `useUniqueId` and will be used by `UniqueIDProvider` and
9027
+ * `WithSSRPlaceholder` in the future. We're placing it as
9028
+ * high up in the render tree as possible to ensure that any
9029
+ * components using that hook or those components will function
9030
+ * correctly.
9031
+ */
9032
+ React.createElement(RenderStateRoot, {
9033
+ throwIfNested: false
9034
+ }, element), container, callback);
9035
+ }
9036
+
9064
9037
  function findChildOrAdd(elem, className) {
9065
9038
  const $child = $(elem).find("." + className);
9066
9039
  if ($child.length === 0) {
@@ -9135,74 +9108,18 @@ var Tex$1 = {
9135
9108
 
9136
9109
  // Store the formula that we're using
9137
9110
  $elem.attr("data-math-formula", text);
9138
- const katex = await getDependencies().getKaTeX();
9139
- // Try to process the nodes with KaTeX first
9140
- try {
9141
- // Don't use the `trust: true` setting with KaTeX. There is a
9142
- // security issue with it as outlined in https://hackerone.com/reports/844216.
9143
- // See https://khanacademy.atlassian.net/browse/FEI-2225 for
9144
- // additional context.
9145
- katex.render(text, $katexHolder[0], {
9146
- colorIsTextColor: true
9147
- });
9148
- // If that worked, and we previously formatted with
9149
- // mathjax, do some mathjax cleanup
9150
- if ($elem.attr("data-math-type") === "mathjax") {
9151
- // Remove the old mathjax stuff
9152
- if (typeof MathJax !== "undefined") {
9153
- const jax = MathJax.Hub.getJaxFor(script);
9154
- if (jax) {
9155
- const e = jax.SourceElement();
9156
- if (e.previousSibling && e.previousSibling.className) {
9157
- jax.Remove();
9158
- }
9159
- }
9160
- }
9161
- }
9162
- $elem.attr("data-math-type", "katex");
9163
- // Call the callback
9111
+ const {
9112
+ TeX
9113
+ } = await getDependencies();
9114
+ // We use createElement instead of JSX here because we can't name this file tex.tsx;
9115
+ // that name is already taken.
9116
+ render( /*#__PURE__*/React.createElement(TeX, {
9117
+ children: text
9118
+ }), $katexHolder[0], () => {
9164
9119
  if (callback) {
9165
9120
  doCallback(elem, callback);
9166
9121
  }
9167
- return;
9168
- } catch (err) {
9169
- getDependencies().logKaTeXError(text, err);
9170
- if (err instanceof katex.ParseError) {
9171
- throw err;
9172
- }
9173
- }
9174
-
9175
- // Otherwise, fallback to MathJax
9176
-
9177
- // (Note: we don't need to do any katex cleanup here, because
9178
- // KaTeX is smart and cleans itself up)
9179
- $elem.attr("data-math-type", "mathjax");
9180
- // Update the script tag, or add one if necessary
9181
- if (!script) {
9182
- $mathjaxHolder.append("<script type='math/tex'>" + text.replace(/<\//g, "< /") + "</script>");
9183
- } else {
9184
- if ("text" in script) {
9185
- // IE8, etc
9186
- script.text = text;
9187
- } else {
9188
- script.textContent = text;
9189
- }
9190
- }
9191
- if (typeof MathJax !== "undefined") {
9192
- // Put the process, a debug log, and the callback into the
9193
- // MathJax queue
9194
- MathJax.Hub.Queue(["Reprocess", MathJax.Hub, $mathjaxHolder[0]]);
9195
- if (callback) {
9196
- MathJax.Hub.Queue(function () {
9197
- const cb = MathJax.Callback(function () {});
9198
- doCallback(elem, function () {
9199
- callback();
9200
- cb();
9201
- });
9202
- return cb;
9203
- });
9204
- }
9205
- }
9122
+ });
9206
9123
  }
9207
9124
  },
9208
9125
  // Function to restore a node to a non-math-processed state
@@ -11166,10 +11083,11 @@ _.extend(GraphUtils.Graphie.prototype, {
11166
11083
  }
11167
11084
  isClickingCanvas = true;
11168
11085
  if (options.onMouseMove) {
11086
+ const handler = options.onMouseMove;
11169
11087
  $(document).bind("vmousemove.mouseLayer", function (e) {
11170
11088
  if (isClickingCanvas) {
11171
11089
  e.preventDefault();
11172
- options.onMouseMove(graph.getMouseCoord(e));
11090
+ handler(graph.getMouseCoord(e));
11173
11091
  }
11174
11092
  });
11175
11093
  }
@@ -11186,18 +11104,20 @@ _.extend(GraphUtils.Graphie.prototype, {
11186
11104
  }
11187
11105
  });
11188
11106
  if (options.onMouseOver) {
11107
+ const handler = options.onMouseOver;
11189
11108
  $(graph.mouselayer.canvas).on("vmouseover", function (e) {
11190
- options.onMouseOver(graph.getMouseCoord(e));
11109
+ handler(graph.getMouseCoord(e));
11191
11110
  });
11192
11111
  }
11193
11112
  if (options.onMouseOut) {
11113
+ const handler = options.onMouseOut;
11194
11114
  $(graph.mouselayer.canvas).on("vmouseout", function (e) {
11195
- options.onMouseOut(graph.getMouseCoord(e));
11115
+ handler(graph.getMouseCoord(e));
11196
11116
  });
11197
11117
  }
11198
11118
  }
11199
11119
  if (!options.allowScratchpad) {
11200
- options.setDrawingAreaAvailable(false);
11120
+ options.setDrawingAreaAvailable == null ? void 0 : options.setDrawingAreaAvailable(false);
11201
11121
  }
11202
11122
 
11203
11123
  // Add mouse and visible wrapper layers for DOM-node-wrapped movables
@@ -15001,26 +14921,6 @@ _.extend(MovableLine$4.prototype, {
15001
14921
  }
15002
14922
  });
15003
14923
 
15004
- function render(element, container, callback) {
15005
- // TODO(LP-11406): Replace this, or callers, with React Portal
15006
- // @ts-expect-error [FEI-5003] - TS2322 - Type 'void' is not assignable to type 'ElementRef<ElementType>'.
15007
- // eslint-disable-next-line no-restricted-syntax
15008
- return ReactDOM__default.render(
15009
- /*#__PURE__*/
15010
- /**
15011
- * `RenderStateRoot` is responsible for tracking whether it's
15012
- * the initial render or subsequent renders. It's used by
15013
- * `useUniqueId` and will be used by `UniqueIDProvider` and
15014
- * `WithSSRPlaceholder` in the future. We're placing it as
15015
- * high up in the render tree as possible to ensure that any
15016
- * components using that hook or those components will function
15017
- * correctly.
15018
- */
15019
- React.createElement(RenderStateRoot, {
15020
- throwIfNested: false
15021
- }, element), container, callback);
15022
- }
15023
-
15024
14924
  /* eslint-disable @babel/no-invalid-this */
15025
14925
  const add$1 = {
15026
14926
  constrain: function () {
@@ -16500,24 +16400,27 @@ const {
16500
16400
  class Graphie extends React.Component {
16501
16401
  constructor(...args) {
16502
16402
  super(...args);
16403
+ this.graphieDivRef = /*#__PURE__*/React.createRef();
16503
16404
  this.getGraphie = () => {
16504
16405
  // @ts-expect-error [FEI-5003] - TS2339 - Property '_graphie' does not exist on type 'Graphie'.
16505
16406
  return this._graphie;
16506
16407
  };
16507
16408
  this._range = () => {
16508
- return _.map(this.props.range, dimRange => {
16509
- if (dimRange[0] >= dimRange[1]) {
16409
+ const boundsCheckRange = range => {
16410
+ if (range[0] >= range[1]) {
16510
16411
  return [-10, 10];
16511
16412
  }
16512
- return dimRange;
16513
- });
16413
+ return range;
16414
+ };
16415
+ return [boundsCheckRange(this.props.range[0]), boundsCheckRange(this.props.range[1])];
16514
16416
  };
16515
16417
  this._box = () => {
16516
- return _.map(this.props.box, pixelDim => {
16418
+ const ensureMinSize = pixelDim => {
16517
16419
  // 340 = default size in the editor. exact value
16518
16420
  // is arbitrary; this is just a safety check.
16519
16421
  return pixelDim > 0 ? pixelDim : 340;
16520
- });
16422
+ };
16423
+ return [ensureMinSize(this.props.box[0]), ensureMinSize(this.props.box[1])];
16521
16424
  };
16522
16425
  this._scale = () => {
16523
16426
  const box = this._box();
@@ -16529,9 +16432,7 @@ class Graphie extends React.Component {
16529
16432
  };
16530
16433
  this._setupGraphie = () => {
16531
16434
  this._removeMovables();
16532
-
16533
- // eslint-disable-next-line react/no-string-refs
16534
- const graphieDiv = ReactDOM__default.findDOMNode(this.refs.graphieDiv);
16435
+ const graphieDiv = ReactDOM__default.findDOMNode(this.graphieDivRef.current);
16535
16436
  // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call. | TS2339 - Property 'empty' does not exist on type 'JQueryStatic'.
16536
16437
  $(graphieDiv).empty();
16537
16438
  // @ts-expect-error [FEI-5003] - TS2339 - Property '_graphie' does not exist on type 'Graphie'.
@@ -16745,29 +16646,12 @@ class Graphie extends React.Component {
16745
16646
  className: "graphie-container"
16746
16647
  }, /*#__PURE__*/React.createElement("div", {
16747
16648
  className: "graphie",
16748
- ref: "graphieDiv"
16649
+ ref: this.graphieDivRef
16749
16650
  }));
16750
16651
  }
16751
16652
  }
16752
16653
 
16753
16654
  // Attach Graphie.createClass and Graphie.createSimpleClass
16754
- Graphie.propTypes = {
16755
- addMouseLayer: PropTypes.bool,
16756
- box: PropTypes.arrayOf(PropTypes.number).isRequired,
16757
- children: PropTypes.node,
16758
- isMobile: PropTypes.bool,
16759
- onClick: PropTypes.func,
16760
- onMouseDown: PropTypes.func,
16761
- onMouseMove: PropTypes.func,
16762
- onMouseUp: PropTypes.func,
16763
- options: PropTypes.shape({
16764
- snapStep: PropTypes.arrayOf(PropTypes.number)
16765
- }),
16766
- range: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
16767
- responsive: PropTypes.bool,
16768
- setDrawingAreaAvailable: PropTypes.func,
16769
- setup: PropTypes.func.isRequired
16770
- };
16771
16655
  Graphie.defaultProps = {
16772
16656
  range: [[-10, 10], [-10, 10]],
16773
16657
  options: {},
@@ -17394,13 +17278,15 @@ class SvgImage extends React.Component {
17394
17278
  }
17395
17279
  });
17396
17280
  }
17397
- const scale = [40 * this.props.scale, 40 * this.props.scale];
17281
+
17282
+ // TODO: the "40" scale factor was introduced in D14974 but is not
17283
+ // documented where it came from.
17398
17284
  graphie = /*#__PURE__*/React.createElement(Graphie
17399
17285
  // eslint-disable-next-line react/no-string-refs
17400
17286
  , {
17401
17287
  ref: "graphie",
17402
17288
  box: box,
17403
- scale: scale,
17289
+ scale: [40 * this.props.scale, 40 * this.props.scale],
17404
17290
  range: this.state.range,
17405
17291
  options: _.pick(this.state, "labels"),
17406
17292
  responsive: responsive,
@@ -17929,6 +17815,18 @@ var JiptParagraphs = {
17929
17815
  joinFromArray: joinFromArray
17930
17816
  };
17931
17817
 
17818
+ const exclamationIcon = {
17819
+ path: "M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",
17820
+ height: 12,
17821
+ width: 12
17822
+ };
17823
+ var Severity = /*#__PURE__*/function (Severity) {
17824
+ Severity[Severity["Error"] = 1] = "Error";
17825
+ Severity[Severity["Warning"] = 2] = "Warning";
17826
+ Severity[Severity["Recommendation"] = 3] = "Recommendation";
17827
+ Severity[Severity["OfflineReportingOnly"] = 4] = "OfflineReportingOnly";
17828
+ return Severity;
17829
+ }(Severity || {});
17932
17830
  /**
17933
17831
  * This component renders "lint" nodes in a markdown parse tree. Lint nodes
17934
17832
  * are inserted into the tree by the Perseus linter (see
@@ -17951,11 +17849,6 @@ var JiptParagraphs = {
17951
17849
  * that has a right margin (like anything blockquoted) the circle will appear
17952
17850
  * to the left of where it belongs. And if there is more
17953
17851
  **/
17954
- const exclamationIcon = {
17955
- path: "M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",
17956
- height: 12,
17957
- width: 12
17958
- };
17959
17852
  class Lint extends React.Component {
17960
17853
  constructor(...args) {
17961
17854
  super(...args);
@@ -17978,11 +17871,11 @@ class Lint extends React.Component {
17978
17871
  let severityStyle;
17979
17872
  let warningText;
17980
17873
  let warningTextStyle;
17981
- if (this.props.severity === 1) {
17874
+ if (this.props.severity === Severity.Error) {
17982
17875
  severityStyle = styles$A.indicatorError;
17983
17876
  warningText = "Error";
17984
17877
  warningTextStyle = styles$A.publishBlockingError;
17985
- } else if (this.props.severity === 2) {
17878
+ } else if (this.props.severity === Severity.Warning) {
17986
17879
  severityStyle = styles$A.indicatorWarning;
17987
17880
  warningText = "Warning";
17988
17881
  warningTextStyle = styles$A.warning;
@@ -18017,7 +17910,6 @@ class Lint extends React.Component {
18017
17910
  componentWillUnmount() {
18018
17911
  // TODO(somewhatabstract): Use WB timing
18019
17912
  // eslint-disable-next-line no-restricted-syntax
18020
- // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
18021
17913
  window.clearTimeout(this._positionTimeout);
18022
17914
  }
18023
17915
 
@@ -18063,24 +17955,6 @@ class Lint extends React.Component {
18063
17955
  }, this.renderLink(styles$A.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
18064
17956
  }
18065
17957
  }
18066
- Lint.propTypes = {
18067
- // The children are the linty content we're highlighting
18068
- children: PropTypes.node,
18069
- // Inline lint is highlighted differently than block lint.
18070
- inline: PropTypes.bool,
18071
- // This is the text that appears in the tooltip
18072
- message: PropTypes.string.isRequired,
18073
- // This is used as the fragment id (hash) in the URL of the link
18074
- ruleName: PropTypes.string.isRequired,
18075
- // Lint warnings inside tables are handled specially
18076
- insideTable: PropTypes.bool.isRequired,
18077
- // Should lint highlighting be rendered as a block to the left of
18078
- // the lint instead of on the right gutter?
18079
- blockHighlight: PropTypes.bool,
18080
- // How important this lint message is for the editor. Severity goes
18081
- // from 1 (indicating an error) to 4 (offline reporting only)
18082
- severity: PropTypes.number
18083
- };
18084
17958
  const styles$A = StyleSheet.create({
18085
17959
  // This is the class of the outermost element.
18086
17960
  // We use relative positioning so that the lint indicator can be
@@ -19324,8 +19198,6 @@ class Renderer extends React.Component {
19324
19198
 
19325
19199
  // The i18n linter.
19326
19200
 
19327
- // @ts-expect-error [FEI-5003] - TS2564 - Property 'lastRenderedMarkdown' has no initializer and is not definitely assigned in the constructor.
19328
-
19329
19201
  // @ts-expect-error [FEI-5003] - TS2564 - Property 'reuseMarkdown' has no initializer and is not definitely assigned in the constructor.
19330
19202
 
19331
19203
  // @ts-expect-error [FEI-5003] - TS2564 - Property 'translationIndex' has no initializer and is not definitely assigned in the constructor.
@@ -20454,9 +20326,6 @@ class Renderer extends React.Component {
20454
20326
  }
20455
20327
  render() {
20456
20328
  const apiOptions = this.getApiOptions();
20457
- const {
20458
- KatexProvider
20459
- } = getDependencies();
20460
20329
  if (this.reuseMarkdown) {
20461
20330
  return this.lastRenderedMarkdown;
20462
20331
  }
@@ -20497,9 +20366,9 @@ class Renderer extends React.Component {
20497
20366
  // Persues.TranslationComponent registry so that when jipt
20498
20367
  // calls its before_dom_insert we can lookup this component by
20499
20368
  // this attribute and render the text with markdown.
20500
- return /*#__PURE__*/React.createElement(KatexProvider, null, /*#__PURE__*/React.createElement(DefinitionProvider, null, /*#__PURE__*/React.createElement("div", {
20369
+ return /*#__PURE__*/React.createElement(DefinitionProvider, null, /*#__PURE__*/React.createElement("div", {
20501
20370
  "data-perseus-component-index": this.translationIndex
20502
- }, content)));
20371
+ }, content));
20503
20372
  }
20504
20373
  }
20505
20374
 
@@ -20547,9 +20416,9 @@ class Renderer extends React.Component {
20547
20416
  [ClassNames.RESPONSIVE_RENDERER]: true,
20548
20417
  [ClassNames.TWO_COLUMN_RENDERER]: this._isTwoColumn
20549
20418
  });
20550
- this.lastRenderedMarkdown = /*#__PURE__*/React.createElement(KatexProvider, null, /*#__PURE__*/React.createElement(DefinitionProvider, null, /*#__PURE__*/React.createElement("div", {
20419
+ this.lastRenderedMarkdown = /*#__PURE__*/React.createElement(DefinitionProvider, null, /*#__PURE__*/React.createElement("div", {
20551
20420
  className: className
20552
- }, markdownContents)));
20421
+ }, markdownContents));
20553
20422
  return this.lastRenderedMarkdown;
20554
20423
  }
20555
20424
  }
@@ -20826,13 +20695,6 @@ class MathOutput extends React.Component {
20826
20695
  this._unbindBlurHandler();
20827
20696
  }
20828
20697
  }
20829
- MathOutput.propTypes = {
20830
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
20831
- className: PropTypes.string,
20832
- labelText: PropTypes.string,
20833
- onFocus: PropTypes.func,
20834
- onBlur: PropTypes.func
20835
- };
20836
20698
  MathOutput.defaultProps = {
20837
20699
  value: "",
20838
20700
  onFocus: function () {},
@@ -21074,9 +20936,9 @@ class InputWithExamples extends React.Component {
21074
20936
  , {
21075
20937
  ref: "tooltip",
21076
20938
  className: "perseus-formats-tooltip preview-measure",
21077
- horizontalPosition: "left",
21078
- horizontalAlign: "left",
21079
- verticalPosition: "bottom",
20939
+ horizontalPosition: HorizontalDirection.Left,
20940
+ horizontalAlign: HorizontalDirection.Left,
20941
+ verticalPosition: VerticalDirection.Bottom,
21080
20942
  arrowSize: 10,
21081
20943
  borderColor: "#ccc",
21082
20944
  show: showExamples
@@ -21164,7 +21026,7 @@ class SimpleKeypadInput extends React.Component {
21164
21026
  onFocus: () => {
21165
21027
  if (keypadElement) {
21166
21028
  keypadElement.configure({
21167
- keypadType: KeypadTypes.FRACTION
21029
+ keypadType: KeypadType.FRACTION
21168
21030
  }, () => {
21169
21031
  if (_this._isMounted) {
21170
21032
  onFocus && onFocus();
@@ -27528,7 +27390,7 @@ var Interactive = {
27528
27390
  hidden: true
27529
27391
  };
27530
27392
 
27531
- /* eslint-disable react/forbid-prop-types, react/no-unsafe, react/sort-comp */
27393
+ /* eslint-disable react/no-unsafe */
27532
27394
  const defaultBackgroundImage$2 = {
27533
27395
  url: null
27534
27396
  };
@@ -27746,6 +27608,34 @@ class Graph extends React.Component {
27746
27608
  return _.pick(this.props, "range", "step", "markings", "labels", "backgroundImage", "showProtractor", "showRuler", "rulerLabel", "rulerTicks", "gridStep", "snapStep");
27747
27609
  };
27748
27610
  }
27611
+ componentDidMount() {
27612
+ this._setupGraphie(true);
27613
+ }
27614
+ UNSAFE_componentWillReceiveProps(nextProps) {
27615
+ const potentialChanges = ["labels", "range", "step", "markings", "showProtractor", "showRuler", "rulerLabel", "rulerTicks", "gridStep", "snapStep"];
27616
+ const self = this;
27617
+ _.each(potentialChanges, function (prop) {
27618
+ if (!_.isEqual(self.props[prop], nextProps[prop])) {
27619
+ self._shouldSetupGraphie = true;
27620
+ }
27621
+ });
27622
+ }
27623
+ componentDidUpdate() {
27624
+ // Only setupGraphie once per componentDidUpdate().
27625
+ // See explanation in setupGraphie().
27626
+ this._hasSetupGraphieThisUpdate = false;
27627
+ if (this._shouldSetupGraphie) {
27628
+ this._setupGraphie(false);
27629
+ this._shouldSetupGraphie = false;
27630
+ }
27631
+ }
27632
+
27633
+ /* Reset the graphie canvas to its initial state
27634
+ *
27635
+ * Use when re-rendering the parent component and you need a blank
27636
+ * graphie.
27637
+ */
27638
+
27749
27639
  render() {
27750
27640
  let image;
27751
27641
  const imageData = this.props.backgroundImage;
@@ -27784,55 +27674,7 @@ class Graph extends React.Component {
27784
27674
  ref: "graphieDiv"
27785
27675
  }));
27786
27676
  }
27787
- componentDidMount() {
27788
- this._setupGraphie(true);
27789
- }
27790
- componentDidUpdate() {
27791
- // Only setupGraphie once per componentDidUpdate().
27792
- // See explanation in setupGraphie().
27793
- this._hasSetupGraphieThisUpdate = false;
27794
- if (this._shouldSetupGraphie) {
27795
- this._setupGraphie(false);
27796
- this._shouldSetupGraphie = false;
27797
- }
27798
- }
27799
- UNSAFE_componentWillReceiveProps(nextProps) {
27800
- const potentialChanges = ["labels", "range", "step", "markings", "showProtractor", "showRuler", "rulerLabel", "rulerTicks", "gridStep", "snapStep"];
27801
- const self = this;
27802
- _.each(potentialChanges, function (prop) {
27803
- if (!_.isEqual(self.props[prop], nextProps[prop])) {
27804
- self._shouldSetupGraphie = true;
27805
- }
27806
- });
27807
- }
27808
-
27809
- /* Reset the graphie canvas to its initial state
27810
- *
27811
- * Use when re-rendering the parent component and you need a blank
27812
- * graphie.
27813
- */
27814
27677
  }
27815
- Graph.propTypes = {
27816
- box: PropTypes.array.isRequired,
27817
- labels: PropTypes.arrayOf(PropTypes.string),
27818
- range: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
27819
- step: PropTypes.arrayOf(PropTypes.number),
27820
- gridStep: PropTypes.arrayOf(PropTypes.number),
27821
- snapStep: PropTypes.arrayOf(PropTypes.number),
27822
- markings: PropTypes.string,
27823
- backgroundImage: PropTypes.shape({
27824
- url: PropTypes.string
27825
- }),
27826
- showProtractor: PropTypes.bool,
27827
- showRuler: PropTypes.bool,
27828
- rulerLabel: PropTypes.string,
27829
- rulerTicks: PropTypes.number,
27830
- onGraphieUpdated: PropTypes.func,
27831
- instructions: PropTypes.string,
27832
- onClick: PropTypes.func,
27833
- setDrawingAreaAvailable: PropTypes.func,
27834
- isMobile: PropTypes.bool
27835
- };
27836
27678
  Graph.defaultProps = {
27837
27679
  labels: ["x", "y"],
27838
27680
  range: [[-10, 10], [-10, 10]],
@@ -27845,10 +27687,6 @@ Graph.defaultProps = {
27845
27687
  showRuler: false,
27846
27688
  rulerLabel: "",
27847
27689
  rulerTicks: 10,
27848
- instructions: null,
27849
- onGraphieUpdated: null,
27850
- onClick: null,
27851
- onMouseDown: null,
27852
27690
  isMobile: false
27853
27691
  };
27854
27692
 
@@ -29316,7 +29154,10 @@ class InteractiveGraph extends React.Component {
29316
29154
  } else {
29317
29155
  instructions = undefined;
29318
29156
  }
29319
- const onMouseDown = this.isClickToAddPoints() ? this.handleAddPointsMouseDown : null;
29157
+ let onMouseDown;
29158
+ if (this.isClickToAddPoints()) {
29159
+ onMouseDown = this.handleAddPointsMouseDown;
29160
+ }
29320
29161
  const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
29321
29162
  const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
29322
29163
  const isMobile = this.props.apiOptions.isMobile;
@@ -29899,7 +29740,6 @@ InteractiveGraph.defaultProps = {
29899
29740
  labels: ["x", "y"],
29900
29741
  range: [[-10, 10], [-10, 10]],
29901
29742
  step: [1, 1],
29902
- // @ts-expect-error [FEI-5003] - TS2739 - Type '{ readonly url: null; }' is missing the following properties from type 'PerseusImageBackground': width, height
29903
29743
  backgroundImage: defaultBackgroundImage$1,
29904
29744
  markings: "graph",
29905
29745
  showTooltips: false,
@@ -32248,14 +32088,18 @@ var LightsPuzzle$1 = {
32248
32088
  transform: transformProps
32249
32089
  };
32250
32090
 
32251
- const HORIZONTAL$2 = "horizontal";
32252
- const VERTICAL$1 = "vertical";
32253
- const STATIC = "static";
32254
- const DRAGGING = "dragging";
32255
- const ANIMATING = "animating";
32256
- const DISABLED = "disabled";
32257
-
32258
- // Augment the given position with the scroll position of the offset parent.
32091
+ let Layout = /*#__PURE__*/function (Layout) {
32092
+ Layout["HORIZONTAL"] = "horizontal";
32093
+ Layout["VERTICAL"] = "vertical";
32094
+ return Layout;
32095
+ }({});
32096
+ var ItemState = /*#__PURE__*/function (ItemState) {
32097
+ ItemState["STATIC"] = "static";
32098
+ ItemState["DRAGGING"] = "dragging";
32099
+ ItemState["ANIMATING"] = "animating";
32100
+ ItemState["DISABLED"] = "disabled";
32101
+ return ItemState;
32102
+ }(ItemState || {}); // Augment the given position with the scroll position of the offset parent.
32259
32103
  const addOffsetParentScroll = ($el, position) => {
32260
32104
  // NOTE(slim): $(el).offsetParent() is NOT equivalent to $el[0].offsetParent.
32261
32105
  // Specifically, when `el` is not positioned, then the native HTMLElement.offsetParent
@@ -32269,14 +32113,13 @@ const addOffsetParentScroll = ($el, position) => {
32269
32113
  left: position.left + $offsetParent.scrollLeft()
32270
32114
  };
32271
32115
  };
32272
-
32273
32116
  // A placeholder that appears in the sortable whenever an item is dragged.
32274
32117
  class Placeholder extends React.Component {
32275
32118
  render() {
32276
32119
  const {
32277
32120
  layout
32278
32121
  } = this.props;
32279
- const className = css(styles$e.card, styles$e.placeholder, layout === HORIZONTAL$2 && styles$e.horizontalCard);
32122
+ const className = css(styles$e.card, styles$e.placeholder, layout === Layout.HORIZONTAL && styles$e.horizontalCard);
32280
32123
  const style = {
32281
32124
  width: this.props.width,
32282
32125
  height: this.props.height
@@ -32290,11 +32133,6 @@ class Placeholder extends React.Component {
32290
32133
  });
32291
32134
  }
32292
32135
  }
32293
- Placeholder.propTypes = {
32294
- layout: PropTypes.oneOf([HORIZONTAL$2, VERTICAL$1]),
32295
- width: PropTypes.number.isRequired,
32296
- height: PropTypes.number.isRequired
32297
- };
32298
32136
  // A draggable item in the sortable. Can be in one of four states:
32299
32137
  // Static: The item is not being interacted with.
32300
32138
  // Dragging: The item is being dragged.
@@ -32321,7 +32159,8 @@ class Draggable extends React.Component {
32321
32159
  mouse: {
32322
32160
  left: 0,
32323
32161
  top: 0
32324
- }
32162
+ },
32163
+ dragging: false
32325
32164
  };
32326
32165
  this.getCurrentPosition = () => {
32327
32166
  return {
@@ -32340,7 +32179,7 @@ class Draggable extends React.Component {
32340
32179
  $(document).off("mouseup", this.onMouseUp);
32341
32180
  };
32342
32181
  this.onMouseDown = event => {
32343
- if (this.props.type !== STATIC) {
32182
+ if (this.props.state !== ItemState.STATIC) {
32344
32183
  return;
32345
32184
  }
32346
32185
  if (!(event.button === 0 || event.touches != null && event.touches.length === 1)) {
@@ -32382,7 +32221,7 @@ class Draggable extends React.Component {
32382
32221
  });
32383
32222
  };
32384
32223
  this.onMouseMove = event => {
32385
- const notDragging = this.props.type !== DRAGGING || !this.state.dragging;
32224
+ const notDragging = this.props.state !== ItemState.DRAGGING || !this.state.dragging;
32386
32225
  if (notDragging) {
32387
32226
  return;
32388
32227
  }
@@ -32400,7 +32239,7 @@ class Draggable extends React.Component {
32400
32239
  }
32401
32240
  };
32402
32241
  this.onMouseUp = event => {
32403
- const notDragging = this.props.type !== DRAGGING || !this.state.dragging;
32242
+ const notDragging = this.props.state !== ItemState.DRAGGING || !this.state.dragging;
32404
32243
  if (notDragging) {
32405
32244
  return;
32406
32245
  }
@@ -32454,20 +32293,20 @@ class Draggable extends React.Component {
32454
32293
  const {
32455
32294
  includePadding,
32456
32295
  layout,
32457
- type
32296
+ state: type
32458
32297
  } = this.props;
32459
32298
 
32460
32299
  // We need to keep backwards compatbility with rules specified directly
32461
32300
  // in CSS. Hence the hacky tacking on of manual classNames.
32462
32301
  // See sortable.less for details.
32463
- let className = css(styles$e.card, styles$e.draggable, layout === HORIZONTAL$2 && styles$e.horizontalCard, layout === VERTICAL$1 && styles$e.verticalCard, type === DRAGGING && styles$e.dragging, type === DISABLED && styles$e.disabled, !includePadding && styles$e.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32302
+ let className = css(styles$e.card, styles$e.draggable, layout === Layout.HORIZONTAL && styles$e.horizontalCard, layout === Layout.VERTICAL && styles$e.verticalCard, type === ItemState.DRAGGING && styles$e.dragging, type === ItemState.DISABLED && styles$e.disabled, !includePadding && styles$e.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32464
32303
  if (!includePadding) {
32465
32304
  className += " perseus-sortable-draggable-unpadded";
32466
32305
  }
32467
32306
  const style = {
32468
32307
  position: "static"
32469
32308
  };
32470
- if (this.props.type === DRAGGING || this.props.type === ANIMATING) {
32309
+ if (this.props.state === ItemState.DRAGGING || this.props.state === ItemState.ANIMATING) {
32471
32310
  _.extend(style, {
32472
32311
  position: "absolute"
32473
32312
  }, this.getCurrentPosition());
@@ -32497,10 +32336,10 @@ class Draggable extends React.Component {
32497
32336
  }));
32498
32337
  }
32499
32338
  componentDidUpdate(prevProps) {
32500
- if (this.props.type === prevProps.type) {
32339
+ if (this.props.state === prevProps.state) {
32501
32340
  return;
32502
32341
  }
32503
- if (this.props.type === ANIMATING) {
32342
+ if (this.props.state === ItemState.ANIMATING) {
32504
32343
  // Start animating
32505
32344
  const current = this.getCurrentPosition();
32506
32345
  const duration = 15 * Math.sqrt(Math.sqrt(Math.pow(this.props.endPosition.left - current.left, 2) + Math.pow(this.props.endPosition.top - current.top, 2)));
@@ -32511,29 +32350,16 @@ class Draggable extends React.Component {
32511
32350
  // Animating -> Static
32512
32351
  complete: this.props.onAnimationEnd
32513
32352
  });
32514
- } else if (this.props.type === STATIC) {
32353
+ } else if (this.props.state === ItemState.STATIC) {
32515
32354
  // Ensure that any animations are done
32516
32355
  // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call. | TS2339 - Property 'finish' does not exist on type 'JQueryStatic'.
32517
32356
  $(ReactDOM__default.findDOMNode(this)).finish();
32518
32357
  }
32519
32358
  }
32520
32359
  }
32521
- Draggable.propTypes = {
32522
- content: PropTypes.string.isRequired,
32523
- endPosition: PropTypes.object.isRequired,
32524
- includePadding: PropTypes.bool,
32525
- layout: PropTypes.oneOf([HORIZONTAL$2, VERTICAL$1]),
32526
- onAnimationEnd: PropTypes.func.isRequired,
32527
- onMouseDown: PropTypes.func.isRequired,
32528
- onMouseMove: PropTypes.func.isRequired,
32529
- onMouseUp: PropTypes.func.isRequired,
32530
- onRender: PropTypes.func.isRequired,
32531
- type: PropTypes.oneOf([STATIC, DRAGGING, ANIMATING, DISABLED]),
32532
- linterContext: PerseusLinter.linterContextProps
32533
- };
32534
32360
  Draggable.defaultProps = {
32535
32361
  includePadding: true,
32536
- type: STATIC,
32362
+ type: ItemState.STATIC,
32537
32363
  linterContext: PerseusLinter.linterContextDefault
32538
32364
  };
32539
32365
  class Sortable extends React.Component {
@@ -32548,7 +32374,7 @@ class Sortable extends React.Component {
32548
32374
  }, 20);
32549
32375
  this.state = {
32550
32376
  items: Sortable.itemsFromProps(this.props),
32551
- katex: null
32377
+ texRendererLoaded: false
32552
32378
  };
32553
32379
  }
32554
32380
  UNSAFE_componentWillReceiveProps(nextProps) {
@@ -32576,20 +32402,13 @@ class Sortable extends React.Component {
32576
32402
  }, 0);
32577
32403
  }
32578
32404
  }
32579
- componentDidMount() {
32580
- getDependencies().getKaTeX().then(katex => {
32581
- this.setState({
32582
- katex
32583
- });
32584
- });
32585
- }
32586
32405
  static itemsFromProps(props) {
32587
- const type = props.disabled ? DISABLED : STATIC;
32406
+ const state = props.disabled ? ItemState.DISABLED : ItemState.STATIC;
32588
32407
  return props.options.map((option, i) => {
32589
32408
  return {
32590
32409
  option: option,
32591
32410
  key: i,
32592
- type: type,
32411
+ state,
32593
32412
  endPosition: {},
32594
32413
  width: 0,
32595
32414
  height: 0
@@ -32611,8 +32430,7 @@ class Sortable extends React.Component {
32611
32430
  // explictly set on Draggables - this prevents them from changing size
32612
32431
  // or shape while being dragged.
32613
32432
 
32614
- // @ts-expect-error [FEI-5003] - TS2740 - Type 'readonly SortableItem[]' is missing the following properties from type 'SortableItem': option, key, type, endPosition, and 2 more.
32615
- let items = _.clone(this.state.items);
32433
+ let items = [...this.state.items];
32616
32434
 
32617
32435
  // Fetches a jQuery list of elements for each item
32618
32436
  const $items = _.map(items, function (item) {
@@ -32630,7 +32448,7 @@ class Sortable extends React.Component {
32630
32448
  if (constraints != null && constraints.width) {
32631
32449
  // Items must be at least as wide as the specified constraint
32632
32450
  syncWidth = _.max(widths.concat(constraints.width));
32633
- } else if (layout === VERTICAL$1) {
32451
+ } else if (layout === Layout.VERTICAL) {
32634
32452
  // Sync widths to get a clean column
32635
32453
  syncWidth = _.max(widths);
32636
32454
  }
@@ -32638,21 +32456,17 @@ class Sortable extends React.Component {
32638
32456
  if (constraints != null && constraints.height) {
32639
32457
  // Items must be at least as high as the specified constraint
32640
32458
  syncHeight = _.max(heights.concat(constraints.height));
32641
- } else if (layout === HORIZONTAL$2) {
32459
+ } else if (layout === Layout.HORIZONTAL) {
32642
32460
  // Sync widths to get a clean row
32643
32461
  syncHeight = _.max(heights);
32644
32462
  }
32645
-
32646
- // @ts-expect-error [FEI-5003] - TS2740 - Type 'any[]' is missing the following properties from type 'SortableItem': option, key, type, endPosition, and 2 more.
32647
32463
  items = _.map(items, function (item, i) {
32648
32464
  item.width = syncWidth || widths[i];
32649
32465
  item.height = syncHeight || heights[i];
32650
32466
  return item;
32651
32467
  });
32652
-
32653
- // @ts-expect-error [FEI-5003] - TS2740 - Type 'SortableItem' is missing the following properties from type 'readonly SortableItem[]': length, concat, join, slice, and 18 more.
32654
32468
  this.setState({
32655
- items: items
32469
+ items
32656
32470
  }, () => {
32657
32471
  this.props.onMeasure && this.props.onMeasure({
32658
32472
  widths: widths,
@@ -32662,14 +32476,30 @@ class Sortable extends React.Component {
32662
32476
  }
32663
32477
  render() {
32664
32478
  var _this$props$constrain, _this$props$constrain2;
32665
- // We don't render the sortable until KaTeX has fully loaded, in case
32666
- // the draggables are rendering KaTeX content. This is un-optimal as
32667
- // we end up loading KaTeX even when we may not need it, however it
32668
- // helps to ensure that the dimensions of the draggables (and thus the
32669
- // sortable) will be correct when they render, if their contents are
32670
- // KaTeX-derived.
32671
- if (this.props.waitForKatexLoad && !this.state.katex) {
32672
- return /*#__PURE__*/React.createElement(CircularSpinner, null);
32479
+ // To minimize layout shift, we display a spinner until our math
32480
+ // renderer is ready to render the math inside the sortable. To
32481
+ // do this, we:
32482
+ // - render a dummy TeX component to force the math renderer to load
32483
+ // - display a spinner until the TeX component calls its onRender
32484
+ // callback, signifying that the math is rendered (from which we can
32485
+ // infer that the math renderer has loaded)
32486
+ //
32487
+ // If we didn't do this, the user might see a sortable with empty
32488
+ // cells on first render, and then the math would pop in a few moments
32489
+ // later once the rendering library loaded.
32490
+ if (this.props.waitForTexRendererToLoad && !this.state.texRendererLoaded) {
32491
+ const {
32492
+ TeX
32493
+ } = getDependencies();
32494
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CircularSpinner, null), /*#__PURE__*/React.createElement("div", {
32495
+ style: {
32496
+ display: "none"
32497
+ }
32498
+ }, /*#__PURE__*/React.createElement(TeX, {
32499
+ onRender: () => this.setState({
32500
+ texRendererLoaded: true
32501
+ })
32502
+ }, "1")));
32673
32503
  }
32674
32504
  const cards = [];
32675
32505
  const {
@@ -32678,19 +32508,19 @@ class Sortable extends React.Component {
32678
32508
  // We need to keep backwards compatbility with rules specified directly
32679
32509
  // in CSS. See sortable.less for details.
32680
32510
  const className = css(styles$e.sortable) + " perseus-sortable";
32681
- const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === VERTICAL$1;
32682
- const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === HORIZONTAL$2;
32511
+ const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
32512
+ const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
32683
32513
  _.each(this.state.items, function (item, i, items) {
32684
32514
  const isLast = i === items.length - 1;
32685
- const isStatic = item.type === STATIC || item.type === DISABLED;
32515
+ const isStatic = item.state === ItemState.STATIC || item.state === ItemState.DISABLED;
32686
32516
  let margin;
32687
32517
 
32688
32518
  // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
32689
- if (this.props.layout === HORIZONTAL$2) {
32519
+ if (this.props.layout === Layout.HORIZONTAL) {
32690
32520
  // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
32691
32521
  margin = "0 " + this.props.margin + "px 0 0"; // right
32692
32522
  // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
32693
- } else if (this.props.layout === VERTICAL$1) {
32523
+ } else if (this.props.layout === Layout.VERTICAL) {
32694
32524
  // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
32695
32525
  margin = "0 0 " + this.props.margin + "px 0"; // bottom
32696
32526
  }
@@ -32698,7 +32528,7 @@ class Sortable extends React.Component {
32698
32528
  cards.push( /*#__PURE__*/React.createElement(Draggable, {
32699
32529
  content: item.option,
32700
32530
  key: item.key,
32701
- type: item.type
32531
+ state: item.state
32702
32532
  // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
32703
32533
  ,
32704
32534
  ref: item.key,
@@ -32747,7 +32577,7 @@ class Sortable extends React.Component {
32747
32577
  // @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
32748
32578
  this, item.key)
32749
32579
  }));
32750
- if (item.type === DRAGGING || item.type === ANIMATING) {
32580
+ if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
32751
32581
  cards.push( /*#__PURE__*/React.createElement(Placeholder, {
32752
32582
  key: "placeholder_" + item.key,
32753
32583
  ref: "placeholder_" + item.key,
@@ -32766,7 +32596,7 @@ class Sortable extends React.Component {
32766
32596
  // Static -> Dragging
32767
32597
  const items = _.map(this.state.items, function (item) {
32768
32598
  if (item.key === key) {
32769
- item.type = DRAGGING;
32599
+ item.state = ItemState.DRAGGING;
32770
32600
  }
32771
32601
  return item;
32772
32602
  });
@@ -32826,7 +32656,7 @@ class Sortable extends React.Component {
32826
32656
 
32827
32657
  // @ts-expect-error [FEI-5003] - TS2551 - Property 'splice' does not exist on type 'readonly SortableItem[]'. Did you mean 'slice'?
32828
32658
  items.splice(currentIndex, 1);
32829
- if (this.props.layout === HORIZONTAL$2) {
32659
+ if (this.props.layout === Layout.HORIZONTAL) {
32830
32660
  // @ts-expect-error [FEI-5003] - TS2339 - Property 'offset' does not exist on type 'JQueryStatic'. | TS2339 - Property 'offset' does not exist on type 'JQueryStatic'.
32831
32661
  const midWidth = $draggable.offset().left - $sortable.offset().left;
32832
32662
  let sumWidth = 0;
@@ -32866,7 +32696,7 @@ class Sortable extends React.Component {
32866
32696
  const nextAnimationFrame = requestAnimationFrame(() => {
32867
32697
  const items = _.map(this.state.items, function (item) {
32868
32698
  if (item.key === key) {
32869
- item.type = ANIMATING;
32699
+ item.state = ItemState.ANIMATING;
32870
32700
  const $placeholder = $(
32871
32701
  // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
32872
32702
  ReactDOM__default.findDOMNode(
@@ -32896,7 +32726,7 @@ class Sortable extends React.Component {
32896
32726
  // Animating -> Static
32897
32727
  const items = _.map(this.state.items, function (item) {
32898
32728
  if (item.key === key) {
32899
- item.type = STATIC;
32729
+ item.state = ItemState.STATIC;
32900
32730
  }
32901
32731
  return item;
32902
32732
  });
@@ -32909,7 +32739,7 @@ class Sortable extends React.Component {
32909
32739
  }
32910
32740
  }
32911
32741
  Sortable.defaultProps = {
32912
- layout: HORIZONTAL$2,
32742
+ layout: Layout.HORIZONTAL,
32913
32743
  padding: true,
32914
32744
  disabled: false,
32915
32745
  constraints: {},
@@ -32917,7 +32747,7 @@ Sortable.defaultProps = {
32917
32747
  margin: 5,
32918
32748
  onChange: function () {},
32919
32749
  linterContext: PerseusLinter.linterContextDefault,
32920
- waitForKatexLoad: true
32750
+ waitForTexRendererToLoad: true
32921
32751
  };
32922
32752
  const styles$e = StyleSheet.create({
32923
32753
  sortable: {
@@ -32980,7 +32810,7 @@ class Matcher extends React.Component {
32980
32810
  this.state = {
32981
32811
  leftHeight: 0,
32982
32812
  rightHeight: 0,
32983
- katex: null
32813
+ texRendererLoaded: false
32984
32814
  };
32985
32815
  this.changeAndTrack = e => {
32986
32816
  this.props.onChange(e);
@@ -32999,10 +32829,10 @@ class Matcher extends React.Component {
32999
32829
  });
33000
32830
  };
33001
32831
  this.getUserInput = () => {
33002
- // If KaTeX hasn't loaded then we won't be able to get the contents
33003
- // of the sortables on the left and right, so we just return empty
33004
- // arrays until we render for the first time.
33005
- if (!this.state.katex) {
32832
+ // If the math renderer hasn't loaded then we won't be able to get the
32833
+ // contents of the sortables on the left and right, so we just return
32834
+ // empty arrays until we render for the first time.
32835
+ if (!this.state.texRendererLoaded) {
33006
32836
  return {
33007
32837
  left: [],
33008
32838
  right: []
@@ -33032,20 +32862,33 @@ class Matcher extends React.Component {
33032
32862
  return Matcher.validate(this.getUserInput(), rubric);
33033
32863
  };
33034
32864
  }
33035
- componentDidMount() {
33036
- getDependencies().getKaTeX().then(katex => this.setState({
33037
- katex
33038
- }));
33039
- }
33040
32865
  render() {
33041
- // We don't render the Matcher until KaTeX has fully loaded, in case
33042
- // the sortables are rendering KaTeX content. This is un-optimal as
33043
- // we end up loading KaTeX even when we may not need it, however it
33044
- // helps to ensure that the dimensions of the sortables (and thus the
33045
- // Matcher) will be correct when they render, if their contents are
33046
- // KaTeX-derived.
33047
- if (!this.state.katex) {
33048
- return /*#__PURE__*/React.createElement(CircularSpinner, null);
32866
+ // To minimize layout shift, we display a spinner until our math
32867
+ // renderer is ready to render the math inside the matcher. To
32868
+ // do this, we:
32869
+ // - render a dummy TeX component to force the math renderer to load
32870
+ // - display a spinner until the TeX component calls its onRender
32871
+ // callback, signifying that the math is rendered (from which we can
32872
+ // infer that the math renderer has loaded)
32873
+ //
32874
+ // If we didn't do this, the user might see a matcher with empty
32875
+ // columns on first render, and then the math would pop in a few
32876
+ // moments later once the rendering library loaded.
32877
+ if (!this.state.texRendererLoaded) {
32878
+ const {
32879
+ TeX
32880
+ } = getDependencies();
32881
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CircularSpinner, null), /*#__PURE__*/React.createElement("div", {
32882
+ style: {
32883
+ display: "none"
32884
+ }
32885
+ }, /*#__PURE__*/React.createElement(TeX, {
32886
+ onRender: () => {
32887
+ this.setState({
32888
+ texRendererLoaded: true
32889
+ });
32890
+ }
32891
+ }, "1")));
33049
32892
  }
33050
32893
 
33051
32894
  // Use the same random() function to shuffle both columns sequentially
@@ -33083,7 +32926,7 @@ class Matcher extends React.Component {
33083
32926
  className: css(styles$d.column)
33084
32927
  }, /*#__PURE__*/React.createElement(Sortable, {
33085
32928
  options: left,
33086
- layout: "vertical",
32929
+ layout: Layout.VERTICAL,
33087
32930
  padding: this.props.padding,
33088
32931
  disabled: !this.props.orderMatters,
33089
32932
  constraints: constraints,
@@ -33100,7 +32943,7 @@ class Matcher extends React.Component {
33100
32943
  // @ts-expect-error [FEI-5003] - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33101
32944
  , {
33102
32945
  options: right,
33103
- layout: "vertical",
32946
+ layout: Layout.VERTICAL,
33104
32947
  padding: this.props.padding,
33105
32948
  constraints: constraints,
33106
32949
  onMeasure: this.onMeasureRight,
@@ -39735,11 +39578,7 @@ class Histogram extends React.Component {
39735
39578
  box: this.props.box,
39736
39579
  range: range,
39737
39580
  data: data,
39738
- scale: [
39739
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Coordinates'.
39740
- Util.scaleFromExtent(range[0], this.props.box[0]),
39741
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Coordinates'.
39742
- Util.scaleFromExtent(range[1], this.props.box[1])]
39581
+ scale: [Util.scaleFromExtent(range[0], this.props.box[0]), Util.scaleFromExtent(range[1], this.props.box[1])]
39743
39582
  };
39744
39583
  const axisStyle = {
39745
39584
  stroke: "#000",
@@ -44157,7 +43996,7 @@ const ProvideKeypad = {
44157
43996
  _this._keypadContainer = document.createElement("div");
44158
43997
  // @ts-expect-error [FEI-5003] - TS2339 - Property '_keypadContainer' does not exist on type '{ readonly propTypes: { readonly apiOptions: React.PropType<{ customKeypad?: boolean | undefined; nativeKeypadProxy?: ((...a: readonly any[]) => unknown) | undefined; }>; readonly keypadStyle: Requireable<any>; }; readonly getInitialState: () => { ...; }; readonly componentDidMount: () => void; readonly componentWil...'.
44159
43998
  (_document$body = document.body) == null ? void 0 : _document$body.appendChild(_this._keypadContainer);
44160
- render( /*#__PURE__*/React.createElement(Keypad, {
43999
+ render( /*#__PURE__*/React.createElement(LegacyKeypad, {
44161
44000
  onElementMounted: element => {
44162
44001
  // NOTE(kevinb): The reason why this setState works is
44163
44002
  // b/c we're calling it manually from item-renderer.jsx
@@ -45531,98 +45370,88 @@ ElementContainer.defaultProps = {
45531
45370
  title: "More"
45532
45371
  };
45533
45372
 
45534
- class HUD extends React.Component {
45535
- constructor(...args) {
45536
- super(...args);
45537
- this.renderVisibleIcon = () => {
45538
- return /*#__PURE__*/React.createElement("svg", {
45539
- width: "24",
45540
- height: "24",
45541
- viewBox: "0 0 24 24",
45542
- className: css(styles$2.icon)
45543
- }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
45544
- id: "a",
45545
- 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"
45546
- })), /*#__PURE__*/React.createElement("g", {
45547
- fill: "none",
45548
- fillRule: "evenodd"
45549
- }, /*#__PURE__*/React.createElement("path", {
45550
- fill: "none",
45551
- d: "M0 0h24v24H0z"
45552
- }), /*#__PURE__*/React.createElement("mask", {
45553
- id: "b",
45554
- fill: "#fff"
45555
- }, /*#__PURE__*/React.createElement("use", {
45556
- href: "#a"
45557
- })), /*#__PURE__*/React.createElement("use", {
45558
- fill: "#fff",
45559
- fillRule: "nonzero",
45560
- href: "#a"
45561
- }), /*#__PURE__*/React.createElement("g", {
45562
- fill: "#fff",
45563
- mask: "url(#b)"
45564
- }, /*#__PURE__*/React.createElement("path", {
45565
- d: "M0 0h24v24H0z"
45566
- }))));
45567
- };
45568
- this.renderHiddenIcon = () => {
45569
- return /*#__PURE__*/React.createElement("svg", {
45570
- width: "24",
45571
- height: "24",
45572
- viewBox: "0 0 24 24",
45573
- className: css(styles$2.icon)
45574
- }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
45575
- id: "a",
45576
- 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"
45577
- })), /*#__PURE__*/React.createElement("g", {
45578
- fill: "none",
45579
- fillRule: "evenodd"
45580
- }, /*#__PURE__*/React.createElement("path", {
45581
- fill: "none",
45582
- d: "M0 0h24v24H0z"
45583
- }), /*#__PURE__*/React.createElement("mask", {
45584
- id: "b",
45585
- fill: "#fff"
45586
- }, /*#__PURE__*/React.createElement("use", {
45587
- href: "#a"
45588
- })), /*#__PURE__*/React.createElement("use", {
45589
- fill: "#fff",
45590
- fillRule: "nonzero",
45591
- href: "#a"
45592
- }), /*#__PURE__*/React.createElement("g", {
45593
- fill: "#fff",
45594
- mask: "url(#b)"
45595
- }, /*#__PURE__*/React.createElement("path", {
45596
- d: "M0 0h24v24H0z"
45597
- }))));
45598
- };
45373
+ // Displays a stylized open eye: lint warnings are visible
45374
+ const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
45375
+ width: "24",
45376
+ height: "24",
45377
+ viewBox: "0 0 24 24",
45378
+ className: css(styles$2.icon)
45379
+ }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
45380
+ id: "a",
45381
+ 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"
45382
+ })), /*#__PURE__*/React.createElement("g", {
45383
+ fill: "none",
45384
+ fillRule: "evenodd"
45385
+ }, /*#__PURE__*/React.createElement("path", {
45386
+ fill: "none",
45387
+ d: "M0 0h24v24H0z"
45388
+ }), /*#__PURE__*/React.createElement("mask", {
45389
+ id: "b",
45390
+ fill: "#fff"
45391
+ }, /*#__PURE__*/React.createElement("use", {
45392
+ href: "#a"
45393
+ })), /*#__PURE__*/React.createElement("use", {
45394
+ fill: "#fff",
45395
+ fillRule: "nonzero",
45396
+ href: "#a"
45397
+ }), /*#__PURE__*/React.createElement("g", {
45398
+ fill: "#fff",
45399
+ mask: "url(#b)"
45400
+ }, /*#__PURE__*/React.createElement("path", {
45401
+ d: "M0 0h24v24H0z"
45402
+ }))));
45403
+
45404
+ // Displays a stylized eye with a line through it: I don't want to see lint
45405
+ const HiddenIcon = () => /*#__PURE__*/React.createElement("svg", {
45406
+ width: "24",
45407
+ height: "24",
45408
+ viewBox: "0 0 24 24",
45409
+ className: css(styles$2.icon)
45410
+ }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
45411
+ id: "a",
45412
+ 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"
45413
+ })), /*#__PURE__*/React.createElement("g", {
45414
+ fill: "none",
45415
+ fillRule: "evenodd"
45416
+ }, /*#__PURE__*/React.createElement("path", {
45417
+ fill: "none",
45418
+ d: "M0 0h24v24H0z"
45419
+ }), /*#__PURE__*/React.createElement("mask", {
45420
+ id: "b",
45421
+ fill: "#fff"
45422
+ }, /*#__PURE__*/React.createElement("use", {
45423
+ href: "#a"
45424
+ })), /*#__PURE__*/React.createElement("use", {
45425
+ fill: "#fff",
45426
+ fillRule: "nonzero",
45427
+ href: "#a"
45428
+ }), /*#__PURE__*/React.createElement("g", {
45429
+ fill: "#fff",
45430
+ mask: "url(#b)"
45431
+ }, /*#__PURE__*/React.createElement("path", {
45432
+ d: "M0 0h24v24H0z"
45433
+ }))));
45434
+ const HUD = ({
45435
+ message,
45436
+ enabled,
45437
+ onClick,
45438
+ fixedPosition: _fixedPosition = true
45439
+ }) => {
45440
+ let state;
45441
+ let icon;
45442
+ if (enabled) {
45443
+ state = styles$2.enabled;
45444
+ icon = /*#__PURE__*/React.createElement(VisibleIcon, null);
45445
+ } else {
45446
+ state = styles$2.disabled;
45447
+ icon = /*#__PURE__*/React.createElement(HiddenIcon, null);
45599
45448
  }
45600
- render() {
45601
- let state;
45602
- let icon;
45603
- if (this.props.enabled) {
45604
- state = styles$2.enabled;
45605
- icon = this.renderVisibleIcon();
45606
- } else {
45607
- state = styles$2.disabled;
45608
- icon = this.renderHiddenIcon();
45449
+ return /*#__PURE__*/React.createElement("button", {
45450
+ className: css(styles$2.hud, _fixedPosition && styles$2.hudFixedPosition, state),
45451
+ onClick: e => {
45452
+ onClick();
45609
45453
  }
45610
- return /*#__PURE__*/React.createElement("button", {
45611
- className: css(styles$2.hud, this.props.fixedPosition && styles$2.hudFixedPosition, state),
45612
- onClick: e => {
45613
- this.props.onClick();
45614
- }
45615
- }, icon, this.props.message);
45616
- }
45617
- }
45618
- HUD.propTypes = {
45619
- message: PropTypes.string.isRequired,
45620
- enabled: PropTypes.bool.isRequired,
45621
- onClick: PropTypes.func.isRequired,
45622
- fixedPosition: PropTypes.bool
45623
- };
45624
- HUD.defaultProps = {
45625
- fixedPosition: true
45454
+ }, icon, message);
45626
45455
  };
45627
45456
  const styles$2 = StyleSheet.create({
45628
45457
  hud: {