@khanacademy/perseus 33.1.0 → 33.2.1

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
@@ -8780,10 +8780,10 @@ var Raphael$1 = (function () {
8780
8780
  * provided on KhanUtil.
8781
8781
  */
8782
8782
  const KhanColors = {
8783
- BLUE: "#6495ED",
8783
+ BLUE: wonderBlocksTokens.color.blue,
8784
8784
  ORANGE: "#FFA500",
8785
8785
  PINK: "#FF00AF",
8786
- GREEN: "#28AE7B",
8786
+ GREEN: wonderBlocksTokens.color.green,
8787
8787
  PURPLE: "#9D38BD",
8788
8788
  RED: "#DF0030",
8789
8789
  GRAY: "gray",
@@ -8859,11 +8859,9 @@ const KhanColors = {
8859
8859
  // of any redesigns.
8860
8860
  _BACKGROUND: "#FDFDFD",
8861
8861
  // TODO(eater): Get rid of this altogether.
8862
- INTERACTING: "#71B307",
8863
- // KA_GREEN
8864
- INTERACTIVE: "#71B307",
8865
- // KA_GREEN
8866
- DYNAMIC: "#6495ED" // BLUE
8862
+ INTERACTING: wonderBlocksTokens.color.green,
8863
+ INTERACTIVE: wonderBlocksTokens.color.green,
8864
+ DYNAMIC: wonderBlocksTokens.color.blue
8867
8865
  };
8868
8866
 
8869
8867
  // DrawingTransform is responsible for transforming from "math coordinates"
@@ -10147,21 +10145,50 @@ const setLabelMargins = function (span, size) {
10147
10145
  marginTop: -height / 2 - y * scale
10148
10146
  });
10149
10147
  } else {
10150
- const $container = $span.closest(".svg-image");
10148
+ // We are using jQuery to collect information and calculate a scale
10149
+ // since we don't have a way to pass it to this function.
10150
+ // We need the width of the container in order to calculate the scale to apply to the label.
10151
+ // Unfortunately, the DOM tree leading to the label is not consistent.
10152
+ // Therefore, we need to check different elements and different style properties to get the width of the container.
10153
+ // Some graphie labels exist within an ".svg-image" container, and others do not.
10154
+ // All graphie labels have a ".graphie" container.
10155
+ // When a label has an ".svg-image" container,
10156
+ // the width information in the ".graphie" element is expressed as a percentage instead of pixels,
10157
+ // so we can't use it.
10158
+ // Instead, the ".svg-image" container can be used to get the width information.
10159
+ // The following lines determine which container element to use for the width measurement.
10160
+ const $svgImage = $span.closest(".svg-image");
10161
+ const $graphie = $span.closest(".graphie");
10162
+ // If an ".svg-image" container exists in the DOM tree, then use it, otherwise use the ".graphie" container.
10163
+ const $container = $svgImage.length > 0 ? $svgImage : $graphie;
10164
+
10151
10165
  // Ensuring that the line-height of the text doesn't throw off placement of the text element.
10152
10166
  // Inherited line-height values can really mess up placement.
10153
10167
  $container.css("line-height", "normal");
10154
10168
 
10155
- // The 'max-width' value is the same as the expected (100% scale) width of the graphie.
10156
- // We are using jQuery to get this information since we don't have a way to pass it to this function.
10157
- const expectedWidth = $container.css("max-width") ?? "0px";
10169
+ // The expected width of the graphie is found in the "max-width" property on ".svg-image" containers,
10170
+ // and is found in the "width" property on ".graphie" containers.
10171
+ const widthValues = $container.css(["max-width", "width"]) ?? {
10172
+ // The browser will always return a value, but tests won't, so ensuring something is returned.
10173
+ "max-width": "0px"
10174
+ };
10175
+ const expectedWidth =
10176
+ // Verified in Chrome, Firefox, and Safari - all return the same "none" value if the property does not exist.
10177
+ widthValues["max-width"] !== "none" ? widthValues["max-width"] : widthValues["width"];
10158
10178
  // We can calculate the true scale of the graphie by taking actual width and dividing by the expected width.
10159
- // NOTE: Using 'slice' to remove the "px" unit from the end of the expected width value.
10160
- const scale = ($container.width() ?? 0) / parseInt(expectedWidth.replace(/px$/, "")) * 100;
10179
+ // NOTE: Using 'replace' to remove the "px" unit from the end of the expected width value.
10180
+ let scale = ($container.width() ?? 0) / parseInt(expectedWidth.replace(/px$/, "")) * 100;
10181
+ // If something failed in the calculation, then default to 100% scale.
10182
+ if (isNaN(scale)) {
10183
+ scale = 100;
10184
+ } else if (scale === 0) {
10185
+ scale = 100;
10186
+ }
10161
10187
 
10162
10188
  // Any padding needs to be scaled accordingly.
10163
- const currentPadding = $span.css("padding") ?? "0px";
10164
- const newPadding = Math.round(parseInt(currentPadding.slice(0, -2)) * scale) / 100;
10189
+ const padding = $span.css("padding") ?? "0px";
10190
+ const currentPadding = padding !== "none" ? padding : "0px";
10191
+ const newPadding = Math.round(parseInt(currentPadding.replace(/px$/, "")) * scale) / 100;
10165
10192
 
10166
10193
  // "multipliers" basically move the position of the text by using 1, 0, -1
10167
10194
  // 'margin-left' and 'margin-top' are used to position the text.
@@ -29953,7 +29980,8 @@ function LockedLabel(props) {
29953
29980
  left: x,
29954
29981
  top: y,
29955
29982
  color: lockedFigureColors[color],
29956
- fontSize: wonderBlocksTokens.font.size[size]
29983
+ fontSize: wonderBlocksTokens.font.size[size],
29984
+ backgroundColor: "rgba(255, 255, 255, 0.8)"
29957
29985
  }
29958
29986
  }, /*#__PURE__*/React__namespace.createElement(TeX, null, text));
29959
29987
  }
@@ -31990,7 +32018,8 @@ function UnlimitedPointGraph(props) {
31990
32018
  const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
31991
32019
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("rect", {
31992
32020
  style: {
31993
- fill: "rgba(0,0,0,0)"
32021
+ fill: "rgba(0,0,0,0)",
32022
+ cursor: "crosshair"
31994
32023
  },
31995
32024
  width: widthPx,
31996
32025
  height: heightPx,
@@ -32160,6 +32189,17 @@ function useDraggablePx(args) {
32160
32189
  });
32161
32190
  }
32162
32191
 
32192
+ /**
32193
+ * Render the Mafs graph with the specified background and graph elements.
32194
+ *
32195
+ * Render order (back to front):
32196
+ * - Grid
32197
+ * - Axis Ticks, Axis Arrows, and Axis Labels
32198
+ * - Locked Figures
32199
+ * - Locked Labels
32200
+ * - Protractor
32201
+ * - Interactive Graph Elements
32202
+ */
32163
32203
  const MafsGraph = props => {
32164
32204
  const {
32165
32205
  state,
@@ -32238,8 +32278,6 @@ const MafsGraph = props => {
32238
32278
  }, fullGraphAriaDescription), /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32239
32279
  box: props.box,
32240
32280
  backgroundImage: props.backgroundImage
32241
- }), props.showLabelsFlag && props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLabelsLayer, {
32242
- lockedFigures: props.lockedFigures
32243
32281
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32244
32282
  style: {
32245
32283
  position: "absolute",
@@ -32269,28 +32307,64 @@ const MafsGraph = props => {
32269
32307
  props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)), /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
32270
32308
  lockedFigures: props.lockedFigures,
32271
32309
  range: state.range
32272
- }), props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
32310
+ }))), props.showLabelsFlag && props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLabelsLayer, {
32311
+ lockedFigures: props.lockedFigures
32312
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32313
+ style: {
32314
+ position: "absolute"
32315
+ }
32316
+ }, /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
32317
+ preserveAspectRatio: false,
32318
+ viewBox: {
32319
+ x: state.range[X],
32320
+ y: state.range[Y],
32321
+ padding: 0
32322
+ },
32323
+ pan: false,
32324
+ zoom: false,
32325
+ width: width,
32326
+ height: height
32327
+ }, props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
32273
32328
  state,
32274
32329
  dispatch
32275
32330
  }))))), renderGraphControls({
32276
32331
  state,
32277
- dispatch
32332
+ dispatch,
32333
+ width
32278
32334
  })));
32279
32335
  };
32280
- const renderPointGraphControls = props => /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32336
+ const renderPointGraphControls = props => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32337
+ style: {
32338
+ flexDirection: "row",
32339
+ width: props.width
32340
+ }
32341
+ }, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32281
32342
  kind: "secondary",
32282
32343
  style: {
32283
32344
  width: "100%",
32284
32345
  marginLeft: "20px"
32285
32346
  },
32347
+ tabIndex: 0,
32286
32348
  onClick: () => {
32287
32349
  props.dispatch(actions.pointGraph.addPoint([0, 0]));
32288
32350
  }
32289
- }, "Add Point");
32351
+ }, "Add Point"), (props.state.focusedPointIndex !== null || props.state.previouslyFocusedPointIndex !== null) && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
32352
+ kind: "secondary",
32353
+ color: "destructive",
32354
+ tabIndex: 0,
32355
+ style: {
32356
+ width: "100%",
32357
+ marginLeft: "20px"
32358
+ },
32359
+ onClick: event => {
32360
+ props.dispatch(actions.pointGraph.removePoint(props.state.previouslyFocusedPointIndex));
32361
+ }
32362
+ }, "Remove Point"));
32290
32363
  const renderGraphControls = props => {
32291
32364
  const {
32292
32365
  state,
32293
- dispatch
32366
+ dispatch,
32367
+ width
32294
32368
  } = props;
32295
32369
  const {
32296
32370
  type
@@ -32300,7 +32374,8 @@ const renderGraphControls = props => {
32300
32374
  if (state.numPoints === "unlimited") {
32301
32375
  return renderPointGraphControls({
32302
32376
  state,
32303
- dispatch
32377
+ dispatch,
32378
+ width
32304
32379
  });
32305
32380
  }
32306
32381
  return null;
@@ -32474,7 +32549,8 @@ function initializeGraphState(params) {
32474
32549
  type: graph.type,
32475
32550
  coords: getPointCoords(graph, range, step),
32476
32551
  numPoints: graph.numPoints || 0,
32477
- focusedPointIndex: null
32552
+ focusedPointIndex: null,
32553
+ previouslyFocusedPointIndex: null
32478
32554
  };
32479
32555
  case "circle":
32480
32556
  return {
@@ -32771,6 +32847,7 @@ function doBlurPoint(state, action) {
32771
32847
  case "point":
32772
32848
  return {
32773
32849
  ...state,
32850
+ previouslyFocusedPointIndex: state.focusedPointIndex,
32774
32851
  focusedPointIndex: null
32775
32852
  };
32776
32853
  default:
@@ -32817,7 +32894,6 @@ function doMovePointInFigure(state, action) {
32817
32894
  }
32818
32895
  case "angle":
32819
32896
  case "circle":
32820
- throw new Error("FIXME implement circle reducer");
32821
32897
  case "point":
32822
32898
  case "polygon":
32823
32899
  case "quadratic":
@@ -33143,7 +33219,8 @@ function doRemovePoint(state, action) {
33143
33219
  return {
33144
33220
  ...state,
33145
33221
  coords: state.coords.filter((_, i) => i !== action.index),
33146
- focusedPointIndex: null
33222
+ focusedPointIndex: null,
33223
+ previouslyFocusedPointIndex: null
33147
33224
  };
33148
33225
  }
33149
33226
  const getDeltaVertex = (maxMoves, minMoves, delta) => {
@@ -39967,15 +40044,15 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
39967
40044
 
39968
40045
  // Render the text labels
39969
40046
  results.push(graphie.style(props.isMobile ? {
39970
- color: KhanColors.BLUE_D
40047
+ color: KhanColors.BLUE
39971
40048
  } : {}, () => _label(graphie, props.labelStyle, leftLabel, leftLabel, base)));
39972
40049
  results.push(graphie.style(props.isMobile ? {
39973
- color: KhanColors.BLUE_D
40050
+ color: KhanColors.BLUE
39974
40051
  } : {}, () => _label(graphie, props.labelStyle, rightLabel, rightLabel, base)));
39975
40052
 
39976
40053
  // Render the labels' lines
39977
40054
  graphie.style({
39978
- stroke: props.isMobile ? KhanColors.BLUE_D : KhanColors.DYNAMIC,
40055
+ stroke: KhanColors.BLUE,
39979
40056
  strokeWidth: 3.5
39980
40057
  }, () => {
39981
40058
  results.push(graphie.line([leftLabel, -0.2], [leftLabel, 0.2]));
@@ -40162,21 +40239,21 @@ class NumberLine extends React__namespace.Component {
40162
40239
  if (isOpen) {
40163
40240
  fill = KhanColors._BACKGROUND;
40164
40241
  } else if (props.static) {
40165
- fill = KhanColors.DYNAMIC;
40242
+ fill = KhanColors.BLUE;
40166
40243
  } else {
40167
- fill = KhanColors.INTERACTIVE;
40244
+ fill = KhanColors.GREEN;
40168
40245
  }
40169
40246
  const normalStyle = {
40170
40247
  fill: fill,
40171
- stroke: props.static ? KhanColors.DYNAMIC : KhanColors.INTERACTIVE,
40248
+ stroke: props.static ? KhanColors.BLUE : KhanColors.GREEN,
40172
40249
  "stroke-width": isOpen ? 3 : 1
40173
40250
  };
40174
40251
  const highlightStyle = {
40175
- fill: isOpen ? KhanColors._BACKGROUND : KhanColors.INTERACTING,
40252
+ fill: isOpen ? KhanColors._BACKGROUND : KhanColors.GREEN,
40176
40253
  "stroke-width": isOpen ? 3 : 1
40177
40254
  };
40178
40255
  const mobileDotStyle = props.isInequality ? {
40179
- stroke: KhanColors.INTERACTIVE,
40256
+ stroke: KhanColors.GREEN,
40180
40257
  "fill-opacity": isOpen ? 0 : 1
40181
40258
  } : {};
40182
40259
  return /*#__PURE__*/React__namespace.createElement(MovablePoint
@@ -40236,7 +40313,7 @@ class NumberLine extends React__namespace.Component {
40236
40313
  const end = this._getInequalityEndpoint(props);
40237
40314
  const style = {
40238
40315
  arrows: "->",
40239
- stroke: this.props.apiOptions.isMobile ? KhanColors.INTERACTIVE : KhanColors.DYNAMIC,
40316
+ stroke: this.props.apiOptions.isMobile ? KhanColors.GREEN : KhanColors.BLUE,
40240
40317
  strokeWidth: 3.5
40241
40318
  };
40242
40319
  const isGreater = ["ge", "gt"].includes(props.rel);
@@ -43409,7 +43486,7 @@ class PhetSimulation extends React__namespace.Component {
43409
43486
  className: aphrodite.css(styles$6.iframeResponsive),
43410
43487
  src: this.state.url?.toString(),
43411
43488
  allow: "fullscreen"
43412
- })), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
43489
+ })), this.state.url !== null && /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
43413
43490
  icon: cornersOutIcon__default["default"],
43414
43491
  onClick: () => {
43415
43492
  this.iframeRef.current?.requestFullscreen();
@@ -43420,8 +43497,7 @@ class PhetSimulation extends React__namespace.Component {
43420
43497
  marginTop: 5,
43421
43498
  marginBottom: 5,
43422
43499
  alignSelf: "flex-end"
43423
- },
43424
- disabled: this.state.url === null
43500
+ }
43425
43501
  }));
43426
43502
  }
43427
43503
  }
@@ -44972,7 +45048,7 @@ const init = function (options) {
44972
45048
 
44973
45049
  // This file is processed by a Rollup plugin (replace) to inject the production
44974
45050
  const libName = "@khanacademy/perseus";
44975
- const libVersion = "33.1.0";
45051
+ const libVersion = "33.2.1";
44976
45052
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
44977
45053
 
44978
45054
  const apiVersion = {