@khanacademy/perseus 18.0.1 → 19.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2776,7 +2776,7 @@ function gridDimensionConfig(absTickStep, extent, dimensionConstraint, gridStep)
2776
2776
  *
2777
2777
  * TODO(somewhatabstract, FEI-3464): Consolidate query string parsing functions.
2778
2778
  */
2779
- function getGridStep$1(range, step, boxSize) {
2779
+ function getGridStep(range, step, boxSize) {
2780
2780
  // @ts-expect-error - TS2322 - Type '(number | null | undefined)[]' is not assignable to type 'Coordinates'.
2781
2781
  return ___default["default"](2).times(function (i) {
2782
2782
  const scale = scaleFromExtent(range[i], boxSize);
@@ -2958,13 +2958,13 @@ function eq$2(x, y) {
2958
2958
  * Deep approximate equality on primitives, numbers, arrays, and objects.
2959
2959
  * Recursive.
2960
2960
  */
2961
- function deepEq$6(x, y) {
2961
+ function deepEq$5(x, y) {
2962
2962
  if (Array.isArray(x) && Array.isArray(y)) {
2963
2963
  if (x.length !== y.length) {
2964
2964
  return false;
2965
2965
  }
2966
2966
  for (let i = 0; i < x.length; i++) {
2967
- if (!deepEq$6(x[i], y[i])) {
2967
+ if (!deepEq$5(x[i], y[i])) {
2968
2968
  return false;
2969
2969
  }
2970
2970
  }
@@ -2982,10 +2982,10 @@ function deepEq$6(x, y) {
2982
2982
  if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
2983
2983
  return x === y || ___default["default"].all(x, function (v, k) {
2984
2984
  // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
2985
- return deepEq$6(y[k], v);
2985
+ return deepEq$5(y[k], v);
2986
2986
  }) && ___default["default"].all(y, function (v, k) {
2987
2987
  // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
2988
- return deepEq$6(x[k], v);
2988
+ return deepEq$5(x[k], v);
2989
2989
  });
2990
2990
  }
2991
2991
  if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
@@ -3185,7 +3185,7 @@ const supportsPassiveEvents = () => {
3185
3185
  * Pass this function as the touchstart for an element to
3186
3186
  * avoid sending the touch to the mobile scratchpad
3187
3187
  */
3188
- function captureScratchpadTouchStart$4(e) {
3188
+ function captureScratchpadTouchStart$3(e) {
3189
3189
  e.stopPropagation();
3190
3190
  }
3191
3191
  function getImageSize(url, callback) {
@@ -3273,7 +3273,7 @@ const Util = {
3273
3273
  firstNumericalParse: firstNumericalParse$1,
3274
3274
  stringArrayOfSize: stringArrayOfSize$1,
3275
3275
  gridDimensionConfig,
3276
- getGridStep: getGridStep$1,
3276
+ getGridStep,
3277
3277
  snapStepFromGridStep,
3278
3278
  scaleFromExtent,
3279
3279
  tickStepFromExtent,
@@ -3282,7 +3282,7 @@ const Util = {
3282
3282
  constrainedTickStepsFromTickSteps,
3283
3283
  DeprecationMixin: DeprecationMixin$1,
3284
3284
  eq: eq$2,
3285
- deepEq: deepEq$6,
3285
+ deepEq: deepEq$5,
3286
3286
  parseQueryString,
3287
3287
  updateQueryString: updateQueryString$2,
3288
3288
  strongEncodeURIComponent,
@@ -3292,7 +3292,7 @@ const Util = {
3292
3292
  resetTouchHandlers,
3293
3293
  extractPointerLocation,
3294
3294
  supportsPassiveEvents,
3295
- captureScratchpadTouchStart: captureScratchpadTouchStart$4,
3295
+ captureScratchpadTouchStart: captureScratchpadTouchStart$3,
3296
3296
  getImageSize,
3297
3297
  getImageSizeModern: getImageSizeModern,
3298
3298
  getRealImageUrl: getRealImageUrl,
@@ -13479,7 +13479,7 @@ ___default["default"].extend(MovableAngle.prototype, {
13479
13479
 
13480
13480
  /* eslint-disable @babel/no-invalid-this */
13481
13481
  const nestedMap$1 = Util.nestedMap;
13482
- const deepEq$5 = Util.deepEq;
13482
+ const deepEq$4 = Util.deepEq;
13483
13483
 
13484
13484
  /**
13485
13485
  * A base class for all Graphie Movables
@@ -13576,7 +13576,7 @@ const createSimpleClass = function (addFunction) {
13576
13576
  this._prevProps = this.props;
13577
13577
  },
13578
13578
  modify: function (graphie) {
13579
- if (!deepEq$5(this.props, this._prevProps)) {
13579
+ if (!deepEq$4(this.props, this._prevProps)) {
13580
13580
  this.remove();
13581
13581
  this.add(graphie);
13582
13582
  this._prevProps = this.props;
@@ -13621,7 +13621,7 @@ var GraphieClasses = {
13621
13621
  * take appropriate action in onMoveStart, onMove, onMoveEnd
13622
13622
  */
13623
13623
  const normalizeOptions$3 = InteractiveUtil.normalizeOptions;
13624
- const assert$9 = InteractiveUtil.assert;
13624
+ const assert$8 = InteractiveUtil.assert;
13625
13625
 
13626
13626
  // state parameters that should be converted into an array of
13627
13627
  // functions
@@ -13692,7 +13692,7 @@ ___default["default"].extend(Movable.prototype, {
13692
13692
  * Simulates a mouse grab event on the movable object.
13693
13693
  */
13694
13694
  grab: function (coord) {
13695
- assert$9(kmath.point.is(coord));
13695
+ assert$8(kmath.point.is(coord));
13696
13696
  const self = this;
13697
13697
  const graphie = self.graphie;
13698
13698
  const state = self.state;
@@ -14158,7 +14158,7 @@ var MovableLineOptions = {
14158
14158
  /**
14159
14159
  * MovableLine
14160
14160
  */
14161
- const assert$8 = InteractiveUtil.assert;
14161
+ const assert$7 = InteractiveUtil.assert;
14162
14162
  const normalizeOptions$2 = InteractiveUtil.normalizeOptions;
14163
14163
  const FUNCTION_ARRAY_OPTIONS$2 = ["add", "draw", "remove", "onMoveStart", "constraints", "onMove", "onMoveEnd"];
14164
14164
 
@@ -14184,8 +14184,8 @@ const DEFAULT_STATE$2 = {
14184
14184
  mouseTarget: null
14185
14185
  };
14186
14186
  const MovableLine$4 = function (graphie, movable, options) {
14187
- assert$8(graphie != null);
14188
- assert$8(options != null);
14187
+ assert$7(graphie != null);
14188
+ assert$7(options != null);
14189
14189
 
14190
14190
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
14191
14191
  ___default["default"].extend(this, {
@@ -14742,7 +14742,7 @@ var MovablePointOptions = {
14742
14742
  }
14743
14743
  };
14744
14744
 
14745
- const assert$7 = InteractiveUtil.assert;
14745
+ const assert$6 = InteractiveUtil.assert;
14746
14746
  const normalizeOptions$1 = InteractiveUtil.normalizeOptions;
14747
14747
  const {
14748
14748
  processMath
@@ -14878,7 +14878,7 @@ ___default["default"].extend(MovablePoint$5.prototype, {
14878
14878
  const self = this;
14879
14879
  const graphie = self.graphie;
14880
14880
  const state = ___default["default"].extend(self.state, normalizeOptions$1(FUNCTION_ARRAY_OPTIONS$1, options));
14881
- assert$7(kmath.point.is(state.coord));
14881
+ assert$6(kmath.point.is(state.coord));
14882
14882
 
14883
14883
  // Default things inside the state.normalStyle object, because
14884
14884
  // _.extend is not deep.
@@ -15080,12 +15080,12 @@ ___default["default"].extend(MovablePoint$5.prototype, {
15080
15080
  return result !== false;
15081
15081
  },
15082
15082
  setCoord: function (coord) {
15083
- assert$7(kmath.point.is(coord, 2));
15083
+ assert$6(kmath.point.is(coord, 2));
15084
15084
  this.state.coord = ___default["default"].clone(coord);
15085
15085
  this.draw();
15086
15086
  },
15087
15087
  setCoordConstrained: function (coord) {
15088
- assert$7(kmath.point.is(coord, 2));
15088
+ assert$6(kmath.point.is(coord, 2));
15089
15089
  const result = this._applyConstraints(coord, this.coord());
15090
15090
  if (result !== false) {
15091
15091
  this.state.coord = ___default["default"].clone(result);
@@ -15481,7 +15481,7 @@ var MovablePolygonOptions = {
15481
15481
  * Creates and adds a polygon to the graph that can be dragged around.
15482
15482
  * It allows constraints on its movement and draws when moves happen.
15483
15483
  */
15484
- const assert$6 = InteractiveUtil.assert;
15484
+ const assert$5 = InteractiveUtil.assert;
15485
15485
  const normalizeOptions = InteractiveUtil.normalizeOptions;
15486
15486
 
15487
15487
  // State parameters that should be converted into an array of
@@ -15520,8 +15520,8 @@ const DEFAULT_STATE = {
15520
15520
  mouseTarget: null
15521
15521
  };
15522
15522
  const MovablePolygon = function (graphie, movable, options) {
15523
- assert$6(graphie != null);
15524
- assert$6(options != null);
15523
+ assert$5(graphie != null);
15524
+ assert$5(options != null);
15525
15525
 
15526
15526
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
15527
15527
  ___default["default"].extend(this, {
@@ -16039,11 +16039,11 @@ var Movables = {
16039
16039
  const GraphieMovable = GraphieClasses.GraphieMovable;
16040
16040
  const createGraphie = GraphUtils.createGraphie;
16041
16041
  const {
16042
- deepEq: deepEq$4,
16042
+ deepEq: deepEq$3,
16043
16043
  nestedMap
16044
16044
  } = Util;
16045
16045
  const {
16046
- assert: assert$5
16046
+ assert: assert$4
16047
16047
  } = InteractiveUtil;
16048
16048
  class Graphie extends React__namespace.Component {
16049
16049
  graphieDivRef = /*#__PURE__*/React__namespace.createRef();
@@ -16074,7 +16074,7 @@ class Graphie extends React__namespace.Component {
16074
16074
  if (this.props.setup !== prevProps.setup) {
16075
16075
  Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", Errors.Internal);
16076
16076
  }
16077
- if (!deepEq$4(this.props.options, prevProps.options) || !deepEq$4(this.props.box, prevProps.box) || !deepEq$4(this.props.range, prevProps.range)) {
16077
+ if (!deepEq$3(this.props.options, prevProps.options) || !deepEq$3(this.props.box, prevProps.box) || !deepEq$3(this.props.range, prevProps.range)) {
16078
16078
  this._setupGraphie();
16079
16079
  }
16080
16080
  this._updateMovables();
@@ -16218,7 +16218,7 @@ class Graphie extends React__namespace.Component {
16218
16218
 
16219
16219
  // Instantiate the descriptor to turn it into a real Movable
16220
16220
  const child = new childDescriptor.type(childDescriptor.props);
16221
- assert$5(child instanceof GraphieMovable, "All children of a Graphie component must be Graphie " + "movables");
16221
+ assert$4(child instanceof GraphieMovable, "All children of a Graphie component must be Graphie " + "movables");
16222
16222
 
16223
16223
  // Give each child a key
16224
16224
  const keyProp = childDescriptor.key;
@@ -18405,7 +18405,7 @@ const registerWidgets = widgets => {
18405
18405
  * @param name - the widget that you are trying to replace
18406
18406
  * @param replacementName - the name of the widget that takes its place
18407
18407
  *
18408
- * e.g. replaceWidget("transformer", "always-correct") will make it so the
18408
+ * e.g. replaceWidget("transformer", "deprecated-standin") will make it so the
18409
18409
  * transformer widget is replaced by the always correct widget
18410
18410
  */
18411
18411
  const replaceWidget = (name, replacementName) => {
@@ -18416,9 +18416,6 @@ const replaceWidget = (name, replacementName) => {
18416
18416
  return;
18417
18417
  }
18418
18418
  registerWidget(name, substituteWidget);
18419
- if (Log) {
18420
- Log.log(`INFO: Replacing widget ${name} with ${replacementName}`);
18421
- }
18422
18419
  };
18423
18420
  const registerEditors = editorsToRegister => {
18424
18421
  editorsToRegister.forEach(editor => {
@@ -18445,9 +18442,6 @@ const replaceEditor = (name, replacementName) => {
18445
18442
  return;
18446
18443
  }
18447
18444
  editors[name] = substituteEditor;
18448
- if (Log) {
18449
- Log.log(`INFO: Replacing editor ${name} with ${replacementName}`);
18450
- }
18451
18445
  };
18452
18446
  const getWidget = name => {
18453
18447
  // TODO(alex): Consider referring to these as renderers to avoid
@@ -20958,7 +20952,7 @@ class Tooltip extends React__namespace.Component {
20958
20952
 
20959
20953
  /* eslint-disable react/sort-comp */
20960
20954
  const {
20961
- captureScratchpadTouchStart: captureScratchpadTouchStart$3
20955
+ captureScratchpadTouchStart: captureScratchpadTouchStart$2
20962
20956
  } = Util;
20963
20957
  class InputWithExamples extends React__namespace.Component {
20964
20958
  static defaultProps = {
@@ -21016,7 +21010,7 @@ class InputWithExamples extends React__namespace.Component {
21016
21010
  // Add useful props required for MATH and TEXT modes
21017
21011
  ___default["default"].extend(inputProps, {
21018
21012
  onChange: this.props.onChange,
21019
- onTouchStart: captureScratchpadTouchStart$3
21013
+ onTouchStart: captureScratchpadTouchStart$2
21020
21014
  });
21021
21015
 
21022
21016
  // And add final props that are MATH- and TEXT-specific
@@ -23044,7 +23038,7 @@ var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) =>
23044
23038
  })));
23045
23039
 
23046
23040
  const {
23047
- captureScratchpadTouchStart: captureScratchpadTouchStart$2
23041
+ captureScratchpadTouchStart: captureScratchpadTouchStart$1
23048
23042
  } = Util;
23049
23043
 
23050
23044
  // exported for tests
@@ -23296,7 +23290,7 @@ const BaseRadio = function (props) {
23296
23290
  onClick: clickHandler
23297
23291
  // @ts-expect-error - TS2322 - Type '((e: TouchEvent) => void) | null' is not assignable to type 'TouchEventHandler<HTMLLIElement> | undefined'.
23298
23292
  ,
23299
- onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$2
23293
+ onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$1
23300
23294
  }, /*#__PURE__*/React__namespace.createElement(Element, _extends({}, elementProps, {
23301
23295
  ref: ref
23302
23296
  })));
@@ -26841,9 +26835,9 @@ var Iframe$1 = {
26841
26835
  };
26842
26836
 
26843
26837
  /* eslint-disable react/sort-comp */
26844
- const defaultBoxSize$2 = 400;
26838
+ const defaultBoxSize$1 = 400;
26845
26839
  const defaultRange = [0, 10];
26846
- const defaultBackgroundImage$3 = {
26840
+ const defaultBackgroundImage$2 = {
26847
26841
  url: null,
26848
26842
  width: 0,
26849
26843
  height: 0
@@ -26858,8 +26852,8 @@ class ImageWidget extends React__namespace.Component {
26858
26852
  alignment: DEFAULT_ALIGNMENT,
26859
26853
  title: "",
26860
26854
  range: [defaultRange, defaultRange],
26861
- box: [defaultBoxSize$2, defaultBoxSize$2],
26862
- backgroundImage: defaultBackgroundImage$3,
26855
+ box: [defaultBoxSize$1, defaultBoxSize$1],
26856
+ backgroundImage: defaultBackgroundImage$2,
26863
26857
  labels: [],
26864
26858
  alt: "",
26865
26859
  caption: "",
@@ -27677,7 +27671,7 @@ var Interactive = {
27677
27671
  };
27678
27672
 
27679
27673
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
27680
- const defaultBackgroundImage$2 = {
27674
+ const defaultBackgroundImage$1 = {
27681
27675
  url: null
27682
27676
  };
27683
27677
 
@@ -27713,7 +27707,7 @@ class Graph extends React__namespace.Component {
27713
27707
  gridStep: [1, 1],
27714
27708
  snapStep: [0.5, 0.5],
27715
27709
  markings: "graph",
27716
- backgroundImage: defaultBackgroundImage$2,
27710
+ backgroundImage: defaultBackgroundImage$1,
27717
27711
  showProtractor: false,
27718
27712
  showRuler: false,
27719
27713
  rulerLabel: "",
@@ -27981,7 +27975,7 @@ class Graph extends React__namespace.Component {
27981
27975
  */
27982
27976
  const {
27983
27977
  eq: eq$1,
27984
- deepEq: deepEq$3
27978
+ deepEq: deepEq$2
27985
27979
  } = Util;
27986
27980
 
27987
27981
  // This should really be a readonly tuple of [number, number]
@@ -28094,7 +28088,7 @@ function similar(coords1, coords2, tolerance) {
28094
28088
  angles = rotate(angles, i);
28095
28089
  // @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
28096
28090
  sides = rotate(sides, i);
28097
- if (deepEq$3(angles1, angles)) {
28091
+ if (deepEq$2(angles1, angles)) {
28098
28092
  const sidePairs = ___default["default"].zip(sides1, sides);
28099
28093
  const factors = ___default["default"].map(sidePairs, function (pair) {
28100
28094
  return pair[0] / pair[1];
@@ -28188,11 +28182,11 @@ const {
28188
28182
  DeprecationMixin
28189
28183
  } = Util;
28190
28184
  const TRASH_ICON_URI = "https://ka-perseus-graphie.s3.amazonaws.com/b1452c0d79fd0f7ff4c3af9488474a0a0decb361.png";
28191
- const defaultBackgroundImage$1 = {
28185
+ const defaultBackgroundImage = {
28192
28186
  url: null
28193
28187
  };
28194
28188
  const eq = Util.eq;
28195
- const deepEq$2 = Util.deepEq;
28189
+ const deepEq$1 = Util.deepEq;
28196
28190
  const UNLIMITED = "unlimited";
28197
28191
 
28198
28192
  // Sample background image:
@@ -28249,7 +28243,7 @@ class InteractiveGraph extends React__namespace.Component {
28249
28243
  labels: ["x", "y"],
28250
28244
  range: [[-10, 10], [-10, 10]],
28251
28245
  step: [1, 1],
28252
- backgroundImage: defaultBackgroundImage$1,
28246
+ backgroundImage: defaultBackgroundImage,
28253
28247
  markings: "graph",
28254
28248
  showTooltips: false,
28255
28249
  showProtractor: false,
@@ -29842,7 +29836,7 @@ class InteractiveGraph extends React__namespace.Component {
29842
29836
  const correctCoeffs = this.getQuadraticCoefficients(
29843
29837
  // @ts-expect-error - TS2345 - Argument of type 'readonly Coord[] | undefined' is not assignable to parameter of type 'readonly Coord[]'.
29844
29838
  rubric.correct.coords);
29845
- if (deepEq$2(guessCoeffs, correctCoeffs)) {
29839
+ if (deepEq$1(guessCoeffs, correctCoeffs)) {
29846
29840
  return {
29847
29841
  type: "points",
29848
29842
  earned: 1,
@@ -29858,7 +29852,7 @@ class InteractiveGraph extends React__namespace.Component {
29858
29852
  const canonicalGuessCoeffs = canonicalSineCoefficients(guessCoeffs);
29859
29853
  const canonicalCorrectCoeffs = canonicalSineCoefficients(correctCoeffs);
29860
29854
  // If the canonical coefficients match, it's correct.
29861
- if (deepEq$2(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
29855
+ if (deepEq$1(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
29862
29856
  return {
29863
29857
  type: "points",
29864
29858
  earned: 1,
@@ -29867,7 +29861,7 @@ class InteractiveGraph extends React__namespace.Component {
29867
29861
  };
29868
29862
  }
29869
29863
  } else if (state.type === "circle" && rubric.correct.type === "circle") {
29870
- if (deepEq$2(state.center, rubric.correct.center) && eq(state.radius, rubric.correct.radius)) {
29864
+ if (deepEq$1(state.center, rubric.correct.center) && eq(state.radius, rubric.correct.radius)) {
29871
29865
  return {
29872
29866
  type: "points",
29873
29867
  earned: 1,
@@ -29886,7 +29880,7 @@ class InteractiveGraph extends React__namespace.Component {
29886
29880
  guess?.sort();
29887
29881
  // @ts-expect-error - TS2339 - Property 'sort' does not exist on type 'readonly Coord[]'.
29888
29882
  correct.sort();
29889
- if (deepEq$2(guess, correct)) {
29883
+ if (deepEq$1(guess, correct)) {
29890
29884
  return {
29891
29885
  type: "points",
29892
29886
  earned: 1,
@@ -29909,7 +29903,7 @@ class InteractiveGraph extends React__namespace.Component {
29909
29903
  /* exact */
29910
29904
  guess.sort();
29911
29905
  correct.sort();
29912
- match = deepEq$2(guess, correct);
29906
+ match = deepEq$1(guess, correct);
29913
29907
  }
29914
29908
  if (match) {
29915
29909
  return {
@@ -29925,7 +29919,7 @@ class InteractiveGraph extends React__namespace.Component {
29925
29919
  guess = ___default["default"].invoke(guess, "sort").sort();
29926
29920
  // @ts-expect-error - TS2345 - Argument of type '(readonly Coord[])[] | undefined' is not assignable to parameter of type 'Collection<any>'.
29927
29921
  correct = ___default["default"].invoke(correct, "sort").sort();
29928
- if (deepEq$2(guess, correct)) {
29922
+ if (deepEq$1(guess, correct)) {
29929
29923
  return {
29930
29924
  type: "points",
29931
29925
  earned: 1,
@@ -29938,7 +29932,7 @@ class InteractiveGraph extends React__namespace.Component {
29938
29932
  const correct = rubric.correct.coords;
29939
29933
  if (
29940
29934
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'.
29941
- deepEq$2(guess[0], correct[0]) &&
29935
+ deepEq$1(guess[0], correct[0]) &&
29942
29936
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
29943
29937
  collinear(correct[0], correct[1], guess[1])) {
29944
29938
  return {
@@ -29969,7 +29963,7 @@ class InteractiveGraph extends React__namespace.Component {
29969
29963
  /* exact */
29970
29964
  match =
29971
29965
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
29972
- deepEq$2(guess[1], correct[1]) &&
29966
+ deepEq$1(guess[1], correct[1]) &&
29973
29967
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
29974
29968
  collinear(correct[1], correct[0], guess[0]) &&
29975
29969
  // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
@@ -33132,7 +33126,7 @@ var Matcher$1 = {
33132
33126
 
33133
33127
  const {
33134
33128
  firstNumericalParse,
33135
- captureScratchpadTouchStart: captureScratchpadTouchStart$1
33129
+ captureScratchpadTouchStart
33136
33130
  } = Util;
33137
33131
  const toNumericString = KhanMath.toNumericString;
33138
33132
  const getNumericFormat = KhanMath.getNumericFormat;
@@ -33205,7 +33199,7 @@ class NumberInput extends React__namespace.Component {
33205
33199
  onKeyDown: this._onKeyDown
33206
33200
  // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
33207
33201
  ,
33208
- onTouchStart: captureScratchpadTouchStart$1,
33202
+ onTouchStart: captureScratchpadTouchStart,
33209
33203
  defaultValue: toNumericString(this.props.value, this.state.format),
33210
33204
  value: undefined
33211
33205
  }));
@@ -33331,7 +33325,7 @@ class NumberInput extends React__namespace.Component {
33331
33325
  // Type imports
33332
33326
 
33333
33327
  const {
33334
- assert: assert$4
33328
+ assert: assert$3
33335
33329
  } = InteractiveUtil;
33336
33330
  const {
33337
33331
  stringArrayOfSize
@@ -33365,12 +33359,12 @@ const getDefaultPath$1 = function () {
33365
33359
  };
33366
33360
  const getRowFromPath$1 = function (path) {
33367
33361
  // 'path' should be a (row, column) pair
33368
- assert$4(___default["default"].isArray(path) && path.length === 2);
33362
+ assert$3(___default["default"].isArray(path) && path.length === 2);
33369
33363
  return +path[0];
33370
33364
  };
33371
33365
  const getColumnFromPath$1 = function (path) {
33372
33366
  // 'path' should be a (row, column) pair
33373
- assert$4(___default["default"].isArray(path) && path.length === 2);
33367
+ assert$3(___default["default"].isArray(path) && path.length === 2);
33374
33368
  return +path[1];
33375
33369
  };
33376
33370
  const getRefForPath$1 = function (path) {
@@ -34871,7 +34865,7 @@ const MovablePoint$1 = Graphie.MovablePoint;
34871
34865
  // @ts-expect-error - TS2339 - Property 'Line' does not exist on type 'typeof Graphie'.
34872
34866
  const Line$1 = Graphie.Line;
34873
34867
  const {
34874
- assert: assert$3
34868
+ assert: assert$2
34875
34869
  } = InteractiveUtil;
34876
34870
  const bound = (x, gt, lt) => Math.min(Math.max(x, gt), lt);
34877
34871
  const EN_DASH = "\u2013";
@@ -35147,7 +35141,7 @@ class NumberLine extends React__namespace.Component {
35147
35141
  const snapX = props.tickStep / props.snapDivisions;
35148
35142
  let x = bound(numLinePosition, left, right);
35149
35143
  x = left + kmath.number.roundTo(x - left, snapX);
35150
- assert$3(___default["default"].isFinite(x));
35144
+ assert$2(___default["default"].isFinite(x));
35151
35145
  return x;
35152
35146
  };
35153
35147
 
@@ -38254,7 +38248,7 @@ var PassageRefTarget$1 = {
38254
38248
 
38255
38249
  /* eslint-disable react/no-unsafe */
38256
38250
  const {
38257
- deepEq: deepEq$1
38251
+ deepEq
38258
38252
  } = Util;
38259
38253
  class Plotter extends React__namespace.Component {
38260
38254
  // @ts-expect-error - TS2564 - Property 'shouldSetupGraphie' has no initializer and is not definitely assigned in the constructor.
@@ -39047,7 +39041,7 @@ class Plotter extends React__namespace.Component {
39047
39041
  }
39048
39042
  ___default["default"].extend(Plotter, {
39049
39043
  validate: function (guess, rubric) {
39050
- if (deepEq$1(guess, rubric.starting)) {
39044
+ if (deepEq(guess, rubric.starting)) {
39051
39045
  return {
39052
39046
  type: "invalid",
39053
39047
  message: null
@@ -39055,7 +39049,7 @@ ___default["default"].extend(Plotter, {
39055
39049
  }
39056
39050
  return {
39057
39051
  type: "points",
39058
- earned: deepEq$1(guess, rubric.correct) ? 1 : 0,
39052
+ earned: deepEq(guess, rubric.correct) ? 1 : 0,
39059
39053
  total: 1,
39060
39054
  message: null
39061
39055
  };
@@ -39417,7 +39411,7 @@ class InfoTip extends React__namespace.Component {
39417
39411
 
39418
39412
  /* eslint-disable @typescript-eslint/no-unused-vars, react/no-unsafe, react/sort-comp */
39419
39413
  const {
39420
- assert: assert$2
39414
+ assert: assert$1
39421
39415
  } = InteractiveUtil;
39422
39416
  // @ts-expect-error - TS2339 - Property 'Path' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Arc' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Circle' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Label' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Line' does not exist on type 'typeof Graphie'. | TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'. | TS2339 - Property 'MovableLine' does not exist on type 'typeof Graphie'.
39423
39417
  const {
@@ -39429,7 +39423,7 @@ const {
39429
39423
  MovablePoint,
39430
39424
  MovableLine
39431
39425
  } = Graphie;
39432
- const defaultBoxSize$1 = 400;
39426
+ const defaultBoxSize = 400;
39433
39427
  const maxSampleSize = 1000;
39434
39428
  class Histogram extends React__namespace.Component {
39435
39429
  static propTypes = {
@@ -39442,7 +39436,7 @@ class Histogram extends React__namespace.Component {
39442
39436
  data: null,
39443
39437
  xAxisLabel: "Proportion (%)",
39444
39438
  yAxisLabel: "Number of times seen",
39445
- box: [defaultBoxSize$1, defaultBoxSize$1]
39439
+ box: [defaultBoxSize, defaultBoxSize]
39446
39440
  };
39447
39441
  UNSAFE_componentWillReceiveProps(nextProps) {
39448
39442
  // Reset the threshold if the range has changed
@@ -39945,7 +39939,7 @@ class Simulator extends React__namespace.Component {
39945
39939
  return true;
39946
39940
  };
39947
39941
  focusInputPath = path => {
39948
- assert$2(path.length > 0);
39942
+ assert$1(path.length > 0);
39949
39943
  const inputID = ___default["default"].head(path);
39950
39944
  // eslint-disable-next-line react/no-string-refs
39951
39945
  const inputComponent = this.refs[inputID];
@@ -39953,7 +39947,7 @@ class Simulator extends React__namespace.Component {
39953
39947
  inputComponent.focus();
39954
39948
  };
39955
39949
  blurInputPath = path => {
39956
- assert$2(path.length > 0);
39950
+ assert$1(path.length > 0);
39957
39951
  const inputID = ___default["default"].head(path);
39958
39952
  // eslint-disable-next-line react/no-string-refs
39959
39953
  const inputComponent = this.refs[inputID];
@@ -39961,17 +39955,17 @@ class Simulator extends React__namespace.Component {
39961
39955
  inputComponent.blur();
39962
39956
  };
39963
39957
  getDOMNodeForPath = path => {
39964
- assert$2(path.length > 0);
39958
+ assert$1(path.length > 0);
39965
39959
  const inputID = ___default["default"].head(path);
39966
39960
  // eslint-disable-next-line react/no-string-refs
39967
39961
  return ReactDOM__default["default"].findDOMNode(this.refs[inputID]);
39968
39962
  };
39969
39963
  getGrammarTypeForPath = path => {
39970
- assert$2(path.length > 0);
39964
+ assert$1(path.length > 0);
39971
39965
  return "number";
39972
39966
  };
39973
39967
  setInputValue = (path, newValue, cb) => {
39974
- assert$2(path.length > 0);
39968
+ assert$1(path.length > 0);
39975
39969
  const inputID = ___default["default"].head(path);
39976
39970
  const capitalizedID = inputID.charAt(0).toUpperCase() + inputID.slice(1);
39977
39971
  const functionName = "handle" + capitalizedID + "Change";
@@ -40131,7 +40125,7 @@ var Sorter$1 = {
40131
40125
  };
40132
40126
 
40133
40127
  const {
40134
- assert: assert$1
40128
+ assert
40135
40129
  } = InteractiveUtil;
40136
40130
 
40137
40131
  /* Input handling: Maps a (row, column) pair to a unique ref used by React,
@@ -40145,12 +40139,12 @@ const getDefaultPath = function () {
40145
40139
  };
40146
40140
  const getRowFromPath = function (path) {
40147
40141
  // 'path' should be a (row, column) pair
40148
- assert$1(___default["default"].isArray(path) && path.length === 2);
40142
+ assert(___default["default"].isArray(path) && path.length === 2);
40149
40143
  return +path[0];
40150
40144
  };
40151
40145
  const getColumnFromPath = function (path) {
40152
40146
  // 'path' should be a (row, column) pair
40153
- assert$1(___default["default"].isArray(path) && path.length === 2);
40147
+ assert(___default["default"].isArray(path) && path.length === 2);
40154
40148
  return +path[1];
40155
40149
  };
40156
40150
  const getRefForPath = function (path) {
@@ -40424,2415 +40418,6 @@ var Table$1 = {
40424
40418
  isLintable: true
40425
40419
  };
40426
40420
 
40427
- const {
40428
- deepEq,
40429
- getGridStep,
40430
- captureScratchpadTouchStart
40431
- } = Util;
40432
- const {
40433
- assert
40434
- } = InteractiveUtil;
40435
- const ROTATE_SNAP_DEGREES = 15;
40436
- const DEGREE_SIGN = "\u00B0";
40437
- const RENDER_TRANSFORM_DELAY_IN_MS = 300;
40438
- const ROTATE_HANDLE_DIST = 1.5;
40439
- const REFLECT_ROTATE_HANDLE_DIST = 2;
40440
- const REFLECT_BUTTON_SIZE = 1;
40441
- const defaultBoxSize = 400;
40442
- const defaultBackgroundImage = {
40443
- url: null
40444
- };
40445
-
40446
- /* Does a pluck on keys inside objects in an object
40447
- *
40448
- * Ex:
40449
- * tools = {
40450
- * translation: {
40451
- * enabled: true
40452
- * },
40453
- * rotation: {
40454
- * enabled: false
40455
- * }
40456
- * };
40457
- * pluckObject(tools, "enabled") returns {
40458
- * translation: true
40459
- * rotation: false
40460
- * }
40461
- */
40462
- function pluckObject(object, subKey) {
40463
- return ___default["default"].object(___default["default"].map(object, function (value, key) {
40464
- return [key, value[subKey]];
40465
- }));
40466
- }
40467
- const defaultGraphProps = function (setProps, boxSize) {
40468
- setProps = setProps || {};
40469
- const labels = setProps.labels || ["x", "y"];
40470
- const range = setProps.range || [[-10, 10], [-10, 10]];
40471
- const step = setProps.step || [1, 1];
40472
- const gridStep = setProps.gridStep || getGridStep(range, step, boxSize);
40473
- return {
40474
- box: [boxSize, boxSize],
40475
- labels: labels,
40476
- range: range,
40477
- step: step,
40478
- gridStep: gridStep,
40479
- valid: true,
40480
- backgroundImage: defaultBackgroundImage,
40481
- markings: "grid",
40482
- showProtractor: false
40483
- };
40484
- };
40485
- const defaultTransformerProps = {
40486
- apiOptions: ApiOptions.defaults,
40487
- gradeEmpty: false,
40488
- graphMode: "interactive",
40489
- listMode: "dynamic",
40490
- graph: {},
40491
- tools: {
40492
- translation: {
40493
- enabled: true,
40494
- required: false,
40495
- constraints: {}
40496
- },
40497
- rotation: {
40498
- enabled: true,
40499
- required: false,
40500
- constraints: {
40501
- fixed: false
40502
- },
40503
- coord: [1, 6]
40504
- },
40505
- reflection: {
40506
- enabled: true,
40507
- required: false,
40508
- constraints: {
40509
- fixed: false
40510
- },
40511
- coords: [[2, -4], [2, 2]]
40512
- },
40513
- dilation: {
40514
- enabled: true,
40515
- required: false,
40516
- constraints: {
40517
- fixed: false
40518
- },
40519
- coord: [6, 6]
40520
- }
40521
- },
40522
- drawSolutionShape: true,
40523
- starting: {
40524
- shape: {
40525
- type: "polygon-3",
40526
- coords: [[2, 2], [2, 6], [7, 2]]
40527
- },
40528
- transformations: []
40529
- },
40530
- correct: {
40531
- shape: {
40532
- type: "polygon-3",
40533
- coords: [[2, 2], [2, 6], [7, 2]]
40534
- },
40535
- transformations: []
40536
- }
40537
- };
40538
- function colorForTool(tool) {
40539
- return tool.constraints.fixed ? KhanColors.DYNAMIC : KhanColors.INTERACTIVE;
40540
- }
40541
-
40542
- /* Scales a distance from the default range of
40543
- * [-10, 10] to a given props.range pair
40544
- *
40545
- * Used for sizing various transformation tools
40546
- * (rotation handle, dilation circle)
40547
- */
40548
- function scaleToRange(dist, range) {
40549
- const spreadX = range[0][1] - range[0][0];
40550
- const spreadY = range[1][1] - range[1][0];
40551
- return dist * Math.max(spreadX, spreadY) / 20;
40552
- }
40553
- function dilatePointFromCenter(point, dilationCenter, scale) {
40554
- const pv = kmath.vector.subtract(point, dilationCenter);
40555
- const pvScaled = kmath.vector.scale(pv, scale);
40556
- const transformedPoint = kmath.vector.add(dilationCenter, pvScaled);
40557
- return transformedPoint;
40558
- }
40559
-
40560
- // TODO(jack): i18nize this
40561
- function stringFromDecimal(number) {
40562
- return String(KhanMath.roundTo(9, number));
40563
- }
40564
- function stringFromFraction(number) {
40565
- const frac = KhanMath.toFraction(number, kmath.number.DEFAULT_TOLERANCE);
40566
- if (frac[1] === 1) {
40567
- return stringFromDecimal(number);
40568
- }
40569
- return stringFromDecimal(frac[0]) + "/" + stringFromDecimal(frac[1]);
40570
- }
40571
- function texFromPoint(point) {
40572
- const {
40573
- TeX
40574
- } = getDependencies();
40575
- return [/*#__PURE__*/React__namespace.createElement(TeX, {
40576
- key: "("
40577
- }, "("), stringFromDecimal(point[0]), /*#__PURE__*/React__namespace.createElement(TeX, {
40578
- key: ","
40579
- }, ", {}"), stringFromDecimal(point[1]), /*#__PURE__*/React__namespace.createElement(TeX, {
40580
- key: ")"
40581
- }, ")")];
40582
- }
40583
- function texFromVector(vector) {
40584
- const {
40585
- TeX
40586
- } = getDependencies();
40587
- return [/*#__PURE__*/React__namespace.createElement(TeX, {
40588
- key: "<"
40589
- }, i18n__namespace.doNotTranslate("\\langle")), stringFromDecimal(vector[0]), /*#__PURE__*/React__namespace.createElement(TeX, {
40590
- key: ","
40591
- }, ", {}"), stringFromDecimal(vector[1]), /*#__PURE__*/React__namespace.createElement(TeX, {
40592
- key: ">"
40593
- }, i18n__namespace.doNotTranslate("\\rangle"))];
40594
- }
40595
- function texFromAngleDeg(angleDeg) {
40596
- return stringFromDecimal(angleDeg) + DEGREE_SIGN;
40597
- }
40598
- function orderInsensitiveCoordsEqual(coords1, coords2) {
40599
- coords1 = ___default["default"].clone(coords1).sort(kmath.point.compare);
40600
- coords2 = ___default["default"].clone(coords2).sort(kmath.point.compare);
40601
- return ___default["default"].all(___default["default"].map(coords1, function (coord1, i) {
40602
- const coord2 = coords2[i];
40603
- return kmath.point.equal(coord1, coord2);
40604
- }));
40605
- }
40606
- const inputComponentForApiOptions = apiOptions => {
40607
- if (apiOptions.customKeypad) {
40608
- return SimpleKeypadInput;
40609
- }
40610
- return NumberInput;
40611
- };
40612
-
40613
- /* Perform operations on raw transform objects */
40614
- const TransformOps = {
40615
- apply: function (transform) {
40616
- // Any transformation with empty text boxes is a no-op until
40617
- // filled out (these show up as nulls in transform.vector/line/etc).
40618
- // TODO (jack): Merge this just into reflections now that other
40619
- // transforms are always valid (after merging transformation
40620
- // collapsing, which may use isValid)
40621
- // @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
40622
- if (!Transformations[transform.type].isValid(transform)) {
40623
- return ___default["default"].identity; // do not transform the coord
40624
- }
40625
- // @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
40626
- return Transformations[transform.type].apply(transform);
40627
- },
40628
- append: function (transformList, newTransform) {
40629
- // Append newTransform to transformList, and collapse the last
40630
- // two transforms if they are collapsable
40631
- const results = TransformOps._appendAndCollapseLastTwo(transformList, newTransform);
40632
- // Collapse any no-ops at the end of the transformation list
40633
- return TransformOps._collapseFinalNoOps(results);
40634
- },
40635
- _collapseFinalNoOps: function (transforms) {
40636
- // Collapse no-op transformations at the end of the list
40637
- if (transforms.length && TransformOps.isNoOp(___default["default"].last(transforms))) {
40638
- return ___default["default"].initial(transforms);
40639
- }
40640
- return transforms;
40641
- },
40642
- _appendAndCollapseLastTwo: function (transformList, newTransform) {
40643
- if (!transformList.length) {
40644
- return [newTransform];
40645
- }
40646
- const collapsed = TransformOps.collapse(___default["default"].last(transformList), newTransform);
40647
- return ___default["default"].initial(transformList).concat(collapsed);
40648
- },
40649
- isNoOp: function (transform) {
40650
- return Transformations[transform.type].isNoOp(transform);
40651
- },
40652
- collapse: function (transform1, transform2) {
40653
- // We can only collapse transforms that have the same type
40654
- if (transform1.type !== transform2.type) {
40655
- return [transform1, transform2];
40656
- }
40657
-
40658
- // Clicking the button again removes empty transformations
40659
- if (TransformOps.isEmpty(transform1) && TransformOps.isEmpty(transform2)) {
40660
- return [];
40661
- }
40662
-
40663
- // Don't collapse invalid transformations otherwise
40664
- if (!TransformOps.isValid(transform1) || !TransformOps.isValid(transform2)) {
40665
- return [transform1, transform2];
40666
- }
40667
- return TransformOps._collapseValidMonotypedTransforms(transform1, transform2);
40668
- },
40669
- isValid: function (transform) {
40670
- // @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
40671
- return Transformations[transform.type].isValid(transform);
40672
- },
40673
- isEmpty: function (transform) {
40674
- // @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
40675
- return Transformations[transform.type].isEmpty(transform);
40676
- },
40677
- _collapseValidMonotypedTransforms: function (transform1, transform2) {
40678
- let collapsed = Transformations[transform1.type].collapse(transform1, transform2);
40679
- if (collapsed) {
40680
- // Force all answers into an array
40681
- if (!___default["default"].isArray(collapsed)) {
40682
- collapsed = [collapsed];
40683
- }
40684
- // Add types to all transforms in the answer
40685
- ___default["default"].each(collapsed, function (transform) {
40686
- transform.type = transform1.type;
40687
- });
40688
- return collapsed;
40689
- }
40690
- // These transforms can't be collapsed together
40691
- return [transform1, transform2];
40692
- },
40693
- toTeX: function (transform) {
40694
- return Transformations[transform.type].toTeX(transform);
40695
- },
40696
- /* A react representation of this transform object */
40697
- ListItem: createReactClass__default["default"]({
40698
- displayName: "ListItem",
40699
- render: function () {
40700
- if (this.props.mode === "dynamic") {
40701
- return /*#__PURE__*/React__namespace.createElement("div", null, TransformOps.toTeX(this.props.transform));
40702
- }
40703
- if (this.props.mode === "interactive") {
40704
- const TransformClass = Transformations[this.props.transform.type].Input;
40705
- return /*#__PURE__*/React__namespace.createElement(TransformClass
40706
- // eslint-disable-next-line react/no-string-refs
40707
- , _extends({
40708
- ref: "transform",
40709
- onChange: this.handleChange,
40710
- onFocus: this.props.onFocus,
40711
- onBlur: this.props.onBlur,
40712
- keypadElement: this.props.keypadElement,
40713
- apiOptions: this.props.apiOptions
40714
- }, this.props.transform));
40715
- }
40716
- throw new PerseusError("Invalid mode: " + this.props.mode, Errors.InvalidInput);
40717
- },
40718
- value: function () {
40719
- if (this.props.mode === "interactive") {
40720
- return ___default["default"].extend({
40721
- type: this.props.transform.type
40722
- },
40723
- // eslint-disable-next-line react/no-string-refs
40724
- this.refs.transform.value());
40725
- }
40726
- return this.props.transform;
40727
- },
40728
- handleChange: ___default["default"].debounce(function (callback) {
40729
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
40730
- this.props.onChange(this.value(), callback);
40731
- }, RENDER_TRANSFORM_DELAY_IN_MS),
40732
- /* InputPath API: depending on the API call, this could involve simply
40733
- * navigating to the right ref and calling the function on that
40734
- * component, or threading the call down and returning the result. */
40735
- _getComponentAtPath: function (path) {
40736
- // eslint-disable-next-line react/no-string-refs
40737
- const transform = this.refs.transform;
40738
- const ref = ___default["default"].head(path);
40739
- return transform.refs[ref];
40740
- },
40741
- focus: function () {
40742
- // eslint-disable-next-line react/no-string-refs
40743
- const transform = this.refs.transform;
40744
- const path = ___default["default"].head(transform.getInputPaths());
40745
- if (path) {
40746
- this.focusInputPath(path);
40747
- }
40748
- },
40749
- focusInputPath: function (path) {
40750
- this._getComponentAtPath(path).focus();
40751
- },
40752
- blurInputPath: function (path) {
40753
- this._getComponentAtPath(path).blur();
40754
- },
40755
- getDOMNodeForPath: function (path) {
40756
- return ReactDOM__default["default"].findDOMNode(this._getComponentAtPath(path));
40757
- },
40758
- getGrammarTypeForPath: function (path) {
40759
- return "number";
40760
- },
40761
- setInputValue: function (path, value, cb) {
40762
- // `value` comes in as a string on mobile, but we need a number
40763
- // We let through the empty string so that "Clear" works -- in
40764
- // that case, the transformer widget will just act as if there is
40765
- // no input, which is what we want.
40766
- // @ts-expect-error - TS2339 - Property 'length' does not exist on type 'string | number'.
40767
- if (value.length) {
40768
- // @ts-expect-error - TS2345 - Argument of type 'string | number' is not assignable to parameter of type 'string'.
40769
- value = parseFloat(value);
40770
- if (isNaN(value)) {
40771
- return;
40772
- }
40773
- }
40774
- // eslint-disable-next-line react/no-string-refs
40775
- this.refs.transform.setInputValue(path, value, cb);
40776
- },
40777
- getInputPaths: function () {
40778
- // If we're in dynamic mode, then the list items are made up of
40779
- // static text.
40780
- if (this.props.mode === "dynamic") {
40781
- return [];
40782
- }
40783
- // eslint-disable-next-line react/no-string-refs
40784
- return this.refs.transform.getInputPaths();
40785
- }
40786
- })
40787
- };
40788
- const Transformations = {
40789
- translation: {
40790
- // I18N: As in the command, "Translate the polygon"
40791
- verbName: i18n__namespace._("Translate"),
40792
- nounName: i18n__namespace._("Translation"),
40793
- lowerNounName: i18n__namespace._("translation"),
40794
- apply: function (transform) {
40795
- return function (coord) {
40796
- return kmath.vector.add(coord, transform.vector);
40797
- };
40798
- },
40799
- isValid: function (transform) {
40800
- return ___default["default"].isFinite(transform.vector[0]) && ___default["default"].isFinite(transform.vector[1]);
40801
- },
40802
- isEmpty: function (transform) {
40803
- return transform.vector[0] === null && transform.vector[1] === null;
40804
- },
40805
- isNoOp: function (transform) {
40806
- return kmath.vector.equal(transform.vector, [0, 0]);
40807
- },
40808
- collapse: function (transform1, transform2) {
40809
- return {
40810
- vector: kmath.vector.add(transform1.vector, transform2.vector)
40811
- };
40812
- },
40813
- toTeX: function (transform) {
40814
- // I18N: As in the command, "Translation by <3, 1>"
40815
- return i18n__namespace.$_("Translation by %(vector)s", {
40816
- vector: texFromVector(transform.vector)
40817
- });
40818
- },
40819
- Input: class extends React__namespace.Component {
40820
- state = {
40821
- vector: this.props.vector || [null, null]
40822
- };
40823
- componentDidUpdate(prevProps) {
40824
- if (!deepEq(this.props, prevProps)) {
40825
- this.setState({
40826
- vector: this.props.vector
40827
- });
40828
- }
40829
- }
40830
- render() {
40831
- const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
40832
- const {
40833
- TeX
40834
- } = getDependencies();
40835
- const vector = [/*#__PURE__*/React__namespace.createElement(TeX, {
40836
- key: "<"
40837
- }, i18n__namespace.doNotTranslate("\\langle")), /*#__PURE__*/React__namespace.createElement(InputComponent, {
40838
- key: "vec_x"
40839
- // eslint-disable-next-line react/no-string-refs
40840
- ,
40841
- ref: "x",
40842
- placeholder: 0,
40843
- value: this.state.vector[0],
40844
- useArrowKeys: true,
40845
- onChange: val0 => {
40846
- const val1 = this.state.vector[1];
40847
- this.setState({
40848
- vector: [val0, val1]
40849
- }, () => {
40850
- this.props.onChange();
40851
- });
40852
- },
40853
- onFocus: ___default["default"].partial(this.props.onFocus, "x"),
40854
- onBlur: ___default["default"].partial(this.props.onBlur, "x"),
40855
- keypadElement: this.props.keypadElement
40856
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
40857
- key: ","
40858
- }, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
40859
- key: "vec_y"
40860
- // eslint-disable-next-line react/no-string-refs
40861
- ,
40862
- ref: "y",
40863
- placeholder: 0,
40864
- value: this.state.vector[1],
40865
- useArrowKeys: true,
40866
- onChange: val1 => {
40867
- const val0 = this.state.vector[0];
40868
- this.setState({
40869
- vector: [val0, val1]
40870
- }, () => {
40871
- this.props.onChange();
40872
- });
40873
- },
40874
- onFocus: ___default["default"].partial(this.props.onFocus, "y"),
40875
- onBlur: ___default["default"].partial(this.props.onBlur, "y"),
40876
- keypadElement: this.props.keypadElement
40877
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
40878
- key: ">"
40879
- }, i18n__namespace.doNotTranslate("\\rangle"))];
40880
- return /*#__PURE__*/React__namespace.createElement("div", null, i18n__namespace.$_("Translation by %(vector)s", {
40881
- vector: vector
40882
- }));
40883
- }
40884
- value = () => {
40885
- // eslint-disable-next-line react/no-string-refs
40886
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
40887
- const x = this.refs.x.getValue();
40888
- // eslint-disable-next-line react/no-string-refs
40889
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
40890
- const y = this.refs.y.getValue();
40891
- return {
40892
- vector: [x, y]
40893
- };
40894
- };
40895
-
40896
- /* InputPath API */
40897
- setInputValue = (path, value, cb) => {
40898
- const id = ___default["default"].first(path);
40899
- const vector = ___default["default"].clone(this.state.vector);
40900
- if (id === "x") {
40901
- vector[0] = value;
40902
- } else if (id === "y") {
40903
- vector[1] = value;
40904
- }
40905
- this.setState({
40906
- vector: vector
40907
- }, () => {
40908
- this.props.onChange(cb);
40909
- });
40910
- };
40911
- getInputPaths = () => {
40912
- return [["x"], ["y"]];
40913
- };
40914
- }
40915
- },
40916
- rotation: {
40917
- // I18N: As in the command, "Rotate the polygon"
40918
- verbName: i18n__namespace._("Rotate"),
40919
- nounName: i18n__namespace._("Rotation"),
40920
- lowerNounName: i18n__namespace._("rotation"),
40921
- apply: function (transform) {
40922
- return function (coord) {
40923
- return kmath.point.rotateDeg(coord, transform.angleDeg, transform.center);
40924
- };
40925
- },
40926
- isValid: function (transform) {
40927
- return ___default["default"].isFinite(transform.angleDeg) && ___default["default"].isFinite(transform.center[0]) && ___default["default"].isFinite(transform.center[1]);
40928
- },
40929
- isEmpty: function (transform) {
40930
- return transform.angleDeg === null && transform.center[0] === null && transform.center[1] === null;
40931
- },
40932
- isNoOp: function (transform) {
40933
- return kmath.number.equal(transform.angleDeg, 0);
40934
- },
40935
- collapse: function (transform1, transform2) {
40936
- if (!kmath.point.equal(transform1.center, transform2.center)) {
40937
- return false;
40938
- }
40939
- return {
40940
- center: transform1.center,
40941
- angleDeg: transform1.angleDeg + transform2.angleDeg
40942
- };
40943
- },
40944
- toTeX: function (transform) {
40945
- return i18n__namespace.$_("Rotation by %(degrees)s about %(point)s", {
40946
- degrees: texFromAngleDeg(transform.angleDeg),
40947
- point: texFromPoint(transform.center)
40948
- });
40949
- },
40950
- Input: class extends React__namespace.Component {
40951
- state = {
40952
- center: this.props.center || [null, null],
40953
- angleDeg: this.props.angleDeg || null
40954
- };
40955
- componentDidUpdate(prevProps) {
40956
- if (!deepEq(this.props, prevProps)) {
40957
- this.setState({
40958
- center: this.props.center,
40959
- angleDeg: this.props.angleDeg
40960
- });
40961
- }
40962
- }
40963
- render() {
40964
- const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
40965
- const {
40966
- TeX
40967
- } = getDependencies();
40968
- const point = [/*#__PURE__*/React__namespace.createElement(TeX, {
40969
- key: "("
40970
- }, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
40971
- key: "X"
40972
- // eslint-disable-next-line react/no-string-refs
40973
- ,
40974
- ref: "centerX",
40975
- placeholder: 0,
40976
- value: this.state.center[0],
40977
- useArrowKeys: true,
40978
- onChange: val0 => {
40979
- const val1 = this.state.center[1];
40980
- this.setState({
40981
- center: [val0, val1]
40982
- }, () => {
40983
- this.props.onChange();
40984
- });
40985
- },
40986
- onFocus: ___default["default"].partial(this.props.onFocus, "centerX"),
40987
- onBlur: ___default["default"].partial(this.props.onBlur, "centerX"),
40988
- keypadElement: this.props.keypadElement
40989
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
40990
- key: ","
40991
- }, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
40992
- key: "Y"
40993
- // eslint-disable-next-line react/no-string-refs
40994
- ,
40995
- ref: "centerY",
40996
- placeholder: 0,
40997
- value: this.state.center[1],
40998
- useArrowKeys: true,
40999
- onChange: val1 => {
41000
- const val0 = this.state.center[0];
41001
- this.setState({
41002
- center: [val0, val1]
41003
- }, () => {
41004
- this.props.onChange();
41005
- });
41006
- },
41007
- onFocus: ___default["default"].partial(this.props.onFocus, "centerY"),
41008
- onBlur: ___default["default"].partial(this.props.onBlur, "centerY"),
41009
- keypadElement: this.props.keypadElement
41010
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41011
- key: ")"
41012
- }, ")")];
41013
- const degrees = [/*#__PURE__*/React__namespace.createElement(InputComponent, {
41014
- key: "deg"
41015
- // eslint-disable-next-line react/no-string-refs
41016
- ,
41017
- ref: "angleDeg",
41018
- placeholder: 0,
41019
- value: this.state.angleDeg,
41020
- useArrowKeys: true,
41021
- onChange: val => {
41022
- this.setState({
41023
- angleDeg: val
41024
- }, () => {
41025
- this.props.onChange();
41026
- });
41027
- },
41028
- onFocus: ___default["default"].partial(this.props.onFocus, "angleDeg"),
41029
- onBlur: ___default["default"].partial(this.props.onBlur, "angleDeg"),
41030
- keypadElement: this.props.keypadElement
41031
- }), DEGREE_SIGN];
41032
- // I18N: %(point)s must come before %(degrees)s in this phrase
41033
- const text = i18n__namespace.$_("Rotation about %(point)s by %(degrees)s", {
41034
- point,
41035
- degrees
41036
- });
41037
- return /*#__PURE__*/React__namespace.createElement("div", null, text);
41038
- }
41039
- value = () => {
41040
- // eslint-disable-next-line react/no-string-refs
41041
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41042
- const angleDeg = this.refs.angleDeg.getValue();
41043
- // eslint-disable-next-line react/no-string-refs
41044
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41045
- const centerX = this.refs.centerX.getValue();
41046
- // eslint-disable-next-line react/no-string-refs
41047
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41048
- const centerY = this.refs.centerY.getValue();
41049
- return {
41050
- angleDeg: angleDeg,
41051
- center: [centerX, centerY]
41052
- };
41053
- };
41054
-
41055
- /* InputPath API */
41056
- setInputValue = (path, value, cb) => {
41057
- const id = ___default["default"].first(path);
41058
- let angleDeg = ___default["default"].clone(this.state.angleDeg);
41059
- const center = ___default["default"].clone(this.state.center);
41060
- if (id === "angleDeg") {
41061
- angleDeg = value;
41062
- } else if (id === "centerX") {
41063
- center[0] = value;
41064
- } else if (id === "centerY") {
41065
- center[1] = value;
41066
- }
41067
- this.setState({
41068
- angleDeg: angleDeg,
41069
- center: center
41070
- }, () => {
41071
- this.props.onChange(cb);
41072
- });
41073
- };
41074
- getInputPaths = () => {
41075
- return [["centerX"], ["centerY"], ["angleDeg"]];
41076
- };
41077
- }
41078
- },
41079
- reflection: {
41080
- // I18N: As in the command, "Reflect the polygon"
41081
- verbName: i18n__namespace._("Reflect"),
41082
- nounName: i18n__namespace._("Reflection"),
41083
- lowerNounName: i18n__namespace._("reflection"),
41084
- apply: function (transform) {
41085
- return function (coord) {
41086
- return kmath.point.reflectOverLine(coord, transform.line);
41087
- };
41088
- },
41089
- isValid: function (transform) {
41090
- // A bit hacky, but we'll also define reflecting over a
41091
- // single point as a no-op, to avoid NaN fun.
41092
- return ___default["default"].all(___default["default"].flatten(transform.line), ___default["default"].isFinite) && !kmath.point.equal(transform.line[0], transform.line[1]);
41093
- },
41094
- isEmpty: function (transform) {
41095
- return ___default["default"].all(___default["default"].flatten(transform.line), ___default["default"].isNull);
41096
- },
41097
- isNoOp: function (transform) {
41098
- // Invalid transforms are implicitly no-ops, so we don't
41099
- // have to catch that case here.
41100
- return false;
41101
- },
41102
- collapse: function (transform1, transform2) {
41103
- if (!kmath.line.equal(transform1.line, transform2.line)) {
41104
- return false;
41105
- }
41106
- return [];
41107
- },
41108
- toTeX: function (transform) {
41109
- const point1 = transform.line[0];
41110
- const point2 = transform.line[1];
41111
- return i18n__namespace.$_("Reflection over the line from %(point1)s to %(point2)s", {
41112
- point1: texFromPoint(point1),
41113
- point2: texFromPoint(point2)
41114
- });
41115
- },
41116
- Input: class extends React__namespace.Component {
41117
- state = {
41118
- line: this.props.line || [[null, null], [null, null]]
41119
- };
41120
- componentDidUpdate(prevProps) {
41121
- if (!deepEq(this.props, prevProps)) {
41122
- this.setState({
41123
- line: this.props.line
41124
- });
41125
- }
41126
- }
41127
- render() {
41128
- const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
41129
- const {
41130
- TeX
41131
- } = getDependencies();
41132
- const point1 = [/*#__PURE__*/React__namespace.createElement(TeX, {
41133
- key: "("
41134
- }, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
41135
- key: "x1"
41136
- // eslint-disable-next-line react/no-string-refs
41137
- ,
41138
- ref: "x1",
41139
- value: this.state.line[0][0],
41140
- useArrowKeys: true
41141
- // eslint-disable-next-line react/jsx-no-bind
41142
- ,
41143
- onChange: this.changePoint.bind(this, 0, 0),
41144
- onFocus: ___default["default"].partial(this.props.onFocus, "x1"),
41145
- onBlur: ___default["default"].partial(this.props.onBlur, "x1"),
41146
- keypadElement: this.props.keypadElement
41147
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41148
- key: ","
41149
- }, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
41150
- key: "y1"
41151
- // eslint-disable-next-line react/no-string-refs
41152
- ,
41153
- ref: "y1",
41154
- value: this.state.line[0][1],
41155
- useArrowKeys: true
41156
- // eslint-disable-next-line react/jsx-no-bind
41157
- ,
41158
- onChange: this.changePoint.bind(this, 0, 1),
41159
- onFocus: ___default["default"].partial(this.props.onFocus, "y1"),
41160
- onBlur: ___default["default"].partial(this.props.onBlur, "y1"),
41161
- keypadElement: this.props.keypadElement
41162
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41163
- key: ")"
41164
- }, ")")];
41165
- const point2 = [/*#__PURE__*/React__namespace.createElement(TeX, {
41166
- key: "("
41167
- }, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
41168
- key: "x2"
41169
- // eslint-disable-next-line react/no-string-refs
41170
- ,
41171
- ref: "x2",
41172
- value: this.state.line[1][0],
41173
- useArrowKeys: true
41174
- // eslint-disable-next-line react/jsx-no-bind
41175
- ,
41176
- onChange: this.changePoint.bind(this, 1, 0),
41177
- onFocus: ___default["default"].partial(this.props.onFocus, "x2"),
41178
- onBlur: ___default["default"].partial(this.props.onBlur, "x2"),
41179
- keypadElement: this.props.keypadElement
41180
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41181
- key: ","
41182
- }, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
41183
- key: "y2"
41184
- // eslint-disable-next-line react/no-string-refs
41185
- ,
41186
- ref: "y2",
41187
- value: this.state.line[1][1],
41188
- useArrowKeys: true
41189
- // eslint-disable-next-line react/jsx-no-bind
41190
- ,
41191
- onChange: this.changePoint.bind(this, 1, 1),
41192
- onFocus: ___default["default"].partial(this.props.onFocus, "y2"),
41193
- onBlur: ___default["default"].partial(this.props.onBlur, "y2"),
41194
- keypadElement: this.props.keypadElement
41195
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41196
- key: ")"
41197
- }, ")")];
41198
- return /*#__PURE__*/React__namespace.createElement("div", null, i18n__namespace.$_("Reflection over the line from " + "%(point1)s to %(point2)s", {
41199
- point1,
41200
- point2
41201
- }));
41202
- }
41203
- changePoint = (i, j, val, cb) => {
41204
- const line = ___default["default"].map(this.state.line, ___default["default"].clone);
41205
- // @ts-expect-error - TS2538 - Type 'undefined' cannot be used as an index type.
41206
- line[i][j] = val;
41207
- this.setState({
41208
- line: line
41209
- }, () => {
41210
- this.props.onChange(cb);
41211
- });
41212
- };
41213
- value = () => {
41214
- // eslint-disable-next-line react/no-string-refs
41215
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41216
- const x1 = this.refs.x1.getValue();
41217
- // eslint-disable-next-line react/no-string-refs
41218
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41219
- const y1 = this.refs.y1.getValue();
41220
- // eslint-disable-next-line react/no-string-refs
41221
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41222
- const x2 = this.refs.x2.getValue();
41223
- // eslint-disable-next-line react/no-string-refs
41224
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41225
- const y2 = this.refs.y2.getValue();
41226
- return {
41227
- line: [[x1, y1], [x2, y2]]
41228
- };
41229
- };
41230
-
41231
- /* InputPath API */
41232
- setInputValue = (path, value, cb) => {
41233
- const id = ___default["default"].first(path);
41234
- let j;
41235
- if (id[0] === "x") {
41236
- j = 0;
41237
- } else if (id[0] === "y") {
41238
- j = 1;
41239
- }
41240
- let i;
41241
- if (id[1] === "1") {
41242
- i = 0;
41243
- } else if (id[1] === "2") {
41244
- i = 1;
41245
- }
41246
- this.changePoint(i, j, value, cb);
41247
- };
41248
- getInputPaths = () => {
41249
- return [["x1"], ["y1"], ["x2"], ["y2"]];
41250
- };
41251
- }
41252
- },
41253
- dilation: {
41254
- // I18N: As in the command, "Dilate the polygon"
41255
- verbName: i18n__namespace._("Dilate"),
41256
- nounName: i18n__namespace._("Dilation"),
41257
- lowerNounName: i18n__namespace._("dilation"),
41258
- apply: function (transform) {
41259
- return function (coord) {
41260
- return dilatePointFromCenter(coord, transform.center, transform.scale);
41261
- };
41262
- },
41263
- isValid: function (transform) {
41264
- return ___default["default"].isFinite(transform.scale) && ___default["default"].isFinite(transform.center[0]) && ___default["default"].isFinite(transform.center[1]);
41265
- },
41266
- isEmpty: function (transform) {
41267
- return transform.scale === null && transform.center[0] === null && transform.center[1] === null;
41268
- },
41269
- isNoOp: function (transform) {
41270
- return kmath.number.equal(transform.scale, 1);
41271
- },
41272
- collapse: function (transform1, transform2) {
41273
- if (!kmath.point.equal(transform1.center, transform2.center)) {
41274
- return false;
41275
- }
41276
- return {
41277
- center: transform1.center,
41278
- scale: transform1.scale * transform2.scale
41279
- };
41280
- },
41281
- toTeX: function (transform) {
41282
- const scaleString = stringFromFraction(transform.scale);
41283
- return i18n__namespace.$_("Dilation of scale %(scale)s about %(point)s", {
41284
- scale: scaleString,
41285
- point: texFromPoint(transform.center)
41286
- });
41287
- },
41288
- Input: class extends React__namespace.Component {
41289
- state = {
41290
- center: this.props.center || [null, null],
41291
- scale: this.props.scale || null
41292
- };
41293
- componentDidUpdate(prevProps) {
41294
- if (!deepEq(this.props, prevProps)) {
41295
- this.setState({
41296
- center: this.props.center,
41297
- scale: this.props.scale
41298
- });
41299
- }
41300
- }
41301
- render() {
41302
- const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
41303
- const {
41304
- TeX
41305
- } = getDependencies();
41306
- const point = [/*#__PURE__*/React__namespace.createElement(TeX, {
41307
- key: "("
41308
- }, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
41309
- key: "point_x"
41310
- // eslint-disable-next-line react/no-string-refs
41311
- ,
41312
- ref: "x",
41313
- placeholder: 0,
41314
- value: this.state.center[0],
41315
- useArrowKeys: true,
41316
- onChange: val0 => {
41317
- const val1 = this.state.center[1];
41318
- this.setState({
41319
- center: [val0, val1]
41320
- }, () => {
41321
- this.props.onChange();
41322
- });
41323
- },
41324
- onFocus: ___default["default"].partial(this.props.onFocus, "x"),
41325
- onBlur: ___default["default"].partial(this.props.onBlur, "x"),
41326
- keypadElement: this.props.keypadElement
41327
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41328
- key: ","
41329
- }, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
41330
- key: "point_y"
41331
- // eslint-disable-next-line react/no-string-refs
41332
- ,
41333
- ref: "y",
41334
- placeholder: 0,
41335
- value: this.state.center[1],
41336
- useArrowKeys: true,
41337
- onChange: val1 => {
41338
- const val0 = this.state.center[0];
41339
- this.setState({
41340
- center: [val0, val1]
41341
- }, () => {
41342
- this.props.onChange();
41343
- });
41344
- },
41345
- onFocus: ___default["default"].partial(this.props.onFocus, "y"),
41346
- onBlur: ___default["default"].partial(this.props.onBlur, "y"),
41347
- keypadElement: this.props.keypadElement
41348
- }), /*#__PURE__*/React__namespace.createElement(TeX, {
41349
- key: ")"
41350
- }, ")")];
41351
- const scale = /*#__PURE__*/React__namespace.createElement(InputComponent
41352
- // eslint-disable-next-line react/no-string-refs
41353
- , {
41354
- ref: "scale",
41355
- placeholder: 1,
41356
- value: this.state.scale,
41357
- useArrowKeys: true,
41358
- onChange: val => {
41359
- this.setState({
41360
- scale: val
41361
- }, () => {
41362
- this.props.onChange();
41363
- });
41364
- },
41365
- onFocus: ___default["default"].partial(this.props.onFocus, "scale"),
41366
- onBlur: ___default["default"].partial(this.props.onBlur, "scale"),
41367
- keypadElement: this.props.keypadElement
41368
- });
41369
- return /*#__PURE__*/React__namespace.createElement("div", null, i18n__namespace.$_("Dilation about %(point)s by %(scale)s", {
41370
- point,
41371
- scale
41372
- }));
41373
- }
41374
- value = () => {
41375
- // eslint-disable-next-line react/no-string-refs
41376
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41377
- const scale = this.refs.scale.getValue();
41378
- // eslint-disable-next-line react/no-string-refs
41379
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41380
- const x = this.refs.x.getValue();
41381
- // eslint-disable-next-line react/no-string-refs
41382
- // @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
41383
- const y = this.refs.y.getValue();
41384
- return {
41385
- scale: scale,
41386
- center: [x, y]
41387
- };
41388
- };
41389
-
41390
- /* InputPath API */
41391
- setInputValue = (path, value, cb) => {
41392
- const id = ___default["default"].first(path);
41393
- let scale = this.state.scale;
41394
- const center = ___default["default"].clone(this.state.center);
41395
- if (id === "x") {
41396
- center[0] = value;
41397
- } else if (id === "y") {
41398
- center[1] = value;
41399
- } else if (id === "scale") {
41400
- scale = value;
41401
- }
41402
- this.setState({
41403
- scale: scale,
41404
- center: center
41405
- }, () => {
41406
- this.props.onChange(cb);
41407
- });
41408
- };
41409
- getInputPaths = () => {
41410
- return [["x"], ["y"], ["scale"]];
41411
- };
41412
- }
41413
- }
41414
- };
41415
-
41416
- /* Various functions to deal with different shape types */
41417
- const ShapeTypes = {
41418
- getPointCountForType: function (type) {
41419
- const splitType = type.split("-");
41420
- if (splitType[0] === "polygon") {
41421
- return splitType[1] || 3;
41422
- }
41423
- if (splitType[0] === "line" || splitType[0] === "lineSegment") {
41424
- return 2;
41425
- }
41426
- if (splitType[0] === "angle") {
41427
- return 3;
41428
- }
41429
- if (splitType[0] === "circle") {
41430
- return 2;
41431
- }
41432
- if (splitType[0] === "point") {
41433
- return 1;
41434
- }
41435
- },
41436
- addMovableShape: function (graphie, options) {
41437
- if (options.editable && options.translatable) {
41438
- throw new PerseusError("It doesn't make sense to have a movable shape " + "where you can stretch the points and translate them " + "simultaneously. options: " + JSON.stringify(options), Errors.InvalidInput);
41439
- }
41440
- const points = ___default["default"].map(options.shape.coords, function (coord) {
41441
- let isMoving = false;
41442
- let previousCoord = coord;
41443
- const onMove = function (x, y) {
41444
- if (!isMoving) {
41445
- previousCoord = currentPoint.coord;
41446
- isMoving = true;
41447
- }
41448
- let moveVector = kmath.vector.subtract([x, y], currentPoint.coord);
41449
-
41450
- // Translate from (x, y) semantics to (dX, dY) semantics
41451
- // This is more useful for translations on multiple points,
41452
- // where we care about how the points moved, not where any
41453
- // individual point ended up
41454
- if (options.onMove) {
41455
- moveVector = options.onMove(moveVector[0], moveVector[1]);
41456
- }
41457
-
41458
- // Perform a translation on all points in this shape when
41459
- // any point moves
41460
- if (options.translatable) {
41461
- ___default["default"].each(points, function (point) {
41462
- // The point itself will be updated by the
41463
- // movablePoint class, so only translate the other
41464
- // points
41465
- if (point !== currentPoint) {
41466
- point.setCoord(kmath.vector.add(point.coord, moveVector));
41467
- }
41468
- });
41469
- }
41470
-
41471
- // Update our shape and our currentPoint
41472
- // Without this, some shapes (circles, angles) appear
41473
- // "bouncy" as they are updated with currentPoint at the
41474
- // current mouse coordinate (oldCoord), rather than newCoord
41475
- const oldCoord = currentPoint.coord;
41476
- const newCoord = kmath.vector.add(currentPoint.coord, moveVector);
41477
- // Temporarily change our coordinate so that
41478
- // shape.update() sees the new coordinate
41479
- currentPoint.coord = newCoord;
41480
- shape.update();
41481
- // ...But don't break onMove, which assumes it
41482
- // is the only thing changing our coord
41483
- currentPoint.coord = oldCoord;
41484
- return newCoord;
41485
- };
41486
- const onMoveEnd = function () {
41487
- // onMove isn't guaranteed to be called before onMoveEnd, so
41488
- // we have to take into account that we may not have moved and
41489
- // set previousCoord.
41490
- if (options.onMoveEnd && isMoving) {
41491
- isMoving = false;
41492
- // We don't use the supplied x and y parameters here
41493
- // because MovablePoint's onMoveEnd semantics suck.
41494
- // It returns the mouseX, mouseY without processing them
41495
- // through onMove, leaving us with weird fractional moves
41496
- const change = kmath.vector.subtract(currentPoint.coord, previousCoord);
41497
- options.onMoveEnd(change[0], change[1]);
41498
- }
41499
- shape.update();
41500
- };
41501
- const currentPoint = graphie.addMovablePoint({
41502
- coord: coord,
41503
- normalStyle: options.normalPointStyle,
41504
- highlightStyle: options.highlightPointStyle,
41505
- constraints: {
41506
- fixed: !options.translatable && !options.editable
41507
- },
41508
- visible: options.showPoints,
41509
- snapX: options.snap && options.snap[0] || 0,
41510
- snapY: options.snap && options.snap[1] || 0,
41511
- bounded: false,
41512
- // Don't bound it when placing it on the graph
41513
- onMove: onMove,
41514
- onMoveEnd: onMoveEnd
41515
- });
41516
-
41517
- // Bound it when moving
41518
- // We can't set this earlier, because doing so would mean any
41519
- // points outside of the graph would be moved into a moved into
41520
- // a position that doesn't preserve the shape
41521
- currentPoint.bounded = true;
41522
- return currentPoint;
41523
- });
41524
- const shape = ShapeTypes.addShape(graphie, options, points);
41525
- const removeShapeWithoutPoints = shape.remove;
41526
- shape.remove = function () {
41527
- removeShapeWithoutPoints.apply(shape);
41528
- ___default["default"].invoke(points, "remove");
41529
- };
41530
- return shape;
41531
- },
41532
- addShape: function (graphie, options, points) {
41533
- points = points || options.shape.coords;
41534
- const types = ShapeTypes._typesOf(options.shape);
41535
- const typeOptions = options.shape.options || ShapeTypes.defaultOptions(types);
41536
-
41537
- // @ts-expect-error - TS2554 - Expected 4 arguments, but got 3.
41538
- const shapes = ShapeTypes._mapTypes(types, points, function (type, points, i) {
41539
- const shapeOptions = ___default["default"].extend({}, options, typeOptions[i]);
41540
- return ShapeTypes._addType(graphie, type, points, shapeOptions);
41541
- });
41542
- const updateFuncs = ___default["default"].filter(___default["default"].pluck(shapes, "update"), ___default["default"].identity);
41543
- const update = function () {
41544
- ___default["default"].invoke(updateFuncs, "call");
41545
- };
41546
- const removeFuncs = ___default["default"].filter(___default["default"].pluck(shapes, "remove"), ___default["default"].identity);
41547
- const remove = function () {
41548
- ___default["default"].invoke(removeFuncs, "call");
41549
- };
41550
- const getOptions = function () {
41551
- return ___default["default"].map(shapes, function (shape) {
41552
- if (shape.getOptions) {
41553
- return shape.getOptions();
41554
- }
41555
- return {};
41556
- });
41557
- };
41558
- const toJSON = function () {
41559
- const coords = ___default["default"].map(points, function (pt) {
41560
- if (___default["default"].isArray(pt)) {
41561
- return pt;
41562
- }
41563
- return pt.coord;
41564
- });
41565
- return {
41566
- type: types,
41567
- coords: coords,
41568
- options: getOptions()
41569
- };
41570
- };
41571
- return {
41572
- type: types,
41573
- points: points,
41574
- update: update,
41575
- remove: remove,
41576
- toJSON: toJSON,
41577
- getOptions: getOptions
41578
- };
41579
- },
41580
- equal: function (shape1, shape2) {
41581
- const types1 = ShapeTypes._typesOf(shape1);
41582
- const types2 = ShapeTypes._typesOf(shape2);
41583
- if (types1.length !== types2.length) {
41584
- return false;
41585
- }
41586
- // @ts-expect-error - TS2554 - Expected 4 arguments, but got 3.
41587
- const shapes1 = ShapeTypes._mapTypes(types1, shape1.coords, ShapeTypes._combine);
41588
- // @ts-expect-error - TS2554 - Expected 4 arguments, but got 3.
41589
- const shapes2 = ShapeTypes._mapTypes(types2, shape2.coords, ShapeTypes._combine);
41590
- return ___default["default"].all(___default["default"].map(shapes1, function (partialShape1, i) {
41591
- const partialShape2 = shapes2[i];
41592
- if (partialShape1.type !== partialShape2.type) {
41593
- return false;
41594
- }
41595
- return ShapeTypes._forType(partialShape1.type).equal(partialShape1.coords, partialShape2.coords);
41596
- }));
41597
- },
41598
- _typesOf: function (shape) {
41599
- let types = shape.type;
41600
- if (!___default["default"].isArray(types)) {
41601
- types = [types];
41602
- }
41603
- return ___default["default"].map(types, function (type) {
41604
- if (type === "polygon") {
41605
- return "polygon-3";
41606
- }
41607
- return type;
41608
- });
41609
- },
41610
- defaultOptions: function (types) {
41611
- return ___default["default"].map(types, function (type) {
41612
- const typeDefaultOptions = ShapeTypes._forType(type).defaultOptions;
41613
- return ___default["default"].extend({}, typeDefaultOptions);
41614
- });
41615
- },
41616
- _forType: function (type) {
41617
- const baseType = type.split("-")[0];
41618
- return ShapeTypes[baseType];
41619
- },
41620
- _mapTypes: function (types, points, func, context) {
41621
- return ___default["default"].map(types, function (type, i) {
41622
- const pointCount = ShapeTypes.getPointCountForType(type);
41623
- const currentPoints = ___default["default"].first(points, pointCount);
41624
- points = ___default["default"].rest(points, pointCount);
41625
- return func.call(context, type, currentPoints, i);
41626
- });
41627
- },
41628
- _addType: function (graphie, type, points, options) {
41629
- const lineCoords = ___default["default"].isArray(points[0]) ? {
41630
- coordA: points[0],
41631
- coordZ: points[1]
41632
- } : {
41633
- pointA: points[0],
41634
- pointZ: points[1]
41635
- };
41636
- type = type.split("-")[0];
41637
- if (type === "polygon") {
41638
- const polygon = graphie.addMovablePolygon(___default["default"].extend({}, options, {
41639
- fixed: !options.editable,
41640
- snapX: options.snap && options.snap[0] || 0,
41641
- snapY: options.snap && options.snap[1] || 0,
41642
- points: points,
41643
- constrainToGraph: false
41644
- }));
41645
- return {
41646
- update: polygon.transform.bind(polygon),
41647
- remove: polygon.remove.bind(polygon)
41648
- };
41649
- }
41650
- if (type === "line" || type === "lineSegment") {
41651
- const line = graphie.addMovableLineSegment(___default["default"].extend({}, options, lineCoords, {
41652
- movePointsWithLine: true,
41653
- fixed: true,
41654
- constraints: {
41655
- fixed: true
41656
- },
41657
- extendLine: type === "line"
41658
- }));
41659
-
41660
- // TODO(jack): Hide points on uneditable lines when translation
41661
- // is a vector.
41662
- // We can't just remove the points yet, because they are the
41663
- // translation handle for the line.
41664
- return {
41665
- update: line.transform.bind(line, true),
41666
- remove: line.remove.bind(line)
41667
- };
41668
- }
41669
- if (type === "angle") {
41670
- // If this angle is editable, we want to be able to make angles
41671
- // both larger and smaller than 180 degrees.
41672
- // If this angle is not editable, it should always maintain
41673
- // it's angle measure, even if it is reflected (causing the
41674
- // clockwise-ness of the points to change)
41675
- const shouldChangeReflexivity = options.editable ? null : false;
41676
- const angle = graphie.addMovableAngle({
41677
- angleLabel: "$deg0",
41678
- fixed: true,
41679
- points: points,
41680
- normalStyle: options.normalStyle,
41681
- reflex: options.reflex
41682
- });
41683
-
41684
- // Hide non-vertex points on uneditable angles
41685
- if (!___default["default"].isArray(points[0]) && !options.editable) {
41686
- points[0].remove();
41687
- points[2].remove();
41688
- }
41689
- return {
41690
- update: angle.update.bind(angle, shouldChangeReflexivity),
41691
- remove: angle.remove.bind(angle),
41692
- getOptions: function () {
41693
- return {
41694
- reflex: angle.isReflex()
41695
- };
41696
- }
41697
- };
41698
- }
41699
- if (type === "circle") {
41700
- let perimeter = {
41701
- // temporary object for the first removal
41702
- remove: ___default["default"].identity
41703
- };
41704
- const redrawPerim = function () {
41705
- const coord0 = points[0].coord || points[0];
41706
- const coord1 = points[1].coord || points[1];
41707
- const radius = kmath.point.distanceToPoint(coord0, coord1);
41708
- // @ts-expect-error - TS2554 - Expected 1 arguments, but got 0.
41709
- perimeter.remove();
41710
- perimeter = graphie.circle(coord0, radius, ___default["default"].extend({
41711
- stroke: KhanColors.DYNAMIC,
41712
- "stroke-width": 2
41713
- }, options.normalStyle));
41714
- };
41715
- redrawPerim();
41716
- if (points[1].remove && !options.editable) {
41717
- points[1].remove();
41718
- }
41719
- return {
41720
- update: redrawPerim,
41721
- remove: function () {
41722
- // Not _.bind because the remove function changes
41723
- // when the perimeter is redrawn
41724
- // @ts-expect-error - TS2554 - Expected 1 arguments, but got 0.
41725
- perimeter.remove();
41726
- }
41727
- };
41728
- }
41729
- if (type === "point") {
41730
- // do nothing
41731
- return {
41732
- update: null,
41733
- remove: null
41734
- };
41735
- }
41736
- throw new PerseusError("Invalid shape type " + type, Errors.InvalidInput);
41737
- },
41738
- _combine: function (type, coords) {
41739
- return {
41740
- type: type,
41741
- coords: coords
41742
- };
41743
- },
41744
- polygon: {
41745
- equal: orderInsensitiveCoordsEqual
41746
- },
41747
- line: {
41748
- equal: kmath.line.equal
41749
- },
41750
- lineSegment: {
41751
- equal: orderInsensitiveCoordsEqual
41752
- },
41753
- angle: {
41754
- equal: function (points1, points2) {
41755
- if (!kmath.point.equal(points1[1], points2[1])) {
41756
- return false;
41757
- }
41758
- const line1_0 = [points1[1], points1[0]];
41759
- const line1_2 = [points1[1], points1[2]];
41760
- const line2_0 = [points2[1], points2[0]];
41761
- const line2_2 = [points2[1], points2[2]];
41762
- const equalUnflipped =
41763
- // @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'. | TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'.
41764
- kmath.ray.equal(line1_0, line2_0) && kmath.ray.equal(line1_2, line2_2);
41765
- const equalFlipped =
41766
- // @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'. | TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'.
41767
- kmath.ray.equal(line1_0, line2_2) && kmath.ray.equal(line1_2, line2_0);
41768
- return equalUnflipped || equalFlipped;
41769
- },
41770
- defaultOptions: {
41771
- reflex: false
41772
- }
41773
- },
41774
- circle: {
41775
- equal: function (points1, points2) {
41776
- const radius1 = kmath.point.distanceToPoint(points1[0], points1[1]);
41777
- const radius2 = kmath.point.distanceToPoint(points2[0], points2[1]);
41778
- return kmath.point.equal(points1[0], points2[0]) && kmath.number.equal(radius1, radius2);
41779
- }
41780
- },
41781
- point: {
41782
- equal: kmath.point.equal
41783
- }
41784
- };
41785
- const TransformationListItem = TransformOps.ListItem;
41786
- class TransformationList extends React__namespace.Component {
41787
- render() {
41788
- if (this.props.mode === "static") {
41789
- return /*#__PURE__*/React__namespace.createElement("span", null); // don't render anything
41790
- }
41791
-
41792
- const transformationList = ___default["default"].map(this.props.transformations, function (transform, i) {
41793
- return /*#__PURE__*/React__namespace.createElement(TransformationListItem, {
41794
- ref: "transformation" + i,
41795
- key: "transformation" + i,
41796
- transform: transform
41797
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41798
- ,
41799
- mode: this.props.mode
41800
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41801
- ,
41802
- onChange: this.handleChange
41803
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41804
- ,
41805
- onFocus: ___default["default"].partial(this.props.onFocus, "" + i)
41806
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41807
- ,
41808
- onBlur: ___default["default"].partial(this.props.onBlur, "" + i)
41809
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41810
- ,
41811
- keypadElement: this.props.keypadElement
41812
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41813
- ,
41814
- apiOptions: this.props.apiOptions
41815
- });
41816
- }, this);
41817
- return /*#__PURE__*/React__namespace.createElement("div", {
41818
- className: "perseus-transformation-list"
41819
- }, transformationList);
41820
- }
41821
- _transformationRefs = () => {
41822
- return ___default["default"].times(this.props.transformations.length, i => {
41823
- // eslint-disable-next-line react/no-string-refs
41824
- return this.refs["transformation" + i];
41825
- });
41826
- };
41827
- value = () => {
41828
- return ___default["default"].invoke(this._transformationRefs(), "value");
41829
- };
41830
- handleChange = (changed, callback) => {
41831
- this.props.onChange(this.value(), callback);
41832
- };
41833
- focusLast = () => {
41834
- const transformationRefs = this._transformationRefs();
41835
- if (transformationRefs.length !== 0) {
41836
- // @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
41837
- ___default["default"].last(transformationRefs).focus();
41838
- }
41839
- };
41840
- }
41841
- class ToolButton extends React__namespace.Component {
41842
- render() {
41843
- const classes = this.props.toggled ? "simple-button exercise-orange toggled highlighted-tool-button" : "simple-button";
41844
- return /*#__PURE__*/React__namespace.createElement("button", {
41845
- type: "button",
41846
- className: classes,
41847
- disabled: this.props.disabled,
41848
- onClick: this.props.onClick
41849
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
41850
- ,
41851
- onTouchStart: captureScratchpadTouchStart
41852
- }, this.props.children);
41853
- }
41854
- }
41855
- class ToolsBar extends React__namespace.Component {
41856
- state = {
41857
- selected: null
41858
- };
41859
- render() {
41860
- const tools = ___default["default"].map(Transformations, function (tool, type) {
41861
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41862
- if (this.props.enabled[type]) {
41863
- return /*#__PURE__*/React__namespace.createElement(ToolButton, {
41864
- key: type
41865
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41866
- ,
41867
- disabled: this.props.apiOptions.readOnly
41868
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41869
- ,
41870
- toggled: this.state.selected === type
41871
- // eslint-disable-next-line react/jsx-no-bind
41872
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41873
- ,
41874
- onClick: this.changeSelected.bind(this, type)
41875
- }, tool.verbName);
41876
- }
41877
- }, this);
41878
- return /*#__PURE__*/React__namespace.createElement("div", {
41879
- className: "transformer-tools-bar"
41880
- }, /*#__PURE__*/React__namespace.createElement("span", {
41881
- className: "simple-button-group"
41882
- }, tools), /*#__PURE__*/React__namespace.createElement("button", {
41883
- className: "transformer-undo-button simple-button",
41884
- type: "button",
41885
- disabled: this.props.apiOptions.readOnly,
41886
- onClick: this.props.onUndoClick
41887
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
41888
- ,
41889
- onTouchStart: captureScratchpadTouchStart
41890
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconUndo), " " + i18n__namespace._("Undo")), /*#__PURE__*/React__namespace.createElement("div", {
41891
- className: "clear"
41892
- }));
41893
- }
41894
- changeSelected = tool => {
41895
- this.props.removeTool(this.state.selected);
41896
- if (!tool || tool === this.state.selected) {
41897
- this.setState({
41898
- selected: null
41899
- });
41900
- } else {
41901
- this.props.addTool(tool);
41902
- this.setState({
41903
- selected: tool
41904
- });
41905
- }
41906
- };
41907
- }
41908
- class AddTransformBar extends React__namespace.Component {
41909
- render() {
41910
- const tools = ___default["default"].map(Transformations, function (tool, type) {
41911
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41912
- if (this.props.enabled[type]) {
41913
- return /*#__PURE__*/React__namespace.createElement(ToolButton, {
41914
- key: type,
41915
- toggled: false
41916
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41917
- ,
41918
- disabled: this.props.apiOptions.readOnly
41919
- // eslint-disable-next-line react/jsx-no-bind
41920
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
41921
- ,
41922
- onClick: this.changeSelected.bind(this, type)
41923
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconPlus), " ", tool.nounName);
41924
- }
41925
- }, this);
41926
- return /*#__PURE__*/React__namespace.createElement("div", {
41927
- className: "transformer-tools-bar"
41928
- }, tools, /*#__PURE__*/React__namespace.createElement("button", {
41929
- className: "transformer-undo-button simple-button",
41930
- type: "button",
41931
- onClick: this.props.onUndoClick,
41932
- disabled: this.props.apiOptions.readOnly
41933
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
41934
- ,
41935
- onTouchStart: captureScratchpadTouchStart
41936
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconUndo), " " + i18n__namespace._("Undo")), /*#__PURE__*/React__namespace.createElement("div", {
41937
- className: "clear"
41938
- }));
41939
- }
41940
- changeSelected = tool => {
41941
- if (tool) {
41942
- this.props.addTool(tool);
41943
- }
41944
- };
41945
- }
41946
-
41947
- // there's no transform in the exports
41948
-
41949
- class Transformer extends React__namespace.Component {
41950
- // @ts-expect-error - TS2564 - Property 'tools' has no initializer and is not definitely assigned in the constructor.
41951
-
41952
- // @ts-expect-error - TS2564 - Property 'transformations' has no initializer and is not definitely assigned in the constructor.
41953
-
41954
- // This is not the same as TransformerShape
41955
-
41956
- static defaultProps = ___default["default"].defaults({
41957
- transformations: []
41958
- }, defaultTransformerProps);
41959
- render() {
41960
- // Fill in any missing value in this.props.graph
41961
- // this can happen because the graph json doesn't include
41962
- // box, for example
41963
- const graph = ___default["default"].extend(defaultGraphProps(this.props.graph, defaultBoxSize), this.props.graph);
41964
- const interactiveToolsMode = this.props.graphMode === "interactive";
41965
- const ToolsBarClass = interactiveToolsMode ? ToolsBar : AddTransformBar;
41966
-
41967
- // This style is applied inline because it is dependent on the
41968
- // size of the graph as set by the graph.box prop, and this also
41969
- // lets us specify it in the same place the graph's width is
41970
- // specified.
41971
- const toolsBar = /*#__PURE__*/React__namespace.createElement("div", {
41972
- style: {
41973
- width: graph.box[0]
41974
- }
41975
- }, /*#__PURE__*/React__namespace.createElement(ToolsBarClass
41976
- // eslint-disable-next-line react/no-string-refs
41977
- , {
41978
- ref: "toolsBar",
41979
- enabled: pluckObject(this.props.tools, "enabled"),
41980
- apiOptions: this.props.apiOptions,
41981
- addTool: this.addTool,
41982
- removeTool: this.removeTool,
41983
- onUndoClick: this.handleUndoClick
41984
- }));
41985
- return /*#__PURE__*/React__namespace.createElement("div", {
41986
- className: "perseus-widget " + "perseus-widget-transformer"
41987
- }, /*#__PURE__*/React__namespace.createElement(Graph
41988
- // eslint-disable-next-line react/no-string-refs
41989
- , {
41990
- ref: "graph",
41991
- box: graph.box,
41992
- range: graph.range,
41993
- labels: graph.labels,
41994
- step: graph.step,
41995
- gridStep: graph.gridStep,
41996
- markings: graph.markings,
41997
- backgroundImage: graph.backgroundImage,
41998
- showProtractor: graph.showProtractor,
41999
- onGraphieUpdated: this.setupGraphie,
42000
- setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable
42001
- }), !interactiveToolsMode && i18n__namespace._("Add transformations below:"), this.props.graphMode === "static" && [/*#__PURE__*/React__namespace.createElement("br", {
42002
- key: "static-br"
42003
- }), /*#__PURE__*/React__namespace.createElement("em", {
42004
- key: "static-nomove"
42005
- }, " ", i18n__namespace._("Note: For this question, the shape will not move."), " ")], interactiveToolsMode && toolsBar, /*#__PURE__*/React__namespace.createElement(TransformationList
42006
- // eslint-disable-next-line react/no-string-refs
42007
- , {
42008
- ref: "transformationList",
42009
- mode: this.props.listMode,
42010
- transformations: this.props.transformations,
42011
- onChange: this.setTransformationProps,
42012
- onFocus: this._handleFocus,
42013
- onBlur: this._handleBlur,
42014
- keypadElement: this.props.keypadElement,
42015
- apiOptions: this.props.apiOptions
42016
- }), !interactiveToolsMode && toolsBar);
42017
- }
42018
- componentDidMount() {
42019
- this.setupGraphie(this.graphie());
42020
- }
42021
- componentDidUpdate(prevProps) {
42022
- if (this.shouldSetupGraphie(this.props, prevProps)) {
42023
- // eslint-disable-next-line react/no-string-refs
42024
- // @ts-expect-error - TS2339 - Property 'reset' does not exist on type 'ReactInstance'.
42025
- this.refs.graph.reset();
42026
- } else if (!deepEq(this.props.transformations, this.transformations)) {
42027
- this.setTransformations(this.props.transformations);
42028
- }
42029
- }
42030
- shouldSetupGraphie = (nextProps, prevProps) => {
42031
- if (!deepEq(prevProps.starting, nextProps.starting)) {
42032
- return true;
42033
- }
42034
- if (prevProps.graphMode !== nextProps.graphMode) {
42035
- return true;
42036
- }
42037
- if (prevProps.listMode !== nextProps.listMode) {
42038
- return true;
42039
- }
42040
- if (prevProps.drawSolutionShape !== nextProps.drawSolutionShape) {
42041
- return true;
42042
- }
42043
- if (nextProps.drawSolutionShape && !deepEq(prevProps.correct.shape, nextProps.correct.shape)) {
42044
- return true;
42045
- }
42046
- if (!deepEq(this.tools, nextProps.tools)) {
42047
- return true;
42048
- }
42049
- return false;
42050
- };
42051
- graphie = () => {
42052
- // eslint-disable-next-line react/no-string-refs
42053
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
42054
- return this.refs.graph.graphie();
42055
- };
42056
- setupGraphie = graphie => {
42057
- // A background image of our solution:
42058
- if (this.props.drawSolutionShape && this.props.correct.shape && this.props.correct.shape.coords) {
42059
- // @ts-expect-error - TS2554 - Expected 3 arguments, but got 2.
42060
- ShapeTypes.addShape(graphie, {
42061
- fixed: true,
42062
- shape: this.props.correct.shape,
42063
- normalStyle: {
42064
- stroke: KhanColors.GRAY,
42065
- "stroke-dasharray": "",
42066
- "stroke-width": 2
42067
- }
42068
- });
42069
- }
42070
- this.currentTool = null;
42071
- // eslint-disable-next-line react/no-string-refs
42072
- // @ts-expect-error - TS2339 - Property 'changeSelected' does not exist on type 'ReactInstance'.
42073
- this.refs.toolsBar.changeSelected(null);
42074
- this.addTransformerShape(this.props.starting.shape, /* translatable */false);
42075
- this.setTransformations(this.props.transformations);
42076
-
42077
- // Save a copy of our tools so that we can check future
42078
- // this.props.tools changes against them
42079
- // This seems weird, but gives us an easy way to tell whether
42080
- // props changes were self-inflicted (for which a graphie reset
42081
- // is not required, and is in fact a bad idea right now because
42082
- // of resetting the size of the dilation tool).
42083
- // TODO (jack): A deepClone method would be nice here
42084
- this.tools = {
42085
- translation: ___default["default"].clone(this.props.tools.translation),
42086
- rotation: ___default["default"].clone(this.props.tools.rotation),
42087
- reflection: ___default["default"].clone(this.props.tools.reflection),
42088
- dilation: ___default["default"].clone(this.props.tools.dilation)
42089
- };
42090
- };
42091
-
42092
- /* Applies all transformations in `transformations`
42093
- * to the starting shape, and updates this.transformations
42094
- * to reflect this
42095
- *
42096
- * Usually called with this.props.transformations
42097
- */
42098
- setTransformations = transformations => {
42099
- this.resetCoords();
42100
- this.transformations = ___default["default"].clone(transformations);
42101
- ___default["default"].each(this.transformations, this.applyTransform);
42102
- };
42103
-
42104
- // the polygon that we transform
42105
- addTransformerShape = (shape, translatable) => {
42106
- const self = this;
42107
- const graphie = this.graphie();
42108
- this.shape = ShapeTypes.addMovableShape(graphie, {
42109
- shape: shape,
42110
- editable: false,
42111
- showPoints: this.props.graphMode !== "static",
42112
- translatable: translatable,
42113
- onMove: function (dX, dY) {
42114
- dX = KhanMath.roundToNearest(graphie.snap[0], dX);
42115
- dY = KhanMath.roundToNearest(graphie.snap[1], dY);
42116
- // NOTE(kevinb): object is missing .constraints property
42117
- // @ts-expect-error - TS2345 - Argument of type '{ type: "translation"; vector: [any, any]; }' is not assignable to parameter of type 'PerseusTransformerTransformation'.
42118
- self.addTransform({
42119
- type: "translation",
42120
- vector: [dX, dY]
42121
- });
42122
- return [dX, dY];
42123
- },
42124
- normalPointStyle: {
42125
- fill: translatable ? KhanColors.INTERACTIVE : KhanColors.DYNAMIC,
42126
- stroke: translatable ? KhanColors.INTERACTIVE : KhanColors.DYNAMIC
42127
- },
42128
- highlightPointStyle: {
42129
- fill: KhanColors.INTERACTING,
42130
- stroke: KhanColors.INTERACTING
42131
- }
42132
- });
42133
- };
42134
- addTool = toolId => {
42135
- const self = this;
42136
- if (this.props.graphMode === "interactive") {
42137
- if (toolId === "translation") {
42138
- this.currentTool = this.addTranslationTool();
42139
- } else if (toolId === "rotation") {
42140
- this.currentTool = this.addRotationTool();
42141
- } else if (toolId === "reflection") {
42142
- this.currentTool = this.addReflectionTool();
42143
- } else if (toolId === "dilation") {
42144
- this.currentTool = this.addDilationTool();
42145
- } else {
42146
- throw new PerseusError("Invalid tool id: " + toolId, Errors.InvalidInput);
42147
- }
42148
- } else {
42149
- let transform;
42150
- if (toolId === "translation") {
42151
- // NOTE(kevinb): object is missing .constraints property
42152
- transform = {
42153
- type: "translation",
42154
- // NOTE(kevib): these should be numbers
42155
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
42156
- vector: [null, null]
42157
- };
42158
- } else if (toolId === "rotation") {
42159
- // NOTE(kevinb): object is missing .constraints property
42160
- transform = {
42161
- type: "rotation",
42162
- // NOTE(kevib): these should be numbers
42163
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
42164
- center: [null, null],
42165
- // NOTE(kevib): this should be a number
42166
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'.
42167
- angleDeg: null
42168
- };
42169
- } else if (toolId === "reflection") {
42170
- // Reflections with nulls in them won't be applied until
42171
- // fills in the blanks
42172
- transform = {
42173
- type: "reflection",
42174
- line: [
42175
- // NOTE(kevib): these should be numbers
42176
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
42177
- [null, null],
42178
- // NOTE(kevib): these should be numbers
42179
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
42180
- [null, null]]
42181
- };
42182
- } else if (toolId === "dilation") {
42183
- // NOTE(kevinb): object is missing .constraints property
42184
- transform = {
42185
- type: "dilation",
42186
- // NOTE(kevib): these should be numbers
42187
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
42188
- center: [null, null],
42189
- // NOTE(kevib): this should be a number
42190
- // @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'.
42191
- scale: null
42192
- };
42193
- } else {
42194
- throw new PerseusError("Invalid tool id: " + toolId, Errors.InvalidInput);
42195
- }
42196
- this.doTransform(transform, function () {
42197
- // @ts-expect-error - TS2339 - Property 'focusLast' does not exist on type 'ReactInstance'.
42198
- self.refs.transformationList.focusLast();
42199
- });
42200
- }
42201
- };
42202
- removeTool = toolId => {
42203
- if (this.currentTool) {
42204
- this.currentTool.remove();
42205
- }
42206
- this.currentTool = null;
42207
- };
42208
- addTranslationTool = () => {
42209
- const self = this;
42210
- this.shape?.remove();
42211
- this.addTransformerShape(this.shape?.toJSON(), /* translatable */true);
42212
- return {
42213
- remove: function () {
42214
- self.shape?.remove();
42215
- self.addTransformerShape(self.shape?.toJSON(), /* translatable */false);
42216
- }
42217
- };
42218
- };
42219
-
42220
- // Snaps a coord to this.graphie()'s snap
42221
- // @ts-expect-error - TS2322 - Type '(coord: Coord) => number[]' is not assignable to type '(arg1: Coord) => Coord'.
42222
- snapCoord = coord => {
42223
- const graphie = this.graphie();
42224
- return ___default["default"].map(coord, function (val, dim) {
42225
- return KhanMath.roundToNearest(graphie.snap[dim], val);
42226
- });
42227
- };
42228
-
42229
- // Normalize the coords into something that fits the new 45 degree
42230
- // reflection line.
42231
- // @ts-expect-error - TS2322 - Type '(messyCoords: [Coord, Coord]) => any[]' is not assignable to type '(arg1: [Coord, Coord]) => [Coord, Coord]'.
42232
- normalizeReflectionCoords = messyCoords => {
42233
- // @ts-expect-error - TS2345 - Argument of type 'Point' is not assignable to parameter of type 'Coord'.
42234
- const midpoint = this.snapCoord(kmath.line.midpoint(messyCoords));
42235
- const origDirectionPolar = kmath.vector.polarDegFromCart(kmath.vector.subtract(messyCoords[0], messyCoords[1]));
42236
- const direction = kmath.vector.cartFromPolarDeg(1, KhanMath.roundToNearest(45, origDirectionPolar[1]));
42237
- const coords = ___default["default"].map([-1, 1], function (directionCoefficient) {
42238
- const coord = kmath.vector.add(midpoint, kmath.vector.scale(direction, directionCoefficient *
42239
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
42240
- this.scaleToCurrentRange(REFLECT_ROTATE_HANDLE_DIST)));
42241
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
42242
- return this.snapCoord(coord);
42243
- }, this);
42244
- return coords;
42245
- };
42246
- addReflectionTool = () => {
42247
- const options = this.props.tools.reflection;
42248
- if (!options.enabled) {
42249
- return;
42250
- }
42251
- const self = this;
42252
- // eslint-disable-next-line react/no-string-refs
42253
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
42254
- const graphie = this.refs.graph.graphie();
42255
- const updateReflectionTool = function () {
42256
- self.changeTool("reflection", {
42257
- coords: ___default["default"].pluck(reflectPoints, "coord")
42258
- });
42259
- };
42260
- const coords = this.normalizeReflectionCoords(options.coords);
42261
-
42262
- // The points defining the line of reflection; hidden from the
42263
- // user.
42264
- const reflectPoints = ___default["default"].map(coords, function (coord) {
42265
- return graphie.addMovablePoint({
42266
- coord: coord,
42267
- visible: false
42268
- });
42269
- }, this);
42270
-
42271
- // the line of reflection
42272
- // TODO(jack): graphie.style here is a hack to prevent the dashed
42273
- // style from leaking into the rest of the shapes. Remove when
42274
- // graphie.addMovableLineSegment doesn't leak styles anymore.
42275
- let reflectLine;
42276
- const normalColor = colorForTool(options);
42277
- graphie.style({}, function () {
42278
- reflectLine = graphie.addMovableLineSegment({
42279
- fixed: options.constraints.fixed,
42280
- constraints: options.constraints,
42281
- pointA: reflectPoints[0],
42282
- pointZ: reflectPoints[1],
42283
- snapX: graphie.snap[0],
42284
- snapY: graphie.snap[1],
42285
- extendLine: true,
42286
- normalStyle: {
42287
- stroke: normalColor,
42288
- "stroke-width": 2,
42289
- "stroke-dasharray": "- "
42290
- },
42291
- highlightStyle: {
42292
- stroke: KhanColors.INTERACTING,
42293
- "stroke-width": 2,
42294
- "stroke-dasharray": "- " // TODO(jack) solid doesn't
42295
- // work here, but would be
42296
- // nicer
42297
- },
42298
-
42299
- movePointsWithLine: true,
42300
- onMoveEnd: updateReflectionTool
42301
- });
42302
- });
42303
-
42304
- // the "button" point in the center of the line of reflection
42305
- const reflectButton = graphie.addReflectButton({
42306
- fixed: options.constraints.fixed,
42307
- line: reflectLine,
42308
- size: this.scaleToCurrentRange(REFLECT_BUTTON_SIZE),
42309
- onClick: function () {
42310
- self.doTransform({
42311
- type: "reflection",
42312
- // @ts-expect-error - TS2322 - Type 'any[]' is not assignable to type '[Coord, Coord]'.
42313
- line: ___default["default"].pluck(reflectPoints, "coord")
42314
- });
42315
- if (reflectRotateHandle) {
42316
- // flip the rotation handle
42317
- // @ts-expect-error - TS2339 - Property 'setCoord' does not exist on type 'never'.
42318
- reflectRotateHandle.setCoord(kmath.vector.add(reflectButton.coord, kmath.vector.subtract(reflectButton.coord,
42319
- // @ts-expect-error - TS2339 - Property 'coord' does not exist on type 'never'.
42320
- reflectRotateHandle.coord)));
42321
- // @ts-expect-error - TS2339 - Property 'update' does not exist on type 'never'.
42322
- reflectRotateHandle.update();
42323
- }
42324
- },
42325
- normalStyle: {
42326
- stroke: normalColor,
42327
- "stroke-width": 2,
42328
- fill: normalColor
42329
- },
42330
- highlightStyle: {
42331
- stroke: KhanColors.INTERACTING,
42332
- "stroke-width": 3,
42333
- fill: KhanColors.INTERACTING
42334
- },
42335
- onMoveEnd: updateReflectionTool
42336
- });
42337
- let reflectRotateHandle = null;
42338
- if (!options.constraints.fixed) {
42339
- // The rotation handle for rotating the line of reflection
42340
- const initRotateHandleAngle = kmath.vector.polarDegFromCart(kmath.vector.subtract(reflectPoints[1].coord, reflectPoints[0].coord))[1] + 90; // 90 degrees off of the line
42341
- reflectRotateHandle = graphie.addRotateHandle({
42342
- center: reflectButton,
42343
- radius: this.scaleToCurrentRange(REFLECT_ROTATE_HANDLE_DIST),
42344
- angleDeg: initRotateHandleAngle,
42345
- width: this.scaleToCurrentRange(0.24),
42346
- hoverWidth: this.scaleToCurrentRange(0.4),
42347
- lengthAngle: 17,
42348
- onMove: function (newAngle) {
42349
- return KhanMath.roundToNearest(45, newAngle);
42350
- },
42351
- onMoveEnd: updateReflectionTool
42352
- });
42353
- }
42354
-
42355
- // Move the reflectButton and reflectRotateHandle with the line
42356
- $__default["default"](reflectLine).on("move", function () {
42357
- reflectButton.update();
42358
- $__default["default"](reflectButton).trigger("move"); // update the rotation handle,
42359
- // which watches for this in util/interactive.js.
42360
- });
42361
-
42362
- // Update the line and reflect button when the reflectRotateHandle is
42363
- // rotated
42364
- if (reflectRotateHandle) {
42365
- $__default["default"](reflectRotateHandle).on("move", function () {
42366
- const rotateHandleApprox = self.snapCoord(
42367
- // @ts-expect-error - TS2531 - Object is possibly 'null'.
42368
- reflectRotateHandle.coord);
42369
- const rotateVector = kmath.vector.subtract(rotateHandleApprox, reflectButton.coord);
42370
- const flipped = reflectButton.isFlipped() ? 1 : 0;
42371
- reflectPoints[flipped].setCoord(kmath.vector.add(reflectButton.coord, kmath.vector.rotateDeg(rotateVector, 90)));
42372
- reflectPoints[1 - flipped].setCoord(kmath.vector.add(reflectButton.coord, kmath.vector.rotateDeg(rotateVector, -90)));
42373
- reflectLine.transform(true);
42374
- reflectButton.update();
42375
- });
42376
- }
42377
- return {
42378
- remove: function () {
42379
- reflectButton.remove();
42380
- if (reflectRotateHandle) {
42381
- // @ts-expect-error - TS2339 - Property 'remove' does not exist on type 'never'.
42382
- reflectRotateHandle.remove();
42383
- }
42384
- reflectLine.remove();
42385
- reflectPoints[0].remove();
42386
- reflectPoints[1].remove();
42387
- }
42388
- };
42389
- };
42390
-
42391
- /* Scales a distance from the default range of
42392
- * [-10, 10] to the current this.props.graph.range
42393
- *
42394
- * Used for sizing various transformation tools
42395
- * (rotation handle, dilation circle)
42396
- */
42397
- scaleToCurrentRange = dist => {
42398
- // eslint-disable-next-line react/no-string-refs
42399
- // @ts-expect-error - TS2339 - Property 'props' does not exist on type 'ReactInstance'.
42400
- return scaleToRange(dist, this.refs.graph.props.range);
42401
- };
42402
- addRotationTool = () => {
42403
- const options = this.props.tools.rotation;
42404
- if (!options.enabled) {
42405
- return;
42406
- }
42407
- const self = this;
42408
- // eslint-disable-next-line react/no-string-refs
42409
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
42410
- const graphie = this.refs.graph.graphie();
42411
- const pointColor = colorForTool(options);
42412
- // The center of our rotation, which can be moved to change the
42413
- // center of rotation
42414
- this.rotatePoint = graphie.addMovablePoint({
42415
- constraints: options.constraints,
42416
- coord: options.coord,
42417
- snapX: graphie.snap[0],
42418
- snapY: graphie.snap[1],
42419
- normalStyle: {
42420
- // ugh, this seems to be a global and
42421
- "stroke-dasharray": "",
42422
- // is set to dash above
42423
- stroke: pointColor,
42424
- fill: pointColor
42425
- },
42426
- highlightStyle: {
42427
- "stroke-dasharray": "",
42428
- stroke: KhanColors.INTERACTING,
42429
- fill: KhanColors.INTERACTING
42430
- }
42431
- });
42432
-
42433
- // The point that we move around the center of rotation to actually
42434
- // cause rotations
42435
- this.rotateHandle = graphie.addRotateHandle({
42436
- center: this.rotatePoint,
42437
- radius: this.scaleToCurrentRange(ROTATE_HANDLE_DIST),
42438
- width: this.scaleToCurrentRange(0.24),
42439
- hoverWidth: this.scaleToCurrentRange(0.4),
42440
- onMove: function (newAngle, oldAngle) {
42441
- const transform = self.getRotationTransformFromAngle(self.rotatePoint.coord, newAngle - oldAngle);
42442
-
42443
- // Rotate polygon with rotateHandle
42444
- self.doTransform(transform);
42445
-
42446
- // @ts-expect-error - TS2339 - Property 'angleDeg' does not exist on type 'PerseusTransformerTransformation'.
42447
- return oldAngle + transform.angleDeg;
42448
- }
42449
- });
42450
-
42451
- // Update tools.rotation.coord
42452
- this.rotatePoint.onMoveEnd = (x, y) => {
42453
- self.changeTool("rotation", {
42454
- coord: [x, y]
42455
- });
42456
- };
42457
- return {
42458
- remove: function () {
42459
- self.rotateHandle?.remove();
42460
- self.rotatePoint?.remove();
42461
- }
42462
- };
42463
- };
42464
- addDilationTool = () => {
42465
- const options = this.props.tools.dilation;
42466
- if (!options.enabled) {
42467
- return;
42468
- }
42469
- const self = this;
42470
- // eslint-disable-next-line react/no-string-refs
42471
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
42472
- const graphie = this.refs.graph.graphie();
42473
- const pointColor = colorForTool(options);
42474
- // the circle for causing dilation transforms
42475
- self.dilationCircle = graphie.addCircleGraph({
42476
- centerConstraints: options.constraints,
42477
- center: options.coord,
42478
- radius: self.scaleToCurrentRange(2),
42479
- snapX: graphie.snap[0],
42480
- snapY: graphie.snap[1],
42481
- minRadius: self.scaleToCurrentRange(1),
42482
- snapRadius: self.scaleToCurrentRange(0.5),
42483
- onResize: function (newRadius, oldRadius) {
42484
- // NOTE(kevinb): object is missing .constraints property
42485
- // @ts-expect-error - TS2345 - Argument of type '{ type: "dilation"; center: any; scale: number; }' is not assignable to parameter of type 'PerseusTransformerTransformation'.
42486
- self.doTransform({
42487
- type: "dilation",
42488
- center: self.dilationCircle.centerPoint.coord,
42489
- scale: newRadius / oldRadius
42490
- });
42491
- },
42492
- circleNormalStyle: {
42493
- stroke: pointColor,
42494
- "stroke-width": 2,
42495
- "stroke-dasharray": "- ",
42496
- "fill-opacity": 0
42497
- },
42498
- circleHighlightStyle: {
42499
- stroke: KhanColors.INTERACTING,
42500
- "stroke-width": 2,
42501
- "stroke-dasharray": "",
42502
- fill: KhanColors.INTERACTING,
42503
- "fill-opacity": 0.05
42504
- },
42505
- centerNormalStyle: {
42506
- stroke: pointColor,
42507
- fill: pointColor,
42508
- "stroke-width": 2,
42509
- "stroke-dasharray": ""
42510
- },
42511
- centerHighlightStyle: {
42512
- stroke: pointColor,
42513
- fill: pointColor,
42514
- "stroke-width": 2,
42515
- "stroke-dasharray": ""
42516
- }
42517
- });
42518
- const origOnMoveEnd = this.dilationCircle.centerPoint.onMoveEnd;
42519
- this.dilationCircle.centerPoint.onMoveEnd = function () {
42520
- if (origOnMoveEnd) {
42521
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
42522
- args[_key] = arguments[_key];
42523
- }
42524
- origOnMoveEnd(args);
42525
- }
42526
- self.changeTool("dilation", {
42527
- coord: self.dilationCircle.centerPoint.coord
42528
- });
42529
- };
42530
- return {
42531
- remove: function () {
42532
- self.dilationCircle?.remove();
42533
- }
42534
- };
42535
- };
42536
-
42537
- // returns a transformation object representing a rotation
42538
- // rounds the angle to the nearest 15 degrees
42539
- // @ts-expect-error - TS2322 - Type '(center: Coord, angleChanged: number) => { type: "rotation"; center: Coord; angleDeg: number; }' is not assignable to type '(arg1: Coord, arg2: number) => PerseusTransformerTransformation'.
42540
- getRotationTransformFromAngle = (center, angleChanged) => {
42541
- angleChanged = (angleChanged + 360) % 360;
42542
- if (angleChanged > 180) {
42543
- angleChanged -= 360;
42544
- }
42545
- const roundedAngle = Math.round(angleChanged / ROTATE_SNAP_DEGREES) * ROTATE_SNAP_DEGREES;
42546
-
42547
- // NOTE(kevinb): return object is missing .constraints property
42548
- return {
42549
- type: "rotation",
42550
- center: center,
42551
- angleDeg: roundedAngle
42552
- };
42553
- };
42554
-
42555
- // apply and save a transform
42556
- doTransform = (transform, callback) => {
42557
- this.applyTransform(transform);
42558
- this.addTransform(transform, callback);
42559
- };
42560
-
42561
- // apply a transform to our polygon (without modifying our transformation
42562
- // list)
42563
- applyTransform = transform => {
42564
- if (this.props.graphMode !== "static") {
42565
- const transformFunc = TransformOps.apply(transform);
42566
- // @ts-expect-error - TS2345 - Argument of type '(coord: any) => any' is not assignable to parameter of type 'PerseusTransformerTransformation'.
42567
- this.applyCoordTransformation(transformFunc);
42568
- }
42569
- };
42570
-
42571
- // transform our polygon by transforming each point using a given function
42572
- applyCoordTransformation = pointTransform => {
42573
- ___default["default"].each(this.shape.points, function (point) {
42574
- // @ts-expect-error - TS2349 - This expression is not callable.
42575
- const newCoord = pointTransform(point.coord);
42576
- point.setCoord(newCoord);
42577
- });
42578
- this.shape?.update();
42579
- };
42580
- resetCoords = () => {
42581
- const startCoords = this.props.starting.shape.coords;
42582
- ___default["default"].each(this.shape.points, function (point, i) {
42583
- point.setCoord(startCoords[i]);
42584
- });
42585
- this.shape?.update();
42586
- };
42587
-
42588
- // Remove the last transformation
42589
- handleUndoClick = () => {
42590
- // eslint-disable-next-line react/no-string-refs
42591
- // @ts-expect-error - TS2339 - Property 'changeSelected' does not exist on type 'ReactInstance'.
42592
- this.refs.toolsBar.changeSelected(null);
42593
- if (this.props.transformations.length) {
42594
- this.props.onChange({
42595
- transformations: ___default["default"].initial(this.props.transformations)
42596
- });
42597
- }
42598
- };
42599
- setTransformationProps = (newTransfomationList, callback) => {
42600
- this.props.onChange({
42601
- transformations: newTransfomationList
42602
- },
42603
- // @ts-expect-error - TS2345 - Argument of type '(arg1: any) => unknown' is not assignable to parameter of type '() => unknown'.
42604
- callback);
42605
- };
42606
-
42607
- // add a transformation to our props list of transformation
42608
- addTransform = (transform, callback) => {
42609
- this.transformations = TransformOps.append(this.transformations, transform);
42610
- this.props.onChange({
42611
- transformations: ___default["default"].clone(this.transformations)
42612
- },
42613
- // @ts-expect-error - TS2345 - Argument of type '((arg1: any) => unknown) | undefined' is not assignable to parameter of type '(() => unknown) | undefined'.
42614
- callback);
42615
- };
42616
- changeTool = (tool, changes) => {
42617
- const newTools = ___default["default"].clone(this.props.tools);
42618
- newTools[tool] = ___default["default"].extend({}, this.props.tools[tool], changes);
42619
- this.tools[tool] = ___default["default"].clone(newTools[tool]);
42620
- this.props.onChange({
42621
- // @ts-expect-error - TS2740 - Type '{ dilation: DilationTool; reflection: ReflectionTool; rotation: RotationTool; translation: TranslationTool; }' is missing the following properties from type 'readonly any[]': length, concat, join, slice, and 18 more.
42622
- tools: newTools
42623
- });
42624
- this.props.trackInteraction();
42625
- };
42626
- simpleValidate = rubric => {
42627
- return Transformer.validate(this.getUserInput(), rubric);
42628
- };
42629
-
42630
- /**
42631
- * Calculate where the coordinates would be if they were
42632
- * moved, even if we're in formal mode with no movement
42633
- * (and thus the actual movablepoints may not have moved
42634
- */
42635
- // @ts-expect-error - TS2322 - Type '() => [Coord, Coord] | readonly Coord[] | [Coord, Coord, Coord]' is not assignable to type '() => Coord'.
42636
- getCoords = () => {
42637
- const startCoords = this.props.starting.shape.coords;
42638
- const transforms = this.props.transformations;
42639
- return ___default["default"].reduce(transforms, function (coords, transform) {
42640
- return ___default["default"].map(coords, TransformOps.apply(transform));
42641
- }, startCoords);
42642
- };
42643
- getEditorJSON = () => {
42644
- const json = ___default["default"].pick(this.props, "grading", "starting", "graphMode", "listMode", "tools", "drawSolutionShape", "gradeEmpty");
42645
- // eslint-disable-next-line react/no-string-refs
42646
- // @ts-expect-error - TS2339 - Property 'graph' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'. | TS2339 - Property 'toJSON' does not exist on type 'ReactInstance'.
42647
- json.graph = this.refs.graph.toJSON();
42648
- // @ts-expect-error - TS2339 - Property 'version' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'.
42649
- json.version = 1.2; // Give us some safety to change the format
42650
- // when we realize that I wrote
42651
- // a horrible json spec for this widget
42652
-
42653
- // @ts-expect-error - TS2339 - Property 'answer' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'.
42654
- json.answer = this.getUserInput();
42655
- return json;
42656
- };
42657
- getUserInput = () => {
42658
- return {
42659
- transformations: this.props.transformations,
42660
- // This doesn't call this.shape.toJSON() because that doesn't
42661
- // handle coordinates in formal mode without movement, since
42662
- // the movablepoints never move
42663
- shape: {
42664
- type: this.shape.type,
42665
- coords: this.getCoords(),
42666
- options: this.shape?.getOptions()
42667
- }
42668
- };
42669
- };
42670
-
42671
- /* InputPath API */
42672
-
42673
- _handleFocus = (() => {
42674
- var _this = this;
42675
- return function () {
42676
- for (var _len2 = arguments.length, path = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
42677
- path[_key2] = arguments[_key2];
42678
- }
42679
- _this.props.onFocus(path);
42680
- };
42681
- })();
42682
- _handleBlur = (() => {
42683
- var _this2 = this;
42684
- return function () {
42685
- for (var _len3 = arguments.length, path = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
42686
- path[_key3] = arguments[_key3];
42687
- }
42688
- _this2.props.onBlur(path);
42689
- };
42690
- })();
42691
- _getTransformationForID = transformationID => {
42692
- // Returns the 'transformation' component corresponding to a given ID
42693
- const refPath = ["transformationList", "transformation" + transformationID];
42694
-
42695
- // Follow the path of references
42696
- let component = this;
42697
- ___default["default"].each(refPath, ref => {
42698
- // @ts-expect-error - TS2322 - Type 'ReactInstance' is not assignable to type 'this'.
42699
- component = component.refs[ref];
42700
- });
42701
- return component;
42702
- };
42703
- getInputPaths = () => {
42704
- // If we're in static mode, then there is no transformation list, and,
42705
- // as a result, no input paths.
42706
- if (this.props.listMode === "static") {
42707
- return [];
42708
- }
42709
- let inputPaths = [];
42710
- ___default["default"].each(this.props.transformations, (transformation, i) => {
42711
- // @ts-expect-error - TS2345 - Argument of type 'number' is not assignable to parameter of type 'string'.
42712
- transformation = this._getTransformationForID(i);
42713
- // @ts-expect-error - TS2339 - Property 'getInputPaths' does not exist on type 'PerseusTransformerTransformation'.
42714
- const innerPaths = transformation.getInputPaths();
42715
- const fullPaths = ___default["default"].map(innerPaths, innerPath => {
42716
- return ["" + i].concat(innerPath);
42717
- });
42718
- // @ts-expect-error - TS2345 - Argument of type 'string[][]' is not assignable to parameter of type 'ConcatArray<never>'.
42719
- inputPaths = inputPaths.concat(fullPaths);
42720
- });
42721
- return inputPaths;
42722
- };
42723
- _passToInner = function (functionName, path) {
42724
- if (!path || !path.length) {
42725
- return;
42726
- }
42727
-
42728
- // First argument tells us which transformation will receive the call;
42729
- // remaining arguments are used within that transformation to identify
42730
- // a specific input.
42731
- const innerPath = ___default["default"].rest(path);
42732
-
42733
- // Pass arguments down to appropriate 'transformation' component
42734
- const transformationID = ___default["default"].head(path);
42735
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
42736
- const caller = this._getTransformationForID(transformationID);
42737
- for (var _len4 = arguments.length, args = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
42738
- args[_key4 - 2] = arguments[_key4];
42739
- }
42740
- return caller[functionName](innerPath, ...args);
42741
- };
42742
- focus = () => {
42743
- // Just focus the first showing input
42744
- const inputs = this.getInputPaths();
42745
- if (inputs.length > 0) {
42746
- this.focusInputPath(inputs[0]);
42747
- return true;
42748
- }
42749
- return false;
42750
- };
42751
- focusInputPath = path => {
42752
- // Since the transformer exposes the input API, it needs to be robust
42753
- // to empty paths. We don't expect this to happen, as entire-widget
42754
- // focusing is typically done through the focus() method, which already
42755
- // handles the empty path case properly, but it's better to be safe
42756
- // here.
42757
- if (path.length === 0) {
42758
- return false;
42759
- }
42760
- assert(path.length >= 2);
42761
- return this._passToInner("focusInputPath", path);
42762
- };
42763
- blurInputPath = path => {
42764
- // Since the transformer exposes the input API, it needs to be robust
42765
- // to empty paths (which indicate a blurring of the entire widget,
42766
- // e.g., when switching from interacting with the transformer to
42767
- // interacting with some other widget).
42768
- if (path.length === 0) {
42769
- return false;
42770
- }
42771
- assert(path.length >= 2);
42772
- return this._passToInner("blurInputPath", path);
42773
- };
42774
- setInputValue = (path, value, cb) => {
42775
- assert(path.length >= 2);
42776
- return this._passToInner("setInputValue", path, value, cb);
42777
- };
42778
- getDOMNodeForPath = path => {
42779
- assert(path.length >= 2);
42780
- return this._passToInner("getDOMNodeForPath", path);
42781
- };
42782
- getGrammarTypeForPath = path => {
42783
- assert(path.length >= 2);
42784
- return this._passToInner("getGrammarTypeForPath", path);
42785
- };
42786
- static validate(guess, rubric) {
42787
- // Check for any required transformations
42788
- for (const type in Transformations) {
42789
- if (rubric.tools[type].required) {
42790
- const isUsed = ___default["default"].any(___default["default"].map(guess.transformations, function (transform) {
42791
- // Required transformations must appear in the
42792
- // transformation list, and must not be no-ops
42793
- return transform.type === type && !TransformOps.isEmpty(transform) && !TransformOps.isNoOp(transform);
42794
- }));
42795
- if (!isUsed) {
42796
- return {
42797
- type: "invalid",
42798
- message: i18n__namespace._("Your transformation must use a " + "%(type)s.", {
42799
- type: Transformations[type].lowerNounName
42800
- })
42801
- };
42802
- }
42803
- }
42804
- }
42805
-
42806
- // Compare shapes
42807
- if (ShapeTypes.equal(guess.shape, rubric.correct.shape)) {
42808
- return {
42809
- type: "points",
42810
- earned: 1,
42811
- total: 1,
42812
- message: null
42813
- };
42814
- }
42815
- if (!rubric.gradeEmpty && deepEq(guess.shape.coords, rubric.starting.shape.coords)) {
42816
- return {
42817
- type: "invalid",
42818
- message: i18n__namespace._("Use the interactive graph to define a " + "correct transformation.")
42819
- };
42820
- }
42821
- return {
42822
- type: "points",
42823
- earned: 0,
42824
- total: 1,
42825
- message: null
42826
- };
42827
- }
42828
- }
42829
- var Transformer$1 = {
42830
- name: "transformer",
42831
- displayName: "Transformer (deprecated)",
42832
- hidden: true,
42833
- widget: Transformer
42834
- };
42835
-
42836
40421
  var hubble = {exports: {}};
42837
40422
 
42838
40423
  (function (module, exports) {
@@ -44058,7 +41643,7 @@ var Video$1 = {
44058
41643
  };
44059
41644
 
44060
41645
  /* eslint-disable import/no-named-as-default */
44061
- var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Transformer$1, Unit, Video$1, DeprecatedStandin$1];
41646
+ var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Unit, Video$1, DeprecatedStandin$1];
44062
41647
 
44063
41648
  /**
44064
41649
  * This should be called by all clients, specifying whether extra widgets are
@@ -44102,7 +41687,7 @@ const init = function (options) {
44102
41687
 
44103
41688
  // This file is processed by a Rollup plugin (replace) to inject the production
44104
41689
  const libName = "@khanacademy/perseus";
44105
- const libVersion = "18.0.1";
41690
+ const libVersion = "19.0.0";
44106
41691
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
44107
41692
 
44108
41693
  const apiVersion = {
@@ -45547,8 +43132,6 @@ const ItemExtras = [
45547
43132
 
45548
43133
  // prettier-ignore
45549
43134
 
45550
- // prettier-ignore
45551
-
45552
43135
  //prettier-ignore
45553
43136
 
45554
43137
  // A background image applied to various widgets.
@@ -46673,10 +44256,7 @@ function violatingWidgets(itemData) {
46673
44256
  */
46674
44257
  const registerAllWidgetsForTesting = () => {
46675
44258
  registerWidgets(allWidgets);
46676
-
46677
- // When it's time to replace the transformer widget
46678
- // uncomment this line
46679
- // Widgets.replaceWidget("transformer", "deprecated-standin");
44259
+ replaceWidget("transformer", "deprecated-standin");
46680
44260
  };
46681
44261
 
46682
44262
  /**
@@ -47136,7 +44716,6 @@ exports.Renderer = Renderer;
47136
44716
  exports.ServerItemRenderer = ref;
47137
44717
  exports.SizingUtils = sizingUtils;
47138
44718
  exports.TableWidget = Table$1;
47139
- exports.TransformerWidget = Transformer$1;
47140
44719
  exports.Util = Util;
47141
44720
  exports.WIDGET_PROP_DENYLIST = denylist;
47142
44721
  exports.WidgetJsonifyDeprecated = WidgetJsonifyDeprecated;