@khanacademy/perseus 21.2.2 → 21.3.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/es/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,22 @@ 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
+
4305
4325
  .MafsView .movable-point-hitbox {
4306
4326
  fill: transparent;
4307
4327
  }
@@ -4372,3 +4392,14 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4372
4392
  .MafsView .movable-point:focus-visible .movable-point-focus-outline {
4373
4393
  visibility: visible;
4374
4394
  }
4395
+
4396
+ @font-face {
4397
+ font-family: Mafs-MJXTEX;
4398
+ src: url("https://cdn.kastatic.org/fonts/mathjax/MathJax_Main-Regular.woff")
4399
+ format("woff");
4400
+ }
4401
+
4402
+ .MafsView .axis-ticks text {
4403
+ font-size: 14px;
4404
+ font-family: "Mafs-MJXTEX";
4405
+ }
package/dist/es/index.js CHANGED
@@ -7,7 +7,7 @@ import * as i18n from '@khanacademy/wonder-blocks-i18n';
7
7
  import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
8
8
  import classNames from 'classnames';
9
9
  import * as React from 'react';
10
- import React__default, { useState, useEffect, useRef, createContext } from 'react';
10
+ import React__default, { useState, useEffect, useRef, createContext, useImperativeHandle } from 'react';
11
11
  import _, { debounce as debounce$1 } from 'underscore';
12
12
  import Clickable from '@khanacademy/wonder-blocks-clickable';
13
13
  import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
@@ -28239,14 +28239,6 @@ function changeRange(range) {
28239
28239
  };
28240
28240
  }
28241
28241
 
28242
- const GraphStateContext = /*#__PURE__*/createContext({
28243
- state: {},
28244
- dispatch: () => {}
28245
- });
28246
- function useGraphState() {
28247
- return React__default.useContext(GraphStateContext);
28248
- }
28249
-
28250
28242
  /**
28251
28243
  * 44 is touch best practice and AAA compliant for WCAG
28252
28244
  * https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
@@ -28332,9 +28324,6 @@ const getLines = points => points.map((point, i) => {
28332
28324
 
28333
28325
  const defaultStroke = "var(--movable-line-stroke-color)";
28334
28326
  const MovableLine = props => {
28335
- const {
28336
- state
28337
- } = useGraphState();
28338
28327
  const {
28339
28328
  start,
28340
28329
  end,
@@ -28359,12 +28348,13 @@ const MovableLine = props => {
28359
28348
  onMove: newPoint => {
28360
28349
  onMove(vec.sub(newPoint, midpoint));
28361
28350
  },
28362
- constrain: p => snap(state.snapStep, p)
28351
+ constrain: p => p
28363
28352
  });
28364
28353
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("g", {
28365
28354
  ref: line,
28366
28355
  tabIndex: 0,
28367
28356
  className: "movable-line",
28357
+ "data-test-id": "movable-line",
28368
28358
  style: {
28369
28359
  cursor: dragging ? "grabbing" : "grab"
28370
28360
  }
@@ -28375,6 +28365,16 @@ const MovableLine = props => {
28375
28365
  stroke: "transparent",
28376
28366
  strokeWidth: TARGET_SIZE
28377
28367
  }
28368
+ }), /*#__PURE__*/React.createElement(SVGLine, {
28369
+ start: startPtPx,
28370
+ end: endPtPx,
28371
+ className: "movable-line-focus-outline",
28372
+ style: {}
28373
+ }), /*#__PURE__*/React.createElement(SVGLine, {
28374
+ start: startPtPx,
28375
+ end: endPtPx,
28376
+ className: "movable-line-focus-outline-gap",
28377
+ style: {}
28378
28378
  }), /*#__PURE__*/React.createElement(SVGLine, {
28379
28379
  start: startPtPx,
28380
28380
  end: endPtPx,
@@ -28382,7 +28382,8 @@ const MovableLine = props => {
28382
28382
  stroke,
28383
28383
  strokeWidth: "var(--movable-line-stroke-weight)"
28384
28384
  },
28385
- dragging: dragging
28385
+ dragging: dragging,
28386
+ testId: "movable-line__line"
28386
28387
  })), startExtend && /*#__PURE__*/React.createElement(Vector, {
28387
28388
  tail: start,
28388
28389
  tip: startExtend,
@@ -28398,18 +28399,30 @@ function SVGLine(props) {
28398
28399
  start,
28399
28400
  end,
28400
28401
  style,
28401
- dragging
28402
+ dragging,
28403
+ className,
28404
+ testId
28402
28405
  } = props;
28406
+ const draggingClass = dragging ? "movable-dragging" : "";
28403
28407
  return /*#__PURE__*/React.createElement("line", {
28404
28408
  x1: start[0],
28405
28409
  y1: start[1],
28406
28410
  x2: end[0],
28407
28411
  y2: end[1],
28408
28412
  style: style,
28409
- className: dragging ? "movable-dragging" : undefined
28413
+ className: `${className} ${draggingClass}`,
28414
+ "data-test-id": testId
28410
28415
  });
28411
28416
  }
28412
28417
 
28418
+ const GraphStateContext = /*#__PURE__*/createContext({
28419
+ state: {},
28420
+ dispatch: () => {}
28421
+ });
28422
+ function useGraphState() {
28423
+ return React__default.useContext(GraphStateContext);
28424
+ }
28425
+
28413
28426
  // The hitbox size of 48px by 48px is preserved from the legacy interactive
28414
28427
  // graph.
28415
28428
  const hitboxSizePx = 48;
@@ -28441,7 +28454,8 @@ const StyledMovablePoint = props => {
28441
28454
  touchAction: "none",
28442
28455
  outline: "none",
28443
28456
  "--movable-point-color": color$1
28444
- }
28457
+ },
28458
+ "data-test-id": "movable-point"
28445
28459
  }, /*#__PURE__*/React.createElement("circle", {
28446
28460
  className: "movable-point-hitbox",
28447
28461
  r: hitboxSizePx / 2,
@@ -28465,7 +28479,8 @@ const StyledMovablePoint = props => {
28465
28479
  cy: y,
28466
28480
  style: {
28467
28481
  fill: color$1
28468
- }
28482
+ },
28483
+ "data-test-id": "movable-point__center"
28469
28484
  }));
28470
28485
  };
28471
28486
 
@@ -28922,7 +28937,13 @@ const YGridTick = ({
28922
28937
  x2: xPosition + tickSize / 2,
28923
28938
  y2: yPosition,
28924
28939
  style: tickStyle
28925
- }));
28940
+ }), y !== -1 && /*#__PURE__*/React.createElement("text", {
28941
+ height: 20,
28942
+ width: 50,
28943
+ textAnchor: "end",
28944
+ x: xPosition - 10,
28945
+ y: yPosition + 5
28946
+ }, y.toString()));
28926
28947
  };
28927
28948
  const XGridTick = ({
28928
28949
  x
@@ -28937,13 +28958,23 @@ const XGridTick = ({
28937
28958
  x2: xPosition,
28938
28959
  y2: yPosition - tickSize / 2,
28939
28960
  style: tickStyle
28940
- }));
28961
+ }), x !== -1 && /*#__PURE__*/React.createElement("text", {
28962
+ height: 20,
28963
+ width: 50,
28964
+ textAnchor: "middle",
28965
+ x: xPosition,
28966
+ y: yPosition + 25
28967
+ }, x.toString()));
28941
28968
  };
28942
28969
  function generateTickLocations(tickStep, min, max) {
28943
28970
  const ticks = [];
28971
+
28972
+ // Add ticks in the positive direction
28944
28973
  for (let i = 0 + tickStep; i < max; i += tickStep) {
28945
28974
  ticks.push(i);
28946
28975
  }
28976
+
28977
+ // Add ticks in the negative direction
28947
28978
  for (let i = 0 - tickStep; i > min; i -= tickStep) {
28948
28979
  ticks.push(i);
28949
28980
  }
@@ -28972,24 +29003,6 @@ const AxisTicks = props => {
28972
29003
  }));
28973
29004
  };
28974
29005
 
28975
- /**
28976
- * lineLabelText get the text that should
28977
- * be displayed for a specific tick place
28978
- *
28979
- * @param {number} n the tick number
28980
- * @param {number} tickStep how frequently a label should appear
28981
- * @param {vec.Vector2} range the min/max range on the axis
28982
- */
28983
- const lineLabelText = (n, tickStep, range) => {
28984
- const [min, max] = range;
28985
- const isOnStep = n % tickStep === 0;
28986
- const isNegativeOne = n === -1;
28987
- const isMin = n === min;
28988
- const isMax = n === max;
28989
- const shouldRender = isOnStep && !isNegativeOne && !isMin && !isMax;
28990
- return shouldRender ? `${n}` : "";
28991
- };
28992
-
28993
29006
  /**
28994
29007
  * axisOptions determine axis options for Mafs
28995
29008
  *
@@ -29001,12 +29014,10 @@ const lineLabelText = (n, tickStep, range) => {
29001
29014
  * @param {number} axisIndex which axis we're getting options for
29002
29015
  */
29003
29016
  const axisOptions = (props, axisIndex) => {
29004
- const axisStep = props.tickStep[axisIndex];
29005
- const axisRange = props.range[axisIndex];
29006
29017
  return {
29007
29018
  axis: props.markings === "graph",
29008
29019
  lines: props.gridStep[axisIndex],
29009
- labels: n => lineLabelText(n, axisStep, axisRange)
29020
+ labels: false
29010
29021
  };
29011
29022
  };
29012
29023
  const Grid = props => {
@@ -30234,9 +30245,22 @@ const renderGraph = props => {
30234
30245
  return new UnreachableCaseError(type);
30235
30246
  }
30236
30247
  };
30237
- const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
30238
- const [width, height] = props.box;
30248
+ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
30239
30249
  const [state, dispatch] = React.useReducer(interactiveGraphReducer, props, initializeGraphState);
30250
+ useImperativeHandle(ref, () => ({
30251
+ getUserInput: () => getGradableGraph(state, props.graph)
30252
+ }));
30253
+ return /*#__PURE__*/React.createElement(MafsGraph, _extends({
30254
+ state: state,
30255
+ dispatch: dispatch
30256
+ }, props));
30257
+ });
30258
+ const MafsGraph = props => {
30259
+ const {
30260
+ state,
30261
+ dispatch
30262
+ } = props;
30263
+ const [width, height] = props.box;
30240
30264
  const prevState = useRef(state);
30241
30265
  useEffect(() => {
30242
30266
  if (prevState.current !== state) {
@@ -30251,16 +30275,13 @@ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
30251
30275
  const [xSnap, ySnap] = props.snapStep;
30252
30276
  useEffect(() => {
30253
30277
  dispatch(changeSnapStep([xSnap, ySnap]));
30254
- }, [xSnap, ySnap]);
30278
+ }, [dispatch, xSnap, ySnap]);
30255
30279
 
30256
30280
  // Destructuring first to keep useEffect from making excess calls
30257
30281
  const [[xMinRange, xMaxRange], [yMinRange, yMaxRange]] = props.range;
30258
30282
  useEffect(() => {
30259
30283
  dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
30260
- }, [xMinRange, xMaxRange, yMinRange, yMaxRange]);
30261
- React.useImperativeHandle(ref, () => ({
30262
- getUserInput: () => getGradableGraph(state, props.graph)
30263
- }));
30284
+ }, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
30264
30285
  return /*#__PURE__*/React.createElement(GraphStateContext.Provider, {
30265
30286
  value: {
30266
30287
  state,
@@ -30270,7 +30291,9 @@ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
30270
30291
  style: {
30271
30292
  width,
30272
30293
  height,
30273
- position: "relative"
30294
+ position: "relative",
30295
+ padding: "25px 25px 0 0",
30296
+ boxSizing: "content-box"
30274
30297
  }
30275
30298
  }, /*#__PURE__*/React.createElement(LegacyGrid, {
30276
30299
  box: props.box,
@@ -30304,7 +30327,7 @@ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
30304
30327
  state,
30305
30328
  dispatch
30306
30329
  })))));
30307
- });
30330
+ };
30308
30331
 
30309
30332
  const {
30310
30333
  DeprecationMixin
@@ -31608,7 +31631,7 @@ class InteractiveGraph extends React.Component {
31608
31631
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
31609
31632
  const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
31610
31633
  const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
31611
- return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, this.props, {
31634
+ return /*#__PURE__*/React.createElement(StatefulMafsGraph, _extends({}, this.props, {
31612
31635
  ref: this.mafsRef,
31613
31636
  gridStep: gridStep,
31614
31637
  snapStep: snapStep,
@@ -42347,7 +42370,7 @@ const init = function init(options) {
42347
42370
 
42348
42371
  // This file is processed by a Rollup plugin (replace) to inject the production
42349
42372
  const libName = "@khanacademy/perseus";
42350
- const libVersion = "21.2.2";
42373
+ const libVersion = "21.3.0";
42351
42374
  addLibraryVersionToPerseusDebug(libName, libVersion);
42352
42375
 
42353
42376
  const apiVersion = {