@khanacademy/perseus 22.0.1 → 22.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -2470,7 +2470,10 @@ img.zoom-img {
2470
2470
  padding-top: 5px;
2471
2471
  }
2472
2472
  .framework-perseus .svg-image {
2473
- display: inline-block;
2473
+ display: block;
2474
+ margin: 0 auto;
2475
+ margin-inline-start: auto;
2476
+ margin-inline-end: auto;
2474
2477
  }
2475
2478
  .framework-perseus .unresponsive-svg-image,
2476
2479
  .framework-perseus .perseus-rendered-radio .unresponsive-svg-image {
@@ -2750,6 +2753,16 @@ body.mobile .categorizer-container td.category input[type="radio"] + span:active
2750
2753
  .perseus-image-editor .graph-settings {
2751
2754
  margin-top: 5px;
2752
2755
  }
2756
+ .perseus-image-widget {
2757
+ margin-inline-start: auto;
2758
+ margin-inline-end: auto;
2759
+ }
2760
+ .perseus-hint-renderer .perseus-image-widget {
2761
+ margin-inline-start: 0;
2762
+ }
2763
+ .perseus-hint-renderer .svg-image {
2764
+ margin-inline-start: 0;
2765
+ }
2753
2766
  .perseus-widget-interactive-graph {
2754
2767
  box-sizing: content-box;
2755
2768
  padding: 25px 25px 0 0;
package/dist/index.js CHANGED
@@ -32,8 +32,8 @@ var caretUp = require('@phosphor-icons/core/assets/regular/caret-up.svg');
32
32
  var debounce$1 = require('lodash.debounce');
33
33
  var mafs = require('mafs');
34
34
  var wonderBlocksIcon = require('@khanacademy/wonder-blocks-icon');
35
- var questionIcon = require('@phosphor-icons/core/regular/question.svg');
36
35
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
36
+ var questionIcon = require('@phosphor-icons/core/regular/question.svg');
37
37
  var createReactClass = require('create-react-class');
38
38
  var Switch = require('@khanacademy/wonder-blocks-switch');
39
39
  var Pill = require('@khanacademy/wonder-blocks-pill');
@@ -649,6 +649,9 @@ class InnerMathInput extends React__namespace.Component {
649
649
  class MathInput extends React__namespace.Component {
650
650
  static contextType = mathInput.MathInputI18nContext;
651
651
  inputRef = /*#__PURE__*/React__namespace.createRef();
652
+ blur() {
653
+ this.inputRef.current?.blur();
654
+ }
652
655
  focus() {
653
656
  this.inputRef.current?.focus();
654
657
  }
@@ -2594,7 +2597,11 @@ class Expression extends React__namespace.Component {
2594
2597
  blurInputPath = inputPath => {
2595
2598
  // eslint-disable-next-line react/no-string-refs
2596
2599
  // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
2597
- this.refs.input?.blur();
2600
+ if (typeof this.refs.input?.blur === "function") {
2601
+ // eslint-disable-next-line react/no-string-refs
2602
+ // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
2603
+ this.refs.input?.blur();
2604
+ }
2598
2605
  };
2599
2606
 
2600
2607
  // HACK(joel)
@@ -21944,10 +21951,14 @@ class SimpleKeypadInput extends React__namespace.Component {
21944
21951
  }
21945
21952
 
21946
21953
  blur() {
21954
+ // eslint-disable-next-line react/no-string-refs
21947
21955
  // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
21948
- this.refs.input?.blur(); // eslint-disable-line react/no-string-refs
21956
+ if (typeof this.refs.input?.blur === "function") {
21957
+ // eslint-disable-next-line react/no-string-refs
21958
+ // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
21959
+ this.refs.input?.blur();
21960
+ }
21949
21961
  }
21950
-
21951
21962
  getValue() {
21952
21963
  return this.props.value;
21953
21964
  }
@@ -22152,7 +22163,11 @@ class InputNumber extends React__namespace.Component {
22152
22163
  blurInputPath = inputPath => {
22153
22164
  // eslint-disable-next-line react/no-string-refs
22154
22165
  // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
22155
- this.refs.input?.blur();
22166
+ if (typeof this.refs.input?.blur === "function") {
22167
+ // eslint-disable-next-line react/no-string-refs
22168
+ // @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
22169
+ this.refs.input?.blur();
22170
+ }
22156
22171
  };
22157
22172
  getInputPaths = () => {
22158
22173
  // The widget itself is an input, so we return a single empty list to
@@ -28746,6 +28761,93 @@ class Graph extends React__namespace.Component {
28746
28761
  }
28747
28762
  }
28748
28763
 
28764
+ const defaultGraphConfig = {
28765
+ range: [[0, 1], [0, 1]],
28766
+ snapStep: [1, 1],
28767
+ markings: "none",
28768
+ showTooltips: false,
28769
+ graphDimensionsInPixels: [1, 1],
28770
+ width: 0,
28771
+ height: 0,
28772
+ labels: []
28773
+ };
28774
+ const GraphConfigContext = /*#__PURE__*/React.createContext(defaultGraphConfig);
28775
+ function useGraphConfig() {
28776
+ return React__default["default"].useContext(GraphConfigContext);
28777
+ }
28778
+
28779
+ const matrixBuilder = mafs.vec.matrixBuilder;
28780
+ // When converting vectors, we don't need to translate because a vector
28781
+ // is like a pair of x and y distances, which are not bound to specific graph locations.
28782
+ function vectorsToPixels(vectors, graphState) {
28783
+ let translation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [0, 0];
28784
+ const {
28785
+ range,
28786
+ width,
28787
+ height
28788
+ } = graphState;
28789
+ const [[xMin, xMax], [yMin, yMax]] = range;
28790
+ const transformToPx = matrixBuilder().translate(...translation).scale(width / (xMax - xMin), -height / (yMax - yMin)).get();
28791
+ return vectors.map(p => mafs.vec.transform(p, transformToPx));
28792
+ }
28793
+
28794
+ // When converting points, we translate so the pixel point ends up in the right location.
28795
+ // This is because points are specific locations on graphs, unlike vectors.
28796
+ function pointToPixel(point, graphState) {
28797
+ const [[xMin], [, yMax]] = graphState.range;
28798
+ const [a, b] = [-xMin, -yMax];
28799
+ return vectorsToPixels([point], graphState, [a, b])[0];
28800
+ }
28801
+ const useTransformVectorsToPixels = function () {
28802
+ const graphState = useGraphConfig();
28803
+ for (var _len = arguments.length, vectors = new Array(_len), _key = 0; _key < _len; _key++) {
28804
+ vectors[_key] = arguments[_key];
28805
+ }
28806
+ return vectorsToPixels(vectors, graphState);
28807
+ };
28808
+
28809
+ function AxisLabels() {
28810
+ const {
28811
+ range,
28812
+ labels,
28813
+ width,
28814
+ height
28815
+ } = useGraphConfig();
28816
+ const yAxisLabelLocation = [0, range[1][1]];
28817
+ const xAxisLabelLocation = [range[0][1], 0];
28818
+ const [xAxisLabelText, yAxisLabelText] = labels;
28819
+ const graphInfo = {
28820
+ range,
28821
+ width,
28822
+ height
28823
+ };
28824
+ const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
28825
+ // The default location for the y-axis-label is at the maximum y point
28826
+ // This is just underneath the tick line for that point. The -24 moves the
28827
+ // label up one grid square, so it sits on top of the graph
28828
+ const [x2, y2] = mafs.vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
28829
+ const {
28830
+ TeX
28831
+ } = getDependencies();
28832
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("span", {
28833
+ style: {
28834
+ position: "absolute",
28835
+ left: x1,
28836
+ top: y1,
28837
+ fontSize: "14px",
28838
+ transform: "translate(7px, -50%)"
28839
+ }
28840
+ }, /*#__PURE__*/React__default["default"].createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default["default"].createElement("span", {
28841
+ style: {
28842
+ position: "absolute",
28843
+ left: x2,
28844
+ top: y2,
28845
+ fontSize: "14px",
28846
+ transform: "translate(-50%, 0px)"
28847
+ }
28848
+ }, /*#__PURE__*/React__default["default"].createElement(TeX, null, yAxisLabelText)));
28849
+ }
28850
+
28749
28851
  // TODO(FEI-4010): Remove `Perseus` prefix for all types here
28750
28852
  // TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
28751
28853
 
@@ -29037,29 +29139,17 @@ function snap(snapStep, point) {
29037
29139
  return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
29038
29140
  }
29039
29141
 
29040
- const useTransform = function () {
29041
- const {
29042
- viewTransform,
29043
- userTransform
29044
- } = mafs.useTransformContext();
29045
- const transformToPx = mafs.vec.matrixMult(viewTransform, userTransform);
29046
- for (var _len = arguments.length, points = new Array(_len), _key = 0; _key < _len; _key++) {
29047
- points[_key] = arguments[_key];
29048
- }
29049
- const transformedPoints = points.map(point => mafs.vec.transform(point, transformToPx));
29050
- return transformedPoints;
29051
- };
29052
-
29053
29142
  /**
29054
- * Given two points, find the tips that extends through the points to the edge of the range.
29055
- * @param collinearPoint - The point that the line passes through. Needed to establish slope.
29056
- * @param extendFrom - The point that the line extends from to the edge of the graph.
29143
+ * Given a ray and a rectangular box, find the point where the ray intersects
29144
+ * the edge of the box. Assumes the `initialPoint` is inside the box.
29145
+ * @param initialPoint - The starting point of the ray.
29146
+ * @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
29147
+ * @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
29057
29148
  */
29058
- const getRayIntersectionCoords = (collinearPoint, extendFrom, range) => {
29059
- // edges of the graph
29060
- const [[xMin, xMax], [yMin, yMax]] = range;
29061
- const [aX, aY] = collinearPoint;
29062
- const [bX, bY] = extendFrom;
29149
+ const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
29150
+ const [[xMin, xMax], [yMin, yMax]] = box;
29151
+ const [aX, aY] = throughPoint;
29152
+ const [bX, bY] = initialPoint;
29063
29153
  const yDiff = bY - aY;
29064
29154
  const xDiff = bX - aX;
29065
29155
  const slope = yDiff / xDiff;
@@ -29161,7 +29251,7 @@ function scaleCommandBy(scaleFactor) {
29161
29251
  // don't want that.
29162
29252
  const arrowPath = pathBuilder().move(-3, 4).curve(-2.75, 2.5, 0, 0.25, 0.75, 0).curve(0, -0.25, -2.75, -2.5, -3, -4).scale(1.4).build();
29163
29253
  function Arrowhead(props) {
29164
- const [point] = useTransform([props.x, props.y]);
29254
+ const [point] = useTransformVectorsToPixels(props.tip);
29165
29255
  return /*#__PURE__*/React__namespace.createElement("g", {
29166
29256
  transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
29167
29257
  }, /*#__PURE__*/React__namespace.createElement("g", {
@@ -29183,7 +29273,7 @@ function Vector(props) {
29183
29273
  tip,
29184
29274
  color
29185
29275
  } = props;
29186
- const [tailPx, tipPx] = useTransform(tail, tip);
29276
+ const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
29187
29277
  const direction = mafs.vec.sub(tip, tail);
29188
29278
  return /*#__PURE__*/React__namespace.createElement("g", {
29189
29279
  style: {
@@ -29194,8 +29284,7 @@ function Vector(props) {
29194
29284
  start: tailPx,
29195
29285
  end: tipPx
29196
29286
  }), /*#__PURE__*/React__namespace.createElement(Arrowhead, {
29197
- x: tip[0],
29198
- y: tip[1],
29287
+ tip: tip,
29199
29288
  angle: angleDegrees(direction)
29200
29289
  }));
29201
29290
  }
@@ -29214,12 +29303,16 @@ const MovableLine = props => {
29214
29303
  stroke = defaultStroke
29215
29304
  } = props;
29216
29305
  const midpoint = mafs.vec.midpoint(start, end);
29217
- const [startPtPx, endPtPx] = useTransform(start, end);
29306
+ const [startPtPx, endPtPx] = useTransformVectorsToPixels(start, end);
29307
+ const {
29308
+ graphDimensionsInPixels
29309
+ } = useGraphConfig();
29218
29310
  let startExtend = undefined;
29219
29311
  let endExtend = undefined;
29220
29312
  if (extend) {
29221
- startExtend = extend.start ? getRayIntersectionCoords(end, start, extend.range) : undefined;
29222
- endExtend = extend.end ? getRayIntersectionCoords(start, end, extend.range) : undefined;
29313
+ const trimmedRange = trimRange(extend.range, graphDimensionsInPixels);
29314
+ startExtend = extend.start ? getIntersectionOfRayWithBox(start, end, trimmedRange) : undefined;
29315
+ endExtend = extend.end ? getIntersectionOfRayWithBox(end, start, trimmedRange) : undefined;
29223
29316
  }
29224
29317
  const line = React.useRef(null);
29225
29318
  const {
@@ -29276,16 +29369,24 @@ const MovableLine = props => {
29276
29369
  color: stroke
29277
29370
  }));
29278
29371
  };
29279
-
29280
- const defaultGraphConfig = {
29281
- range: [[0, 1], [0, 1]],
29282
- snapStep: [1, 1],
29283
- markings: "none",
29284
- showTooltips: false
29285
- };
29286
- const GraphConfigContext = /*#__PURE__*/React.createContext(defaultGraphConfig);
29287
- function useGraphConfig() {
29288
- return React__default["default"].useContext(GraphConfigContext);
29372
+ function trimRange(range, graphDimensionsInPixels) {
29373
+ const pixelsToTrim = 4;
29374
+ const [xRange, yRange] = range;
29375
+ const [pixelsWide, pixelsTall] = graphDimensionsInPixels;
29376
+ const graphUnitsPerPixelX = size(xRange) / pixelsWide;
29377
+ const graphUnitsPerPixelY = size(yRange) / pixelsTall;
29378
+ const graphUnitsToTrimX = pixelsToTrim * graphUnitsPerPixelX;
29379
+ const graphUnitsToTrimY = pixelsToTrim * graphUnitsPerPixelY;
29380
+ return [trim(xRange, graphUnitsToTrimX), trim(yRange, graphUnitsToTrimY)];
29381
+ }
29382
+ function trim(interval, amount) {
29383
+ if (size(interval) < amount * 2) {
29384
+ return [0, 0];
29385
+ }
29386
+ return [interval[0] + amount, interval[1] - amount];
29387
+ }
29388
+ function size(interval) {
29389
+ return interval[1] - interval[0];
29289
29390
  }
29290
29391
 
29291
29392
  // The hitbox size of 48px by 48px is preserved from the legacy interactive
@@ -29320,13 +29421,13 @@ const StyledMovablePoint = props => {
29320
29421
  constrain: p => snap(snapStep, p)
29321
29422
  });
29322
29423
  const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""}`;
29323
- const [[x, y]] = useTransform(point);
29424
+ const [[x, y]] = useTransformVectorsToPixels(point);
29324
29425
  const [xMin, xMax] = range[0];
29325
29426
  const [yMin, yMax] = range[1];
29326
- const [[verticalStartX]] = useTransform([xMin, 0]);
29327
- const [[verticalEndX]] = useTransform([xMax, 0]);
29328
- const [[_, horizontalStartY]] = useTransform([0, yMin]);
29329
- const [[__, horizontalEndY]] = useTransform([0, yMax]);
29427
+ const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
29428
+ const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
29429
+ const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
29430
+ const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
29330
29431
  const showHairlines = dragging && markings !== "none";
29331
29432
  const hairlines = /*#__PURE__*/React__namespace.createElement("g", null, /*#__PURE__*/React__namespace.createElement("line", {
29332
29433
  x1: verticalStartX,
@@ -29654,7 +29755,7 @@ const isRightAngle = angle => Math.abs(angle - Math.PI / 2) < 0.01;
29654
29755
  */
29655
29756
  const shouldDrawArcOutside = (midpoint, vertex, range, polygonLines) => {
29656
29757
  // Create a ray from the midpoint (inside angle) to the edge of the range
29657
- const rangeIntersectionPoint = getRayIntersectionCoords(midpoint, vertex, range);
29758
+ const rangeIntersectionPoint = getIntersectionOfRayWithBox(vertex, midpoint, range);
29658
29759
  let lineIntersectionCount = 0;
29659
29760
  polygonLines.forEach(line => linesIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
29660
29761
 
@@ -29779,23 +29880,19 @@ function AxisArrows() {
29779
29880
  const axisColor = "var(--mafs-fg)";
29780
29881
  return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
29781
29882
  color: axisColor,
29782
- x: xMin,
29783
- y: 0,
29883
+ tip: [xMin, 0],
29784
29884
  angle: 180
29785
29885
  }), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
29786
29886
  color: axisColor,
29787
- x: xMax,
29788
- y: 0,
29887
+ tip: [xMax, 0],
29789
29888
  angle: 0
29790
29889
  }), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
29791
29890
  color: axisColor,
29792
- x: 0,
29793
- y: yMin,
29891
+ tip: [0, yMin],
29794
29892
  angle: 270
29795
29893
  }), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
29796
29894
  color: axisColor,
29797
- x: 0,
29798
- y: yMax,
29895
+ tip: [0, yMax],
29799
29896
  angle: 90
29800
29897
  }));
29801
29898
  }
@@ -29821,7 +29918,7 @@ const YGridTick = _ref => {
29821
29918
  tickStep
29822
29919
  } = _ref;
29823
29920
  const pointOnAxis = [0, y];
29824
- const [[xPosition, yPosition]] = useTransform(pointOnAxis);
29921
+ const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
29825
29922
  return /*#__PURE__*/React__namespace.createElement("g", {
29826
29923
  className: "y-axis-ticks"
29827
29924
  }, /*#__PURE__*/React__namespace.createElement("line", {
@@ -29845,7 +29942,7 @@ const XGridTick = _ref2 => {
29845
29942
  tickStep
29846
29943
  } = _ref2;
29847
29944
  const pointOnAxis = [x, 0];
29848
- const [[xPosition, yPosition]] = useTransform(pointOnAxis);
29945
+ const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
29849
29946
  return /*#__PURE__*/React__namespace.createElement("g", {
29850
29947
  className: "x-axis-ticks"
29851
29948
  }, /*#__PURE__*/React__namespace.createElement("line", {
@@ -30067,96 +30164,26 @@ const styles$k = aphrodite.StyleSheet.create({
30067
30164
  }
30068
30165
  });
30069
30166
 
30070
- const colors$1 = {
30071
- grayLight: "#aaa",
30072
- basicBorderColor: "#ccc",
30073
- white: "#fff"
30074
- };
30075
- const triangleBeforeAfter = {
30076
- borderBottom: "9px solid transparent",
30077
- borderTop: "9px solid transparent",
30078
- content: '" "',
30079
- height: "0",
30080
- position: "absolute",
30081
- top: "0",
30082
- width: "0"
30167
+ const InfoTip$1 = props => {
30168
+ return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
30169
+ content: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.Body, {
30170
+ style: styles$j.body
30171
+ }, props.children),
30172
+ placement: "right"
30173
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
30174
+ size: "small",
30175
+ icon: questionIcon__default["default"],
30176
+ style: styles$j.spacingLeft
30177
+ }));
30083
30178
  };
30084
30179
  const styles$j = aphrodite.StyleSheet.create({
30085
- infoTip: {
30086
- display: "inline-block",
30087
- marginLeft: "5px",
30088
- position: "relative"
30089
- },
30090
- infoTipContainer: {
30091
- position: "absolute",
30092
- top: "-12px",
30093
- left: "22px",
30094
- zIndex: 1000
30095
- },
30096
- infoTipTriangle: {
30097
- height: "10px",
30098
- left: "0",
30099
- position: "absolute",
30100
- top: "8px",
30101
- width: "0",
30102
- zIndex: 1,
30103
- ":before": {
30104
- ...triangleBeforeAfter,
30105
- borderRight: "9px solid #bbb",
30106
- right: "0"
30107
- },
30108
- ":after": {
30109
- ...triangleBeforeAfter,
30110
- borderRight: `9px solid ${colors$1.white}`,
30111
- right: "-1px"
30112
- }
30113
- },
30114
- verticalShadow: {
30115
- border: `1px solid ${colors$1.basicBorderColor}`,
30116
- boxShadow: `0 1px 3px ${colors$1.basicBorderColor}`,
30117
- borderBottom: `1px solid ${colors$1.grayLight}`
30180
+ spacingLeft: {
30181
+ marginInlineStart: wonderBlocksTokens.spacing.xxxSmall_4
30118
30182
  },
30119
- infoTipContentContainer: {
30120
- background: colors$1.white,
30121
- padding: "5px 10px",
30122
- width: "240px"
30183
+ body: {
30184
+ padding: wonderBlocksTokens.spacing.medium_16
30123
30185
  }
30124
30186
  });
30125
- class InfoTip$1 extends React__namespace.Component {
30126
- state = {
30127
- hover: false
30128
- };
30129
- handleMouseEnter = () => {
30130
- this.setState({
30131
- hover: true
30132
- });
30133
- };
30134
- handleMouseLeave = () => {
30135
- this.setState({
30136
- hover: false
30137
- });
30138
- };
30139
- render() {
30140
- return /*#__PURE__*/React__namespace.createElement("div", {
30141
- className: aphrodite.css(styles$j.infoTip)
30142
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30143
- onMouseEnter: this.handleMouseEnter,
30144
- onMouseLeave: this.handleMouseLeave
30145
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
30146
- size: "small",
30147
- icon: questionIcon__default["default"]
30148
- })), /*#__PURE__*/React__namespace.createElement("div", {
30149
- className: aphrodite.css(styles$j.infoTipContainer),
30150
- style: {
30151
- display: this.state.hover ? "block" : "none"
30152
- }
30153
- }, /*#__PURE__*/React__namespace.createElement("div", {
30154
- className: aphrodite.css(styles$j.infoTipTriangle)
30155
- }), /*#__PURE__*/React__namespace.createElement("div", {
30156
- className: aphrodite.css(styles$j.verticalShadow, styles$j.infoTipContentContainer)
30157
- }, this.props.children)));
30158
- }
30159
- }
30160
30187
 
30161
30188
  /**
30162
30189
  * A wrapper around info-tip/info-tip.jsx that can be rendered on the
@@ -31013,7 +31040,7 @@ const getDefaultPoints = _ref => {
31013
31040
  function getGradableGraph(state, initialGraph) {
31014
31041
  if (!state.hasBeenInteractedWith) {
31015
31042
  return {
31016
- type: initialGraph.type
31043
+ ...initialGraph
31017
31044
  };
31018
31045
  }
31019
31046
  if (initialGraph.type === "linear-system" && state.type === "linear-system") {
@@ -31180,7 +31207,8 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
31180
31207
  const MafsGraph = props => {
31181
31208
  const {
31182
31209
  state,
31183
- dispatch
31210
+ dispatch,
31211
+ labels
31184
31212
  } = props;
31185
31213
  const [width, height] = props.box;
31186
31214
  const prevState = React.useRef(state);
@@ -31209,7 +31237,11 @@ const MafsGraph = props => {
31209
31237
  range: state.range,
31210
31238
  snapStep: state.snapStep,
31211
31239
  markings: props.markings,
31212
- showTooltips: !!props.showTooltips
31240
+ showTooltips: !!props.showTooltips,
31241
+ graphDimensionsInPixels: props.box,
31242
+ width,
31243
+ height,
31244
+ labels
31213
31245
  }
31214
31246
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31215
31247
  style: {
@@ -31228,7 +31260,7 @@ const MafsGraph = props => {
31228
31260
  bottom: 0,
31229
31261
  left: 0
31230
31262
  }
31231
- }, /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
31263
+ }, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
31232
31264
  preserveAspectRatio: false,
31233
31265
  viewBox: {
31234
31266
  x: props.range[0],
@@ -32455,8 +32487,12 @@ class LegacyInteractiveGraph extends React__namespace.Component {
32455
32487
  graph: graph
32456
32488
  });
32457
32489
  };
32458
- getUserInput = () => InteractiveGraph.getUserInputFromProps(this.props);
32459
- simpleValidate = rubric => InteractiveGraph.validate(this.getUserInput(), rubric, this);
32490
+ getUserInput() {
32491
+ return InteractiveGraph.getUserInputFromProps(this.props);
32492
+ }
32493
+ simpleValidate(rubric) {
32494
+ return InteractiveGraph.validate(this.getUserInput(), rubric, this);
32495
+ }
32460
32496
  focus = $__default["default"].noop;
32461
32497
  render() {
32462
32498
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
@@ -32535,7 +32571,9 @@ class InteractiveGraph extends React__namespace.Component {
32535
32571
  }
32536
32572
  throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
32537
32573
  };
32538
- simpleValidate = rubric => InteractiveGraph.validate(this.getUserInput?.(), rubric, this);
32574
+ simpleValidate(rubric) {
32575
+ return InteractiveGraph.validate(this.getUserInput?.(), rubric, this);
32576
+ }
32539
32577
  render() {
32540
32578
  // Mafs shim
32541
32579
  if (this.props.apiOptions?.flags?.["mafs"]?.[this.props.graph.type]) {
@@ -43336,7 +43374,7 @@ const init = function (options) {
43336
43374
 
43337
43375
  // This file is processed by a Rollup plugin (replace) to inject the production
43338
43376
  const libName = "@khanacademy/perseus";
43339
- const libVersion = "22.0.1";
43377
+ const libVersion = "22.1.0";
43340
43378
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
43341
43379
 
43342
43380
  const apiVersion = {