@khanacademy/perseus 19.1.4 → 19.1.5

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
@@ -3999,10 +3999,10 @@ class FixedToResponsive extends React__namespace.Component {
3999
3999
 
4000
4000
  /* Local helper methods. */
4001
4001
 
4002
- function getKey(eventName, id) {
4002
+ function getKey$1(eventName, id) {
4003
4003
  return eventName + ":" + id;
4004
4004
  }
4005
- function getEventName(key) {
4005
+ function getEventName$1(key) {
4006
4006
  return key.split(":")[0];
4007
4007
  }
4008
4008
  const MovableHelperMethods = {
@@ -4083,7 +4083,7 @@ const MovableHelperMethods = {
4083
4083
 
4084
4084
  // If there's an existing handler, replace it by using its index in
4085
4085
  // `this.state[eventName]`; otherwise, add this handler to the end
4086
- const key = getKey(eventName, id);
4086
+ const key = getKey$1(eventName, id);
4087
4087
  const index = this._listenerMap[key] = this._listenerMap[key] || this.state[eventName].length;
4088
4088
  this.state[eventName][index] = func;
4089
4089
  },
@@ -4095,7 +4095,7 @@ const MovableHelperMethods = {
4095
4095
  */
4096
4096
  unlisten: function (eventName, id) {
4097
4097
  this._listenerMap = this._listenerMap || {};
4098
- const key = getKey(eventName, id);
4098
+ const key = getKey$1(eventName, id);
4099
4099
  const index = this._listenerMap[key];
4100
4100
  if (index !== undefined) {
4101
4101
  // Remove handler from list of event handlers and listenerMap
@@ -4105,7 +4105,7 @@ const MovableHelperMethods = {
4105
4105
  // Re-index existing events: if they occur after `index`, decrement
4106
4106
  const keys = ___default["default"].keys(this._listenerMap);
4107
4107
  ___default["default"].each(keys, function (key) {
4108
- if (getEventName(key) === eventName &&
4108
+ if (getEventName$1(key) === eventName &&
4109
4109
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
4110
4110
  this._listenerMap[key] > index) {
4111
4111
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
@@ -8707,6 +8707,9 @@ class Graphie$1 {
8707
8707
  // TODO(benchristel): xpixels and ypixels are never used by this class, but
8708
8708
  // other code reaches in to access them :(
8709
8709
  // Refactor to accessor methods that look at this.dimensions.
8710
+ // set by Movables
8711
+ // TODO(benchristel): consider putting this state on the Movable instead of
8712
+ // on the Graphie
8710
8713
  constructor(el) {
8711
8714
  this.el = el;
8712
8715
  $__default["default"](el).css("position", "relative");
@@ -9538,6 +9541,11 @@ class Graphie$1 {
9538
9541
  });
9539
9542
  return processed;
9540
9543
  }
9544
+
9545
+ // This is a stub that's overridden in interactive.ts
9546
+ getMouseCoord(event) {
9547
+ throw new Error("getMouseCoord is a stub, and is not implemented");
9548
+ }
9541
9549
  }
9542
9550
  const labelDirections = {
9543
9551
  center: [-0.5, -0.5],
@@ -13746,8 +13754,7 @@ var GraphieClasses = {
13746
13754
  const normalizeOptions$3 = InteractiveUtil.normalizeOptions;
13747
13755
  const assert$8 = InteractiveUtil.assert;
13748
13756
 
13749
- // Default "props" and "state". Both are added to this.state and
13750
- // receive magic getter methods (this.isHovering() etc).
13757
+ // Default "props" and "state". Both are added to this.state.
13751
13758
  // However, properties in DEFAULT_PROPS are updated on `modify()`,
13752
13759
  // while those in DEFAULT_STATE persist and are not updated.
13753
13760
  // Things that the user might want to change should be on "props",
@@ -13762,29 +13769,26 @@ const DEFAULT_STATE$3 = {
13762
13769
  isDragging: false,
13763
13770
  mouseTarget: null
13764
13771
  };
13765
- const Movable = function (graphie, options) {
13766
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
13767
- ___default["default"].extend(this, {
13768
- graphie,
13769
- state: {
13770
- // Set here because this must be unique for each instance
13772
+ class Movable {
13773
+ // TODO(benchristel): delete _listenerMap; it's unused
13774
+ _listenerMap = {};
13775
+ constructor(graphie, options) {
13776
+ this.graphie = graphie;
13777
+ this.state = {
13771
13778
  id: ___default["default"].uniqueId("movable")
13772
- }
13773
- });
13774
-
13775
- // We only set DEFAULT_STATE once, here
13776
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
13777
- this.modify(___default["default"].extend({}, DEFAULT_STATE$3, options));
13778
- };
13779
- InteractiveUtil.createGettersFor(Movable, ___default["default"].extend({}, DEFAULT_PROPS$3, DEFAULT_STATE$3));
13780
- InteractiveUtil.addMovableHelperMethodsTo(Movable);
13781
- ___default["default"].extend(Movable.prototype, {
13782
- cloneState: function () {
13783
- return {
13784
- ...this.state
13785
13779
  };
13786
- },
13787
- _createDefaultState: function () {
13780
+ this.modify({
13781
+ ...DEFAULT_STATE$3,
13782
+ ...options
13783
+ });
13784
+ }
13785
+ modify(options) {
13786
+ this.update({
13787
+ ...this._createDefaultState(),
13788
+ ...options
13789
+ });
13790
+ }
13791
+ _createDefaultState() {
13788
13792
  return {
13789
13793
  id: this.state.id,
13790
13794
  add: [],
@@ -13799,66 +13803,11 @@ ___default["default"].extend(Movable.prototype, {
13799
13803
  // be persistent, and updated appropriately in modify()
13800
13804
  ...DEFAULT_PROPS$3
13801
13805
  };
13802
- },
13803
- /**
13804
- * Resets the object to its state as if it were constructed with
13805
- * `options` originally. The only state maintained is `state.id`
13806
- *
13807
- * Analogous to React.js's replaceProps
13808
- */
13809
- modify: function (options) {
13810
- this.update({
13811
- ...this._createDefaultState(),
13812
- ...options
13813
- });
13814
- },
13815
- /**
13816
- * Simulates a mouse grab event on the movable object.
13817
- */
13818
- grab: function (coord) {
13819
- assert$8(kmath.point.is(coord));
13820
- const self = this;
13821
- const graphie = self.graphie;
13822
- const state = self.state;
13823
- state.isHovering = true;
13824
- state.isDragging = true;
13825
- graphie.isDragging = true;
13826
- const startMouseCoord = coord;
13827
- let prevMouseCoord = startMouseCoord;
13828
- self._fireEvent(state.onMoveStart, startMouseCoord, startMouseCoord);
13829
- const moveHandler = function (e) {
13830
- e.preventDefault();
13831
- const mouseCoord = graphie.getMouseCoord(e);
13832
- self._fireEvent(state.onMove, mouseCoord, prevMouseCoord);
13833
- self.draw();
13834
- prevMouseCoord = mouseCoord;
13835
- };
13836
- const upHandler = function (e) {
13837
- $__default["default"](document).unbind("vmousemove", moveHandler);
13838
- $__default["default"](document).unbind("vmouseup", upHandler);
13839
- if (state.isHovering) {
13840
- self._fireEvent(state.onClick, prevMouseCoord, startMouseCoord);
13841
- }
13842
- state.isHovering = self.state.isMouseOver;
13843
- state.isDragging = false;
13844
- graphie.isDragging = false;
13845
- self._fireEvent(state.onMoveEnd, prevMouseCoord, startMouseCoord);
13846
- self.draw();
13847
- };
13848
- $__default["default"](document).bind("vmousemove", moveHandler);
13849
- $__default["default"](document).bind("vmouseup", upHandler);
13850
- },
13851
- /**
13852
- * Adjusts constructor parameters without changing previous settings
13853
- * for any option not specified
13854
- *
13855
- * Analogous to React.js's setProps
13856
- */
13857
- update: function (options) {
13858
- const self = this;
13859
- const graphie = self.graphie;
13860
- const prevState = self.cloneState();
13861
- const state = ___default["default"].extend(self.state, normalizeOptions$3(options));
13806
+ }
13807
+ update(options) {
13808
+ const graphie = this.graphie;
13809
+ const prevState = this.cloneState();
13810
+ const state = Object.assign(this.state, normalizeOptions$3(options));
13862
13811
 
13863
13812
  // the invisible shape in front of the point that gets mouse events
13864
13813
  if (state.mouseTarget && !prevState.mouseTarget) {
@@ -13870,24 +13819,24 @@ ___default["default"].extend(Movable.prototype, {
13870
13819
  }
13871
13820
  const isMouse = !("ontouchstart" in window);
13872
13821
  if (isMouse) {
13873
- $mouseTarget.on("vmouseover", function () {
13822
+ $mouseTarget.on("vmouseover", () => {
13874
13823
  state.isMouseOver = true;
13875
13824
  if (!graphie.isDragging) {
13876
13825
  state.isHovering = true;
13877
13826
  }
13878
- if (self.state.added) {
13827
+ if (this.state.added) {
13879
13828
  // Avoid drawing if the point has been removed
13880
- self.draw();
13829
+ this.draw();
13881
13830
  }
13882
13831
  });
13883
- $mouseTarget.on("vmouseout", function () {
13832
+ $mouseTarget.on("vmouseout", () => {
13884
13833
  state.isMouseOver = false;
13885
13834
  if (!state.isDragging) {
13886
13835
  state.isHovering = false;
13887
13836
  }
13888
- if (self.state.added) {
13837
+ if (this.state.added) {
13889
13838
  // Avoid drawing if the point has been removed
13890
- self.draw();
13839
+ this.draw();
13891
13840
  }
13892
13841
  });
13893
13842
  }
@@ -13899,13 +13848,13 @@ ___default["default"].extend(Movable.prototype, {
13899
13848
  }, {
13900
13849
  passive: false
13901
13850
  });
13902
- $mouseTarget.on("vmousedown", function (e) {
13851
+ $mouseTarget.on("vmousedown", e => {
13903
13852
  if (e.which !== 0 && e.which !== 1) {
13904
13853
  return;
13905
13854
  }
13906
13855
  e.preventDefault();
13907
13856
  const mouseCoord = graphie.getMouseCoord(e);
13908
- self.grab(mouseCoord);
13857
+ this.grab(mouseCoord);
13909
13858
  });
13910
13859
  }
13911
13860
  if (state.mouseTarget && state.cursor !== undefined) {
@@ -13922,39 +13871,217 @@ ___default["default"].extend(Movable.prototype, {
13922
13871
 
13923
13872
  // Trigger an add event if this hasn't been added before
13924
13873
  if (!state.added) {
13925
- self._fireEvent(state.modify, self.cloneState(), {});
13874
+ // TODO(benchristel): No one seems to handle the modify event. Can
13875
+ // we delete this?
13876
+ // @ts-expect-error - TS2345: Argument of type '{}' is not assignable to parameter of type 'State'.
13877
+ this._fireEvent(state.modify, this.cloneState(), {});
13926
13878
  state.added = true;
13927
13879
 
13928
13880
  // Update the state for `added` and in case the add event
13929
13881
  // changed it
13930
- self.prevState = self.cloneState();
13882
+ this.prevState = this.cloneState();
13931
13883
  }
13932
13884
 
13933
13885
  // Trigger a modify event
13934
- self._fireEvent(state.modify, self.cloneState(), self.prevState);
13935
- },
13936
- remove: function () {
13937
- this.state.added = false;
13938
- this._fireEvent(this.state.remove);
13939
- if (this.state.mouseTarget) {
13940
- $__default["default"](this.state.mouseTarget).off();
13941
- this.state.mouseTarget.remove();
13942
- this.state.mouseTarget = null;
13886
+ this._fireEvent(state.modify, this.cloneState(), this.prevState);
13887
+ }
13888
+ cloneState() {
13889
+ return {
13890
+ ...this.state
13891
+ };
13892
+ }
13893
+
13894
+ /**
13895
+ * Fire an onSomething type event to all functions in listeners
13896
+ */
13897
+ _fireEvent(listeners) {
13898
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
13899
+ args[_key - 1] = arguments[_key];
13943
13900
  }
13944
- },
13901
+ if (listeners == null) {
13902
+ return;
13903
+ }
13904
+ for (const listener of listeners) {
13905
+ listener.call(this, ...args);
13906
+ }
13907
+ }
13908
+
13909
+ /**
13910
+ * Call all draw functions, and update our prevState for the next
13911
+ * draw function
13912
+ */
13913
+ draw() {
13914
+ const currState = this.cloneState();
13915
+ this._fireEvent(this.state.draw, currState, this.prevState);
13916
+ this.prevState = currState;
13917
+ }
13918
+
13919
+ /**
13920
+ * Simulates a mouse grab event on the movable object.
13921
+ */
13922
+ grab(coord) {
13923
+ assert$8(kmath.point.is(coord));
13924
+ const graphie = this.graphie;
13925
+ const state = this.state;
13926
+ state.isHovering = true;
13927
+ state.isDragging = true;
13928
+ graphie.isDragging = true;
13929
+ const startMouseCoord = coord;
13930
+ let prevMouseCoord = startMouseCoord;
13931
+ this._fireEvent(state.onMoveStart, startMouseCoord, startMouseCoord);
13932
+ const moveHandler = e => {
13933
+ e.preventDefault();
13934
+ const mouseCoord = graphie.getMouseCoord(e);
13935
+ this._fireEvent(state.onMove, mouseCoord, prevMouseCoord);
13936
+ this.draw();
13937
+ prevMouseCoord = mouseCoord;
13938
+ };
13939
+ const upHandler = () => {
13940
+ $__default["default"](document).unbind("vmousemove", moveHandler);
13941
+ $__default["default"](document).unbind("vmouseup", upHandler);
13942
+ if (state.isHovering) {
13943
+ this._fireEvent(state.onClick, prevMouseCoord, startMouseCoord);
13944
+ }
13945
+ state.isHovering = this.state.isMouseOver;
13946
+ state.isDragging = false;
13947
+ graphie.isDragging = false;
13948
+ this._fireEvent(state.onMoveEnd, prevMouseCoord, startMouseCoord);
13949
+ this.draw();
13950
+ };
13951
+ $__default["default"](document).bind("vmousemove", moveHandler);
13952
+ $__default["default"](document).bind("vmouseup", upHandler);
13953
+ }
13954
+ _applyConstraints(current, previous, extraOptions) {
13955
+ let skipRemaining = false;
13956
+ return (this.state.constraints ?? []).reduce((memo, constraint) => {
13957
+ // A move that has been cancelled won't be propagated to later
13958
+ // constraints calls
13959
+ if (memo === false) {
13960
+ return false;
13961
+ }
13962
+ if (skipRemaining) {
13963
+ return memo;
13964
+ }
13965
+ const result = constraint.call(this, memo, previous, {
13966
+ onSkipRemaining: () => {
13967
+ skipRemaining = true;
13968
+ },
13969
+ ...extraOptions
13970
+ });
13971
+ if (result === false) {
13972
+ // Returning false cancels the move
13973
+ return false;
13974
+ }
13975
+ if (kmath.point.is(result, 2)) {
13976
+ // Returning a coord from constraints overrides the move
13977
+ return result;
13978
+ }
13979
+ if (result === true || result == null) {
13980
+ // Returning true or undefined allow the move to occur
13981
+ return memo;
13982
+ }
13983
+ // Anything else is an error
13984
+ throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
13985
+ }, current);
13986
+ }
13987
+
13945
13988
  // Change z-order to back
13946
- toBack: function () {
13989
+ toBack() {
13947
13990
  if (this.state.mouseTarget) {
13948
13991
  this.state.mouseTarget.toBack();
13949
13992
  }
13950
- },
13993
+ }
13994
+
13951
13995
  // Change z-order to front
13952
- toFront: function () {
13996
+ toFront() {
13953
13997
  if (this.state.mouseTarget) {
13954
13998
  this.state.mouseTarget.toFront();
13955
13999
  }
13956
14000
  }
13957
- });
14001
+
14002
+ /**
14003
+ * Add a listener to any event: startMove, constraints, onMove, onMoveEnd,
14004
+ * etc. If a listener is already bound to the given eventName and id, then
14005
+ * it is overwritten by func.
14006
+ *
14007
+ * eventName: the string name of the event to listen to. one of:
14008
+ * "onMoveStart", "onMove", "onMoveEnd", "draw", "remove"
14009
+ *
14010
+ * id: a string id that can be used to remove this event at a later time
14011
+ * note: adding multiple listeners with the same id is undefined behavior
14012
+ *
14013
+ * func: the function to call when the event happens, which is called
14014
+ * with the event's standard parameters [usually (coord, prevCoord) or
14015
+ * (state, prevState)]
14016
+ */
14017
+ listen(eventName, id, func) {
14018
+ this._listenerMap = this._listenerMap || {};
14019
+
14020
+ // If there's an existing handler, replace it by using its index in
14021
+ // `this.state[eventName]`; otherwise, add this handler to the end
14022
+ const key = getKey(eventName, id);
14023
+ const index = this._listenerMap[key] = this._listenerMap[key] || this.state[eventName].length;
14024
+ this.state[eventName][index] = func;
14025
+ }
14026
+
14027
+ /**
14028
+ * Remove a previously added listener, by the id specified in the
14029
+ * corresponding listen() call
14030
+ *
14031
+ * If the given id has not been registered already, this is a no-op
14032
+ */
14033
+ unlisten(eventName, id) {
14034
+ this._listenerMap = this._listenerMap || {};
14035
+ const key = getKey(eventName, id);
14036
+ const index = this._listenerMap[key];
14037
+ if (index !== undefined) {
14038
+ // Remove handler from list of event handlers and listenerMap
14039
+ this.state[eventName].splice(index, 1);
14040
+ delete this._listenerMap[key];
14041
+
14042
+ // Re-index existing events: if they occur after `index`, decrement
14043
+ const keys = ___default["default"].keys(this._listenerMap);
14044
+ keys.forEach(key => {
14045
+ if (getEventName(key) === eventName && this._listenerMap[key] > index) {
14046
+ this._listenerMap[key]--;
14047
+ }
14048
+ });
14049
+ }
14050
+ }
14051
+ remove() {
14052
+ this.state.added = false;
14053
+ this._fireEvent(this.state.remove);
14054
+ if (this.state.mouseTarget) {
14055
+ $__default["default"](this.state.mouseTarget).off();
14056
+ this.state.mouseTarget.remove();
14057
+ this.state.mouseTarget = null;
14058
+ }
14059
+ }
14060
+ cursor() {
14061
+ return this.state.cursor;
14062
+ }
14063
+ added() {
14064
+ return this.state.added;
14065
+ }
14066
+ isHovering() {
14067
+ return this.state.isHovering;
14068
+ }
14069
+ isMouseOver() {
14070
+ return this.state.isMouseOver;
14071
+ }
14072
+ isDragging() {
14073
+ return this.state.isDragging;
14074
+ }
14075
+ mouseTarget() {
14076
+ return this.state.mouseTarget;
14077
+ }
14078
+ }
14079
+ function getKey(eventName, id) {
14080
+ return eventName + ":" + id;
14081
+ }
14082
+ function getEventName(key) {
14083
+ return key.split(":")[0];
14084
+ }
13958
14085
 
13959
14086
  /* eslint-disable @babel/no-invalid-this */
13960
14087
  /**
@@ -14800,31 +14927,39 @@ const constraints$1 = {
14800
14927
  snap: function (snap) {
14801
14928
  return function (coord) {
14802
14929
  if (snap === null) {
14803
- // NOTE(kevinb): this should probably return the original point
14930
+ // TODO(benchristel), NOTE(kevinb): this should probably return
14931
+ // the original point
14804
14932
  return true;
14805
14933
  }
14806
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
14807
- snap = snap || this.graphie.snap;
14808
- return kmath.point.roundTo(coord, snap);
14934
+ // @ts-expect-error - TS2339: Property 'snap' does not exist on type 'Graphie'.
14935
+ return kmath.point.roundTo(coord, snap || this.graphie.snap);
14809
14936
  };
14810
14937
  },
14811
- bound: function (range, snap, paddingPx) {
14812
- if (paddingPx === undefined) {
14813
- if (range === undefined) {
14814
- paddingPx = 10;
14938
+ bound: function (range, snap, optionalPaddingPx) {
14939
+ const paddingPx = (() => {
14940
+ if (optionalPaddingPx === undefined) {
14941
+ if (range === undefined) {
14942
+ return 10;
14943
+ } else {
14944
+ return 0;
14945
+ }
14815
14946
  } else {
14816
- paddingPx = 0;
14947
+ return optionalPaddingPx;
14817
14948
  }
14818
- }
14949
+ })();
14819
14950
  return function (coord, prev, options) {
14820
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
14821
14951
  const graphie = this.graphie;
14822
14952
  range = range || graphie.range;
14823
14953
  if (snap === undefined) {
14954
+ // @ts-expect-error - Property 'snap' does not exist on type 'Graphie'.
14824
14955
  snap = graphie.snap;
14825
14956
  }
14826
- let lower = graphie.unscalePoint([paddingPx, graphie.ypixels - paddingPx]);
14827
- let upper = graphie.unscalePoint([graphie.xpixels - paddingPx, paddingPx]);
14957
+ let lower = graphie.unscalePoint([paddingPx,
14958
+ // @ts-expect-error - 'graphie.ypixels' is possibly 'undefined'.
14959
+ graphie.ypixels - paddingPx]);
14960
+ let upper = graphie.unscalePoint([
14961
+ // @ts-expect-error - 'graphie.ypixels' is possibly 'undefined'.
14962
+ graphie.xpixels - paddingPx, paddingPx]);
14828
14963
  if (snap) {
14829
14964
  lower = kmath.point.ceilTo(lower, snap);
14830
14965
  upper = kmath.point.floorTo(upper, snap);
@@ -41611,7 +41746,7 @@ const init = function (options) {
41611
41746
 
41612
41747
  // This file is processed by a Rollup plugin (replace) to inject the production
41613
41748
  const libName = "@khanacademy/perseus";
41614
- const libVersion = "19.1.4";
41749
+ const libVersion = "19.1.5";
41615
41750
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
41616
41751
 
41617
41752
  const apiVersion = {