@khanacademy/perseus 57.2.0 → 57.2.2

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
@@ -1078,7 +1078,7 @@ div.graphie {
1078
1078
  font-size: 14px;
1079
1079
  }
1080
1080
  .framework-perseus .number-input {
1081
- border: 1px solid #ccc;
1081
+ border: 1px solid #909296;
1082
1082
  border-radius: 5px;
1083
1083
  margin: 0;
1084
1084
  padding: 5px 0;
@@ -2966,7 +2966,6 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
2966
2966
  --movable-point-hover-expansion: 2px;
2967
2967
  --movable-point-focus-ring-offset: 2px;
2968
2968
 
2969
- --movable-line-stroke-color: var(--mafs-blue);
2970
2969
  --movable-line-stroke-weight: 2px;
2971
2970
  --movable-line-stroke-weight-active: 4px;
2972
2971
  overflow: visible !important;
package/dist/es/index.js CHANGED
@@ -27,7 +27,7 @@ import { KeypadContext } from '@khanacademy/keypad-context';
27
27
  import { TextField } from '@khanacademy/wonder-blocks-form';
28
28
  import { entries, UnreachableCaseError, keys } from '@khanacademy/wonder-stuff-core';
29
29
  import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
30
- import { point, KhanMath, number, vector as vector$3, line, geometry, angles, coefficients } from '@khanacademy/kmath';
30
+ import { point, KhanMath, vector as vector$3, number, line, geometry, angles, coefficients } from '@khanacademy/kmath';
31
31
  import _classPrivateFieldLooseBase from '@babel/runtime/helpers/classPrivateFieldLooseBase';
32
32
  import _classPrivateFieldLooseKey from '@babel/runtime/helpers/classPrivateFieldLooseKey';
33
33
  import SimpleMarkdown from '@khanacademy/simple-markdown';
@@ -48,6 +48,7 @@ import { Popper } from 'react-popper';
48
48
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
49
49
  import cornersOutIcon from '@phosphor-icons/core/regular/corners-out.svg';
50
50
  import Link from '@khanacademy/wonder-blocks-link';
51
+ import { addLibraryVersionToPerseusDebug } from '@khanacademy/perseus-utils';
51
52
 
52
53
  /**
53
54
  * The translated strings that are used to render Perseus.
@@ -767,9 +768,12 @@ class InnerMathInput extends React.Component {
767
768
  // a keyboard event is "keydown" type.
768
769
  // In react without WonderBlocks, "enter" or "space" keydown events
769
770
  // are also "click" events, differentiated by "detail".
770
- if (e.type === "click") {
771
+ if ((e == null ? void 0 : e.type) === "click") {
771
772
  this.focus();
772
773
  }
774
+ if (key === "DISMISS") {
775
+ this.closeKeypad();
776
+ }
773
777
  };
774
778
  }
775
779
  componentDidMount() {
@@ -829,10 +833,9 @@ class InnerMathInput extends React.Component {
829
833
  onFocus: () => this.focus(),
830
834
  onBlur: () => this.blur()
831
835
  }), /*#__PURE__*/React.createElement(Popover, {
832
- rootBoundary: "document",
833
836
  opened: this.state.keypadOpen,
834
- onClose: () => this.closeKeypad(),
835
837
  dismissEnabled: true,
838
+ rootBoundary: "document",
836
839
  "aria-label": this.context.strings.mathInputTitle,
837
840
  "aria-describedby": `popover-content-${popoverContentUniqueId}`,
838
841
  content: () => {
@@ -841,7 +844,6 @@ class InnerMathInput extends React.Component {
841
844
  id: `popover-content-${popoverContentUniqueId}`,
842
845
  style: a11y.srOnly
843
846
  }, this.context.strings.mathInputDescription), /*#__PURE__*/React.createElement(PopoverContentCore, {
844
- closeButtonVisible: true,
845
847
  style: styles$D.popoverContent
846
848
  }, /*#__PURE__*/React.createElement(DesktopKeypad, _extends({
847
849
  onAnalyticsEvent: this.props.onAnalyticsEvent,
@@ -849,7 +851,9 @@ class InnerMathInput extends React.Component {
849
851
  onClickKey: this.handleKeypadPress,
850
852
  cursorContext: this.state.cursorContext,
851
853
  convertDotToTimes: this.props.convertDotToTimes
852
- }, (_this$props$keypadBut = this.props.keypadButtonSets) != null ? _this$props$keypadBut : mapButtonSets((_this$props = this.props) == null ? void 0 : _this$props.buttonSets)))));
854
+ }, (_this$props$keypadBut = this.props.keypadButtonSets) != null ? _this$props$keypadBut : mapButtonSets((_this$props = this.props) == null ? void 0 : _this$props.buttonSets), {
855
+ showDismiss: true
856
+ }))));
853
857
  }
854
858
  }, this.props.buttonsVisible === "never" ? /*#__PURE__*/React.createElement(MathInputIcon, {
855
859
  hovered: false,
@@ -1003,7 +1007,6 @@ const styles$D = StyleSheet.create({
1003
1007
  },
1004
1008
  popoverContent: {
1005
1009
  padding: 0,
1006
- paddingBottom: spacing.xxSmall_6,
1007
1010
  maxWidth: "initial"
1008
1011
  }
1009
1012
  });
@@ -3021,6 +3024,7 @@ Zoom.prototype.zoomImage = function () {
3021
3024
  img.src = this._targetImage.src;
3022
3025
  img.alt = this._targetImage.alt;
3023
3026
  img.tabIndex = 0;
3027
+ img.role = "button";
3024
3028
  this.$zoomedImage = $zoomedImage;
3025
3029
  };
3026
3030
  Zoom.prototype._zoomOriginal = function () {
@@ -7980,6 +7984,7 @@ var createRoot;
7980
7984
  var m = ReactDOM__default;
7981
7985
  if (process.env.NODE_ENV === 'production') {
7982
7986
  createRoot = m.createRoot;
7987
+ m.hydrateRoot;
7983
7988
  } else {
7984
7989
  var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
7985
7990
  createRoot = function(c, o) {
@@ -15810,12 +15815,19 @@ class ImageLoader extends React.Component {
15810
15815
  };
15811
15816
  }
15812
15817
  const staticUrl = getDependencies().staticUrl;
15818
+
15819
+ // If the image is interactive, it should have a role of "button"
15820
+ // to indicate that it is interactive.
15821
+ const imageRole = imgProps.onClick !== null ? "button" : "img";
15813
15822
  return (
15814
15823
  /*#__PURE__*/
15815
- // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
15824
+ // (LEMS-2871) NOTE: This image IS interactive if it requires zooming, and LevelAccess specifically requested
15825
+ // that the role and tabIndex be set here. When users interact with the image on mobile, it will zoom in.
15826
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
15816
15827
  React.createElement("img", _extends({
15817
15828
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
15818
15829
  tabIndex: 0,
15830
+ role: imageRole,
15819
15831
  src: staticUrl(src),
15820
15832
  onKeyUp: onKeyUp,
15821
15833
  onKeyDown: onKeyDown
@@ -28928,7 +28940,28 @@ const LockedEllipse = props => {
28928
28940
  }));
28929
28941
  };
28930
28942
 
28943
+ function clampDomain(domain, graphBounds) {
28944
+ // If the domain is invalid, return the graph bounds
28945
+ if (domain[0] > domain[1]) {
28946
+ return graphBounds;
28947
+ }
28948
+
28949
+ // If the domain is outside the graph bounds, return null
28950
+ if (domain[0] < graphBounds[0] && domain[1] < graphBounds[0] || domain[0] > graphBounds[1] && domain[1] > graphBounds[1]) {
28951
+ return null;
28952
+ }
28953
+
28954
+ // Clamp the function to the bounds of the graph to prevent memory
28955
+ // leaks when the domain is set to something like [-Infinity, Infinity].
28956
+ const min = Math.max(domain[0], graphBounds[0]);
28957
+ const max = Math.min(domain[1], graphBounds[1]);
28958
+ return [min, max];
28959
+ }
28960
+
28931
28961
  const LockedFunction = props => {
28962
+ const {
28963
+ range
28964
+ } = useGraphConfig();
28932
28965
  const [equation, setEquation] = useState();
28933
28966
  const {
28934
28967
  color,
@@ -28938,8 +28971,7 @@ const LockedFunction = props => {
28938
28971
  } = props;
28939
28972
  const plotProps = {
28940
28973
  color: lockedFigureColors[color],
28941
- style: strokeStyle,
28942
- domain
28974
+ style: strokeStyle
28943
28975
  };
28944
28976
  const hasAria = !!props.ariaLabel;
28945
28977
  useEffect(() => {
@@ -28950,6 +28982,12 @@ const LockedFunction = props => {
28950
28982
  if (typeof equation === "undefined") {
28951
28983
  return null;
28952
28984
  }
28985
+ const clampedDomain = directionalAxis === "x" ? clampDomain(domain, range[0]) : clampDomain(domain, range[1]);
28986
+
28987
+ // The domain entirely is outside the bounds of the graph. Don't render.
28988
+ if (clampedDomain === null) {
28989
+ return null;
28990
+ }
28953
28991
  return /*#__PURE__*/React.createElement("g", {
28954
28992
  className: "locked-function",
28955
28993
  "aria-label": hasAria ? props.ariaLabel : undefined,
@@ -28958,11 +28996,13 @@ const LockedFunction = props => {
28958
28996
  }, directionalAxis === "x" && /*#__PURE__*/React.createElement(Plot$2.OfX, _extends({
28959
28997
  y: x => equation.eval({
28960
28998
  x
28961
- })
28999
+ }),
29000
+ domain: clampedDomain
28962
29001
  }, plotProps)), directionalAxis === "y" && /*#__PURE__*/React.createElement(Plot$2.OfY, _extends({
28963
29002
  x: y => equation.eval({
28964
29003
  y
28965
- })
29004
+ }),
29005
+ domain: clampedDomain
28966
29006
  }, plotProps)));
28967
29007
  };
28968
29008
 
@@ -30344,15 +30384,14 @@ const hitboxSizePx = 48;
30344
30384
  // function with no state or effects) that renders the SVG for a movable point
30345
30385
  // on an interactive graph.
30346
30386
  const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
30347
- var _Object$entries$find$, _Object$entries$find;
30348
30387
  const {
30349
30388
  markings,
30350
30389
  showTooltips,
30351
- interactiveColor
30390
+ interactiveColor,
30391
+ disableKeyboardInteraction
30352
30392
  } = useGraphConfig();
30353
30393
  const {
30354
30394
  point,
30355
- color: color$1 = interactiveColor,
30356
30395
  dragging,
30357
30396
  focused,
30358
30397
  cursor,
@@ -30360,9 +30399,14 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
30360
30399
  onClick = () => {}
30361
30400
  } = props;
30362
30401
 
30363
- // WB Tooltip requires a color name for the background color.
30364
- // Since the color in props is a hex value, a reverse lookup is needed.
30365
- const wbColorName = (_Object$entries$find$ = (_Object$entries$find = Object.entries(color).find(([_, value]) => value === color$1)) == null ? void 0 : _Object$entries$find[0]) != null ? _Object$entries$find$ : "blue";
30402
+ // WB Tooltip requires a WB color name for the background color.
30403
+ // We use the blue color when the points are interactive, and
30404
+ // offBlack64 when they are disabled.
30405
+ // Note: The disabled point color is offBlack50 to contrast with
30406
+ // the interactive blue color, but the tooltip background has to be
30407
+ // darker to contrast with its white text - using offBlack64.
30408
+ const wbColorName = disableKeyboardInteraction ? "fadedOffBlack64" // not see-through
30409
+ : "blue";
30366
30410
  const pointClasses = classNames("movable-point", dragging && "movable-point--dragging", showFocusRing && "movable-point--focus");
30367
30411
  const [[x, y]] = useTransformVectorsToPixels(point);
30368
30412
  const showHairlines = (dragging || focused) && markings !== "none";
@@ -30375,7 +30419,7 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
30375
30419
  ref: hitboxRef,
30376
30420
  className: pointClasses,
30377
30421
  style: {
30378
- "--movable-point-color": color$1,
30422
+ "--movable-point-color": interactiveColor,
30379
30423
  cursor
30380
30424
  },
30381
30425
  "data-testid": "movable-point",
@@ -30402,7 +30446,7 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
30402
30446
  cx: x,
30403
30447
  cy: y,
30404
30448
  style: {
30405
- fill: color$1
30449
+ fill: interactiveColor
30406
30450
  },
30407
30451
  "data-testid": "movable-point__center"
30408
30452
  }));
@@ -30434,7 +30478,6 @@ function useControlPoint(params) {
30434
30478
  ariaDescribedBy,
30435
30479
  ariaLabel,
30436
30480
  ariaLive = "polite",
30437
- color,
30438
30481
  constrain = p => snap(snapStep, p),
30439
30482
  cursor,
30440
30483
  forwardedRef = noop$1,
@@ -30497,6 +30540,7 @@ function useControlPoint(params) {
30497
30540
  "aria-describedby": ariaDescribedBy,
30498
30541
  "aria-label": pointAriaLabel,
30499
30542
  "aria-live": ariaLive,
30543
+ "aria-disabled": disableKeyboardInteraction,
30500
30544
  onFocus: event => {
30501
30545
  onFocus(event);
30502
30546
  setFocused(true);
@@ -30516,7 +30560,6 @@ function useControlPoint(params) {
30516
30560
  point: point,
30517
30561
  dragging: dragging,
30518
30562
  focused: focused,
30519
- color: color,
30520
30563
  ref: visiblePointRef,
30521
30564
  showFocusRing: focused
30522
30565
  });
@@ -30660,6 +30703,7 @@ const Line$1 = props => {
30660
30703
  "aria-label": ariaLabel,
30661
30704
  "aria-describedby": ariaDescribedBy,
30662
30705
  "aria-live": ariaLive,
30706
+ "aria-disabled": disableKeyboardInteraction,
30663
30707
  className: "movable-line",
30664
30708
  "data-testid": "movable-line",
30665
30709
  style: {
@@ -31203,6 +31247,7 @@ function MovableCircle(props) {
31203
31247
  "aria-label": ariaLabel,
31204
31248
  "aria-describedby": ariaDescribedBy,
31205
31249
  "aria-live": "polite",
31250
+ "aria-disabled": disableKeyboardInteraction,
31206
31251
  ref: draggableRef,
31207
31252
  role: "button",
31208
31253
  tabIndex: disableKeyboardInteraction ? -1 : 0,
@@ -33079,7 +33124,8 @@ const LimitedPolygonGraph = statefulProps => {
33079
33124
  // Accessibility-related fields
33080
33125
  role: "button",
33081
33126
  "aria-label": srPolygonGraphPoints ? `${srPolygonElementsNum} ${srPolygonGraphPoints}` : srPolygonElementsNum,
33082
- "aria-live": ariaLives[0]
33127
+ "aria-live": ariaLives[0],
33128
+ "aria-disabled": disableKeyboardInteraction
33083
33129
  }
33084
33130
  }), points.map((point, i) => {
33085
33131
  const angleId = `${id}-angle-${i}`;
@@ -34363,7 +34409,7 @@ const MafsGraph = props => {
34363
34409
  handleKeyboardEvent(event, state, dispatch);
34364
34410
  },
34365
34411
  "aria-label": fullGraphAriaLabel,
34366
- "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && instructionsId),
34412
+ "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && !disableInteraction && instructionsId),
34367
34413
  ref: graphRef,
34368
34414
  tabIndex: 0,
34369
34415
  onFocus: event => {
@@ -41404,51 +41450,9 @@ const init = function init() {
41404
41450
  replaceDeprecatedWidgets();
41405
41451
  };
41406
41452
 
41407
- /**
41408
- * Adds the given perseus library version information to the __perseus_debug__
41409
- * object and ensures that the object is attached to `globalThis` (`window` in
41410
- * browser environments).
41411
- *
41412
- * This allows each library to provide runtime version information to assist in
41413
- * debugging in production environments.
41414
- */
41415
- const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
41416
- // If the library version is the default value, then we don't want to
41417
- // prefix it with a "v" to indicate that it is a version number.
41418
- let prefix = "v";
41419
- if (libraryVersion === "__lib_version__") {
41420
- prefix = "";
41421
- }
41422
- const formattedVersion = `${prefix}${libraryVersion}`;
41423
- if (typeof globalThis !== "undefined") {
41424
- var _globalThis$__perseus;
41425
- globalThis.__perseus_debug__ = (_globalThis$__perseus = globalThis.__perseus_debug__) != null ? _globalThis$__perseus : {};
41426
- const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
41427
- if (existingVersionEntry) {
41428
- // If we already have an entry and it doesn't match the registered
41429
- // version, we morph the entry into an array and log a warning.
41430
- if (existingVersionEntry !== formattedVersion) {
41431
- // Existing entry might be an array already (oops, at least 2
41432
- // versions of the library already loaded!).
41433
- const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
41434
- allVersions.push(formattedVersion);
41435
- globalThis.__perseus_debug__[libraryName] = allVersions;
41436
-
41437
- // eslint-disable-next-line no-console
41438
- console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
41439
- }
41440
- } else {
41441
- globalThis.__perseus_debug__[libraryName] = formattedVersion;
41442
- }
41443
- } else {
41444
- // eslint-disable-next-line no-console
41445
- console.warn(`globalThis not found found (${formattedVersion})`);
41446
- }
41447
- };
41448
-
41449
41453
  // This file is processed by a Rollup plugin (replace) to inject the production
41450
41454
  const libName = "@khanacademy/perseus";
41451
- const libVersion = "57.2.0";
41455
+ const libVersion = "57.2.2";
41452
41456
  addLibraryVersionToPerseusDebug(libName, libVersion);
41453
41457
 
41454
41458
  const apiVersion = {