@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/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/index.js CHANGED
@@ -45,6 +45,7 @@ var reactPopper = require('react-popper');
45
45
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
46
46
  var cornersOutIcon = require('@phosphor-icons/core/regular/corners-out.svg');
47
47
  var Link = require('@khanacademy/wonder-blocks-link');
48
+ var perseusUtils = require('@khanacademy/perseus-utils');
48
49
 
49
50
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
50
51
 
@@ -1069,9 +1070,12 @@ class InnerMathInput extends React__namespace.Component {
1069
1070
  // a keyboard event is "keydown" type.
1070
1071
  // In react without WonderBlocks, "enter" or "space" keydown events
1071
1072
  // are also "click" events, differentiated by "detail".
1072
- if (e.type === "click") {
1073
+ if (e?.type === "click") {
1073
1074
  this.focus();
1074
1075
  }
1076
+ if (key === "DISMISS") {
1077
+ this.closeKeypad();
1078
+ }
1075
1079
  };
1076
1080
  render() {
1077
1081
  let className = classNames__default["default"]({
@@ -1111,17 +1115,15 @@ class InnerMathInput extends React__namespace.Component {
1111
1115
  onFocus: () => this.focus(),
1112
1116
  onBlur: () => this.blur()
1113
1117
  }), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
1114
- rootBoundary: "document",
1115
1118
  opened: this.state.keypadOpen,
1116
- onClose: () => this.closeKeypad(),
1117
1119
  dismissEnabled: true,
1120
+ rootBoundary: "document",
1118
1121
  "aria-label": this.context.strings.mathInputTitle,
1119
1122
  "aria-describedby": `popover-content-${popoverContentUniqueId}`,
1120
1123
  content: () => /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.HeadingMedium, {
1121
1124
  id: `popover-content-${popoverContentUniqueId}`,
1122
1125
  style: a11y.srOnly
1123
1126
  }, this.context.strings.mathInputDescription), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
1124
- closeButtonVisible: true,
1125
1127
  style: styles$D.popoverContent
1126
1128
  }, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends__default["default"]({
1127
1129
  onAnalyticsEvent: this.props.onAnalyticsEvent,
@@ -1129,7 +1131,9 @@ class InnerMathInput extends React__namespace.Component {
1129
1131
  onClickKey: this.handleKeypadPress,
1130
1132
  cursorContext: this.state.cursorContext,
1131
1133
  convertDotToTimes: this.props.convertDotToTimes
1132
- }, this.props.keypadButtonSets ?? mapButtonSets(this.props?.buttonSets)))))
1134
+ }, this.props.keypadButtonSets ?? mapButtonSets(this.props?.buttonSets), {
1135
+ showDismiss: true
1136
+ }))))
1133
1137
  }, this.props.buttonsVisible === "never" ? /*#__PURE__*/React__namespace.createElement(MathInputIcon, {
1134
1138
  hovered: false,
1135
1139
  focused: false,
@@ -1272,7 +1276,6 @@ const styles$D = aphrodite.StyleSheet.create({
1272
1276
  },
1273
1277
  popoverContent: {
1274
1278
  padding: 0,
1275
- paddingBottom: wonderBlocksTokens.spacing.xxSmall_6,
1276
1279
  maxWidth: "initial"
1277
1280
  }
1278
1281
  });
@@ -3275,6 +3278,7 @@ Zoom.prototype.zoomImage = function () {
3275
3278
  img.src = this._targetImage.src;
3276
3279
  img.alt = this._targetImage.alt;
3277
3280
  img.tabIndex = 0;
3281
+ img.role = "button";
3278
3282
  this.$zoomedImage = $zoomedImage;
3279
3283
  };
3280
3284
  Zoom.prototype._zoomOriginal = function () {
@@ -8244,6 +8248,7 @@ var createRoot;
8244
8248
  var m = ReactDOM__default["default"];
8245
8249
  if (process.env.NODE_ENV === 'production') {
8246
8250
  createRoot = m.createRoot;
8251
+ m.hydrateRoot;
8247
8252
  } else {
8248
8253
  var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
8249
8254
  createRoot = function(c, o) {
@@ -16147,12 +16152,19 @@ class ImageLoader extends React__namespace.Component {
16147
16152
  };
16148
16153
  }
16149
16154
  const staticUrl = getDependencies().staticUrl;
16155
+
16156
+ // If the image is interactive, it should have a role of "button"
16157
+ // to indicate that it is interactive.
16158
+ const imageRole = imgProps.onClick !== null ? "button" : "img";
16150
16159
  return (
16151
16160
  /*#__PURE__*/
16152
- // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
16161
+ // (LEMS-2871) NOTE: This image IS interactive if it requires zooming, and LevelAccess specifically requested
16162
+ // that the role and tabIndex be set here. When users interact with the image on mobile, it will zoom in.
16163
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
16153
16164
  React__namespace.createElement("img", _extends__default["default"]({
16154
16165
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
16155
16166
  tabIndex: 0,
16167
+ role: imageRole,
16156
16168
  src: staticUrl(src),
16157
16169
  onKeyUp: onKeyUp,
16158
16170
  onKeyDown: onKeyDown
@@ -29386,7 +29398,28 @@ const LockedEllipse = props => {
29386
29398
  }));
29387
29399
  };
29388
29400
 
29401
+ function clampDomain(domain, graphBounds) {
29402
+ // If the domain is invalid, return the graph bounds
29403
+ if (domain[0] > domain[1]) {
29404
+ return graphBounds;
29405
+ }
29406
+
29407
+ // If the domain is outside the graph bounds, return null
29408
+ if (domain[0] < graphBounds[0] && domain[1] < graphBounds[0] || domain[0] > graphBounds[1] && domain[1] > graphBounds[1]) {
29409
+ return null;
29410
+ }
29411
+
29412
+ // Clamp the function to the bounds of the graph to prevent memory
29413
+ // leaks when the domain is set to something like [-Infinity, Infinity].
29414
+ const min = Math.max(domain[0], graphBounds[0]);
29415
+ const max = Math.min(domain[1], graphBounds[1]);
29416
+ return [min, max];
29417
+ }
29418
+
29389
29419
  const LockedFunction = props => {
29420
+ const {
29421
+ range
29422
+ } = useGraphConfig();
29390
29423
  const [equation, setEquation] = React.useState();
29391
29424
  const {
29392
29425
  color,
@@ -29396,8 +29429,7 @@ const LockedFunction = props => {
29396
29429
  } = props;
29397
29430
  const plotProps = {
29398
29431
  color: perseusCore.lockedFigureColors[color],
29399
- style: strokeStyle,
29400
- domain
29432
+ style: strokeStyle
29401
29433
  };
29402
29434
  const hasAria = !!props.ariaLabel;
29403
29435
  React.useEffect(() => {
@@ -29408,6 +29440,12 @@ const LockedFunction = props => {
29408
29440
  if (typeof equation === "undefined") {
29409
29441
  return null;
29410
29442
  }
29443
+ const clampedDomain = directionalAxis === "x" ? clampDomain(domain, range[0]) : clampDomain(domain, range[1]);
29444
+
29445
+ // The domain entirely is outside the bounds of the graph. Don't render.
29446
+ if (clampedDomain === null) {
29447
+ return null;
29448
+ }
29411
29449
  return /*#__PURE__*/React__namespace.createElement("g", {
29412
29450
  className: "locked-function",
29413
29451
  "aria-label": hasAria ? props.ariaLabel : undefined,
@@ -29416,11 +29454,13 @@ const LockedFunction = props => {
29416
29454
  }, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, _extends__default["default"]({
29417
29455
  y: x => equation.eval({
29418
29456
  x
29419
- })
29457
+ }),
29458
+ domain: clampedDomain
29420
29459
  }, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY, _extends__default["default"]({
29421
29460
  x: y => equation.eval({
29422
29461
  y
29423
- })
29462
+ }),
29463
+ domain: clampedDomain
29424
29464
  }, plotProps)));
29425
29465
  };
29426
29466
 
@@ -30817,11 +30857,11 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
30817
30857
  const {
30818
30858
  markings,
30819
30859
  showTooltips,
30820
- interactiveColor
30860
+ interactiveColor,
30861
+ disableKeyboardInteraction
30821
30862
  } = useGraphConfig();
30822
30863
  const {
30823
30864
  point,
30824
- color = interactiveColor,
30825
30865
  dragging,
30826
30866
  focused,
30827
30867
  cursor,
@@ -30829,12 +30869,14 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
30829
30869
  onClick = () => {}
30830
30870
  } = props;
30831
30871
 
30832
- // WB Tooltip requires a color name for the background color.
30833
- // Since the color in props is a hex value, a reverse lookup is needed.
30834
- const wbColorName = Object.entries(wonderBlocksTokens.color).find(_ref => {
30835
- let [_, value] = _ref;
30836
- return value === color;
30837
- })?.[0] ?? "blue";
30872
+ // WB Tooltip requires a WB color name for the background color.
30873
+ // We use the blue color when the points are interactive, and
30874
+ // offBlack64 when they are disabled.
30875
+ // Note: The disabled point color is offBlack50 to contrast with
30876
+ // the interactive blue color, but the tooltip background has to be
30877
+ // darker to contrast with its white text - using offBlack64.
30878
+ const wbColorName = disableKeyboardInteraction ? "fadedOffBlack64" // not see-through
30879
+ : "blue";
30838
30880
  const pointClasses = classNames("movable-point", dragging && "movable-point--dragging", showFocusRing && "movable-point--focus");
30839
30881
  const [[x, y]] = useTransformVectorsToPixels(point);
30840
30882
  const showHairlines = (dragging || focused) && markings !== "none";
@@ -30847,7 +30889,7 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
30847
30889
  ref: hitboxRef,
30848
30890
  className: pointClasses,
30849
30891
  style: {
30850
- "--movable-point-color": color,
30892
+ "--movable-point-color": interactiveColor,
30851
30893
  cursor
30852
30894
  },
30853
30895
  "data-testid": "movable-point",
@@ -30874,7 +30916,7 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
30874
30916
  cx: x,
30875
30917
  cy: y,
30876
30918
  style: {
30877
- fill: color
30919
+ fill: interactiveColor
30878
30920
  },
30879
30921
  "data-testid": "movable-point__center"
30880
30922
  }));
@@ -30909,7 +30951,6 @@ function useControlPoint(params) {
30909
30951
  ariaDescribedBy,
30910
30952
  ariaLabel,
30911
30953
  ariaLive = "polite",
30912
- color,
30913
30954
  constrain = p => snap(snapStep, p),
30914
30955
  cursor,
30915
30956
  forwardedRef = noop$1,
@@ -30971,6 +31012,7 @@ function useControlPoint(params) {
30971
31012
  "aria-describedby": ariaDescribedBy,
30972
31013
  "aria-label": pointAriaLabel,
30973
31014
  "aria-live": ariaLive,
31015
+ "aria-disabled": disableKeyboardInteraction,
30974
31016
  onFocus: event => {
30975
31017
  onFocus(event);
30976
31018
  setFocused(true);
@@ -30989,7 +31031,6 @@ function useControlPoint(params) {
30989
31031
  point: point,
30990
31032
  dragging: dragging,
30991
31033
  focused: focused,
30992
- color: color,
30993
31034
  ref: visiblePointRef,
30994
31035
  showFocusRing: focused
30995
31036
  });
@@ -31133,6 +31174,7 @@ const Line$1 = props => {
31133
31174
  "aria-label": ariaLabel,
31134
31175
  "aria-describedby": ariaDescribedBy,
31135
31176
  "aria-live": ariaLive,
31177
+ "aria-disabled": disableKeyboardInteraction,
31136
31178
  className: "movable-line",
31137
31179
  "data-testid": "movable-line",
31138
31180
  style: {
@@ -31691,6 +31733,7 @@ function MovableCircle(props) {
31691
31733
  "aria-label": ariaLabel,
31692
31734
  "aria-describedby": ariaDescribedBy,
31693
31735
  "aria-live": "polite",
31736
+ "aria-disabled": disableKeyboardInteraction,
31694
31737
  ref: draggableRef,
31695
31738
  role: "button",
31696
31739
  tabIndex: disableKeyboardInteraction ? -1 : 0,
@@ -33620,7 +33663,8 @@ const LimitedPolygonGraph = statefulProps => {
33620
33663
  // Accessibility-related fields
33621
33664
  role: "button",
33622
33665
  "aria-label": srPolygonGraphPoints ? `${srPolygonElementsNum} ${srPolygonGraphPoints}` : srPolygonElementsNum,
33623
- "aria-live": ariaLives[0]
33666
+ "aria-live": ariaLives[0],
33667
+ "aria-disabled": disableKeyboardInteraction
33624
33668
  }
33625
33669
  }), points.map((point, i) => {
33626
33670
  const angleId = `${id}-angle-${i}`;
@@ -34910,7 +34954,7 @@ const MafsGraph = props => {
34910
34954
  handleKeyboardEvent(event, state, dispatch);
34911
34955
  },
34912
34956
  "aria-label": fullGraphAriaLabel,
34913
- "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && instructionsId),
34957
+ "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && !disableInteraction && instructionsId),
34914
34958
  ref: graphRef,
34915
34959
  tabIndex: 0,
34916
34960
  onFocus: event => {
@@ -41968,51 +42012,10 @@ const init = function () {
41968
42012
  replaceDeprecatedWidgets();
41969
42013
  };
41970
42014
 
41971
- /**
41972
- * Adds the given perseus library version information to the __perseus_debug__
41973
- * object and ensures that the object is attached to `globalThis` (`window` in
41974
- * browser environments).
41975
- *
41976
- * This allows each library to provide runtime version information to assist in
41977
- * debugging in production environments.
41978
- */
41979
- const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
41980
- // If the library version is the default value, then we don't want to
41981
- // prefix it with a "v" to indicate that it is a version number.
41982
- let prefix = "v";
41983
- if (libraryVersion === "__lib_version__") {
41984
- prefix = "";
41985
- }
41986
- const formattedVersion = `${prefix}${libraryVersion}`;
41987
- if (typeof globalThis !== "undefined") {
41988
- globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
41989
- const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
41990
- if (existingVersionEntry) {
41991
- // If we already have an entry and it doesn't match the registered
41992
- // version, we morph the entry into an array and log a warning.
41993
- if (existingVersionEntry !== formattedVersion) {
41994
- // Existing entry might be an array already (oops, at least 2
41995
- // versions of the library already loaded!).
41996
- const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
41997
- allVersions.push(formattedVersion);
41998
- globalThis.__perseus_debug__[libraryName] = allVersions;
41999
-
42000
- // eslint-disable-next-line no-console
42001
- console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
42002
- }
42003
- } else {
42004
- globalThis.__perseus_debug__[libraryName] = formattedVersion;
42005
- }
42006
- } else {
42007
- // eslint-disable-next-line no-console
42008
- console.warn(`globalThis not found found (${formattedVersion})`);
42009
- }
42010
- };
42011
-
42012
42015
  // This file is processed by a Rollup plugin (replace) to inject the production
42013
42016
  const libName = "@khanacademy/perseus";
42014
- const libVersion = "57.2.0";
42015
- addLibraryVersionToPerseusDebug(libName, libVersion);
42017
+ const libVersion = "57.2.2";
42018
+ perseusUtils.addLibraryVersionToPerseusDebug(libName, libVersion);
42016
42019
 
42017
42020
  const apiVersion = {
42018
42021
  major: 12,