@khanacademy/perseus 22.6.0 → 23.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.css CHANGED
@@ -4488,6 +4488,9 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4488
4488
  format("woff");
4489
4489
  }
4490
4490
 
4491
+ .MafsView pattern g {
4492
+ stroke: rgba(33, 36, 44, 0.32);
4493
+ }
4491
4494
  .axis-tick-labels {
4492
4495
  font-size: 14px;
4493
4496
  font-family: "Mafs-MJXTEX";
@@ -4496,6 +4499,8 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4496
4499
  * drag interactions on the graph. */
4497
4500
  user-select: none;
4498
4501
  pointer-events: none;
4502
+ /* Prevent labels from covering up interaction points. */
4503
+ z-index: -1;
4499
4504
  }
4500
4505
 
4501
4506
  .y-axis-tick-labels {
@@ -4520,15 +4525,6 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4520
4525
  transform: translateY(calc(-100% + 0.25em));
4521
4526
  }
4522
4527
 
4523
- .x-axis-tick-labels span,
4524
- .y-axis-tick-labels span {
4525
- &::before {
4526
- content: attr(data-content);
4527
- position: absolute;
4528
- transform: translate(-100%);
4529
- }
4530
- }
4531
-
4532
4528
  .y-axis-tick-labels span {
4533
4529
  display: inline-block;
4534
4530
  height: var(--y-axis-label-height, 20px);
package/dist/index.js CHANGED
@@ -1245,8 +1245,6 @@ const ApiOptions = {
1245
1245
  // drawing area (scratchpad) should be allowed/disallowed.
1246
1246
  // Previously handled by `Khan.scratchpad.enable/disable`
1247
1247
  setDrawingAreaAvailable: PropTypes__default["default"].func,
1248
- // Whether to use the Draft.js editor or the legacy textarea
1249
- useDraftEditor: PropTypes__default["default"].bool,
1250
1248
  // The color used for the hint progress indicator (eg. 1 / 3)
1251
1249
  hintProgressColor: PropTypes__default["default"].string,
1252
1250
  // Whether this Renderer is allowed to auto-scroll the rest of the
@@ -1256,8 +1254,6 @@ const ApiOptions = {
1256
1254
  //
1257
1255
  // Defaults to `false`.
1258
1256
  canScrollPage: PropTypes__default["default"].bool,
1259
- // Whether or not we are rendering content inside of a modal.
1260
- inModal: PropTypes__default["default"].bool,
1261
1257
  // Whether to enable the cross-out feature on multiple-choice radio
1262
1258
  // widgets. This allows users to note which answers they believe to
1263
1259
  // be incorrect, to find the answer by process of elimination.
@@ -1293,9 +1289,7 @@ const ApiOptions = {
1293
1289
  }
1294
1290
  },
1295
1291
  setDrawingAreaAvailable: function () {},
1296
- useDraftEditor: false,
1297
1292
  canScrollPage: false,
1298
- inModal: false,
1299
1293
  crossOutEnabled: false,
1300
1294
  editorChangeDelay: 0
1301
1295
  }
@@ -25197,8 +25191,6 @@ var CSProgram$1 = {
25197
25191
  hidden: true
25198
25192
  };
25199
25193
 
25200
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
25201
-
25202
25194
  class Definition extends React__namespace.Component {
25203
25195
  static contextType = PerseusI18nContext;
25204
25196
  static defaultProps = {
@@ -25410,8 +25402,6 @@ var Dropdown$1 = {
25410
25402
 
25411
25403
  /* eslint-disable react/sort-comp */
25412
25404
 
25413
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
25414
-
25415
25405
  // transform = _.identity
25416
25406
 
25417
25407
  function mediaQueryIsMatched(mediaQuery) {
@@ -28868,7 +28858,6 @@ function AxisLabels() {
28868
28858
 
28869
28859
  // Range is replaced within this file with Interval, but it is used elsewhere
28870
28860
  // and exported from the package, so we need to keep it around.
28871
- // TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
28872
28861
  const ItemExtras = [
28873
28862
  // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
28874
28863
  "calculator",
@@ -30048,9 +30037,14 @@ function initializeGraphState(params) {
30048
30037
  center: [0, 0],
30049
30038
  radiusPoint: [1, 0]
30050
30039
  };
30040
+ case "quadratic":
30041
+ return {
30042
+ ...shared,
30043
+ type: graph.type,
30044
+ coords: getQuadraticCoords(graph, range, step)
30045
+ };
30051
30046
  case "angle":
30052
30047
  case "sinusoid":
30053
- case "quadratic":
30054
30048
  throw new Error("Mafs not yet implemented for graph type: " + graph.type);
30055
30049
  default:
30056
30050
  throw new wonderStuffCore.UnreachableCaseError(graph);
@@ -30148,6 +30142,12 @@ function getGradableGraph(state, initialGraph) {
30148
30142
  radius: getRadius(state)
30149
30143
  };
30150
30144
  }
30145
+ if (state.type === "quadratic" && initialGraph.type === "quadratic") {
30146
+ return {
30147
+ ...initialGraph,
30148
+ coords: state.coords
30149
+ };
30150
+ }
30151
30151
  throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
30152
30152
  }
30153
30153
  const getDefaultSegments = _ref2 => {
@@ -30227,6 +30227,11 @@ const getPolygonCoords = _ref4 => {
30227
30227
  coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
30228
30228
  return coords;
30229
30229
  };
30230
+ const getQuadraticCoords = (graph, range, step) => {
30231
+ let coords = [[0.25, 0.75], [0.5, 0.25], [0.75, 0.75]];
30232
+ coords = normalizePoints(range, step, coords, true);
30233
+ return coords;
30234
+ };
30230
30235
 
30231
30236
  /**
30232
30237
  * determine radius of a circle graph
@@ -30336,6 +30341,82 @@ function crossProduct(as, bs) {
30336
30341
  return result;
30337
30342
  }
30338
30343
 
30344
+ function QuadraticGraph(props) {
30345
+ const {
30346
+ dispatch,
30347
+ graphState
30348
+ } = props;
30349
+ const {
30350
+ coords
30351
+ } = graphState;
30352
+
30353
+ // The coefficients are used to calculate the quadratic equation, plot the graph, and to indicate
30354
+ // to content creators the currently selected "correct answer". ex: y = 0.200x^2 + 0.000x + 0.000
30355
+ // While we should technically never have invalid coordinates, we want to ensure that we have a fallback
30356
+ const coeffRef = React__namespace.useRef([0, 0, 0]);
30357
+ const coeffs = getQuadraticCoefficients(coords);
30358
+ if (coeffs !== undefined) {
30359
+ coeffRef.current = coeffs;
30360
+ }
30361
+
30362
+ // Destructure the coefficients for calculating the quadratic equation
30363
+ const [a, b, c] = coeffRef.current;
30364
+
30365
+ // Calculate the y value based on the current x value
30366
+ const y = x => (a * x + b) * x + c;
30367
+ const handleOnMove = (destination, elementId) => {
30368
+ // If the destination is invalid, we want do not want to move the point
30369
+ const validDestination = isValidDestination(destination, elementId, coords);
30370
+ if (validDestination === false) {
30371
+ return;
30372
+ }
30373
+ dispatch(movePoint(elementId, destination));
30374
+ };
30375
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, {
30376
+ y: y,
30377
+ color: wonderBlocksTokens.color.blue
30378
+ }), coords.map((coord, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
30379
+ key: "point-" + i,
30380
+ point: coord,
30381
+ onMove: destination => handleOnMove(destination, i)
30382
+ })));
30383
+ }
30384
+
30385
+ // Ensure that we are only snapping to coordinates that result in a valid quadratic equation
30386
+ const isValidDestination = (destination, elementId, coords) => {
30387
+ // Set up the new coords and check if the quadratic coefficients are valid
30388
+ const newCoords = [...coords];
30389
+ newCoords[elementId] = destination;
30390
+ const QuadraticCoefficients = getQuadraticCoefficients(newCoords);
30391
+
30392
+ // If the new destination results in an invalid quadratic equation, we don't want to move the point
30393
+ if (QuadraticCoefficients === undefined) {
30394
+ return false;
30395
+ }
30396
+ return true;
30397
+ };
30398
+
30399
+ // Get the quadratic coefficients from the 3 control points
30400
+ // These equations were originally set up in 2013 and may require some
30401
+ // additional comments to help clarify the quadratic formula manipulations
30402
+ // Origin: https://phabricator.khanacademy.org/D2413
30403
+ const getQuadraticCoefficients = coords => {
30404
+ const p1 = coords[0];
30405
+ const p2 = coords[1];
30406
+ const p3 = coords[2];
30407
+
30408
+ // If the denominator is 0, we are going to return undefined as we are
30409
+ // unable to calculate the quadratic coefficients when they hit infinity
30410
+ const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
30411
+ if (denom === 0) {
30412
+ return;
30413
+ }
30414
+ const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
30415
+ const b = (p3[0] * p3[0] * (p1[1] - p2[1]) + p2[0] * p2[0] * (p3[1] - p1[1]) + p1[0] * p1[0] * (p2[1] - p3[1])) / denom;
30416
+ const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
30417
+ return [a, b, c];
30418
+ };
30419
+
30339
30420
  // Universal padding for the axis ticks to ensure that the labels
30340
30421
  // have enough space to render without overlapping the tick lines
30341
30422
  const tickPadding = 5;
@@ -30496,9 +30577,6 @@ const AxisTickLabel = _ref => {
30496
30577
  const pointOnAxis = axis === "x" ? [label, 0] : [0, label];
30497
30578
  const pixelPoint = pointToPixel(pointOnAxis, graphConfig);
30498
30579
 
30499
- // Remove the negative sign from the label string as it is handled in the data-content attribute
30500
- const labelString = Math.abs(label).toString();
30501
-
30502
30580
  // Determine the relevant edge of the graph based on the axis type
30503
30581
  const graphEdge = axis === "x" ? graphConfig.width : graphConfig.height;
30504
30582
 
@@ -30514,15 +30592,9 @@ const AxisTickLabel = _ref => {
30514
30592
  gridStep: gridStep[vectorIndex],
30515
30593
  tickStep: tickStep[vectorIndex]
30516
30594
  });
30517
-
30518
- // Determine whether or not to render a negative symbol for the tick label
30519
- // as the negative sign is handled in the data-content attribute in order to
30520
- // maintain the correct spacing between the labels
30521
- const dataContent = label < 0 && shouldShowLabel ? "−" : null;
30522
30595
  return /*#__PURE__*/React__namespace.createElement("span", {
30523
- className: `${axis}-axis-tick-label`,
30524
- "data-content": dataContent
30525
- }, shouldShowLabel && labelString);
30596
+ className: `${axis}-axis-tick-label`
30597
+ }, shouldShowLabel && label);
30526
30598
  };
30527
30599
 
30528
30600
  // Determine whether or not to show the tick label text
@@ -31477,6 +31549,7 @@ function doMoveControlPoint(state, action) {
31477
31549
  throw new Error("FIXME implement circle reducer");
31478
31550
  case "point":
31479
31551
  case "polygon":
31552
+ case "quadratic":
31480
31553
  throw new Error(`Don't use moveControlPoint for ${state.type} graphs. Use movePoint instead!`);
31481
31554
  default:
31482
31555
  throw new wonderStuffCore.UnreachableCaseError(state);
@@ -31549,8 +31622,24 @@ function doMoveAll(state, action) {
31549
31622
  }
31550
31623
  function doMovePoint(state, action) {
31551
31624
  switch (state.type) {
31552
- case "point":
31553
31625
  case "polygon":
31626
+ case "point":
31627
+ {
31628
+ return {
31629
+ ...state,
31630
+ hasBeenInteractedWith: true,
31631
+ coords: setAtIndex({
31632
+ array: state.coords,
31633
+ index: action.index,
31634
+ newValue: snap(state.snapStep, bound$1({
31635
+ snapStep: state.snapStep,
31636
+ range: state.range,
31637
+ point: action.destination
31638
+ }))
31639
+ })
31640
+ };
31641
+ }
31642
+ case "quadratic":
31554
31643
  {
31555
31644
  return {
31556
31645
  ...state,
@@ -31567,7 +31656,7 @@ function doMovePoint(state, action) {
31567
31656
  };
31568
31657
  }
31569
31658
  default:
31570
- throw new Error("The movePoint action is only for point and polygon graphs");
31659
+ throw new Error("The movePoint action is only for point, quadratic, and polygon graphs");
31571
31660
  }
31572
31661
  }
31573
31662
  function doMoveCenter(state, action) {
@@ -31789,6 +31878,11 @@ const renderGraph = props => {
31789
31878
  graphState: state,
31790
31879
  dispatch: dispatch
31791
31880
  });
31881
+ case "quadratic":
31882
+ return /*#__PURE__*/React__namespace.createElement(QuadraticGraph, {
31883
+ graphState: state,
31884
+ dispatch: dispatch
31885
+ });
31792
31886
  default:
31793
31887
  return new wonderStuffCore.UnreachableCaseError(type);
31794
31888
  }
@@ -44002,7 +44096,7 @@ const init = function (options) {
44002
44096
 
44003
44097
  // This file is processed by a Rollup plugin (replace) to inject the production
44004
44098
  const libName = "@khanacademy/perseus";
44005
- const libVersion = "22.6.0";
44099
+ const libVersion = "23.0.0";
44006
44100
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
44007
44101
 
44008
44102
  const apiVersion = {