@khanacademy/perseus 21.2.2 → 21.3.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.css CHANGED
@@ -4291,9 +4291,13 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4291
4291
  --movable-line-stroke-weight-active: 4px;
4292
4292
  }
4293
4293
 
4294
- .MafsView .movable-line:is(:focus-visible, :hover),
4294
+ .MafsView > svg {
4295
+ /* Chrome/Safari bugfix for LEMS-1906 */
4296
+ display: block;
4297
+ }
4298
+
4299
+ .MafsView .movable-line:hover,
4295
4300
  .movable-dragging {
4296
- outline: none;
4297
4301
  --movable-line-stroke-weight: var(--movable-line-stroke-weight-active);
4298
4302
  }
4299
4303
 
@@ -4302,6 +4306,36 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4302
4306
  outline: none;
4303
4307
  }
4304
4308
 
4309
+ .MafsView
4310
+ .movable-line
4311
+ :is(.movable-line-focus-outline, .movable-line-focus-outline-gap) {
4312
+ stroke: transparent;
4313
+ }
4314
+
4315
+ .MafsView .movable-line:focus-visible .movable-line-focus-outline {
4316
+ stroke: var(--mafs-blue);
4317
+ stroke-width: 10px;
4318
+ }
4319
+
4320
+ .MafsView .movable-line:focus-visible .movable-line-focus-outline-gap {
4321
+ stroke: white;
4322
+ stroke-width: 6px;
4323
+ }
4324
+
4325
+ .MafsView .movable-point {
4326
+ cursor: grab;
4327
+ touch-action: none;
4328
+ outline: none;
4329
+ }
4330
+
4331
+ .MafsView .movable-point.movable-point--dragging {
4332
+ cursor: grabbing;
4333
+ }
4334
+
4335
+ .MafsView .movable-point.movable-point--dragging .movable-point-halo {
4336
+ opacity: 0;
4337
+ }
4338
+
4305
4339
  .MafsView .movable-point-hitbox {
4306
4340
  fill: transparent;
4307
4341
  }
@@ -4313,7 +4347,9 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4313
4347
  .movable-point-halo,
4314
4348
  .movable-point-focus-outline
4315
4349
  ) {
4316
- transition: r 0.15s ease-out;
4350
+ transition:
4351
+ r 0.15s ease-out,
4352
+ opacity 0.15s ease-out;
4317
4353
  }
4318
4354
 
4319
4355
  .MafsView .movable-point-center {
@@ -4372,3 +4408,14 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4372
4408
  .MafsView .movable-point:focus-visible .movable-point-focus-outline {
4373
4409
  visibility: visible;
4374
4410
  }
4411
+
4412
+ @font-face {
4413
+ font-family: Mafs-MJXTEX;
4414
+ src: url("https://cdn.kastatic.org/fonts/mathjax/MathJax_Main-Regular.woff")
4415
+ format("woff");
4416
+ }
4417
+
4418
+ .MafsView .axis-ticks text {
4419
+ font-size: 14px;
4420
+ font-family: "Mafs-MJXTEX";
4421
+ }
package/dist/index.js CHANGED
@@ -28391,14 +28391,6 @@ function changeRange(range) {
28391
28391
  };
28392
28392
  }
28393
28393
 
28394
- const GraphStateContext = /*#__PURE__*/React.createContext({
28395
- state: {},
28396
- dispatch: () => {}
28397
- });
28398
- function useGraphState() {
28399
- return React__default["default"].useContext(GraphStateContext);
28400
- }
28401
-
28402
28394
  /**
28403
28395
  * 44 is touch best practice and AAA compliant for WCAG
28404
28396
  * https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
@@ -28487,9 +28479,6 @@ const getLines = points => points.map((point, i) => {
28487
28479
 
28488
28480
  const defaultStroke = "var(--movable-line-stroke-color)";
28489
28481
  const MovableLine = props => {
28490
- const {
28491
- state
28492
- } = useGraphState();
28493
28482
  const {
28494
28483
  start,
28495
28484
  end,
@@ -28514,12 +28503,13 @@ const MovableLine = props => {
28514
28503
  onMove: newPoint => {
28515
28504
  onMove(mafs.vec.sub(newPoint, midpoint));
28516
28505
  },
28517
- constrain: p => snap(state.snapStep, p)
28506
+ constrain: p => p
28518
28507
  });
28519
28508
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("g", {
28520
28509
  ref: line,
28521
28510
  tabIndex: 0,
28522
28511
  className: "movable-line",
28512
+ "data-test-id": "movable-line",
28523
28513
  style: {
28524
28514
  cursor: dragging ? "grabbing" : "grab"
28525
28515
  }
@@ -28530,6 +28520,16 @@ const MovableLine = props => {
28530
28520
  stroke: "transparent",
28531
28521
  strokeWidth: TARGET_SIZE
28532
28522
  }
28523
+ }), /*#__PURE__*/React__namespace.createElement(SVGLine, {
28524
+ start: startPtPx,
28525
+ end: endPtPx,
28526
+ className: "movable-line-focus-outline",
28527
+ style: {}
28528
+ }), /*#__PURE__*/React__namespace.createElement(SVGLine, {
28529
+ start: startPtPx,
28530
+ end: endPtPx,
28531
+ className: "movable-line-focus-outline-gap",
28532
+ style: {}
28533
28533
  }), /*#__PURE__*/React__namespace.createElement(SVGLine, {
28534
28534
  start: startPtPx,
28535
28535
  end: endPtPx,
@@ -28537,7 +28537,8 @@ const MovableLine = props => {
28537
28537
  stroke,
28538
28538
  strokeWidth: "var(--movable-line-stroke-weight)"
28539
28539
  },
28540
- dragging: dragging
28540
+ dragging: dragging,
28541
+ testId: "movable-line__line"
28541
28542
  })), startExtend && /*#__PURE__*/React__namespace.createElement(mafs.Vector, {
28542
28543
  tail: start,
28543
28544
  tip: startExtend,
@@ -28553,18 +28554,30 @@ function SVGLine(props) {
28553
28554
  start,
28554
28555
  end,
28555
28556
  style,
28556
- dragging
28557
+ dragging,
28558
+ className,
28559
+ testId
28557
28560
  } = props;
28561
+ const draggingClass = dragging ? "movable-dragging" : "";
28558
28562
  return /*#__PURE__*/React__namespace.createElement("line", {
28559
28563
  x1: start[0],
28560
28564
  y1: start[1],
28561
28565
  x2: end[0],
28562
28566
  y2: end[1],
28563
28567
  style: style,
28564
- className: dragging ? "movable-dragging" : undefined
28568
+ className: `${className} ${draggingClass}`,
28569
+ "data-test-id": testId
28565
28570
  });
28566
28571
  }
28567
28572
 
28573
+ const GraphStateContext = /*#__PURE__*/React.createContext({
28574
+ state: {},
28575
+ dispatch: () => {}
28576
+ });
28577
+ function useGraphState() {
28578
+ return React__default["default"].useContext(GraphStateContext);
28579
+ }
28580
+
28568
28581
  // The hitbox size of 48px by 48px is preserved from the legacy interactive
28569
28582
  // graph.
28570
28583
  const hitboxSizePx = 48;
@@ -28586,17 +28599,16 @@ const StyledMovablePoint = props => {
28586
28599
  onMove,
28587
28600
  constrain: p => snap(state.snapStep, p)
28588
28601
  });
28602
+ const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""}`;
28589
28603
  const [[x, y]] = useTransform(point);
28590
28604
  return /*#__PURE__*/React__namespace.createElement("g", {
28591
28605
  ref: hitboxRef,
28592
- className: "movable-point",
28606
+ className: pointClasses,
28593
28607
  tabIndex: 0,
28594
28608
  style: {
28595
- cursor: dragging ? "grabbing" : "grab",
28596
- touchAction: "none",
28597
- outline: "none",
28598
28609
  "--movable-point-color": color
28599
- }
28610
+ },
28611
+ "data-test-id": "movable-point"
28600
28612
  }, /*#__PURE__*/React__namespace.createElement("circle", {
28601
28613
  className: "movable-point-hitbox",
28602
28614
  r: hitboxSizePx / 2,
@@ -28620,7 +28632,8 @@ const StyledMovablePoint = props => {
28620
28632
  cy: y,
28621
28633
  style: {
28622
28634
  fill: color
28623
- }
28635
+ },
28636
+ "data-test-id": "movable-point__center"
28624
28637
  }));
28625
28638
  };
28626
28639
 
@@ -29086,7 +29099,13 @@ const YGridTick = _ref => {
29086
29099
  x2: xPosition + tickSize / 2,
29087
29100
  y2: yPosition,
29088
29101
  style: tickStyle
29089
- }));
29102
+ }), y !== -1 && /*#__PURE__*/React__namespace.createElement("text", {
29103
+ height: 20,
29104
+ width: 50,
29105
+ textAnchor: "end",
29106
+ x: xPosition - 10,
29107
+ y: yPosition + 5
29108
+ }, y.toString()));
29090
29109
  };
29091
29110
  const XGridTick = _ref2 => {
29092
29111
  let {
@@ -29102,13 +29121,23 @@ const XGridTick = _ref2 => {
29102
29121
  x2: xPosition,
29103
29122
  y2: yPosition - tickSize / 2,
29104
29123
  style: tickStyle
29105
- }));
29124
+ }), x !== -1 && /*#__PURE__*/React__namespace.createElement("text", {
29125
+ height: 20,
29126
+ width: 50,
29127
+ textAnchor: "middle",
29128
+ x: xPosition,
29129
+ y: yPosition + 25
29130
+ }, x.toString()));
29106
29131
  };
29107
29132
  function generateTickLocations(tickStep, min, max) {
29108
29133
  const ticks = [];
29134
+
29135
+ // Add ticks in the positive direction
29109
29136
  for (let i = 0 + tickStep; i < max; i += tickStep) {
29110
29137
  ticks.push(i);
29111
29138
  }
29139
+
29140
+ // Add ticks in the negative direction
29112
29141
  for (let i = 0 - tickStep; i > min; i -= tickStep) {
29113
29142
  ticks.push(i);
29114
29143
  }
@@ -29137,24 +29166,6 @@ const AxisTicks = props => {
29137
29166
  }));
29138
29167
  };
29139
29168
 
29140
- /**
29141
- * lineLabelText get the text that should
29142
- * be displayed for a specific tick place
29143
- *
29144
- * @param {number} n the tick number
29145
- * @param {number} tickStep how frequently a label should appear
29146
- * @param {vec.Vector2} range the min/max range on the axis
29147
- */
29148
- const lineLabelText = (n, tickStep, range) => {
29149
- const [min, max] = range;
29150
- const isOnStep = n % tickStep === 0;
29151
- const isNegativeOne = n === -1;
29152
- const isMin = n === min;
29153
- const isMax = n === max;
29154
- const shouldRender = isOnStep && !isNegativeOne && !isMin && !isMax;
29155
- return shouldRender ? `${n}` : "";
29156
- };
29157
-
29158
29169
  /**
29159
29170
  * axisOptions determine axis options for Mafs
29160
29171
  *
@@ -29166,12 +29177,10 @@ const lineLabelText = (n, tickStep, range) => {
29166
29177
  * @param {number} axisIndex which axis we're getting options for
29167
29178
  */
29168
29179
  const axisOptions = (props, axisIndex) => {
29169
- const axisStep = props.tickStep[axisIndex];
29170
- const axisRange = props.range[axisIndex];
29171
29180
  return {
29172
29181
  axis: props.markings === "graph",
29173
29182
  lines: props.gridStep[axisIndex],
29174
- labels: n => lineLabelText(n, axisStep, axisRange)
29183
+ labels: false
29175
29184
  };
29176
29185
  };
29177
29186
  const Grid = props => {
@@ -30418,9 +30427,22 @@ const renderGraph = props => {
30418
30427
  return new wonderStuffCore.UnreachableCaseError(type);
30419
30428
  }
30420
30429
  };
30421
- const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30422
- const [width, height] = props.box;
30430
+ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30423
30431
  const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
30432
+ React.useImperativeHandle(ref, () => ({
30433
+ getUserInput: () => getGradableGraph(state, props.graph)
30434
+ }));
30435
+ return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({
30436
+ state: state,
30437
+ dispatch: dispatch
30438
+ }, props));
30439
+ });
30440
+ const MafsGraph = props => {
30441
+ const {
30442
+ state,
30443
+ dispatch
30444
+ } = props;
30445
+ const [width, height] = props.box;
30424
30446
  const prevState = React.useRef(state);
30425
30447
  React.useEffect(() => {
30426
30448
  if (prevState.current !== state) {
@@ -30435,16 +30457,13 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30435
30457
  const [xSnap, ySnap] = props.snapStep;
30436
30458
  React.useEffect(() => {
30437
30459
  dispatch(changeSnapStep([xSnap, ySnap]));
30438
- }, [xSnap, ySnap]);
30460
+ }, [dispatch, xSnap, ySnap]);
30439
30461
 
30440
30462
  // Destructuring first to keep useEffect from making excess calls
30441
30463
  const [[xMinRange, xMaxRange], [yMinRange, yMaxRange]] = props.range;
30442
30464
  React.useEffect(() => {
30443
30465
  dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
30444
- }, [xMinRange, xMaxRange, yMinRange, yMaxRange]);
30445
- React__namespace.useImperativeHandle(ref, () => ({
30446
- getUserInput: () => getGradableGraph(state, props.graph)
30447
- }));
30466
+ }, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
30448
30467
  return /*#__PURE__*/React__namespace.createElement(GraphStateContext.Provider, {
30449
30468
  value: {
30450
30469
  state,
@@ -30454,7 +30473,9 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30454
30473
  style: {
30455
30474
  width,
30456
30475
  height,
30457
- position: "relative"
30476
+ position: "relative",
30477
+ padding: "25px 25px 0 0",
30478
+ boxSizing: "content-box"
30458
30479
  }
30459
30480
  }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
30460
30481
  box: props.box,
@@ -30488,7 +30509,7 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30488
30509
  state,
30489
30510
  dispatch
30490
30511
  })))));
30491
- });
30512
+ };
30492
30513
 
30493
30514
  const {
30494
30515
  DeprecationMixin
@@ -31764,7 +31785,7 @@ class InteractiveGraph extends React__namespace.Component {
31764
31785
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
31765
31786
  const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
31766
31787
  const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
31767
- return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, this.props, {
31788
+ return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph, _extends({}, this.props, {
31768
31789
  ref: this.mafsRef,
31769
31790
  gridStep: gridStep,
31770
31791
  snapStep: snapStep,
@@ -42495,7 +42516,7 @@ const init = function (options) {
42495
42516
 
42496
42517
  // This file is processed by a Rollup plugin (replace) to inject the production
42497
42518
  const libName = "@khanacademy/perseus";
42498
- const libVersion = "21.2.2";
42519
+ const libVersion = "21.3.1";
42499
42520
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
42500
42521
 
42501
42522
  const apiVersion = {