@khanacademy/perseus 17.5.0 → 17.6.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/es/index.js +415 -618
  3. package/dist/es/index.js.map +1 -1
  4. package/dist/index.js +424 -615
  5. package/dist/index.js.map +1 -1
  6. package/dist/perseus-types.d.ts +2 -1
  7. package/dist/strings.js +1 -0
  8. package/dist/widgets/deprecated-standin/index.d.ts +32 -0
  9. package/dist/widgets/label-image/answer-choices.d.ts +8 -40
  10. package/dist/widgets/label-image/answer-pill.d.ts +3 -1
  11. package/dist/widgets/label-image/marker.d.ts +10 -5
  12. package/dist/widgets/label-image.d.ts +1 -8
  13. package/dist/widgets.d.ts +9 -0
  14. package/package.json +34 -33
  15. package/src/__tests__/widgets.test.ts +20 -0
  16. package/src/extra-widgets.ts +2 -0
  17. package/src/init.ts +5 -0
  18. package/src/perseus-types.ts +4 -1
  19. package/src/util/register-all-widgets-for-testing.ts +4 -0
  20. package/src/widgets/__stories__/orderer.stories.tsx +5 -1
  21. package/src/widgets/__testdata__/orderer.testdata.ts +66 -0
  22. package/src/widgets/deprecated-standin/__stories__/deprecated-standin.stories.tsx +34 -0
  23. package/src/widgets/deprecated-standin/__tests__/__snapshots__/deprecated-standin.test.ts.snap +71 -0
  24. package/src/widgets/deprecated-standin/__tests__/deprecated-standin.test.ts +93 -0
  25. package/src/widgets/deprecated-standin/index.tsx +57 -0
  26. package/src/widgets/iframe.tsx +1 -1
  27. package/src/widgets/input-number.tsx +1 -1
  28. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +29 -34
  29. package/src/widgets/label-image/__tests__/answer-pill.test.tsx +2 -10
  30. package/src/widgets/label-image/answer-choices.tsx +60 -278
  31. package/src/widgets/label-image/answer-pill.tsx +22 -13
  32. package/src/widgets/label-image/marker.tsx +103 -146
  33. package/src/widgets/label-image.test.ts +0 -2
  34. package/src/widgets/label-image.tsx +94 -195
  35. package/src/widgets/lights-puzzle.tsx +1 -1
  36. package/src/widgets/matcher.tsx +1 -1
  37. package/src/widgets/numeric-input.tsx +1 -1
  38. package/src/widgets/radio.ts +1 -1
  39. package/src/widgets/reaction-diagram.tsx +1 -1
  40. package/src/widgets/sequence.tsx +1 -1
  41. package/src/widgets/simulator.tsx +1 -1
  42. package/src/widgets/table.tsx +1 -1
  43. package/src/widgets/transformer.tsx +2 -1
  44. package/src/widgets/unit.tsx +1 -1
  45. package/src/widgets.ts +24 -0
  46. package/tsconfig-build.tsbuildinfo +1 -1
package/dist/index.js CHANGED
@@ -26,12 +26,13 @@ var pureMarkdown = require('@khanacademy/pure-markdown');
26
26
  var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
27
27
  var Button = require('@khanacademy/wonder-blocks-button');
28
28
  var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
29
+ var Banner = require('@khanacademy/wonder-blocks-banner');
29
30
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
30
31
  var debounce = require('lodash.debounce');
31
- var Pill = require('@khanacademy/wonder-blocks-pill');
32
- var reactPopper = require('react-popper');
33
32
  var Switch = require('@khanacademy/wonder-blocks-switch');
34
33
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
34
+ var Pill = require('@khanacademy/wonder-blocks-pill');
35
+ var reactPopper = require('react-popper');
35
36
  var createReactClass = require('create-react-class');
36
37
  var Link = require('@khanacademy/wonder-blocks-link');
37
38
  var perseusCore = require('@khanacademy/perseus-core');
@@ -62,6 +63,7 @@ var i18n__namespace = /*#__PURE__*/_interopNamespace(i18n);
62
63
  var Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip$1);
63
64
  var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
64
65
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
66
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
65
67
  var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
66
68
  var Clickable__default = /*#__PURE__*/_interopDefaultLegacy(Clickable);
67
69
  var Color__default = /*#__PURE__*/_interopDefaultLegacy(Color);
@@ -72,9 +74,10 @@ var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
72
74
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
73
75
  var SimpleMarkdown__default = /*#__PURE__*/_interopDefaultLegacy(SimpleMarkdown);
74
76
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
77
+ var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
75
78
  var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
76
- var Pill__default = /*#__PURE__*/_interopDefaultLegacy(Pill);
77
79
  var Switch__default = /*#__PURE__*/_interopDefaultLegacy(Switch);
80
+ var Pill__default = /*#__PURE__*/_interopDefaultLegacy(Pill);
78
81
  var createReactClass__default = /*#__PURE__*/_interopDefaultLegacy(createReactClass);
79
82
  var Link__default = /*#__PURE__*/_interopDefaultLegacy(Link);
80
83
 
@@ -274,7 +277,7 @@ class MathInput extends React__namespace.Component {
274
277
  className = className + " " + this.props.className;
275
278
  }
276
279
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
277
- style: [styles$C.outerWrapper, this.state.focused && styles$C.wrapperFocused, this.props.hasError && styles$C.wrapperError]
280
+ style: [styles$B.outerWrapper, this.state.focused && styles$B.wrapperFocused, this.props.hasError && styles$B.wrapperError]
278
281
  }, /*#__PURE__*/React__namespace.createElement("div", {
279
282
  style: {
280
283
  display: "flex",
@@ -301,7 +304,7 @@ class MathInput extends React__namespace.Component {
301
304
  dismissEnabled: true,
302
305
  content: () => /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
303
306
  closeButtonVisible: true,
304
- style: styles$C.popoverContent
307
+ style: styles$B.popoverContent
305
308
  }, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends({
306
309
  onAnalyticsEvent: this.props.analytics.onAnalyticsEvent,
307
310
  extraKeys: this.props.extraKeys,
@@ -341,9 +344,9 @@ const MathInputIcon = _ref => {
341
344
  color = Color__default["default"].offBlack;
342
345
  break;
343
346
  }
344
- const dynamicClass = active || focused ? styles$C.iconActive : styles$C.iconInactive;
347
+ const dynamicClass = active || focused ? styles$B.iconActive : styles$B.iconInactive;
345
348
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
346
- style: [styles$C.iconContainer, dynamicClass]
349
+ style: [styles$B.iconContainer, dynamicClass]
347
350
  }, /*#__PURE__*/React__namespace.createElement("svg", {
348
351
  xmlns: "http://www.w3.org/2000/svg",
349
352
  width: "16",
@@ -388,7 +391,7 @@ const inputFocused = {
388
391
  borderColor: Color__default["default"].blue,
389
392
  margin: -1
390
393
  };
391
- const styles$C = aphrodite.StyleSheet.create({
394
+ const styles$B = aphrodite.StyleSheet.create({
392
395
  iconContainer: {
393
396
  display: "flex",
394
397
  justifyContent: "center",
@@ -17624,33 +17627,33 @@ class Lint extends React__namespace.Component {
17624
17627
  let warningText;
17625
17628
  let warningTextStyle;
17626
17629
  if (this.props.severity === Severity.Error) {
17627
- severityStyle = styles$B.indicatorError;
17630
+ severityStyle = styles$A.indicatorError;
17628
17631
  warningText = "Error";
17629
- warningTextStyle = styles$B.publishBlockingError;
17632
+ warningTextStyle = styles$A.publishBlockingError;
17630
17633
  } else if (this.props.severity === Severity.Warning) {
17631
- severityStyle = styles$B.indicatorWarning;
17634
+ severityStyle = styles$A.indicatorWarning;
17632
17635
  warningText = "Warning";
17633
- warningTextStyle = styles$B.warning;
17636
+ warningTextStyle = styles$A.warning;
17634
17637
  } else {
17635
- severityStyle = styles$B.indicatorGuideline;
17638
+ severityStyle = styles$A.indicatorGuideline;
17636
17639
  warningText = "Recommendation";
17637
- warningTextStyle = styles$B.warning;
17640
+ warningTextStyle = styles$A.warning;
17638
17641
  }
17639
17642
  return /*#__PURE__*/React__namespace.createElement("a", {
17640
17643
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
17641
17644
  target: "lint-help-window",
17642
17645
  className: aphrodite.css(style)
17643
17646
  }, /*#__PURE__*/React__namespace.createElement("span", {
17644
- className: aphrodite.css(styles$B.indicator, severityStyle)
17647
+ className: aphrodite.css(styles$A.indicator, severityStyle)
17645
17648
  }, this.props.severity === 1 && /*#__PURE__*/React__namespace.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React__namespace.createElement("div", {
17646
- className: aphrodite.css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
17649
+ className: aphrodite.css(styles$A.tooltip, tooltipAbove && styles$A.tooltipAbove)
17647
17650
  }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React__namespace.createElement("p", {
17648
17651
  key: i,
17649
- className: aphrodite.css(styles$B.tooltipParagraph)
17652
+ className: aphrodite.css(styles$A.tooltipParagraph)
17650
17653
  }, /*#__PURE__*/React__namespace.createElement("span", {
17651
17654
  className: aphrodite.css(warningTextStyle)
17652
17655
  }, warningText, ":", " "), m)), /*#__PURE__*/React__namespace.createElement("div", {
17653
- className: aphrodite.css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
17656
+ className: aphrodite.css(styles$A.tail, tooltipAbove && styles$A.tailAbove)
17654
17657
  })));
17655
17658
  };
17656
17659
 
@@ -17678,20 +17681,20 @@ class Lint extends React__namespace.Component {
17678
17681
  }
17679
17682
  if (blockHighlight) {
17680
17683
  return /*#__PURE__*/React__namespace.createElement("span", {
17681
- className: aphrodite.css(styles$B.lintContainer, styles$B.lintContainerBlock)
17682
- }, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
17684
+ className: aphrodite.css(styles$A.lintContainer, styles$A.lintContainerBlock)
17685
+ }, this.renderLink(styles$A.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
17683
17686
  }
17684
17687
  if (inline) {
17685
17688
  return /*#__PURE__*/React__namespace.createElement("span", {
17686
- className: aphrodite.css(styles$B.lintContainer)
17687
- }, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
17689
+ className: aphrodite.css(styles$A.lintContainer)
17690
+ }, this.renderLink(styles$A.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
17688
17691
  }
17689
17692
  return /*#__PURE__*/React__namespace.createElement("div", {
17690
- className: aphrodite.css(styles$B.lintContainer)
17691
- }, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
17693
+ className: aphrodite.css(styles$A.lintContainer)
17694
+ }, this.renderLink(styles$A.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
17692
17695
  }
17693
17696
  }
17694
- const styles$B = aphrodite.StyleSheet.create({
17697
+ const styles$A = aphrodite.StyleSheet.create({
17695
17698
  // This is the class of the outermost element.
17696
17699
  // We use relative positioning so that the lint indicator can be
17697
17700
  // positioned absolutely relative to the position of the linty container.
@@ -18462,6 +18465,27 @@ const registerWidgets = widgets => {
18462
18465
  });
18463
18466
  validateAlignments();
18464
18467
  };
18468
+
18469
+ /**
18470
+ *
18471
+ * @param name - the widget that you are trying to replace
18472
+ * @param replacementName - the name of the widget that takes its place
18473
+ *
18474
+ * e.g. replaceWidget("transformer", "always-correct") will make it so the
18475
+ * transformer widget is replaced by the always correct widget
18476
+ */
18477
+ const replaceWidget = (name, replacementName) => {
18478
+ const substituteWidget = widgets[replacementName];
18479
+ if (!substituteWidget && Log) {
18480
+ const errorMsg = `Failed to replace ${name} with ${replacementName}`;
18481
+ Log.error(errorMsg, Errors.Internal);
18482
+ return;
18483
+ }
18484
+ registerWidget(name, substituteWidget);
18485
+ if (Log) {
18486
+ Log.log(`INFO: Replacing widget ${name} with ${replacementName}`);
18487
+ }
18488
+ };
18465
18489
  const registerEditors = editorsToRegister => {
18466
18490
  editorsToRegister.forEach(editor => {
18467
18491
  if (!editor.widgetName) {
@@ -18780,6 +18804,7 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
18780
18804
  __proto__: null,
18781
18805
  registerWidget: registerWidget,
18782
18806
  registerWidgets: registerWidgets,
18807
+ replaceWidget: replaceWidget,
18783
18808
  registerEditors: registerEditors,
18784
18809
  getWidget: getWidget,
18785
18810
  getEditor: getEditor,
@@ -19740,7 +19765,7 @@ class Renderer extends React__namespace.Component {
19740
19765
  };
19741
19766
  const mobileInnerStyle = {
19742
19767
  ...innerStyle,
19743
- ...styles$A.mobileZoomableParentFix
19768
+ ...styles$z.mobileZoomableParentFix
19744
19769
  };
19745
19770
  return /*#__PURE__*/React__namespace.createElement("div", {
19746
19771
  key: state.key,
@@ -19877,7 +19902,7 @@ class Renderer extends React__namespace.Component {
19877
19902
  };
19878
19903
  const mobileInnerStyle = {
19879
19904
  ...innerStyle,
19880
- ...styles$A.mobileZoomableParentFix
19905
+ ...styles$z.mobileZoomableParentFix
19881
19906
  };
19882
19907
  const wrappedOutput = /*#__PURE__*/React__namespace.createElement("div", {
19883
19908
  style: {
@@ -20385,7 +20410,7 @@ class Renderer extends React__namespace.Component {
20385
20410
  return this.lastRenderedMarkdown;
20386
20411
  }
20387
20412
  }
20388
- const styles$A = {
20413
+ const styles$z = {
20389
20414
  mobileZoomableParentFix: {
20390
20415
  // NOTE(abdul): There is an issue where transform animations will
20391
20416
  // cause the Zoomable component to disappear when running on the
@@ -21320,10 +21345,10 @@ class InputNumber extends React__namespace.Component {
21320
21345
  // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21321
21346
  // you modify this, double-check if you also need to modify that
21322
21347
  // component.
21323
- const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
21348
+ const inputStyles = [styles$y.default, this.props.size === "small" ? styles$y.small : null, this.props.rightAlign ? styles$y.rightAlign : styles$y.leftAlign];
21324
21349
  // Unanswered
21325
21350
  if (rubric && !this.props.currentValue) {
21326
- inputStyles.push(styles$z.answerStateUnanswered);
21351
+ inputStyles.push(styles$y.answerStateUnanswered);
21327
21352
  }
21328
21353
  return /*#__PURE__*/React__namespace.createElement(InputWithExamples
21329
21354
  // eslint-disable-next-line react/no-string-refs
@@ -21471,7 +21496,7 @@ class InputNumber extends React__namespace.Component {
21471
21496
  return answerString;
21472
21497
  }
21473
21498
  }
21474
- const styles$z = aphrodite.StyleSheet.create({
21499
+ const styles$y = aphrodite.StyleSheet.create({
21475
21500
  default: {
21476
21501
  width: 80,
21477
21502
  height: "auto"
@@ -21509,7 +21534,7 @@ const propTransform$4 = widgetOptions => {
21509
21534
  };
21510
21535
  var InputNumber$1 = {
21511
21536
  name: "input-number",
21512
- displayName: "Number text box (old)",
21537
+ displayName: "Input number (deprecated - use numeric input instead)",
21513
21538
  defaultAlignment: "inline-block",
21514
21539
  hidden: true,
21515
21540
  widget: InputNumber,
@@ -21913,7 +21938,7 @@ const propsTransform = function (widgetOptions) {
21913
21938
  };
21914
21939
  var NumericInput$1 = {
21915
21940
  name: "numeric-input",
21916
- displayName: "Number text box",
21941
+ displayName: "Numeric input",
21917
21942
  defaultAlignment: "inline-block",
21918
21943
  accessible: true,
21919
21944
  widget: NumericInput,
@@ -22469,7 +22494,7 @@ const FocusRing = function (props) {
22469
22494
  };
22470
22495
  return /*#__PURE__*/React__namespace.createElement("span", {
22471
22496
  "data-test-id": "focus-ring",
22472
- className: aphrodite.css(styles$y.ring),
22497
+ className: aphrodite.css(styles$x.ring),
22473
22498
  style: style
22474
22499
  }, children);
22475
22500
  };
@@ -22478,7 +22503,7 @@ FocusRing.defaultProps = {
22478
22503
  color: kaGreen$1,
22479
22504
  multipleSelect: false
22480
22505
  };
22481
- const styles$y = aphrodite.StyleSheet.create({
22506
+ const styles$x = aphrodite.StyleSheet.create({
22482
22507
  ring: {
22483
22508
  margin: "auto",
22484
22509
  display: "inline-block",
@@ -22515,7 +22540,7 @@ function getChoiceLetter(pos) {
22515
22540
  }
22516
22541
 
22517
22542
  const CHOICE_ICON_SIZE = 24;
22518
- const styles$x = aphrodite.StyleSheet.create({
22543
+ const styles$w = aphrodite.StyleSheet.create({
22519
22544
  iconWrapper: {
22520
22545
  display: "inline-block",
22521
22546
  position: "relative"
@@ -22538,7 +22563,7 @@ const CrossOutLine = function (props) {
22538
22563
  width: CROSS_OUT_LINE_SIZE,
22539
22564
  height: CROSS_OUT_LINE_SIZE,
22540
22565
  viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
22541
- className: aphrodite.css(styles$w.crossOutLine),
22566
+ className: aphrodite.css(styles$v.crossOutLine),
22542
22567
  "data-test-id": "choice-icon__cross-out-line"
22543
22568
  }, /*#__PURE__*/React__namespace.createElement("line", {
22544
22569
  // The line stretches from the bottom-left to top-right.
@@ -22553,7 +22578,7 @@ const CrossOutLine = function (props) {
22553
22578
  strokeLinecap: "round"
22554
22579
  }));
22555
22580
  };
22556
- const styles$w = aphrodite.StyleSheet.create({
22581
+ const styles$v = aphrodite.StyleSheet.create({
22557
22582
  crossOutLine: {
22558
22583
  // Center the icon within the container.
22559
22584
  position: "absolute",
@@ -22634,7 +22659,7 @@ const ChoiceIcon = function (props) {
22634
22659
  } = props;
22635
22660
  const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
22636
22661
  return /*#__PURE__*/React__namespace.createElement("div", {
22637
- className: aphrodite.css(styles$x.iconWrapper)
22662
+ className: aphrodite.css(styles$w.iconWrapper)
22638
22663
  }, /*#__PURE__*/React__namespace.createElement(FocusRing, {
22639
22664
  color: Color__default["default"].blue,
22640
22665
  visible: focused || hovered,
@@ -22643,13 +22668,13 @@ const ChoiceIcon = function (props) {
22643
22668
  // @ts-expect-error - TS2322 - Type '{ backgroundColor: string | null | undefined; borderColor: string; color: string; borderRadius: number; }' is not assignable to type 'Properties<string | number, string & {}>'.
22644
22669
  style: dynamicStyles,
22645
22670
  "data-test-id": "choice-icon__library-choice-icon",
22646
- className: aphrodite.css(styles$v.circle, showCorrectness && correct && styles$v.circleCorrect, showCorrectness && !correct && styles$v.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$v.circleIncorrectAnswered)
22671
+ className: aphrodite.css(styles$u.circle, showCorrectness && correct && styles$u.circleCorrect, showCorrectness && !correct && styles$u.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$u.circleIncorrectAnswered)
22647
22672
  // used in BaseRadio editMode to check
22648
22673
  // if we actually clicked on the radio icon
22649
22674
  ,
22650
22675
  "data-is-radio-icon": true
22651
22676
  }, /*#__PURE__*/React__namespace.createElement("div", {
22652
- className: aphrodite.css(styles$v.innerWrapper)
22677
+ className: aphrodite.css(styles$u.innerWrapper)
22653
22678
  }, /*#__PURE__*/React__namespace.createElement(ChoiceInner, {
22654
22679
  pos: pos,
22655
22680
  showCorrectness: showCorrectness,
@@ -22658,7 +22683,7 @@ const ChoiceIcon = function (props) {
22658
22683
  color: dynamicStyles.borderColor
22659
22684
  }));
22660
22685
  };
22661
- const styles$v = aphrodite.StyleSheet.create({
22686
+ const styles$u = aphrodite.StyleSheet.create({
22662
22687
  innerWrapper: {
22663
22688
  width: CHOICE_ICON_SIZE,
22664
22689
  height: CHOICE_ICON_SIZE,
@@ -22750,19 +22775,19 @@ const OptionStatus = function (props) {
22750
22775
  }
22751
22776
  let textStyle;
22752
22777
  if (correct) {
22753
- textStyle = styles$u.correct;
22778
+ textStyle = styles$t.correct;
22754
22779
  } else {
22755
22780
  if (checked || previouslyAnswered) {
22756
- textStyle = styles$u.incorrectAnswered;
22781
+ textStyle = styles$t.incorrectAnswered;
22757
22782
  } else {
22758
- textStyle = styles$u.incorrect;
22783
+ textStyle = styles$t.incorrect;
22759
22784
  }
22760
22785
  }
22761
22786
  return /*#__PURE__*/React__namespace.createElement("div", {
22762
- className: aphrodite.css(styles$u.text, textStyle)
22787
+ className: aphrodite.css(styles$t.text, textStyle)
22763
22788
  }, renderText(checked, correct, crossedOut));
22764
22789
  };
22765
- const styles$u = aphrodite.StyleSheet.create({
22790
+ const styles$t = aphrodite.StyleSheet.create({
22766
22791
  text: {
22767
22792
  alignItems: "center",
22768
22793
  display: "flex",
@@ -22836,8 +22861,8 @@ const Choice = function (props) {
22836
22861
  crossedOut: updatedCrossedOut
22837
22862
  });
22838
22863
  }
22839
- const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$t.description));
22840
- const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$t.rationale));
22864
+ const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$s.description));
22865
+ const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$s.rationale));
22841
22866
 
22842
22867
  // We want to show the choices as dimmed out when the choices are disabled.
22843
22868
  // However, we don't want to do this when we're in review mode in the
@@ -23004,7 +23029,7 @@ const Choice = function (props) {
23004
23029
  "data-test-id": `perseus-radio-rationale-content-${pos}`
23005
23030
  }, rationale));
23006
23031
  };
23007
- const styles$t = aphrodite.StyleSheet.create({
23032
+ const styles$s = aphrodite.StyleSheet.create({
23008
23033
  description: {
23009
23034
  display: "inline-block",
23010
23035
  width: "100%"
@@ -23196,10 +23221,10 @@ const BaseRadio = function (props) {
23196
23221
  const isMobile = apiOptions.isMobile;
23197
23222
  const firstChoiceHighlighted = choices[0].highlighted;
23198
23223
  const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
23199
- const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$s.radio, styles$s.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$s.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$s.radioContainerLastHighlighted));
23200
- const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$s.instructions, isMobile && styles$s.instructionsMobile));
23224
+ const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$r.radio, styles$r.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$r.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$r.radioContainerLastHighlighted));
23225
+ const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$r.instructions, isMobile && styles$r.instructionsMobile));
23201
23226
  const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
23202
- const responsiveClassName = aphrodite.css(styles$s.responsiveFieldset);
23227
+ const responsiveClassName = aphrodite.css(styles$r.responsiveFieldset);
23203
23228
  const fieldset = /*#__PURE__*/React__namespace.createElement("fieldset", {
23204
23229
  className: `perseus-widget-radio-fieldset ${responsiveClassName}`
23205
23230
  }, /*#__PURE__*/React__namespace.createElement("legend", {
@@ -23250,7 +23275,7 @@ const BaseRadio = function (props) {
23250
23275
  const aphroditeClassName = checked => {
23251
23276
  // Whether or not to show correctness borders
23252
23277
  // for this choice and the next choice.
23253
- return aphrodite.css(sharedStyles.aboveScratchpad, styles$s.item, styles$s.responsiveItem, checked && styles$s.selectedItem, checked && choice.highlighted && styles$s.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$s.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$s.nextHighlighted);
23278
+ return aphrodite.css(sharedStyles.aboveScratchpad, styles$r.item, styles$r.responsiveItem, checked && styles$r.selectedItem, checked && choice.highlighted && styles$r.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$r.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$r.nextHighlighted);
23254
23279
  };
23255
23280
 
23256
23281
  // HACK(abdulrahman): Preloads the selection-state
@@ -23324,14 +23349,14 @@ const BaseRadio = function (props) {
23324
23349
  // Allow for horizontal scrolling if content is too wide, which may be
23325
23350
  // an issue especially on phones.
23326
23351
  return /*#__PURE__*/React__namespace.createElement("div", {
23327
- className: aphrodite.css(styles$s.responsiveContainer)
23352
+ className: aphrodite.css(styles$r.responsiveContainer)
23328
23353
  }, fieldset);
23329
23354
  };
23330
23355
  BaseRadio.defaultProps = {
23331
23356
  editMode: false,
23332
23357
  multipleSelect: false
23333
23358
  };
23334
- const styles$s = aphrodite.StyleSheet.create({
23359
+ const styles$r = aphrodite.StyleSheet.create({
23335
23360
  instructions: {
23336
23361
  display: "block",
23337
23362
  color: gray17,
@@ -23921,7 +23946,7 @@ const propUpgrades$1 = {
23921
23946
  };
23922
23947
  var Radio = {
23923
23948
  name: "radio",
23924
- displayName: "Multiple choice",
23949
+ displayName: "Radio / Multiple choice",
23925
23950
  accessible: true,
23926
23951
  widget: Radio$1,
23927
23952
  transform: transform,
@@ -23990,9 +24015,9 @@ class Categorizer extends React__namespace.Component {
23990
24015
  indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
23991
24016
  }
23992
24017
  const table = /*#__PURE__*/React__namespace.createElement("table", {
23993
- className: "categorizer-table " + aphrodite.css(styles$r.mobileTable)
24018
+ className: "categorizer-table " + aphrodite.css(styles$q.mobileTable)
23994
24019
  }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, /*#__PURE__*/React__namespace.createElement("td", {
23995
- className: aphrodite.css(styles$r.emptyHeaderCell)
24020
+ className: aphrodite.css(styles$q.emptyHeaderCell)
23996
24021
  }), this.props.categories.map((category, i) => {
23997
24022
  // Array index is the correct key here, as that's
23998
24023
  // how category grading actually works -- no way
@@ -24000,7 +24025,7 @@ class Categorizer extends React__namespace.Component {
24000
24025
  // middle. (If we later add that, this should be
24001
24026
  // fixed.)
24002
24027
  return /*#__PURE__*/React__namespace.createElement("th", {
24003
- className: aphrodite.css(styles$r.header),
24028
+ className: aphrodite.css(styles$q.header),
24004
24029
  key: i
24005
24030
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
24006
24031
  content: category,
@@ -24020,7 +24045,7 @@ class Categorizer extends React__namespace.Component {
24020
24045
  })), self.props.categories.map((catName, catNum) => {
24021
24046
  const selected = self.props.values[itemNum] === catNum;
24022
24047
  return /*#__PURE__*/React__namespace.createElement("td", {
24023
- className: "category " + aphrodite.css(styles$r.cell),
24048
+ className: "category " + aphrodite.css(styles$q.cell),
24024
24049
  key: catNum
24025
24050
  }, /*#__PURE__*/React__namespace.createElement("div", {
24026
24051
  className: ClassNames.INTERACTIVE,
@@ -24039,7 +24064,7 @@ class Categorizer extends React__namespace.Component {
24039
24064
  onChange: this.onChange.bind(this, itemNum, catNum),
24040
24065
  onClick: e => e.stopPropagation()
24041
24066
  }), !isMobile && /*#__PURE__*/React__namespace.createElement("span", {
24042
- className: aphrodite.css(styles$r.radioSpan, selected && styles$r.checkedRadioSpan, this.props.static && selected && styles$r.staticCheckedRadioSpan)
24067
+ className: aphrodite.css(styles$q.radioSpan, selected && styles$q.checkedRadioSpan, this.props.static && selected && styles$q.staticCheckedRadioSpan)
24043
24068
  }, selected ? /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleThin))));
24044
24069
  }));
24045
24070
  /* eslint-enable max-len */
@@ -24051,7 +24076,7 @@ class Categorizer extends React__namespace.Component {
24051
24076
  "categorizer-container": true,
24052
24077
  "static-mode": this.props.static
24053
24078
  });
24054
- const inlineStyles = this.props.apiOptions.isMobile ? [styles$r.fullBleedContainer] : [];
24079
+ const inlineStyles = this.props.apiOptions.isMobile ? [styles$q.fullBleedContainer] : [];
24055
24080
  return /*#__PURE__*/React__namespace.createElement("div", {
24056
24081
  className: extraClassNames + " " + aphrodite.css(...inlineStyles)
24057
24082
  }, table);
@@ -24100,7 +24125,7 @@ const pageMargin = 16;
24100
24125
 
24101
24126
  // Stylesheets aren't directly testable
24102
24127
  /* c8 ignore next */
24103
- const styles$r = aphrodite.StyleSheet.create({
24128
+ const styles$q = aphrodite.StyleSheet.create({
24104
24129
  mobileTable: {
24105
24130
  [mediaQueries.smOrSmaller]: {
24106
24131
  minWidth: "auto"
@@ -24363,7 +24388,7 @@ class CSProgram extends React__namespace.Component {
24363
24388
  // creator "went wild".
24364
24389
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
24365
24390
  return /*#__PURE__*/React__namespace.createElement("div", {
24366
- className: aphrodite.css(styles$q.widthOverride, styleContainer && styles$q.container)
24391
+ className: aphrodite.css(styles$p.widthOverride, styleContainer && styles$p.container)
24367
24392
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
24368
24393
  sandbox: sandboxOptions,
24369
24394
  src: url,
@@ -24373,7 +24398,7 @@ class CSProgram extends React__namespace.Component {
24373
24398
  }));
24374
24399
  }
24375
24400
  }
24376
- const styles$q = aphrodite.StyleSheet.create({
24401
+ const styles$p = aphrodite.StyleSheet.create({
24377
24402
  // Override the inherited width from the perseus paragraph class
24378
24403
  // 820 is minimum width for 420px editor and 400px canvas
24379
24404
  widthOverride: {
@@ -24421,7 +24446,7 @@ class Definition extends React__namespace.Component {
24421
24446
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
24422
24447
  content: /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
24423
24448
  color: "white",
24424
- style: styles$p.tooltipBody,
24449
+ style: styles$o.tooltipBody,
24425
24450
  closeButtonVisible: true
24426
24451
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
24427
24452
  apiOptions: this.props.apiOptions,
@@ -24452,7 +24477,7 @@ class Definition extends React__namespace.Component {
24452
24477
  });
24453
24478
  }
24454
24479
  }
24455
- const styles$p = {
24480
+ const styles$o = {
24456
24481
  tooltipBody: {
24457
24482
  color: Color__default["default"].offBlack,
24458
24483
  fontSize: 20,
@@ -24469,6 +24494,44 @@ var Definition$1 = {
24469
24494
  transform: x => x
24470
24495
  };
24471
24496
 
24497
+ // The props are type `any` on purpose so that this can receive props
24498
+ // from any deprecated widget
24499
+ class AutoCorrect extends React__default["default"].Component {
24500
+ static validate(userInput, rubric) {
24501
+ // Since this mean to replace an existing widget the learner
24502
+ // WILL earn points for this widget
24503
+ return {
24504
+ type: "points",
24505
+ earned: 1,
24506
+ total: 1,
24507
+ message: null
24508
+ };
24509
+ }
24510
+ getUserInput = () => {
24511
+ return {};
24512
+ };
24513
+ simpleValidate = rubric => {
24514
+ return AutoCorrect.validate(this.getUserInput(), rubric);
24515
+ };
24516
+ render() {
24517
+ return /*#__PURE__*/React__default["default"].createElement("div", {
24518
+ style: {
24519
+ paddingTop: 8,
24520
+ paddingBottom: 8
24521
+ }
24522
+ }, /*#__PURE__*/React__default["default"].createElement(Banner__default["default"], {
24523
+ text: i18n__namespace._("This part of the question is no-longer available. You will not be graded on this part."),
24524
+ kind: "warning",
24525
+ layout: "full-width"
24526
+ }));
24527
+ }
24528
+ }
24529
+ var DeprecatedStandin = {
24530
+ name: "deprecated-standin",
24531
+ displayName: "Deprecated Standin",
24532
+ widget: AutoCorrect
24533
+ };
24534
+
24472
24535
  class Dropdown extends React__namespace.Component {
24473
24536
  static defaultProps = {
24474
24537
  choices: [],
@@ -24617,15 +24680,15 @@ class Explanation extends React__namespace.Component {
24617
24680
  const onClick = this._onClick;
24618
24681
  if (isMobile) {
24619
24682
  linkContainer = /*#__PURE__*/React__namespace.createElement("div", {
24620
- className: aphrodite.css(styles$o.linkContainer)
24683
+ className: aphrodite.css(styles$n.linkContainer)
24621
24684
  }, /*#__PURE__*/React__namespace.createElement("a", {
24622
- className: aphrodite.css(styles$o.mobileExplanationLink),
24685
+ className: aphrodite.css(styles$n.mobileExplanationLink),
24623
24686
  href: href,
24624
24687
  onClick: onClick,
24625
24688
  role: "button",
24626
24689
  "aria-expanded": this.state.expanded
24627
24690
  }, linkAnchor), this.state.expanded && /*#__PURE__*/React__namespace.createElement("svg", {
24628
- className: aphrodite.css(styles$o.disclosureArrow)
24691
+ className: aphrodite.css(styles$n.disclosureArrow)
24629
24692
  }, /*#__PURE__*/React__namespace.createElement("polygon", {
24630
24693
  style: {
24631
24694
  fill: backgroundColor
@@ -24638,13 +24701,13 @@ class Explanation extends React__namespace.Component {
24638
24701
  // an anchor tag (if rendered in a modal) or a Wonder Blocks
24639
24702
  // link component in lesson page, see: `article-page.jsx`.
24640
24703
  linkContainer = /*#__PURE__*/React__namespace.createElement("div", {
24641
- className: aphrodite.css(styles$o.linkContainer, styles$o.articleLink)
24704
+ className: aphrodite.css(styles$n.linkContainer, styles$n.articleLink)
24642
24705
  }, /*#__PURE__*/React__namespace.createElement(Link, {
24643
- className: aphrodite.css(styles$o.explanationLink)
24706
+ className: aphrodite.css(styles$n.explanationLink)
24644
24707
  // HACK(michaelpolyak): WB Link doesn't passthrough
24645
24708
  // class name.
24646
24709
  ,
24647
- style: styles$o.explanationLink,
24710
+ style: styles$n.explanationLink,
24648
24711
  href: href,
24649
24712
  onClick: onClick,
24650
24713
  role: "button",
@@ -24654,9 +24717,9 @@ class Explanation extends React__namespace.Component {
24654
24717
  // NOTE: For exercises, the baseElements `Link` is an
24655
24718
  // anchor tag, see: `perseus-api.jsx`.
24656
24719
  linkContainer = /*#__PURE__*/React__namespace.createElement("div", {
24657
- className: aphrodite.css(styles$o.linkContainer, styles$o.exerciseLink)
24720
+ className: aphrodite.css(styles$n.linkContainer, styles$n.exerciseLink)
24658
24721
  }, /*#__PURE__*/React__namespace.createElement(Link, {
24659
- className: aphrodite.css(styles$o.explanationLink),
24722
+ className: aphrodite.css(styles$n.explanationLink),
24660
24723
  href: href,
24661
24724
  onClick: onClick,
24662
24725
  role: "button",
@@ -24664,11 +24727,11 @@ class Explanation extends React__namespace.Component {
24664
24727
  }, `[${linkAnchor}]`));
24665
24728
  }
24666
24729
  }
24667
- const expandedStyle = isMobile ? styles$o.contentExpandedMobile : styles$o.contentExpanded;
24730
+ const expandedStyle = isMobile ? styles$n.contentExpandedMobile : styles$n.contentExpanded;
24668
24731
  return /*#__PURE__*/React__namespace.createElement("div", {
24669
- className: aphrodite.css(styles$o.container)
24732
+ className: aphrodite.css(styles$n.container)
24670
24733
  }, linkContainer, this.state.expanded && /*#__PURE__*/React__namespace.createElement("div", {
24671
- className: aphrodite.css(styles$o.content, isMobile && styles$o.contentMobile, this.state.expanded && expandedStyle)
24734
+ className: aphrodite.css(styles$n.content, isMobile && styles$n.contentMobile, this.state.expanded && expandedStyle)
24672
24735
  // eslint-disable-next-line react/no-string-refs
24673
24736
  ,
24674
24737
  ref: "content"
@@ -24691,7 +24754,7 @@ const verticalContentPadding = 10;
24691
24754
  const arrowWidth = 30;
24692
24755
  const arrowHeight = 14;
24693
24756
  const backgroundColor = gray95;
24694
- const styles$o = aphrodite.StyleSheet.create({
24757
+ const styles$n = aphrodite.StyleSheet.create({
24695
24758
  container: {
24696
24759
  display: "inline",
24697
24760
  position: "relative"
@@ -24797,15 +24860,15 @@ class GradedGroupAnswerBar extends React__namespace.Component {
24797
24860
  onNextQuestion
24798
24861
  } = this.props;
24799
24862
  const answerBarStyle = {
24800
- ...styles$n.answerBar,
24863
+ ...styles$m.answerBar,
24801
24864
  backgroundColor: answerBarState === "CORRECT" ? Color__default["default"].offWhite : "white",
24802
24865
  // Center the "Correct!" message only when there's no next question
24803
24866
  justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
24804
24867
  };
24805
24868
  const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React__namespace.createElement("span", {
24806
- style: styles$n.text
24869
+ style: styles$m.text
24807
24870
  }, /*#__PURE__*/React__namespace.createElement("span", {
24808
- style: styles$n.tryAgainIcon
24871
+ style: styles$m.tryAgainIcon
24809
24872
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React__namespace.createElement("span", {
24810
24873
  style: {
24811
24874
  marginLeft: 8
@@ -24824,7 +24887,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
24824
24887
  return /*#__PURE__*/React__namespace.createElement("div", {
24825
24888
  style: answerBarStyle
24826
24889
  }, /*#__PURE__*/React__namespace.createElement("span", {
24827
- style: styles$n.text
24890
+ style: styles$m.text
24828
24891
  }, /*#__PURE__*/React__namespace.createElement("span", {
24829
24892
  style: {
24830
24893
  fontSize: 28,
@@ -24846,7 +24909,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
24846
24909
  }
24847
24910
  }
24848
24911
  const fontSize = 17;
24849
- const styles$n = {
24912
+ const styles$m = {
24850
24913
  answerBar: {
24851
24914
  display: "flex",
24852
24915
  alignItems: "center",
@@ -25046,7 +25109,7 @@ class GradedGroup extends React__namespace.Component {
25046
25109
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
25047
25110
  gradeStatus = i18n__namespace._("Incorrect");
25048
25111
  }
25049
- const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$m.gradedGroupInSet) : aphrodite.css(styles$m.gradedGroup);
25112
+ const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$l.gradedGroupInSet) : aphrodite.css(styles$l.gradedGroup);
25050
25113
  const classes = classNames__default["default"]({
25051
25114
  [mobileClass]: apiOptions.isMobile,
25052
25115
  "perseus-graded-group": true,
@@ -25065,7 +25128,7 @@ class GradedGroup extends React__namespace.Component {
25065
25128
  return /*#__PURE__*/React__namespace.createElement("div", {
25066
25129
  className: classes
25067
25130
  }, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
25068
- className: aphrodite.css(styles$m.title)
25131
+ className: aphrodite.css(styles$l.title)
25069
25132
  }, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends({}, this.props, {
25070
25133
  // eslint-disable-next-line react/no-string-refs
25071
25134
  ref: "renderer",
@@ -25098,7 +25161,7 @@ class GradedGroup extends React__namespace.Component {
25098
25161
  }, i18n__namespace._("Next question")), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
25099
25162
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
25100
25163
  tabIndex: "0",
25101
- className: aphrodite.css(styles$m.explanationTitle),
25164
+ className: aphrodite.css(styles$l.explanationTitle),
25102
25165
  onClick: () => this.setState({
25103
25166
  showHint: false
25104
25167
  }),
@@ -25130,7 +25193,7 @@ class GradedGroup extends React__namespace.Component {
25130
25193
  showHint: true
25131
25194
  });
25132
25195
  },
25133
- className: aphrodite.css(styles$m.showHintLink)
25196
+ className: aphrodite.css(styles$l.showHintLink)
25134
25197
  }, i18n__namespace._("Explain"))), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React__namespace.createElement(GradedGroupAnswerBar, {
25135
25198
  apiOptions: apiOptions,
25136
25199
  answerBarState: answerBarState,
@@ -25142,7 +25205,7 @@ class GradedGroup extends React__namespace.Component {
25142
25205
  const traverseChildWidgets$3 = function (props, traverseRenderer) {
25143
25206
  return ___default["default"].extend({}, props, traverseRenderer(props));
25144
25207
  };
25145
- const styles$m = aphrodite.StyleSheet.create({
25208
+ const styles$l = aphrodite.StyleSheet.create({
25146
25209
  gradedGroupInSet: {
25147
25210
  // Reset a few desktop-only styles that come from graded-group.less
25148
25211
  marginLeft: 0,
@@ -25212,20 +25275,20 @@ class Indicators extends React__namespace.Component {
25212
25275
  return /*#__PURE__*/React__namespace.createElement("ul", {
25213
25276
  // reduntantly add class name for use in .less files--
25214
25277
  // the styles object key gets hashed
25215
- className: classNames__default["default"](aphrodite.css(styles$l.indicatorContainer), "indicatorContainer")
25278
+ className: classNames__default["default"](aphrodite.css(styles$k.indicatorContainer), "indicatorContainer")
25216
25279
  }, this.props.gradedGroups.map((_ref, i) => {
25217
25280
  let {
25218
25281
  title
25219
25282
  } = _ref;
25220
25283
  return /*#__PURE__*/React__namespace.createElement("li", {
25221
- className: aphrodite.css(styles$l.indicator),
25284
+ className: aphrodite.css(styles$k.indicator),
25222
25285
  key: title
25223
25286
  }, /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
25224
25287
  role: "button",
25225
25288
  "aria-label": i18n__namespace._("Skip to %(title)s", {
25226
25289
  title
25227
25290
  }),
25228
- style: styles$l.indicatorButton,
25291
+ style: styles$k.indicatorButton,
25229
25292
  onClick: () => this.props.onChangeCurrentGroup(i),
25230
25293
  onKeyDown: e => this.handleKeyDown(e, i)
25231
25294
  }, _ref2 => {
@@ -25235,9 +25298,9 @@ class Indicators extends React__namespace.Component {
25235
25298
  pressed
25236
25299
  } = _ref2;
25237
25300
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
25238
- style: [styles$l.indicatorDot, (hovered || focused || pressed) && styles$l.indicatorDotFocused]
25301
+ style: [styles$k.indicatorDot, (hovered || focused || pressed) && styles$k.indicatorDotFocused]
25239
25302
  }, i === this.props.currentGroup && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
25240
- style: styles$l.indicatorDotActive
25303
+ style: styles$k.indicatorDotActive
25241
25304
  }, /*#__PURE__*/React__namespace.createElement("span", {
25242
25305
  className: aphrodite.css(a11y.srOnly)
25243
25306
  }, i18n__namespace._("Current"))));
@@ -25313,7 +25376,7 @@ class GradedGroupSet extends React__namespace.Component {
25313
25376
  } = getDependencies();
25314
25377
  if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
25315
25378
  return /*#__PURE__*/React__namespace.createElement("div", {
25316
- className: aphrodite.css(styles$l.container)
25379
+ className: aphrodite.css(styles$k.container)
25317
25380
  }, this.props.gradedGroups.map((gradedGroup, i) => {
25318
25381
  return (
25319
25382
  /*#__PURE__*/
@@ -25336,13 +25399,13 @@ class GradedGroupSet extends React__namespace.Component {
25336
25399
  const numGroups = this.props.gradedGroups.length;
25337
25400
  const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
25338
25401
  return /*#__PURE__*/React__namespace.createElement("div", {
25339
- className: aphrodite.css(styles$l.container)
25402
+ className: aphrodite.css(styles$k.container)
25340
25403
  }, /*#__PURE__*/React__namespace.createElement("div", {
25341
- className: aphrodite.css(styles$l.top)
25404
+ className: aphrodite.css(styles$k.top)
25342
25405
  }, /*#__PURE__*/React__namespace.createElement("div", {
25343
- className: aphrodite.css(styles$l.title)
25406
+ className: aphrodite.css(styles$k.title)
25344
25407
  }, currentGroup.title), /*#__PURE__*/React__namespace.createElement("div", {
25345
- className: aphrodite.css(styles$l.spacer)
25408
+ className: aphrodite.css(styles$k.spacer)
25346
25409
  }), /*#__PURE__*/React__namespace.createElement(Indicators, {
25347
25410
  currentGroup: this.state.currentGroup,
25348
25411
  gradedGroups: this.props.gradedGroups,
@@ -25380,7 +25443,7 @@ var GradedGroupSet$1 = {
25380
25443
  tracking: "all",
25381
25444
  isLintable: true
25382
25445
  };
25383
- const styles$l = aphrodite.StyleSheet.create({
25446
+ const styles$k = aphrodite.StyleSheet.create({
25384
25447
  top: {
25385
25448
  display: "flex",
25386
25449
  flexDirection: "row"
@@ -25485,7 +25548,7 @@ class ButtonGroup extends React__namespace.Component {
25485
25548
  id: "" + i,
25486
25549
  ref: "button" + i,
25487
25550
  key: "" + i,
25488
- className: aphrodite.css(styles$k.buttonStyle, button.value === value && styles$k.selectedStyle),
25551
+ className: aphrodite.css(styles$j.buttonStyle, button.value === value && styles$j.selectedStyle),
25489
25552
  onClick: () => this.toggleSelect(button.value)
25490
25553
  }, button.content || "" + button.value);
25491
25554
  });
@@ -25498,7 +25561,7 @@ class ButtonGroup extends React__namespace.Component {
25498
25561
  }, buttons);
25499
25562
  }
25500
25563
  }
25501
- const styles$k = aphrodite.StyleSheet.create({
25564
+ const styles$j = aphrodite.StyleSheet.create({
25502
25565
  buttonStyle: {
25503
25566
  backgroundColor: "white",
25504
25567
  border: "1px solid #ccc",
@@ -26814,7 +26877,7 @@ ___default["default"].extend(Iframe, {
26814
26877
  });
26815
26878
  var Iframe$1 = {
26816
26879
  name: "iframe",
26817
- displayName: "Iframe",
26880
+ displayName: "Iframe (deprecated)",
26818
26881
  widget: Iframe,
26819
26882
  // Let's not expose it to all content creators yet
26820
26883
  hidden: true
@@ -30962,212 +31025,92 @@ var globalStyles = /*#__PURE__*/Object.freeze({
30962
31025
  typography: typography
30963
31026
  });
30964
31027
 
30965
- class AnswerChoice extends React__namespace.Component {
30966
- // The radio button or checkbox input control.
30967
-
30968
- state = {
30969
- isInputFocused: false
30970
- };
30971
- focusInput() {
30972
- if (this._input) {
30973
- this._input.focus();
30974
- }
30975
- }
30976
- handleClick(e) {
31028
+ const AnswerChoices = props => {
31029
+ const onAnswerChange = selected => {
30977
31030
  const {
30978
- checked,
31031
+ choices,
30979
31032
  onChange
30980
- } = this.props;
30981
- e.preventDefault();
30982
-
30983
- // We manually handle clicks, setting focus on the input control.
30984
- this.focusInput();
30985
-
30986
- // And toggling the answer selection state.
30987
- onChange(!checked);
30988
- }
30989
- handleKeyDown(e) {
30990
- const {
30991
- onFocusPrevAnswer,
30992
- onFocusNextAnswer
30993
- } = this.props;
31033
+ } = props;
31034
+ onChange(choices.map(choice => selected.includes(choice.content)));
31035
+ };
30994
31036
 
30995
- // This may override built-in browser arrow key navigation for radio
30996
- // group. Checkbox fieldset does not have such built-in capability,
30997
- // thus we do this manually for both input types.
30998
- switch (e.key) {
30999
- case "ArrowUp":
31000
- e.preventDefault();
31001
- onFocusPrevAnswer();
31002
- break;
31003
- case "ArrowDown":
31004
- e.preventDefault();
31005
- onFocusNextAnswer();
31006
- break;
31007
- }
31008
- }
31009
- handleInputChange(e) {
31010
- // Prevent answer selection from double-toggling, as `handleClick` is
31011
- // handling changes to selection state.
31012
- e.preventDefault();
31013
- }
31014
- handleInputFocus() {
31015
- this.setState({
31016
- isInputFocused: true
31017
- });
31018
- }
31019
- handleInputBlur() {
31020
- this.setState({
31021
- isInputFocused: false
31037
+ // WB Dropdown types only take an array of nodes, so we can't use a
31038
+ // functional component, which can only return a single node.
31039
+ const AnswerItems = choices => choices.map(_ref => {
31040
+ let {
31041
+ content
31042
+ } = _ref;
31043
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
31044
+ key: content,
31045
+ value: content,
31046
+ label: /*#__PURE__*/React__namespace.createElement(Renderer, {
31047
+ content: content,
31048
+ inline: true
31049
+ })
31022
31050
  });
31023
- }
31024
- renderCheckmark() {
31025
- const {
31026
- checked
31027
- } = this.props;
31028
- return /*#__PURE__*/React__namespace.createElement("span", {
31029
- className: aphrodite.css(styles$j.checkmarkContainer)
31030
- }, checked && /*#__PURE__*/React__namespace.createElement(Icon, {
31031
- icon: iconCheckMedium,
31032
- size: 16,
31033
- color: Color__default["default"].offBlack
31034
- }));
31035
- }
31036
- render() {
31037
- const {
31038
- content,
31039
- checked,
31040
- groupName,
31041
- index,
31042
- inputType
31043
- } = this.props;
31044
- const {
31045
- isInputFocused
31046
- } = this.state;
31047
- const answerId = `${groupName}-${index}`;
31048
- return /*#__PURE__*/React__namespace.createElement("div", {
31049
- className: aphrodite.css(styles$j.answerChoice, isInputFocused && styles$j.answerFocused),
31050
- onClick: e => this.handleClick(e),
31051
- onKeyDown: e => this.handleKeyDown(e)
31052
- }, /*#__PURE__*/React__namespace.createElement("span", {
31053
- className: aphrodite.css(styles$j.answerInputWrapper)
31054
- }, /*#__PURE__*/React__namespace.createElement("input", {
31055
- className: aphrodite.css(sharedStyles.perseusSrOnly),
31056
- checked: checked,
31057
- name: groupName,
31058
- id: answerId,
31059
- type: inputType,
31060
- onChange: e => this.handleInputChange(e),
31061
- onFocus: () => this.handleInputFocus(),
31062
- onBlur: () => this.handleInputBlur(),
31063
- ref: node => this._input = node
31064
- }), this.renderCheckmark()), /*#__PURE__*/React__namespace.createElement("label", {
31065
- htmlFor: answerId
31066
- }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31067
- content: content
31068
- })));
31069
- }
31070
- }
31071
- class AnswerChoices extends React__namespace.Component {
31072
- // The rendered answers elements.
31073
-
31074
- constructor(props) {
31075
- super(props);
31076
- this._choices = [];
31077
- this.state = {
31078
- groupName: ___default["default"].uniqueId("answer_choices_")
31079
- };
31080
- }
31081
- focusAnswer() {
31082
- let index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
31083
- const numChoices = this.props.choices.length;
31051
+ });
31052
+ const selectedValues = props.choices.filter(choice => choice.checked).map(choice => choice.content);
31053
+ const {
31054
+ opener,
31055
+ onToggle,
31056
+ disabled
31057
+ } = props;
31058
+ const args = {
31059
+ // reset to allow child (answer pill) to control z-index
31060
+ style: {
31061
+ zIndex: "unset"
31062
+ },
31063
+ children: AnswerItems(props.choices),
31064
+ opener,
31065
+ onToggle,
31066
+ disabled
31067
+ };
31068
+ return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect, _extends({}, args, {
31069
+ selectedValues: selectedValues,
31070
+ onChange: selected => onAnswerChange(selected)
31071
+ })) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, _extends({}, args, {
31072
+ selectedValue: selectedValues[0],
31073
+ onChange: selected => onAnswerChange([selected]),
31074
+ placeholder: props.choices[0].content // not visible, but required
31075
+ }));
31076
+ };
31084
31077
 
31085
- // Wrap the index if necessary.
31086
- if (index < 0) {
31087
- index += numChoices;
31088
- } else if (index >= numChoices) {
31089
- index -= numChoices;
31090
- }
31091
- const choice = this._choices[index];
31092
- if (choice) {
31093
- choice.focusInput();
31094
- }
31095
- }
31096
- onAnswerChange(index, checked) {
31097
- const {
31098
- choices,
31099
- multipleSelect,
31100
- onChange
31101
- } = this.props;
31102
- const selection = [];
31078
+ const strings = {
31079
+ hideAnswersToggleLabel: i18n__namespace._("Hide answer choices")
31080
+ };
31103
31081
 
31104
- // Compile the selection state of answer choices. In single selection
31105
- // mode (radio input type), only 0 or 1 answer may be chosen.
31106
- for (let i = 0; i < choices.length; i++) {
31107
- selection.push(multipleSelect ? i === index ? checked : choices[i].checked : i === index ? checked : false);
31108
- }
31109
- onChange(selection);
31110
- }
31111
- onFocusAnswer(index) {
31112
- this.focusAnswer(index);
31113
- }
31114
- render() {
31115
- const {
31116
- choices,
31117
- multipleSelect
31118
- } = this.props;
31119
- const {
31120
- groupName
31121
- } = this.state;
31122
- return /*#__PURE__*/React__namespace.createElement("fieldset", {
31123
- style: {
31124
- border: "none",
31125
- margin: 0,
31126
- padding: 0
31127
- }
31128
- }, choices.map((choice, index) => /*#__PURE__*/React__namespace.createElement(AnswerChoice, _extends({}, choice, {
31129
- key: choice.content,
31130
- groupName: groupName,
31131
- index: index,
31132
- inputType: multipleSelect ? "checkbox" : "radio",
31133
- onChange: checked => this.onAnswerChange(index, checked),
31134
- onFocusPrevAnswer: () => this.onFocusAnswer(index - 1),
31135
- onFocusNextAnswer: () => this.onFocusAnswer(index + 1),
31136
- ref: node => this._choices[index] = node
31137
- }))));
31138
- }
31139
- }
31140
- const styles$j = aphrodite.StyleSheet.create({
31141
- answerChoice: {
31082
+ const HideAnswersToggle = props => {
31083
+ const idFactory = wonderBlocksCore.useUniqueIdWithMock();
31084
+ const switchId = idFactory.get("hide-answers-toggle");
31085
+ const labelId = idFactory.get("hide-answers-label");
31086
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31087
+ style: styles$i.switchWrapper
31088
+ }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31089
+ id: switchId,
31090
+ checked: props.areAnswersHidden,
31091
+ onChange: props.onChange,
31092
+ "aria-labelledby": labelId
31093
+ }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31094
+ id: labelId,
31095
+ htmlFor: switchId,
31096
+ tag: "label"
31097
+ }, strings.hideAnswersToggleLabel));
31098
+ };
31099
+ const styles$i = aphrodite.StyleSheet.create({
31100
+ switchWrapper: {
31142
31101
  display: "flex",
31102
+ flexDirection: "row",
31103
+ flexWrap: "wrap-reverse",
31143
31104
  alignItems: "center",
31144
- userSelect: "none",
31145
- padding: "10px 16px 10px 0px",
31146
- fontWeight: "bold",
31147
- border: "solid 2px transparent",
31148
- borderRadius: 2,
31149
- ":active": {
31150
- backgroundColor: "rgba(33, 36, 44, 0.08)"
31151
- }
31152
- },
31153
- answerFocused: {
31154
- borderColor: "#1865f2",
31155
- ":active": {
31156
- borderColor: "transparent"
31157
- }
31158
- },
31159
- answerInputWrapper: {
31160
- marginRight: 8
31161
- },
31162
- checkmarkContainer: {
31163
- display: "flex",
31164
- position: "relative",
31165
- width: 16,
31166
- height: 16,
31167
- marginLeft: 8
31105
+ gap: "0.5em",
31106
+ marginTop: "1em"
31168
31107
  }
31169
31108
  });
31170
31109
 
31110
+ const BringToFront = {
31111
+ boxShadow: `0 8px 8px ${Color__default["default"].offBlack64}`,
31112
+ zIndex: 1000
31113
+ };
31171
31114
  const AnswerPill = props => {
31172
31115
  const {
31173
31116
  selectedAnswers,
@@ -31175,7 +31118,9 @@ const AnswerPill = props => {
31175
31118
  markerRef,
31176
31119
  side,
31177
31120
  onClick,
31178
- style
31121
+ style,
31122
+ focused,
31123
+ hovered
31179
31124
  } = props;
31180
31125
  const idFactory = wonderBlocksCore.useUniqueIdWithMock();
31181
31126
  const answerString = selectedAnswers.length > 1 ?
@@ -31186,10 +31131,6 @@ const AnswerPill = props => {
31186
31131
  // has been labeled (answered) correctly.
31187
31132
  const correct = showCorrectness === "correct";
31188
31133
  const incorrect = showCorrectness === "incorrect";
31189
- const bringToFront = {
31190
- boxShadow: `0 8px 8px ${Color__default["default"].offBlack64}`,
31191
- zIndex: 1000
31192
- };
31193
31134
  return /*#__PURE__*/React__namespace.createElement(reactPopper.Popper, {
31194
31135
  placement: side,
31195
31136
  referenceElement: markerRef,
@@ -31210,63 +31151,29 @@ const AnswerPill = props => {
31210
31151
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31211
31152
  onClick: correct ? undefined : onClick,
31212
31153
  ref: ref,
31213
- style: [style, popperStyle, {
31214
- ":hover": bringToFront,
31215
- ":focus": bringToFront
31216
- }, correct && styles$i.correct, incorrect && styles$i.incorrect]
31154
+ style: [style, popperStyle, styles$h.relative, correct && styles$h.correct, incorrect && styles$h.incorrect, (focused || hovered) && BringToFront]
31217
31155
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31218
31156
  content: answerString,
31219
31157
  inline: true
31220
31158
  }));
31221
31159
  });
31222
31160
  };
31223
- const styles$i = aphrodite.StyleSheet.create({
31161
+ const styles$h = aphrodite.StyleSheet.create({
31224
31162
  correct: {
31225
- backgroundColor: "#00880b" // WB green darkened by 18%
31163
+ // WB green darkened by 18%
31164
+ backgroundColor: "#00880b"
31226
31165
  },
31227
-
31228
31166
  incorrect: {
31229
31167
  backgroundColor: Color__default["default"].offBlack64
31230
31168
  }
31231
31169
  });
31232
31170
 
31233
- const strings = {
31234
- hideAnswersToggleLabel: i18n__namespace._("Hide answer choices")
31235
- };
31236
-
31237
- const HideAnswersToggle = props => {
31238
- const idFactory = wonderBlocksCore.useUniqueIdWithMock();
31239
- const switchId = idFactory.get("hide-answers-toggle");
31240
- const labelId = idFactory.get("hide-answers-label");
31241
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31242
- style: styles$h.switchWrapper
31243
- }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31244
- id: switchId,
31245
- checked: props.areAnswersHidden,
31246
- onChange: props.onChange,
31247
- "aria-labelledby": labelId
31248
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31249
- id: labelId,
31250
- htmlFor: switchId,
31251
- tag: "label"
31252
- }, strings.hideAnswersToggleLabel));
31253
- };
31254
- const styles$h = aphrodite.StyleSheet.create({
31255
- switchWrapper: {
31256
- display: "flex",
31257
- flexDirection: "row",
31258
- flexWrap: "wrap-reverse",
31259
- alignItems: "center",
31260
- gap: "0.5em",
31261
- marginTop: "1em"
31262
- }
31263
- });
31264
-
31265
31171
  /* eslint-disable @khanacademy/ts-no-error-suppressions */
31266
31172
  function shouldReduceMotion() {
31267
31173
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
31268
31174
  return !mediaQuery || mediaQuery.matches;
31269
31175
  }
31176
+ const MARKER_SIZE = 24;
31270
31177
  class Marker extends React__namespace.Component {
31271
31178
  // The marker icon element.
31272
31179
 
@@ -31278,123 +31185,101 @@ class Marker extends React__namespace.Component {
31278
31185
  selected,
31279
31186
  showCorrectness,
31280
31187
  showSelected,
31281
- showPulsate,
31282
- focused
31188
+ showPulsate
31283
31189
  } = this.props;
31284
31190
 
31285
31191
  // Only a single marker may be "selected" at a time.
31286
31192
  // `showSelected` is a controlled prop, that may be set to `true` for
31287
31193
  // one marker at a time.
31288
- // `focused` is a controlled state, driven by focus events, and may
31289
- // only be `true` when there's no answer choices popup visible, and
31290
- // keyboard focus is given to the marker.
31291
- const isSelected = showSelected || focused;
31292
- let innerIcon;
31194
+ const isOpen = showSelected;
31195
+ const selectedAnswers = selected;
31293
31196
  let iconStyles;
31197
+ const iconNull = {
31198
+ path: "",
31199
+ height: 0,
31200
+ width: 0
31201
+ };
31202
+
31203
+ // default dot
31204
+ let args = {
31205
+ size: MARKER_SIZE,
31206
+ color: Color__default["default"].white,
31207
+ icon: iconNull
31208
+ };
31294
31209
  if (showCorrectness) {
31295
- innerIcon = /*#__PURE__*/React__namespace.createElement(Icon, {
31296
- icon: showCorrectness === "correct" ? iconCheck : iconMinus,
31297
- size: 24,
31298
- color: Color__default["default"].white
31299
- });
31300
- if (showCorrectness === "correct") {
31301
- iconStyles = [styles$g.markerGraded, styles$g.markerCorrect, isSelected && styles$g.markerSelected];
31302
- } else {
31303
- iconStyles = [styles$g.markerGraded, styles$g.markerIncorrect, isSelected && styles$g.markerSelected];
31304
- }
31305
- } else if (focused) {
31306
- iconStyles = [styles$g.markerFocused, selected && selected.length > 0 && styles$g.markerFilled, showSelected && styles$g.markerSelected];
31307
- } else if (selected && selected.length > 0) {
31308
- iconStyles = [styles$g.markerFilled, isSelected && styles$g.markerSelected];
31309
- } else if (isSelected) {
31210
+ iconStyles = [styles$g.markerGraded, showCorrectness === "correct" ? styles$g.markerCorrect : styles$g.markerIncorrect, isOpen && styles$g.markerSelected];
31211
+ args = {
31212
+ ...args,
31213
+ icon: showCorrectness === "correct" ? iconCheck : iconMinus
31214
+ };
31215
+ } else if (selectedAnswers && selectedAnswers.length > 0) {
31216
+ iconStyles = [styles$g.markerFilled, isOpen && styles$g.markerSelected];
31217
+ } else if (isOpen) {
31310
31218
  iconStyles = [styles$g.markerSelected];
31311
- } else {
31312
- iconStyles = [styles$g.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$g.markerUnfilledPulsateOnce : showPulsate && styles$g.markerUnfilledPulsateInfinite];
31313
- }
31314
- if (isSelected && selected && selected.length === 0) {
31315
- innerIcon = /*#__PURE__*/React__namespace.createElement(Icon, {
31219
+ args = {
31220
+ ...args,
31316
31221
  icon: iconChevronDown,
31317
- size: 8,
31318
- color: Color__default["default"].white
31319
- });
31222
+ size: 8
31223
+ };
31224
+ } else if (showPulsate) {
31225
+ iconStyles = [styles$g.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$g.markerUnfilledPulsateOnce : showPulsate && styles$g.markerUnfilledPulsateInfinite];
31320
31226
  }
31321
31227
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31322
31228
  style: [styles$g.markerIcon, iconStyles],
31323
31229
  ref: node => this._icon = node
31324
- }, innerIcon);
31230
+ }, /*#__PURE__*/React__namespace.createElement(Icon, args));
31325
31231
  }
31326
31232
  render() {
31327
31233
  const {
31328
- label,
31329
- x,
31330
- y,
31331
- showCorrectness
31234
+ showCorrectness,
31235
+ selected,
31236
+ showAnswer,
31237
+ answerSide,
31238
+ answerStyles,
31239
+ hovered,
31240
+ focused
31332
31241
  } = this.props;
31333
31242
 
31334
- // It should no longer be possible to interact with a marker after it
31335
- // has been labeled (answered) correctly.
31336
- const isDisabled = showCorrectness === "correct";
31337
- return /*#__PURE__*/React__namespace.createElement("button", {
31338
- "aria-label": label,
31339
- className: aphrodite.css(styles$g.unstyledButton, styles$g.marker, isDisabled && styles$g.disabled),
31340
- style: {
31341
- left: `${x}%`,
31342
- top: `${y}%`
31343
- },
31344
- tabIndex: isDisabled ? -1 : 0,
31345
- onFocus: this.props.onFocus,
31346
- onBlur: this.props.onBlur,
31347
- onClick: e => {
31348
- e.preventDefault();
31349
- this.props.onClick(e);
31350
- },
31351
- onKeyDown: e => this.props.onKeyDown(e)
31352
- }, this.renderIcon());
31243
+ // We cannot make dropdown openers untabbable, so we isolate tabbing
31244
+ // to answer pills when interaction is disabled.
31245
+ const markerDisabled = showCorrectness === "correct";
31246
+ const active = hovered || focused;
31247
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31248
+ style: [styles$g.marker, active && !markerDisabled && styles$g.markerActive]
31249
+ }, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React__namespace.createElement(AnswerPill, {
31250
+ selectedAnswers: selected,
31251
+ showCorrectness: showCorrectness,
31252
+ side: answerSide,
31253
+ style: answerStyles,
31254
+ markerRef: this._icon ?? undefined,
31255
+ hovered: hovered,
31256
+ focused: focused
31257
+ }));
31353
31258
  }
31354
31259
  }
31355
- const lightShadowColor = "rgba(33, 36, 44, 0.16)";
31356
- const markerSize = 20;
31357
31260
  const styles$g = aphrodite.StyleSheet.create({
31358
- unstyledButton: {
31359
- padding: 0,
31360
- overflow: "visible",
31361
- color: "inherit",
31362
- font: "inherit",
31363
- lineHeight: "normal",
31364
- background: "none",
31365
- border: "none"
31366
- },
31367
31261
  marker: {
31368
31262
  position: "absolute",
31369
- outline: "none",
31370
- // Center marker position based on it's maximum size.
31371
- width: markerSize,
31372
- height: markerSize,
31373
31263
  backgroundColor: Color__default["default"].white,
31374
- borderRadius: 30,
31375
- marginLeft: -15,
31376
- marginTop: -15
31377
- },
31378
- disabled: {
31379
- pointerEvents: "none"
31264
+ borderRadius: MARKER_SIZE,
31265
+ // Center marker position based on its maximum size.
31266
+ width: MARKER_SIZE,
31267
+ height: MARKER_SIZE,
31268
+ marginLeft: MARKER_SIZE / -2,
31269
+ marginTop: MARKER_SIZE / -2,
31270
+ // Add a shadow to the marker to make it stand out from the image.
31271
+ boxShadow: `0 8px 8px ${Color__default["default"].offBlack8}`
31380
31272
  },
31381
31273
  // The base and unfilled marker style.
31382
31274
  markerIcon: {
31383
31275
  display: "flex",
31384
31276
  alignItems: "center",
31385
31277
  justifyContent: "center",
31386
- boxSizing: "content-box",
31387
- width: markerSize,
31388
- height: markerSize,
31389
- marginLeft: 2,
31390
- cursor: "pointer",
31278
+ boxSizing: "border-box",
31279
+ width: MARKER_SIZE,
31280
+ height: MARKER_SIZE,
31391
31281
  border: `2px solid ${Color__default["default"].offBlack64}`,
31392
- borderRadius: markerSize,
31393
- boxShadow: `0 8px 8px ${Color__default["default"].offBlack8}`,
31394
- ":hover": {
31395
- outline: `2px solid ${Color__default["default"].blue}`,
31396
- outlineOffset: 2
31397
- }
31282
+ borderRadius: MARKER_SIZE
31398
31283
  },
31399
31284
  // The animation that presents the marker to the learner
31400
31285
  markerPulsateBase: {
@@ -31415,16 +31300,13 @@ const styles$g = aphrodite.StyleSheet.create({
31415
31300
  animationIterationCount: "0"
31416
31301
  },
31417
31302
  markerUnfilledPulsateInfinite: {
31418
- animationIterationCount: "infinite",
31419
- ":hover": {
31420
- outline: `0px solid ${Color__default["default"].blue}`
31421
- }
31303
+ animationIterationCount: "infinite"
31422
31304
  },
31423
31305
  markerUnfilledPulsateOnce: {
31424
31306
  // Doing the animation twice lets it ease-in and ease-out
31425
31307
  animationIterationCount: "2"
31426
31308
  },
31427
- markerFocused: {
31309
+ markerActive: {
31428
31310
  outline: `2px solid ${Color__default["default"].blue}`,
31429
31311
  outlineOffset: 2
31430
31312
  },
@@ -31433,33 +31315,20 @@ const styles$g = aphrodite.StyleSheet.create({
31433
31315
  boxShadow: `0 8px 8px ${Color__default["default"].offBlack8}`,
31434
31316
  border: `solid 4px ${Color__default["default"].white}`,
31435
31317
  backgroundColor: Color__default["default"].blue,
31436
- borderRadius: markerSize,
31437
- transform: "rotate(180deg)",
31438
- ":hover": {
31439
- outline: `2px solid ${Color__default["default"].blue}`,
31440
- outlineOffset: -2
31441
- }
31318
+ borderRadius: MARKER_SIZE,
31319
+ transform: "rotate(180deg)"
31442
31320
  },
31443
31321
  // The learner has made a selection
31444
31322
  markerFilled: {
31445
- width: markerSize - 2,
31446
- height: markerSize - 2,
31447
- borderRadius: markerSize - 2,
31448
31323
  backgroundColor: "#ECF3FE",
31449
- marginLeft: 3,
31450
- marginTop: 0,
31451
- border: `4px solid ${Color__default["default"].blue}`,
31452
- boxShadow: `0 1px 1px 0 ${lightShadowColor}`
31324
+ border: `4px solid ${Color__default["default"].blue}`
31453
31325
  },
31454
31326
  markerGraded: {
31455
- width: markerSize,
31456
- height: markerSize,
31457
- marginLeft: 1,
31458
- marginTop: 1,
31327
+ width: MARKER_SIZE,
31328
+ height: MARKER_SIZE,
31459
31329
  justifyContent: "center",
31460
31330
  alignItems: "center",
31461
- border: `2px solid ${Color__default["default"].white}`,
31462
- boxShadow: `0 8px 8px ${Color__default["default"].offBlack8}`
31331
+ border: `2px solid ${Color__default["default"].white}`
31463
31332
  },
31464
31333
  markerCorrect: {
31465
31334
  background: "#00880b" // WB green darkened by 18%
@@ -31478,10 +31347,6 @@ const styles$g = aphrodite.StyleSheet.create({
31478
31347
  class LabelImage extends React__namespace.Component {
31479
31348
  // The rendered markers on the question image for labeling.
31480
31349
 
31481
- // The popup component containing the answer choices.
31482
-
31483
- // The rendered list of answer choices for the currently selected marker.
31484
-
31485
31350
  static gradeMarker(marker) {
31486
31351
  const score = {
31487
31352
  hasAnswers: false,
@@ -31715,7 +31580,6 @@ class LabelImage extends React__namespace.Component {
31715
31580
  this._markers = [];
31716
31581
  this.state = {
31717
31582
  activeMarkerIndex: -1,
31718
- focusedMarkerIndex: -1,
31719
31583
  markersInteracted: false,
31720
31584
  hideAnswers: false
31721
31585
  };
@@ -31754,26 +31618,6 @@ class LabelImage extends React__namespace.Component {
31754
31618
  markers: updatedMarkers
31755
31619
  }, null, true);
31756
31620
  }
31757
- dismissMarkerPopup() {
31758
- const {
31759
- activeMarkerIndex
31760
- } = this.state;
31761
-
31762
- // No popup should be open if there's no selected marker.
31763
- if (activeMarkerIndex === -1) {
31764
- return;
31765
- }
31766
- this.setState({
31767
- activeMarkerIndex: -1
31768
- }, () => {
31769
- const marker = this._markers[activeMarkerIndex];
31770
- // Set focus on the just-deselected-marker, to enable to resume
31771
- // navigating between the markers using the keyboard.
31772
- if (marker) {
31773
- ReactDOM__namespace.findDOMNode(marker).focus();
31774
- }
31775
- });
31776
- }
31777
31621
  handleMarkerChange(index, marker) {
31778
31622
  const {
31779
31623
  markers,
@@ -31793,32 +31637,24 @@ class LabelImage extends React__namespace.Component {
31793
31637
  markers: updatedMarkers
31794
31638
  });
31795
31639
  }
31796
- activateMarker(index) {
31640
+ activateMarker(index, opened) {
31641
+ this.props.analytics?.onAnalyticsEvent({
31642
+ type: "perseus:label-image:marker-interacted-with",
31643
+ payload: null
31644
+ });
31797
31645
  const {
31798
31646
  activeMarkerIndex
31799
31647
  } = this.state;
31800
-
31801
- // Select the marker, revealing answer choices.
31802
- if (activeMarkerIndex !== index) {
31648
+ // Set index of opened marker
31649
+ if (activeMarkerIndex !== index && opened) {
31803
31650
  this.setState({
31804
31651
  activeMarkerIndex: index,
31805
31652
  markersInteracted: true
31806
- }, () => {
31807
- // A delay is required to allow answer choices to first render
31808
- // before trying to set focus on the first choice.
31809
- // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
31810
- // eslint-disable-next-line no-restricted-syntax
31811
- setTimeout(() => {
31812
- if (this._answerChoices) {
31813
- this._answerChoices.focusAnswer();
31814
- }
31815
- }, 100);
31816
31653
  });
31817
31654
  } else {
31818
- // The answer choices are shown within a popup attached to the
31819
- // selected marker. Close the popup and set focus back to the
31820
- // marker.
31821
- this.dismissMarkerPopup();
31655
+ this.setState({
31656
+ activeMarkerIndex: -1
31657
+ });
31822
31658
  }
31823
31659
  }
31824
31660
  handleMarkerKeyDown(index, e) {
@@ -31866,8 +31702,7 @@ class LabelImage extends React__namespace.Component {
31866
31702
  handleAnswerChoicesChangeForMarker(index, selection) {
31867
31703
  const {
31868
31704
  choices,
31869
- markers,
31870
- multipleAnswers
31705
+ markers
31871
31706
  } = this.props;
31872
31707
 
31873
31708
  // Compile the user selected answer choices.
@@ -31876,35 +31711,6 @@ class LabelImage extends React__namespace.Component {
31876
31711
  ...markers[index],
31877
31712
  selected: selected.length ? selected : undefined
31878
31713
  });
31879
- if (!multipleAnswers) {
31880
- this.dismissMarkerPopup();
31881
- }
31882
- }
31883
- renderAnswerChoicesForMarker(index, marker) {
31884
- const {
31885
- choices,
31886
- multipleAnswers
31887
- } = this.props;
31888
-
31889
- // The user selected answer choices.
31890
- const selected = marker.selected;
31891
- return /*#__PURE__*/React__namespace.createElement("div", {
31892
- className: classNames__default["default"]("perseus-label-image-widget-answer-choices", aphrodite.css(styles$f.scrollableChoices))
31893
- }, /*#__PURE__*/React__namespace.createElement(AnswerChoices, {
31894
- choices: choices.map(choice => ({
31895
- content: choice,
31896
- checked: selected ? selected.includes(choice) : false
31897
- })),
31898
- multipleSelect: multipleAnswers,
31899
- onChange: selection => {
31900
- this.props.analytics?.onAnalyticsEvent({
31901
- type: "perseus:label-image:choiced-interacted-with",
31902
- payload: null
31903
- });
31904
- this.handleAnswerChoicesChangeForMarker(index, selection);
31905
- },
31906
- ref: node => this._answerChoices = node
31907
- }));
31908
31714
  }
31909
31715
  renderMarkers() {
31910
31716
  const {
@@ -31919,40 +31725,6 @@ class LabelImage extends React__namespace.Component {
31919
31725
 
31920
31726
  // Render all markers for widget.
31921
31727
  return markers.map((marker, index) => {
31922
- const score = LabelImage.gradeMarker(marker);
31923
- // Once the question is answered, show markers
31924
- // with correct answers, otherwise passthrough
31925
- // the correctness state.
31926
- const showCorrectness = questionCompleted && score.hasAnswers && score.isCorrect ? "correct" : marker.showCorrectness;
31927
- const element = /*#__PURE__*/React__namespace.createElement(Marker, _extends({}, marker, {
31928
- showCorrectness: showCorrectness,
31929
- showSelected: index === activeMarkerIndex,
31930
- showPulsate: !markersInteracted,
31931
- key: `${marker.x}.${marker.y}`,
31932
- onClick: () => {
31933
- this.props.analytics?.onAnalyticsEvent({
31934
- type: "perseus:label-image:marker-interacted-with",
31935
- payload: null
31936
- });
31937
- this.activateMarker(index);
31938
- },
31939
- onKeyDown: e => this.handleMarkerKeyDown(index, e),
31940
- ref: node => this._markers[index] = node,
31941
- focused: index === this.state.focusedMarkerIndex,
31942
- onFocus: () => {
31943
- this.setState({
31944
- focusedMarkerIndex: index
31945
- });
31946
- },
31947
- onBlur: () => {
31948
- if (index === this.state.focusedMarkerIndex) {
31949
- this.setState({
31950
- focusedMarkerIndex: -1
31951
- });
31952
- }
31953
- }
31954
- }));
31955
-
31956
31728
  // Determine whether page is rendered in a narrow browser window.
31957
31729
  const isNarrowPage = window.matchMedia(mediaQueries.xsOrSmaller.replace("@media ", "")).matches;
31958
31730
 
@@ -31980,40 +31752,77 @@ class LabelImage extends React__namespace.Component {
31980
31752
  bottom: "top"
31981
31753
  }[markerPosition];
31982
31754
  }
31983
- const answerChoicesActive = index === activeMarkerIndex;
31984
- const adjustPopoverDistance = {
31985
- [side]: 15 // move the popover closer to the marker
31986
- };
31755
+ const score = LabelImage.gradeMarker(marker);
31756
+ // Once the question is answered, show markers
31757
+ // with correct answers, otherwise passthrough
31758
+ // the correctness state.
31759
+ const showCorrectness = questionCompleted && score.hasAnswers && score.isCorrect ? "correct" : marker.showCorrectness;
31987
31760
 
31761
+ // Disable marker interaction once the question is answered correctly.
31762
+ const disabled = showCorrectness === "correct";
31988
31763
  const adjustPillDistance = {
31989
- [`margin${markerPosition.charAt(0).toUpperCase() + markerPosition.slice(1)}`]: 15 // move pill further from marker
31764
+ [`margin${markerPosition.charAt(0).toUpperCase() + markerPosition.slice(1)}`]: 10 // move pill further from marker
31990
31765
  };
31991
31766
 
31992
- const showAnswerChoice = !answerChoicesActive && !this.state.hideAnswers;
31993
- return /*#__PURE__*/React__namespace.createElement("div", {
31994
- key: `answers-${marker.x}.${marker.y}`
31995
- }, /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
31996
- content: () => /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
31997
- style: [adjustPopoverDistance, styles$f.choicesPopover]
31998
- }, this.renderAnswerChoicesForMarker(index, marker)),
31999
- placement: side,
32000
- onClose: () => this.dismissMarkerPopup(),
32001
- opened: answerChoicesActive,
32002
- ref: node => this._selectedMarkerPopup = node,
32003
- showTail: false,
32004
- dismissEnabled: true
32005
- }, element), !!marker.selected && showAnswerChoice && /*#__PURE__*/React__namespace.createElement(AnswerPill, {
32006
- selectedAnswers: marker.selected,
32007
- showCorrectness: showCorrectness,
32008
- markerRef:
32009
- // this throws a warning because it's inadvisable to
32010
- // call ReactDOM fns in render. we aren't storing
32011
- // actual refs in this array, so not much I can do
32012
- // outside of a refactor.
32013
- ReactDOM__namespace.findDOMNode(this._markers[index]),
32014
- side: side,
32015
- onClick: () => this.activateMarker(index),
32016
- style: adjustPillDistance
31767
+ const answerChoicesActive = index === activeMarkerIndex;
31768
+ const showAnswerChoice = marker.selected && !answerChoicesActive && !this.state.hideAnswers;
31769
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31770
+ style: {
31771
+ position: "absolute",
31772
+ left: `${marker.x}%`,
31773
+ top: `${marker.y}%`,
31774
+ // reset to allow child (answer pill) to control z-index
31775
+ zIndex: "unset"
31776
+ }
31777
+ }, /*#__PURE__*/React__namespace.createElement(AnswerChoices, {
31778
+ key: `answers-${marker.x}.${marker.y}`,
31779
+ choices: this.props.choices.map(choice => ({
31780
+ content: choice,
31781
+ checked: marker.selected ? marker.selected.includes(choice) : false
31782
+ })),
31783
+ multipleSelect: this.props.multipleAnswers,
31784
+ onChange: selection => {
31785
+ this.props.analytics?.onAnalyticsEvent({
31786
+ type: "perseus:label-image:choiced-interacted-with",
31787
+ payload: null
31788
+ });
31789
+ this.handleAnswerChoicesChangeForMarker(index, selection);
31790
+ },
31791
+ onToggle: opened => this.activateMarker(index, opened)
31792
+ // cannot change answer choices once question is answered
31793
+ ,
31794
+ disabled: disabled,
31795
+ opener: _ref => {
31796
+ let {
31797
+ opened,
31798
+ text
31799
+ } = _ref;
31800
+ return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
31801
+ role: "button",
31802
+ key: `marker-${marker.x}.${marker.y}`,
31803
+ "aria-label":
31804
+ // already translated in: /widgets/graded-group.tsx
31805
+ showCorrectness === "correct" ? i18n__namespace._("Correct!") : marker.label
31806
+ }, _ref2 => {
31807
+ let {
31808
+ hovered,
31809
+ focused,
31810
+ pressed
31811
+ } = _ref2;
31812
+ return /*#__PURE__*/React__namespace.createElement(Marker, _extends({}, marker, {
31813
+ showCorrectness: showCorrectness,
31814
+ showSelected: opened,
31815
+ showPulsate: !markersInteracted,
31816
+ ref: node => this._markers[index] = node,
31817
+ showAnswer: showAnswerChoice,
31818
+ answerSide: side,
31819
+ answerStyles: adjustPillDistance,
31820
+ analytics: this.props.analytics,
31821
+ focused: focused || pressed,
31822
+ hovered: hovered
31823
+ }));
31824
+ });
31825
+ }
32017
31826
  }));
32018
31827
  });
32019
31828
  }
@@ -32066,10 +31875,10 @@ class LabelImage extends React__namespace.Component {
32066
31875
  // than its rendered in the widget, this would
32067
31876
  // result in a zoom of the image.
32068
31877
  activeMarkerIndex !== -1 && styles$f.imageInteractionDisabled)
32069
- }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref => {
31878
+ }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref3 => {
32070
31879
  let {
32071
31880
  setAssetStatus
32072
- } = _ref;
31881
+ } = _ref3;
32073
31882
  return /*#__PURE__*/React__namespace.createElement(SvgImage, {
32074
31883
  alt: imageAlt,
32075
31884
  src: imageUrl,
@@ -32132,18 +31941,6 @@ const styles$f = aphrodite.StyleSheet.create({
32132
31941
  },
32133
31942
  imageInteractionDisabled: {
32134
31943
  pointerEvents: "none"
32135
- },
32136
- scrollableChoices: {
32137
- paddingTop: 8,
32138
- paddingBottom: 8,
32139
- // Enable scroll for answer choices within popup on mobile phones.
32140
- [mediaQueries.xsOrSmaller]: {
32141
- maxHeight: 250,
32142
- overflowY: "auto"
32143
- }
32144
- },
32145
- choicesPopover: {
32146
- padding: 0
32147
31944
  }
32148
31945
  });
32149
31946
  const LabelImageWithDependencies = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
@@ -32426,7 +32223,7 @@ const transformProps = function (editorProps) {
32426
32223
  };
32427
32224
  var LightsPuzzle$1 = {
32428
32225
  name: "lights-puzzle",
32429
- displayName: "Lights Puzzle",
32226
+ displayName: "Lights puzzle (deprecated)",
32430
32227
  hidden: true,
32431
32228
  widget: LightsPuzzle,
32432
32229
  transform: transformProps
@@ -33366,7 +33163,7 @@ const styles$d = aphrodite.StyleSheet.create({
33366
33163
  });
33367
33164
  var Matcher$1 = {
33368
33165
  name: "matcher",
33369
- displayName: "Two column matcher",
33166
+ displayName: "Matcher (two column)",
33370
33167
  widget: Matcher,
33371
33168
  isLintable: true
33372
33169
  };
@@ -39432,7 +39229,7 @@ class ReactionDiagramWidget extends React__namespace.Component {
39432
39229
  }
39433
39230
  var ReactionDiagram = {
39434
39231
  name: "reaction-diagram",
39435
- displayName: "Chemical reaction",
39232
+ displayName: "Chemical reaction diagram (deprecated)",
39436
39233
  hidden: true,
39437
39234
  widget: ReactionDiagramWidget
39438
39235
  };
@@ -39529,7 +39326,7 @@ const traverseChildWidgets = function (props, traverseRenderer) {
39529
39326
  };
39530
39327
  var Sequence$1 = {
39531
39328
  name: "sequence",
39532
- displayName: "Graded Sequence",
39329
+ displayName: "Graded sequence (deprecated)",
39533
39330
  widget: Sequence,
39534
39331
  traverseChildWidgets: traverseChildWidgets,
39535
39332
  tracking: "all",
@@ -40243,7 +40040,7 @@ const propTransform$1 = editorProps => {
40243
40040
  };
40244
40041
  var Simulator$1 = {
40245
40042
  name: "simulator",
40246
- displayName: "Simulator",
40043
+ displayName: "Simulator (deprecated)",
40247
40044
  widget: Simulator,
40248
40045
  transform: propTransform$1,
40249
40046
  hidden: true
@@ -40657,7 +40454,7 @@ const propTransform = editorProps => {
40657
40454
  };
40658
40455
  var Table$1 = {
40659
40456
  name: "table",
40660
- displayName: "Table of values",
40457
+ displayName: "Table (deprecated - use markdown table instead)",
40661
40458
  accessible: true,
40662
40459
  widget: Table,
40663
40460
  transform: propTransform,
@@ -43069,7 +42866,8 @@ class Transformer extends React__namespace.Component {
43069
42866
  }
43070
42867
  var Transformer$1 = {
43071
42868
  name: "transformer",
43072
- displayName: "Transformer",
42869
+ displayName: "Transformer (deprecated)",
42870
+ hidden: true,
43073
42871
  widget: Transformer
43074
42872
  };
43075
42873
 
@@ -44117,7 +43915,7 @@ const primUnits = function (expr) {
44117
43915
  };
44118
43916
  var Unit = {
44119
43917
  name: "unit-input",
44120
- displayName: "Unit",
43918
+ displayName: "Unit input",
44121
43919
  defaultAlignment: "inline-block",
44122
43920
  widget: OldUnitInput,
44123
43921
  transform: x => lens(x).del(["value"]).freeze(),
@@ -44298,7 +44096,7 @@ var Video$1 = {
44298
44096
  };
44299
44097
 
44300
44098
  /* eslint-disable import/no-named-as-default */
44301
- var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Transformer$1, Unit, Video$1];
44099
+ var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Transformer$1, Unit, Video$1, DeprecatedStandin];
44302
44100
 
44303
44101
  /**
44304
44102
  * This should be called by all clients, specifying whether extra widgets are
@@ -44313,6 +44111,11 @@ const init = function (options) {
44313
44111
  registerWidgets(basicWidgets);
44314
44112
  registerWidgets(extraWidgets);
44315
44113
 
44114
+ // This section replaces widgets
44115
+ // When it's time to replace the transformer widget
44116
+ // uncomment this line
44117
+ // Widgets.replaceWidget("transformer", "always-correct");
44118
+
44316
44119
  // Pass skipMathJax: true if MathJax is already loaded and configured.
44317
44120
  const skipMathJax = options.skipMathJax;
44318
44121
  if (skipMathJax) {
@@ -44337,7 +44140,7 @@ const init = function (options) {
44337
44140
 
44338
44141
  // This file is processed by a Rollup plugin (replace) to inject the production
44339
44142
  const libName = "@khanacademy/perseus";
44340
- const libVersion = "17.5.0";
44143
+ const libVersion = "17.6.1";
44341
44144
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
44342
44145
 
44343
44146
  const apiVersion = {
@@ -45784,6 +45587,8 @@ const ItemExtras = [
45784
45587
 
45785
45588
  // prettier-ignore
45786
45589
 
45590
+ //prettier-ignore
45591
+
45787
45592
  // A background image applied to various widgets.
45788
45593
 
45789
45594
  const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
@@ -46906,6 +46711,10 @@ function violatingWidgets(itemData) {
46906
46711
  */
46907
46712
  const registerAllWidgetsForTesting = () => {
46908
46713
  registerWidgets(allWidgets);
46714
+
46715
+ // When it's time to replace the transformer widget
46716
+ // uncomment this line
46717
+ // Widgets.replaceWidget("transformer", "deprecated-standin");
46909
46718
  };
46910
46719
 
46911
46720
  const EditorJsonify = {