@khanacademy/perseus-editor 2.2.2 → 2.3.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 (48) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/all-widgets.d.ts +2 -2
  3. package/dist/all-widgets.js.flow +2 -2
  4. package/dist/components/graph-points-count-selector.d.ts +7 -0
  5. package/dist/components/graph-points-count-selector.js.flow +12 -0
  6. package/dist/components/graph-type-selector.d.ts +7 -0
  7. package/dist/components/graph-type-selector.js.flow +12 -0
  8. package/dist/components/segment-count-selector.d.ts +6 -0
  9. package/dist/components/segment-count-selector.js.flow +11 -0
  10. package/dist/components/widget-editor.d.ts +31 -0
  11. package/dist/components/widget-editor.js.flow +91 -0
  12. package/dist/components/widget-select.d.ts +10 -0
  13. package/dist/components/widget-select.js.flow +16 -0
  14. package/dist/es/index.js +423 -229
  15. package/dist/es/index.js.map +1 -1
  16. package/dist/index.js +431 -225
  17. package/dist/index.js.map +1 -1
  18. package/dist/testing-widgets.d.ts +2 -2
  19. package/dist/testing-widgets.js.flow +2 -2
  20. package/dist/util/points.d.ts +3 -0
  21. package/dist/util/points.js.flow +9 -0
  22. package/dist/widgets/example-graphie-widget.d.ts +2 -2
  23. package/dist/widgets/example-graphie-widget.js.flow +2 -2
  24. package/dist/widgets/example-widget.d.ts +2 -2
  25. package/dist/widgets/example-widget.js.flow +2 -2
  26. package/dist/widgets/interactive-graph-editor.d.ts +3182 -1
  27. package/dist/widgets/interactive-graph-editor.js.flow +5290 -1
  28. package/package.json +9 -3
  29. package/src/__stories__/editor.stories.tsx +105 -4
  30. package/src/article-editor.tsx +1 -1
  31. package/src/{__stories__ → components/__stories__}/section-control-button.stories.tsx +1 -1
  32. package/src/components/graph-points-count-selector.tsx +29 -0
  33. package/src/components/graph-type-selector.tsx +31 -0
  34. package/src/components/json-editor.tsx +0 -1
  35. package/src/components/segment-count-selector.tsx +27 -0
  36. package/src/components/widget-editor.tsx +232 -0
  37. package/src/components/widget-select.tsx +48 -0
  38. package/src/editor.tsx +4 -270
  39. package/src/util/points.test.ts +24 -0
  40. package/src/util/points.ts +13 -0
  41. package/src/widgets/interactive-graph-editor.tsx +294 -48
  42. package/tsconfig-build.json +0 -1
  43. package/tsconfig-build.tsbuildinfo +1 -1
  44. package/dist/diffs/__stories__/perseus-diff-wrapper.d.ts +0 -6
  45. package/dist/diffs/__stories__/perseus-diff-wrapper.js.flow +0 -12
  46. /package/dist/{section-control-button.d.ts → components/section-control-button.d.ts} +0 -0
  47. /package/dist/{section-control-button.js.flow → components/section-control-button.js.flow} +0 -0
  48. /package/src/{section-control-button.tsx → components/section-control-button.tsx} +0 -0
package/dist/index.js CHANGED
@@ -7,14 +7,17 @@ var React = require('react');
7
7
  var _ = require('underscore');
8
8
  var PropTypes = require('prop-types');
9
9
  var createReactClass = require('create-react-class');
10
- var $ = require('jquery');
11
- var ReactDOM = require('react-dom');
12
- var aphrodite = require('aphrodite');
13
10
  var Clickable = require('@khanacademy/wonder-blocks-clickable');
14
11
  var Color = require('@khanacademy/wonder-blocks-color');
12
+ var aphrodite = require('aphrodite');
13
+ var $ = require('jquery');
14
+ var ReactDOM = require('react-dom');
15
15
  var classNames = require('classnames');
16
16
  var kmath = require('@khanacademy/kmath');
17
17
  var KAS = require('@khanacademy/kas');
18
+ var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
19
+ var Spacing = require('@khanacademy/wonder-blocks-spacing');
20
+ var Typography = require('@khanacademy/wonder-blocks-typography');
18
21
  var Button = require('@khanacademy/wonder-blocks-button');
19
22
  var i18n$1 = require('@khanacademy/wonder-blocks-i18n');
20
23
 
@@ -42,13 +45,15 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
42
45
  var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
43
46
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
44
47
  var createReactClass__default = /*#__PURE__*/_interopDefaultLegacy(createReactClass);
48
+ var Clickable__default = /*#__PURE__*/_interopDefaultLegacy(Clickable);
49
+ var Color__default = /*#__PURE__*/_interopDefaultLegacy(Color);
45
50
  var $__default = /*#__PURE__*/_interopDefaultLegacy($);
46
51
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
47
52
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
48
- var Clickable__default = /*#__PURE__*/_interopDefaultLegacy(Clickable);
49
- var Color__default = /*#__PURE__*/_interopDefaultLegacy(Color);
50
53
  var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
51
54
  var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
55
+ var Spacing__default = /*#__PURE__*/_interopDefaultLegacy(Spacing);
56
+ var Typography__namespace = /*#__PURE__*/_interopNamespace(Typography);
52
57
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
53
58
  var i18n__namespace = /*#__PURE__*/_interopNamespace(i18n$1);
54
59
 
@@ -155,7 +160,7 @@ _defineProperty(DeviceFramer, "propTypes", {
155
160
  nochrome: PropTypes__default["default"].bool
156
161
  });
157
162
 
158
- /* eslint-disable react/prop-types */
163
+ /* eslint-disable @babel/no-invalid-this */
159
164
  const JsonEditor = createReactClass__default["default"]({
160
165
  displayName: "JsonEditor",
161
166
  getInitialState: function () {
@@ -249,6 +254,41 @@ const JsonEditor = createReactClass__default["default"]({
249
254
  }
250
255
  });
251
256
 
257
+ const {
258
+ InlineIcon: InlineIcon$c
259
+ } = perseus.components;
260
+ class SectionControlButton extends React__namespace.Component {
261
+ render() {
262
+ const {
263
+ icon,
264
+ onClick,
265
+ title
266
+ } = this.props;
267
+ return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
268
+ className: "section-control-button " + "simple-button " + "simple-button--small ",
269
+ onClick: e => {
270
+ e.preventDefault();
271
+ onClick();
272
+ },
273
+ role: "button",
274
+ hideDefaultFocusRing: true,
275
+ "aria-label": title,
276
+ style: styles$f.button
277
+ }, _ref => {
278
+ return /*#__PURE__*/React__namespace.createElement(InlineIcon$c, icon);
279
+ });
280
+ }
281
+ }
282
+ const styles$f = aphrodite.StyleSheet.create({
283
+ button: {
284
+ backgroundColor: Color__default["default"].gold,
285
+ margin: 2,
286
+ paddingRight: 10,
287
+ paddingLeft: 10,
288
+ paddingBottom: 2
289
+ }
290
+ });
291
+
252
292
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
253
293
 
254
294
  function getDefaultExportFromCjs (x) {
@@ -17742,110 +17782,6 @@ const DragTarget = createReactClass__default["default"]({
17742
17782
  }
17743
17783
  });
17744
17784
 
17745
- class KatexErrorView extends React__namespace.Component {
17746
- constructor() {
17747
- super(...arguments);
17748
- _defineProperty(this, "state", {
17749
- showErrors: false
17750
- });
17751
- _defineProperty(this, "handleToggleKatexErrors", e => {
17752
- this.setState({
17753
- showErrors: !this.state.showErrors
17754
- });
17755
- });
17756
- }
17757
- render() {
17758
- const {
17759
- errorList
17760
- } = this.props;
17761
- const {
17762
- showErrors
17763
- } = this.state;
17764
-
17765
- // TODO(riley) replace with SVG icons
17766
- const disclosureClass = showErrors ? "icon-chevron-down" : "icon-chevron-right";
17767
- return /*#__PURE__*/React__namespace.createElement("div", {
17768
- className: aphrodite.css(styles$f.errorContainer)
17769
- }, /*#__PURE__*/React__namespace.createElement("div", {
17770
- className: aphrodite.css(styles$f.title),
17771
- onClick: this.handleToggleKatexErrors
17772
- }, /*#__PURE__*/React__namespace.createElement("i", {
17773
- className: disclosureClass,
17774
- style: {
17775
- fontSize: 14
17776
- }
17777
- }), "\xA0 KaTeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React__namespace.createElement("div", {
17778
- className: aphrodite.css(styles$f.errorExplanation)
17779
- }, "These errors will cause your LaTeX to load really slowly for the student. Please fix them if you can. If you can\u2019t because KaTeX doesn\u2019t support the feature you need, please message Cam."), showErrors && errorList.map((e, index) => /*#__PURE__*/React__namespace.createElement("div", {
17780
- className: aphrodite.css(styles$f.error),
17781
- key: index
17782
- }, /*#__PURE__*/React__namespace.createElement("div", {
17783
- style: {
17784
- color: "red"
17785
- }
17786
- }, e.math), /*#__PURE__*/React__namespace.createElement("div", null, e.message))));
17787
- }
17788
- }
17789
- _defineProperty(KatexErrorView, "propTypes", {
17790
- errorList: PropTypes__default["default"].arrayOf(PropTypes__default["default"].shape({
17791
- math: PropTypes__default["default"].string.isRequired,
17792
- message: PropTypes__default["default"].string.isRequired
17793
- })).isRequired
17794
- });
17795
- const styles$f = aphrodite.StyleSheet.create({
17796
- title: {
17797
- backgroundColor: "#eee",
17798
- fontSize: "1.25em",
17799
- padding: "4px 10px"
17800
- },
17801
- errorContainer: {
17802
- border: "1px solid #ddd",
17803
- borderTop: "none"
17804
- },
17805
- errorExplanation: {
17806
- padding: "4px 10px",
17807
- backgroundColor: "pink"
17808
- },
17809
- error: {
17810
- padding: "4px 10px"
17811
- }
17812
- });
17813
-
17814
- const {
17815
- InlineIcon: InlineIcon$c
17816
- } = perseus.components;
17817
- class SectionControlButton extends React__namespace.Component {
17818
- render() {
17819
- const {
17820
- icon,
17821
- onClick,
17822
- title
17823
- } = this.props;
17824
- return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
17825
- className: "section-control-button " + "simple-button " + "simple-button--small ",
17826
- onClick: e => {
17827
- e.preventDefault();
17828
- onClick();
17829
- },
17830
- role: "button",
17831
- hideDefaultFocusRing: true,
17832
- "aria-label": title,
17833
- style: styles$e.button
17834
- }, _ref => {
17835
- return /*#__PURE__*/React__namespace.createElement(InlineIcon$c, icon);
17836
- });
17837
- }
17838
- }
17839
- const styles$e = aphrodite.StyleSheet.create({
17840
- button: {
17841
- backgroundColor: Color__default["default"].gold,
17842
- margin: 2,
17843
- paddingRight: 10,
17844
- paddingLeft: 10,
17845
- paddingBottom: 2
17846
- }
17847
- });
17848
-
17849
17785
  const {
17850
17786
  InlineIcon: InlineIcon$b,
17851
17787
  PropCheckBox: PropCheckBox$e
@@ -17855,80 +17791,6 @@ const {
17855
17791
  iconChevronRight,
17856
17792
  iconTrash: iconTrash$8
17857
17793
  } = perseus.icons;
17858
-
17859
- // like [[snowman input-number 1]]
17860
- const widgetPlaceholder = "[[\u2603 {id}]]";
17861
- const widgetRegExp = "(\\[\\[\u2603 {id}\\]\\])";
17862
- const rWidgetSplit = new RegExp(widgetRegExp.replace("{id}", "[a-z-]+ [0-9]+"), "g");
17863
- const shortcutRegexp = /^\[\[([a-z-]+)$/; // like [[nu, [[int, etc
17864
-
17865
- const ENDS_WITH_A_PARAGRAPH = /(?:\n{2,}|^\n*)$/;
17866
- const TRAILING_NEWLINES = /(\n*)$/;
17867
- const LEADING_NEWLINES = /^(\n*)/;
17868
- const commafyInteger = n => {
17869
- let str = n.toString();
17870
- if (str.length >= 5) {
17871
- str = str.replace(/(\d)(?=(\d{3})+$)/g, "$1{,}");
17872
- }
17873
- return str;
17874
- };
17875
- const makeEndWithAParagraphIfNecessary = content => {
17876
- if (!ENDS_WITH_A_PARAGRAPH.test(content)) {
17877
- const match = TRAILING_NEWLINES.exec(content);
17878
- if (match) {
17879
- const newlines = match[1];
17880
- return content + "\n\n".slice(0, 2 - newlines.length);
17881
- }
17882
- }
17883
- return content;
17884
- };
17885
- const makeStartWithAParagraphAlways = content => {
17886
- const match = LEADING_NEWLINES.exec(content);
17887
- if (!match) {
17888
- return content;
17889
- }
17890
- const newlines = match[1];
17891
- return "\n\n".slice(0, 2 - newlines.length) + content;
17892
- };
17893
- class WidgetSelect extends React__namespace.Component {
17894
- constructor() {
17895
- super(...arguments);
17896
- _defineProperty(this, "handleChange", e => {
17897
- const widgetType = e.currentTarget.value;
17898
- if (widgetType === "") {
17899
- // TODO(alpert): Not sure if change will trigger here
17900
- // but might as well be safe
17901
- return;
17902
- }
17903
- if (this.props.onChange) {
17904
- this.props.onChange(widgetType);
17905
- }
17906
- });
17907
- }
17908
- shouldComponentUpdate() {
17909
- return false;
17910
- }
17911
- render() {
17912
- const widgets = perseus.Widgets.getPublicWidgets();
17913
- const orderedWidgetNames = ___default["default"].sortBy(___default["default"].keys(widgets), name => {
17914
- return widgets[name].displayName;
17915
- });
17916
- const addWidgetString = "Add a widget\u2026";
17917
- return /*#__PURE__*/React__namespace.createElement("select", {
17918
- value: "",
17919
- onChange: this.handleChange
17920
- }, /*#__PURE__*/React__namespace.createElement("option", {
17921
- value: ""
17922
- }, addWidgetString), /*#__PURE__*/React__namespace.createElement("option", {
17923
- disabled: true
17924
- }, "--"), ___default["default"].map(orderedWidgetNames, name => {
17925
- return /*#__PURE__*/React__namespace.createElement("option", {
17926
- key: name,
17927
- value: name
17928
- }, widgets[name].displayName);
17929
- }));
17930
- }
17931
- }
17932
17794
  const _upgradeWidgetInfo = props => {
17933
17795
  // We can't call serialize here because this.refs.widget
17934
17796
  // doesn't exist before this component is mounted.
@@ -18063,6 +17925,150 @@ class WidgetEditor extends React__namespace.Component {
18063
17925
  }
18064
17926
  }
18065
17927
 
17928
+ class WidgetSelect extends React__namespace.Component {
17929
+ constructor() {
17930
+ super(...arguments);
17931
+ _defineProperty(this, "handleChange", e => {
17932
+ const widgetType = e.currentTarget.value;
17933
+ if (widgetType === "") {
17934
+ // TODO(alpert): Not sure if change will trigger here
17935
+ // but might as well be safe
17936
+ return;
17937
+ }
17938
+ if (this.props.onChange) {
17939
+ this.props.onChange(widgetType);
17940
+ }
17941
+ });
17942
+ }
17943
+ shouldComponentUpdate() {
17944
+ return false;
17945
+ }
17946
+ render() {
17947
+ const widgets = perseus.Widgets.getPublicWidgets();
17948
+ const orderedWidgetNames = ___default["default"].sortBy(___default["default"].keys(widgets), name => {
17949
+ return widgets[name].displayName;
17950
+ });
17951
+ const addWidgetString = "Add a widget\u2026";
17952
+ return /*#__PURE__*/React__namespace.createElement("select", {
17953
+ value: "",
17954
+ onChange: this.handleChange
17955
+ }, /*#__PURE__*/React__namespace.createElement("option", {
17956
+ value: ""
17957
+ }, addWidgetString), /*#__PURE__*/React__namespace.createElement("option", {
17958
+ disabled: true
17959
+ }, "--"), ___default["default"].map(orderedWidgetNames, name => {
17960
+ return /*#__PURE__*/React__namespace.createElement("option", {
17961
+ key: name,
17962
+ value: name
17963
+ }, widgets[name].displayName);
17964
+ }));
17965
+ }
17966
+ }
17967
+
17968
+ class KatexErrorView extends React__namespace.Component {
17969
+ constructor() {
17970
+ super(...arguments);
17971
+ _defineProperty(this, "state", {
17972
+ showErrors: false
17973
+ });
17974
+ _defineProperty(this, "handleToggleKatexErrors", e => {
17975
+ this.setState({
17976
+ showErrors: !this.state.showErrors
17977
+ });
17978
+ });
17979
+ }
17980
+ render() {
17981
+ const {
17982
+ errorList
17983
+ } = this.props;
17984
+ const {
17985
+ showErrors
17986
+ } = this.state;
17987
+
17988
+ // TODO(riley) replace with SVG icons
17989
+ const disclosureClass = showErrors ? "icon-chevron-down" : "icon-chevron-right";
17990
+ return /*#__PURE__*/React__namespace.createElement("div", {
17991
+ className: aphrodite.css(styles$e.errorContainer)
17992
+ }, /*#__PURE__*/React__namespace.createElement("div", {
17993
+ className: aphrodite.css(styles$e.title),
17994
+ onClick: this.handleToggleKatexErrors
17995
+ }, /*#__PURE__*/React__namespace.createElement("i", {
17996
+ className: disclosureClass,
17997
+ style: {
17998
+ fontSize: 14
17999
+ }
18000
+ }), "\xA0 KaTeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React__namespace.createElement("div", {
18001
+ className: aphrodite.css(styles$e.errorExplanation)
18002
+ }, "These errors will cause your LaTeX to load really slowly for the student. Please fix them if you can. If you can\u2019t because KaTeX doesn\u2019t support the feature you need, please message Cam."), showErrors && errorList.map((e, index) => /*#__PURE__*/React__namespace.createElement("div", {
18003
+ className: aphrodite.css(styles$e.error),
18004
+ key: index
18005
+ }, /*#__PURE__*/React__namespace.createElement("div", {
18006
+ style: {
18007
+ color: "red"
18008
+ }
18009
+ }, e.math), /*#__PURE__*/React__namespace.createElement("div", null, e.message))));
18010
+ }
18011
+ }
18012
+ _defineProperty(KatexErrorView, "propTypes", {
18013
+ errorList: PropTypes__default["default"].arrayOf(PropTypes__default["default"].shape({
18014
+ math: PropTypes__default["default"].string.isRequired,
18015
+ message: PropTypes__default["default"].string.isRequired
18016
+ })).isRequired
18017
+ });
18018
+ const styles$e = aphrodite.StyleSheet.create({
18019
+ title: {
18020
+ backgroundColor: "#eee",
18021
+ fontSize: "1.25em",
18022
+ padding: "4px 10px"
18023
+ },
18024
+ errorContainer: {
18025
+ border: "1px solid #ddd",
18026
+ borderTop: "none"
18027
+ },
18028
+ errorExplanation: {
18029
+ padding: "4px 10px",
18030
+ backgroundColor: "pink"
18031
+ },
18032
+ error: {
18033
+ padding: "4px 10px"
18034
+ }
18035
+ });
18036
+
18037
+ // like [[snowman input-number 1]]
18038
+ const widgetPlaceholder = "[[\u2603 {id}]]";
18039
+ const widgetRegExp = "(\\[\\[\u2603 {id}\\]\\])";
18040
+ const rWidgetSplit = new RegExp(widgetRegExp.replace("{id}", "[a-z-]+ [0-9]+"), "g");
18041
+ const shortcutRegexp = /^\[\[([a-z-]+)$/; // like [[nu, [[int, etc
18042
+
18043
+ const ENDS_WITH_A_PARAGRAPH = /(?:\n{2,}|^\n*)$/;
18044
+ const TRAILING_NEWLINES = /(\n*)$/;
18045
+ const LEADING_NEWLINES = /^(\n*)/;
18046
+ const commafyInteger = n => {
18047
+ let str = n.toString();
18048
+ if (str.length >= 5) {
18049
+ str = str.replace(/(\d)(?=(\d{3})+$)/g, "$1{,}");
18050
+ }
18051
+ return str;
18052
+ };
18053
+ const makeEndWithAParagraphIfNecessary = content => {
18054
+ if (!ENDS_WITH_A_PARAGRAPH.test(content)) {
18055
+ const match = TRAILING_NEWLINES.exec(content);
18056
+ if (match) {
18057
+ const newlines = match[1];
18058
+ return content + "\n\n".slice(0, 2 - newlines.length);
18059
+ }
18060
+ }
18061
+ return content;
18062
+ };
18063
+ const makeStartWithAParagraphAlways = content => {
18064
+ const match = LEADING_NEWLINES.exec(content);
18065
+ if (!match) {
18066
+ return content;
18067
+ }
18068
+ const newlines = match[1];
18069
+ return "\n\n".slice(0, 2 - newlines.length) + content;
18070
+ };
18071
+
18066
18072
  // This is more general than the actual markdown image parsing regex,
18067
18073
  // which is fine for correctness since it should only mean we could
18068
18074
  // store extra image dimensions, unless the question is insanely
@@ -18762,11 +18768,7 @@ class Editor extends React__namespace.Component {
18762
18768
  // }, this);
18763
18769
 
18764
18770
  this.widgetIds = ___default["default"].keys(widgets);
18765
- widgetsDropDown =
18766
- /*#__PURE__*/
18767
- // eslint-disable-next-line react/no-string-refs
18768
- React__namespace.createElement(WidgetSelect, {
18769
- ref: "widgetSelect",
18771
+ widgetsDropDown = /*#__PURE__*/React__namespace.createElement(WidgetSelect, {
18770
18772
  onChange: this._addWidget
18771
18773
  });
18772
18774
  const insertTemplateString = "Insert template\u2026";
@@ -27097,6 +27099,84 @@ _defineProperty(InteractionEditor, "propTypes", {
27097
27099
  _defineProperty(InteractionEditor, "widgetName", "interaction");
27098
27100
  _defineProperty(InteractionEditor, "defaultProps", defaultInteractionProps);
27099
27101
 
27102
+ const UNLIMITED = "unlimited";
27103
+ // Parses a string (ostensibly from some UI element that only supports string
27104
+ // types, such as a <select />) into a numeric point count or the special sigil
27105
+ // "unlimited". Note that 0 is a special case, and means "unlimited".
27106
+ const parsePointCount = points => {
27107
+ const parsed = parseInt(points, 10);
27108
+ if (isNaN(parsed)) {
27109
+ return UNLIMITED;
27110
+ }
27111
+ return parsed === 0 ? UNLIMITED : parsed;
27112
+ };
27113
+
27114
+ const GraphPointsCountSelector = _ref => {
27115
+ let {
27116
+ numPoints = 1,
27117
+ onChange
27118
+ } = _ref;
27119
+ return /*#__PURE__*/React__namespace.createElement("select", {
27120
+ value: numPoints,
27121
+ onChange: e => {
27122
+ onChange(parsePointCount(e.target.value));
27123
+ }
27124
+ }, [...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement("option", {
27125
+ key: n,
27126
+ value: n
27127
+ }, "".concat(n, " point").concat(n > 1 ? "s" : ""))), /*#__PURE__*/React__namespace.createElement("option", {
27128
+ value: UNLIMITED
27129
+ }, "unlimited"));
27130
+ };
27131
+
27132
+ const GraphTypeSelector = props => {
27133
+ return /*#__PURE__*/React__namespace.createElement("select", {
27134
+ value: props.graphType,
27135
+ onChange: e => {
27136
+ const type = e.target.value;
27137
+ props.onChange(type);
27138
+ }
27139
+ }, /*#__PURE__*/React__namespace.createElement("option", {
27140
+ value: "linear"
27141
+ }, "Linear function"), /*#__PURE__*/React__namespace.createElement("option", {
27142
+ value: "quadratic"
27143
+ }, "Quadratic function"), /*#__PURE__*/React__namespace.createElement("option", {
27144
+ value: "sinusoid"
27145
+ }, "Sinusoid function"), /*#__PURE__*/React__namespace.createElement("option", {
27146
+ value: "circle"
27147
+ }, "Circle"), /*#__PURE__*/React__namespace.createElement("option", {
27148
+ value: "point"
27149
+ }, "Point(s)"), /*#__PURE__*/React__namespace.createElement("option", {
27150
+ value: "linear-system"
27151
+ }, "Linear System"), /*#__PURE__*/React__namespace.createElement("option", {
27152
+ value: "polygon"
27153
+ }, "Polygon"), /*#__PURE__*/React__namespace.createElement("option", {
27154
+ value: "segment"
27155
+ }, "Line Segment(s)"), /*#__PURE__*/React__namespace.createElement("option", {
27156
+ value: "ray"
27157
+ }, "Ray"), /*#__PURE__*/React__namespace.createElement("option", {
27158
+ value: "angle"
27159
+ }, "Angle"));
27160
+ };
27161
+
27162
+ const SegmentCountSelector = _ref => {
27163
+ let {
27164
+ numSegments = 1,
27165
+ onChange
27166
+ } = _ref;
27167
+ return /*#__PURE__*/React__namespace.createElement("select", {
27168
+ key: "segment-select",
27169
+ value: numSegments,
27170
+ onChange: e => {
27171
+ const num = +e.target.value;
27172
+ onChange(num);
27173
+ }
27174
+ }, ___default["default"].range(1, 7).map(n => /*#__PURE__*/React__namespace.createElement("option", {
27175
+ key: n,
27176
+ value: n
27177
+ }, "".concat(n, " segment").concat(n > 1 ? "s" : ""))));
27178
+ };
27179
+
27100
27180
  const {
27101
27181
  InfoTip: InfoTip$e
27102
27182
  } = perseus.components;
@@ -27116,38 +27196,42 @@ const deprecatedProps = {
27116
27196
  };
27117
27197
  }
27118
27198
  };
27119
- const InteractiveGraphEditor = createReactClass__default["default"]({
27120
- displayName: "InteractiveGraphEditor",
27121
- className: "perseus-widget-interactive-graph",
27122
- statics: {
27123
- widgetName: "interactive-graph"
27124
- },
27125
- getDefaultProps: function () {
27126
- return {
27127
- labels: ["x", "y"],
27128
- range: [[-10, 10], [-10, 10]],
27129
- step: [1, 1],
27130
- valid: true,
27131
- backgroundImage: defaultBackgroundImage$1,
27132
- markings: "graph",
27133
- showProtractor: false,
27134
- showRuler: false,
27135
- showTooltips: false,
27136
- rulerLabel: "",
27137
- rulerTicks: 10,
27138
- correct: {
27139
- type: "linear",
27140
- coords: null
27141
- }
27142
- };
27143
- },
27144
- // TODO(jack): Use versioning instead of DeprecationMixin
27145
- deprecatedProps: deprecatedProps,
27199
+ // [min, max]
27200
+
27201
+ // Renders the given children in a View laid out horizontally.
27202
+ const Row = props => {
27203
+ const {
27204
+ children,
27205
+ style
27206
+ } = props;
27207
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
27208
+ style: {
27209
+ ...style,
27210
+ flexDirection: "row",
27211
+ marginTop: Spacing__default["default"].xSmall_8
27212
+ }
27213
+ }, children);
27214
+ };
27215
+ const FieldLabel = props => {
27216
+ return /*#__PURE__*/React__namespace.createElement(Typography__namespace.LabelSmall, {
27217
+ style: {
27218
+ marginRight: Spacing__default["default"].xSmall_8
27219
+ }
27220
+ }, props.children);
27221
+ };
27222
+ class InteractiveGraphEditor extends React__namespace.Component {
27223
+ constructor() {
27224
+ super(...arguments);
27225
+ _defineProperty(this, "displayName", "InteractiveGraphEditor");
27226
+ _defineProperty(this, "className", "perseus-widget-interactive-graph");
27227
+ _defineProperty(this, "deprecatedProps", deprecatedProps);
27228
+ }
27146
27229
  // TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
27147
27230
  UNSAFE_componentWillMount() {
27148
27231
  DeprecationMixin.UNSAFE_componentWillMount.call(this);
27149
- },
27150
- render: function () {
27232
+ }
27233
+ render() {
27234
+ var _this$props$graph$typ, _this$props$graph, _this$props$correct, _this$props$correct2, _this$props$correct3, _this$props$correct4, _this$props$correct5, _this$props$correct6, _this$props$correct7, _this$props$correct8, _this$props$correct9, _this$props$correct10;
27151
27235
  let graph;
27152
27236
  let equationString;
27153
27237
  const gridStep = this.props.gridStep || perseus.Util.getGridStep(this.props.range, this.props.step, perseus.interactiveSizes.defaultBoxSize);
@@ -27207,9 +27291,118 @@ const InteractiveGraphEditor = createReactClass__default["default"]({
27207
27291
  className: "perseus-error"
27208
27292
  }, this.props.valid);
27209
27293
  }
27210
- return /*#__PURE__*/React__namespace.createElement("div", {
27211
- className: "perseus-widget-interactive-graph"
27212
- }, /*#__PURE__*/React__namespace.createElement("div", null, "Correct answer", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer.")), " ", ": ", equationString), /*#__PURE__*/React__namespace.createElement(GraphSettings, {
27294
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(FieldLabel, null, "Type of Graph:"), /*#__PURE__*/React__namespace.createElement(GraphTypeSelector, {
27295
+ graphType: (_this$props$graph$typ = (_this$props$graph = this.props.graph) === null || _this$props$graph === void 0 ? void 0 : _this$props$graph.type) !== null && _this$props$graph$typ !== void 0 ? _this$props$graph$typ : InteractiveGraph.defaultProps.graph.type,
27296
+ onChange: type => {
27297
+ this.props.onChange({
27298
+ graph: {
27299
+ type
27300
+ },
27301
+ correct: {
27302
+ type
27303
+ }
27304
+ });
27305
+ }
27306
+ })), ((_this$props$correct = this.props.correct) === null || _this$props$correct === void 0 ? void 0 : _this$props$correct.type) === "point" && /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(FieldLabel, null, "Number of Points:"), /*#__PURE__*/React__namespace.createElement(GraphPointsCountSelector, {
27307
+ numPoints: (_this$props$correct2 = this.props.correct) === null || _this$props$correct2 === void 0 ? void 0 : _this$props$correct2.numPoints,
27308
+ onChange: points => {
27309
+ this.props.onChange({
27310
+ correct: {
27311
+ type: "point",
27312
+ numPoints: points
27313
+ }
27314
+ });
27315
+ }
27316
+ })), ((_this$props$correct3 = this.props.correct) === null || _this$props$correct3 === void 0 ? void 0 : _this$props$correct3.type) === "polygon" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(FieldLabel, null, "Number of sides:"), /*#__PURE__*/React__namespace.createElement("select", {
27317
+ key: "polygon-select",
27318
+ value: ((_this$props$correct4 = this.props.correct) === null || _this$props$correct4 === void 0 ? void 0 : _this$props$correct4.numSides) || 3,
27319
+ onChange: e => {
27320
+ const graph = {
27321
+ ...this.props.correct,
27322
+ numSides: parsePointCount(e.target.value),
27323
+ coords: null,
27324
+ // reset the snap for UNLIMITED, which
27325
+ // only supports "grid"
27326
+ // From: D6578
27327
+ snapTo: "grid"
27328
+ };
27329
+ this.props.onChange({
27330
+ correct: graph
27331
+ });
27332
+ }
27333
+ }, ___default["default"].map(___default["default"].range(3, 13), function (n) {
27334
+ return /*#__PURE__*/React__namespace.createElement("option", {
27335
+ key: n,
27336
+ value: n
27337
+ }, "".concat(n, " sides"));
27338
+ }), /*#__PURE__*/React__namespace.createElement("option", {
27339
+ value: "unlimited"
27340
+ }, "unlimited sides"))), /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(FieldLabel, null, "Snap to:"), /*#__PURE__*/React__namespace.createElement("select", {
27341
+ key: "polygon-snap",
27342
+ value: (_this$props$correct5 = this.props.correct) === null || _this$props$correct5 === void 0 ? void 0 : _this$props$correct5.snapTo,
27343
+ onChange: e => {
27344
+ const graph = {
27345
+ ...this.props.correct,
27346
+ snapTo: e.target.value,
27347
+ coords: null
27348
+ };
27349
+ this.props.onChange({
27350
+ correct: graph
27351
+ });
27352
+ }
27353
+ }, /*#__PURE__*/React__namespace.createElement("option", {
27354
+ value: "grid"
27355
+ }, "grid"), ((_this$props$correct6 = this.props.correct) === null || _this$props$correct6 === void 0 ? void 0 : _this$props$correct6.numSides) !== "unlimited" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("option", {
27356
+ value: "angles"
27357
+ }, "interior angles"), /*#__PURE__*/React__namespace.createElement("option", {
27358
+ value: "sides"
27359
+ }, "side measures"))), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "These options affect the movement of the vertex points. The grid option will guide the points to the nearest half step along the grid."), /*#__PURE__*/React__namespace.createElement("p", null, "The interior angle and side measure options guide the points to the nearest whole angle or side"), " ", "measure respectively.")), /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(Typography__namespace.LabelSmall, {
27360
+ tag: "label"
27361
+ }, "Show angle measures:", " ", /*#__PURE__*/React__namespace.createElement("input", {
27362
+ type: "checkbox",
27363
+ checked: (_this$props$correct7 = this.props.correct) === null || _this$props$correct7 === void 0 ? void 0 : _this$props$correct7.showAngles,
27364
+ onChange: () => {
27365
+ this.props.onChange({
27366
+ correct: {
27367
+ ...this.props.correct,
27368
+ showAngles: !this.props.correct.showAngles
27369
+ }
27370
+ });
27371
+ }
27372
+ })), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Displays the interior angle measures."))), /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(Typography__namespace.LabelSmall, {
27373
+ tag: "label"
27374
+ }, "Show side measures:", " ", /*#__PURE__*/React__namespace.createElement("input", {
27375
+ type: "checkbox",
27376
+ checked: (_this$props$correct8 = this.props.correct) === null || _this$props$correct8 === void 0 ? void 0 : _this$props$correct8.showSides,
27377
+ onChange: () => {
27378
+ this.props.onChange({
27379
+ correct: {
27380
+ ...this.props.correct,
27381
+ showSides: !this.props.correct.showSides
27382
+ }
27383
+ });
27384
+ }
27385
+ })), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Displays the side lengths.")))), ((_this$props$correct9 = this.props.correct) === null || _this$props$correct9 === void 0 ? void 0 : _this$props$correct9.type) === "segment" && /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(FieldLabel, null, "Number of segments: "), /*#__PURE__*/React__namespace.createElement(SegmentCountSelector, {
27386
+ numSegments: (_this$props$correct10 = this.props.correct) === null || _this$props$correct10 === void 0 ? void 0 : _this$props$correct10.numSegments,
27387
+ onChange: sides => {
27388
+ this.props.onChange({
27389
+ correct: {
27390
+ type: "segment",
27391
+ numSegments: sides,
27392
+ coords: null
27393
+ }
27394
+ });
27395
+ }
27396
+ })), /*#__PURE__*/React__namespace.createElement(Row, null, /*#__PURE__*/React__namespace.createElement(FieldLabel, null, "Correct answer:"), /*#__PURE__*/React__namespace.createElement(Typography__namespace.BodyMonospace, {
27397
+ style: {
27398
+ fontSize: 12,
27399
+ backgroundColor: "#eee",
27400
+ paddingInline: Spacing__default["default"].xxSmall_6,
27401
+ borderColor: "#ccc",
27402
+ borderStyle: "solid",
27403
+ borderWidth: 1
27404
+ }
27405
+ }, equationString), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."))), /*#__PURE__*/React__namespace.createElement(GraphSettings, {
27213
27406
  box: getInteractiveBoxFromSizeClass(sizeClass),
27214
27407
  range: this.props.range,
27215
27408
  labels: this.props.labels,
@@ -27248,21 +27441,22 @@ const InteractiveGraphEditor = createReactClass__default["default"]({
27248
27441
  }, "match exactly"), /*#__PURE__*/React__namespace.createElement("option", {
27249
27442
  value: "congruent"
27250
27443
  }, "be congruent"))), /*#__PURE__*/React__namespace.createElement(InfoTip$e, null, /*#__PURE__*/React__namespace.createElement("p", null, "Congruency requires only that the angle measures are the same. An exact match implies congruency, but also requires that the angles have the same orientation and that the vertices are in the same position.")))), graph);
27251
- },
27252
- changeMatchType: function (e) {
27444
+ }
27445
+ changeMatchType(e) {
27253
27446
  const correct = ___default["default"].extend({}, this.props.correct, {
27254
27447
  match: e.target.value
27255
27448
  });
27256
27449
  this.props.onChange({
27257
27450
  correct: correct
27258
27451
  });
27259
- },
27260
- serialize: function () {
27452
+ }
27453
+ serialize() {
27261
27454
  const json = ___default["default"].pick(this.props, "step", "backgroundImage", "markings", "labels", "showProtractor", "showRuler", "showTooltips", "rulerLabel", "rulerTicks", "range", "gridStep", "snapStep");
27262
27455
 
27263
27456
  // eslint-disable-next-line react/no-string-refs
27264
27457
  const graph = this.refs.graph;
27265
27458
  if (graph) {
27459
+ // @ts-expect-error TS2339 Property 'getUserInput' does not exist on type 'ReactInstance'. Property 'getUserInput' does not exist on type 'Component<any, {}, any>'.
27266
27460
  const correct = graph && graph.getUserInput();
27267
27461
  ___default["default"].extend(json, {
27268
27462
  graph: {
@@ -27277,8 +27471,20 @@ const InteractiveGraphEditor = createReactClass__default["default"]({
27277
27471
  }
27278
27472
  });
27279
27473
  }
27474
+ // @ts-expect-error TS2739 Type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "step" | "gridStep" | "snapStep" | "backgroundImage" | "markings" | "labels" | ... 5 more ... | "range">' is missing the following properties from type 'PerseusInteractiveGraphWidgetOptions': graph, correct
27280
27475
  return json;
27281
27476
  }
27477
+ }
27478
+ _defineProperty(InteractiveGraphEditor, "widgetName", "interactive-graph");
27479
+ _defineProperty(InteractiveGraphEditor, "defaultProps", {
27480
+ ...InteractiveGraph.defaultProps,
27481
+ valid: true,
27482
+ backgroundImage: defaultBackgroundImage$1,
27483
+ showTooltips: false,
27484
+ correct: {
27485
+ type: InteractiveGraph.defaultProps.graph.type,
27486
+ coords: null
27487
+ }
27282
27488
  });
27283
27489
 
27284
27490
  class FormWrappedTextField extends React__namespace.Component {