@khanacademy/perseus 46.0.0 → 47.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -649,7 +649,7 @@ class InnerMathInput extends React__namespace.Component {
649
649
  className = className + " " + this.props.className;
650
650
  }
651
651
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
652
- style: [styles$E.outerWrapper, this.state.focused && styles$E.wrapperFocused, this.props.hasError && styles$E.wrapperError]
652
+ style: [styles$D.outerWrapper, this.state.focused && styles$D.wrapperFocused, this.props.hasError && styles$D.wrapperError]
653
653
  }, /*#__PURE__*/React__namespace.createElement("div", {
654
654
  style: {
655
655
  display: "flex",
@@ -685,7 +685,7 @@ class InnerMathInput extends React__namespace.Component {
685
685
  style: a11y.srOnly
686
686
  }, this.context.strings.mathInputDescription), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
687
687
  closeButtonVisible: true,
688
- style: styles$E.popoverContent
688
+ style: styles$D.popoverContent
689
689
  }, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends({
690
690
  onAnalyticsEvent: this.props.onAnalyticsEvent,
691
691
  extraKeys: this.props.extraKeys,
@@ -750,9 +750,9 @@ const MathInputIcon = _ref => {
750
750
  fillColor = wonderBlocksTokens.color.offBlack;
751
751
  break;
752
752
  }
753
- const dynamicClass = active || focused ? styles$E.iconActive : styles$E.iconInactive;
753
+ const dynamicClass = active || focused ? styles$D.iconActive : styles$D.iconInactive;
754
754
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
755
- style: [styles$E.iconContainer, dynamicClass]
755
+ style: [styles$D.iconContainer, dynamicClass]
756
756
  }, /*#__PURE__*/React__namespace.createElement("svg", {
757
757
  xmlns: "http://www.w3.org/2000/svg",
758
758
  width: "16",
@@ -797,7 +797,7 @@ const inputFocused = {
797
797
  borderColor: wonderBlocksTokens.color.blue,
798
798
  margin: -1
799
799
  };
800
- const styles$E = aphrodite.StyleSheet.create({
800
+ const styles$D = aphrodite.StyleSheet.create({
801
801
  iconContainer: {
802
802
  display: "flex",
803
803
  justifyContent: "center",
@@ -2603,7 +2603,7 @@ class Expression extends React__namespace.Component {
2603
2603
  render() {
2604
2604
  if (this.props.apiOptions.customKeypad) {
2605
2605
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
2606
- className: aphrodite.css(styles$D.mobileLabelInputWrapper)
2606
+ className: aphrodite.css(styles$C.mobileLabelInputWrapper)
2607
2607
  }, !!this.props.visibleLabel && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
2608
2608
  htmlFor: this._textareaId,
2609
2609
  tag: "label"
@@ -2637,7 +2637,7 @@ class Expression extends React__namespace.Component {
2637
2637
  ERROR_TITLE
2638
2638
  } = this.context.strings;
2639
2639
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
2640
- className: aphrodite.css(styles$D.desktopLabelInputWrapper)
2640
+ className: aphrodite.css(styles$C.desktopLabelInputWrapper)
2641
2641
  }, !!this.props.visibleLabel && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
2642
2642
  htmlFor: this._textareaId,
2643
2643
  tag: "label"
@@ -2676,7 +2676,7 @@ class Expression extends React__namespace.Component {
2676
2676
  }))));
2677
2677
  }
2678
2678
  }
2679
- const styles$D = aphrodite.StyleSheet.create({
2679
+ const styles$C = aphrodite.StyleSheet.create({
2680
2680
  mobileLabelInputWrapper: {
2681
2681
  padding: "15px 4px 0"
2682
2682
  },
@@ -18124,33 +18124,33 @@ class Lint extends React__namespace.Component {
18124
18124
  let warningText;
18125
18125
  let warningTextStyle;
18126
18126
  if (this.props.severity === Severity.Error) {
18127
- severityStyle = styles$C.indicatorError;
18127
+ severityStyle = styles$B.indicatorError;
18128
18128
  warningText = "Error";
18129
- warningTextStyle = styles$C.publishBlockingError;
18129
+ warningTextStyle = styles$B.publishBlockingError;
18130
18130
  } else if (this.props.severity === Severity.Warning) {
18131
- severityStyle = styles$C.indicatorWarning;
18131
+ severityStyle = styles$B.indicatorWarning;
18132
18132
  warningText = "Warning";
18133
- warningTextStyle = styles$C.warning;
18133
+ warningTextStyle = styles$B.warning;
18134
18134
  } else {
18135
- severityStyle = styles$C.indicatorGuideline;
18135
+ severityStyle = styles$B.indicatorGuideline;
18136
18136
  warningText = "Recommendation";
18137
- warningTextStyle = styles$C.warning;
18137
+ warningTextStyle = styles$B.warning;
18138
18138
  }
18139
18139
  return /*#__PURE__*/React__namespace.createElement("a", {
18140
18140
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
18141
18141
  target: "lint-help-window",
18142
18142
  className: aphrodite.css(style)
18143
18143
  }, /*#__PURE__*/React__namespace.createElement("span", {
18144
- className: aphrodite.css(styles$C.indicator, severityStyle)
18144
+ className: aphrodite.css(styles$B.indicator, severityStyle)
18145
18145
  }, this.props.severity === 1 && /*#__PURE__*/React__namespace.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React__namespace.createElement("div", {
18146
- className: aphrodite.css(styles$C.tooltip, tooltipAbove && styles$C.tooltipAbove)
18146
+ className: aphrodite.css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
18147
18147
  }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React__namespace.createElement("p", {
18148
18148
  key: i,
18149
- className: aphrodite.css(styles$C.tooltipParagraph)
18149
+ className: aphrodite.css(styles$B.tooltipParagraph)
18150
18150
  }, /*#__PURE__*/React__namespace.createElement("span", {
18151
18151
  className: aphrodite.css(warningTextStyle)
18152
18152
  }, warningText, ":", " "), m)), /*#__PURE__*/React__namespace.createElement("div", {
18153
- className: aphrodite.css(styles$C.tail, tooltipAbove && styles$C.tailAbove)
18153
+ className: aphrodite.css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
18154
18154
  })));
18155
18155
  };
18156
18156
 
@@ -18178,20 +18178,20 @@ class Lint extends React__namespace.Component {
18178
18178
  }
18179
18179
  if (blockHighlight) {
18180
18180
  return /*#__PURE__*/React__namespace.createElement("span", {
18181
- className: aphrodite.css(styles$C.lintContainer, styles$C.lintContainerBlock)
18182
- }, this.renderLink(styles$C.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
18181
+ className: aphrodite.css(styles$B.lintContainer, styles$B.lintContainerBlock)
18182
+ }, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
18183
18183
  }
18184
18184
  if (inline) {
18185
18185
  return /*#__PURE__*/React__namespace.createElement("span", {
18186
- className: aphrodite.css(styles$C.lintContainer)
18187
- }, this.renderLink(styles$C.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
18186
+ className: aphrodite.css(styles$B.lintContainer)
18187
+ }, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
18188
18188
  }
18189
18189
  return /*#__PURE__*/React__namespace.createElement("div", {
18190
- className: aphrodite.css(styles$C.lintContainer)
18191
- }, this.renderLink(styles$C.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
18190
+ className: aphrodite.css(styles$B.lintContainer)
18191
+ }, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
18192
18192
  }
18193
18193
  }
18194
- const styles$C = aphrodite.StyleSheet.create({
18194
+ const styles$B = aphrodite.StyleSheet.create({
18195
18195
  // This is the class of the outermost element.
18196
18196
  // We use relative positioning so that the lint indicator can be
18197
18197
  // positioned absolutely relative to the position of the linty container.
@@ -19012,8 +19012,6 @@ function getWidgetFromWidgetMap(widgetId, widgetMap) {
19012
19012
 
19013
19013
  /**
19014
19014
  * Get select widgets from a widget map.
19015
- * Useful for multi-items that needs to split
19016
- * one PerseusItem into several
19017
19015
  *
19018
19016
  * @param {ReadonlyArray<string>} widgetIds to extract
19019
19017
  * @param {PerseusWidgetsMap} widgetMap to extract from
@@ -20618,7 +20616,7 @@ class Renderer extends React__namespace.Component {
20618
20616
  };
20619
20617
  const mobileInnerStyle = {
20620
20618
  ...innerStyle,
20621
- ...styles$B.mobileZoomableParentFix
20619
+ ...styles$A.mobileZoomableParentFix
20622
20620
  };
20623
20621
  return /*#__PURE__*/React__namespace.createElement("div", {
20624
20622
  key: state.key,
@@ -20758,7 +20756,7 @@ class Renderer extends React__namespace.Component {
20758
20756
  };
20759
20757
  const mobileInnerStyle = {
20760
20758
  ...innerStyle,
20761
- ...styles$B.mobileZoomableParentFix
20759
+ ...styles$A.mobileZoomableParentFix
20762
20760
  };
20763
20761
  const wrappedOutput = /*#__PURE__*/React__namespace.createElement("div", {
20764
20762
  style: {
@@ -21221,7 +21219,7 @@ class Renderer extends React__namespace.Component {
21221
21219
  return this.lastRenderedMarkdown;
21222
21220
  }
21223
21221
  }
21224
- const styles$B = {
21222
+ const styles$A = {
21225
21223
  mobileZoomableParentFix: {
21226
21224
  // NOTE(abdul): There is an issue where transform animations will
21227
21225
  // cause the Zoomable component to disappear when running on the
@@ -22187,10 +22185,10 @@ class InputNumber extends React__namespace.Component {
22187
22185
  // Note: This is _very_ similar to what `numeric-input.jsx` does. If
22188
22186
  // you modify this, double-check if you also need to modify that
22189
22187
  // component.
22190
- const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
22188
+ const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
22191
22189
  // Unanswered
22192
22190
  if (this.props.reviewMode && !this.props.currentValue) {
22193
- inputStyles.push(styles$A.answerStateUnanswered);
22191
+ inputStyles.push(styles$z.answerStateUnanswered);
22194
22192
  }
22195
22193
  return /*#__PURE__*/React__namespace.createElement(InputWithExamples
22196
22194
  // eslint-disable-next-line react/no-string-refs
@@ -22209,7 +22207,7 @@ class InputNumber extends React__namespace.Component {
22209
22207
  });
22210
22208
  }
22211
22209
  }
22212
- const styles$A = aphrodite.StyleSheet.create({
22210
+ const styles$z = aphrodite.StyleSheet.create({
22213
22211
  default: {
22214
22212
  width: 80,
22215
22213
  height: "auto"
@@ -23377,7 +23375,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
23377
23375
  const rects = this.state.cachedHighlightRects;
23378
23376
  return /*#__PURE__*/React__namespace.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React__namespace.createElement("div", {
23379
23377
  key: index,
23380
- className: aphrodite.css(styles$z.highlightRect),
23378
+ className: aphrodite.css(styles$y.highlightRect),
23381
23379
  style: {
23382
23380
  // NOTE(mdr): We apply `position: absolute` here
23383
23381
  // rather than in Aphrodite styles, because
@@ -23396,7 +23394,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
23396
23394
  })));
23397
23395
  }
23398
23396
  }
23399
- const styles$z = aphrodite.StyleSheet.create({
23397
+ const styles$y = aphrodite.StyleSheet.create({
23400
23398
  highlightRect: {
23401
23399
  background: "#fffabe" // highlighter yellow :)
23402
23400
  }
@@ -23477,7 +23475,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
23477
23475
  // TooltipContent wouldn't let me overwrite
23478
23476
  // user-select and onClick
23479
23477
  const content = /*#__PURE__*/React__namespace.createElement("div", {
23480
- className: aphrodite.css(styles$y.tooltipLabel),
23478
+ className: aphrodite.css(styles$x.tooltipLabel),
23481
23479
  onClick: this.props.onClick
23482
23480
  }, this.props.label);
23483
23481
  const style = {
@@ -23497,7 +23495,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
23497
23495
  }, /*#__PURE__*/React__namespace.createElement("div", null)));
23498
23496
  }
23499
23497
  }
23500
- const styles$y = aphrodite.StyleSheet.create({
23498
+ const styles$x = aphrodite.StyleSheet.create({
23501
23499
  tooltipLabel: {
23502
23500
  // Unlike most tooltip contents, we don't want this label to be
23503
23501
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -24055,7 +24053,7 @@ class HighlightableContent extends React__namespace.PureComponent {
24055
24053
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
24056
24054
  const buildHighlight = r => this._buildHighlight(r);
24057
24055
  return /*#__PURE__*/React__namespace.createElement("div", {
24058
- className: aphrodite.css(styles$x.container),
24056
+ className: aphrodite.css(styles$w.container),
24059
24057
  ref: container => this._container = container
24060
24058
  }, /*#__PURE__*/React__namespace.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React__namespace.createElement(HighlightingUI, {
24061
24059
  buildHighlight: buildHighlight,
@@ -24076,14 +24074,14 @@ class HighlightableContent extends React__namespace.PureComponent {
24076
24074
  onAddHighlight: this._handleAddHighlight,
24077
24075
  onRemoveHighlight: this._handleRemoveHighlight
24078
24076
  })), /*#__PURE__*/React__namespace.createElement("div", {
24079
- className: aphrodite.css(styles$x.content),
24077
+ className: aphrodite.css(styles$w.content),
24080
24078
  ref: content => this._content = content
24081
24079
  }, /*#__PURE__*/React__namespace.createElement(WordIndexer, {
24082
24080
  onWordsUpdate: this._handleWordsUpdate
24083
24081
  }, this.props.children)));
24084
24082
  }
24085
24083
  }
24086
- const styles$x = aphrodite.StyleSheet.create({
24084
+ const styles$w = aphrodite.StyleSheet.create({
24087
24085
  // We render content with z-index 1, and highlights with z-index 0, so that
24088
24086
  // content will receive the browser's native pointer events. (Highlights
24089
24087
  // have their own magic code to manage hover detection, despite being
@@ -24505,7 +24503,7 @@ class LineHeightMeasurer extends React__namespace.Component {
24505
24503
  }
24506
24504
  render() {
24507
24505
  return /*#__PURE__*/React__namespace.createElement("div", {
24508
- className: aphrodite.css(styles$w.measurer),
24506
+ className: aphrodite.css(styles$v.measurer),
24509
24507
  "aria-hidden": "true"
24510
24508
  }, /*#__PURE__*/React__namespace.createElement("div", {
24511
24509
  ref: ref => this._line = ref,
@@ -24513,7 +24511,7 @@ class LineHeightMeasurer extends React__namespace.Component {
24513
24511
  }, "Line Height Measurement"));
24514
24512
  }
24515
24513
  }
24516
- const styles$w = aphrodite.StyleSheet.create({
24514
+ const styles$v = aphrodite.StyleSheet.create({
24517
24515
  measurer: {
24518
24516
  position: "absolute",
24519
24517
  top: 0,
@@ -25494,11 +25492,11 @@ const FocusRing = function (_ref) {
25494
25492
  };
25495
25493
  return /*#__PURE__*/React__namespace.createElement("span", {
25496
25494
  "data-testid": "focus-ring",
25497
- className: aphrodite.css(styles$v.ring),
25495
+ className: aphrodite.css(styles$u.ring),
25498
25496
  style: style
25499
25497
  }, children);
25500
25498
  };
25501
- const styles$v = aphrodite.StyleSheet.create({
25499
+ const styles$u = aphrodite.StyleSheet.create({
25502
25500
  ring: {
25503
25501
  margin: "auto",
25504
25502
  display: "inline-block",
@@ -25525,7 +25523,7 @@ function getChoiceLetter(pos, strings) {
25525
25523
  }
25526
25524
 
25527
25525
  const CHOICE_ICON_SIZE = 24;
25528
- const styles$u = aphrodite.StyleSheet.create({
25526
+ const styles$t = aphrodite.StyleSheet.create({
25529
25527
  iconWrapper: {
25530
25528
  display: "inline-block",
25531
25529
  position: "relative"
@@ -25548,7 +25546,7 @@ const CrossOutLine = function (props) {
25548
25546
  width: CROSS_OUT_LINE_SIZE,
25549
25547
  height: CROSS_OUT_LINE_SIZE,
25550
25548
  viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
25551
- className: aphrodite.css(styles$t.crossOutLine),
25549
+ className: aphrodite.css(styles$s.crossOutLine),
25552
25550
  "data-testid": "choice-icon__cross-out-line"
25553
25551
  }, /*#__PURE__*/React__namespace.createElement("line", {
25554
25552
  // The line stretches from the bottom-left to top-right.
@@ -25563,7 +25561,7 @@ const CrossOutLine = function (props) {
25563
25561
  strokeLinecap: "round"
25564
25562
  }));
25565
25563
  };
25566
- const styles$t = aphrodite.StyleSheet.create({
25564
+ const styles$s = aphrodite.StyleSheet.create({
25567
25565
  crossOutLine: {
25568
25566
  // Center the icon within the container.
25569
25567
  position: "absolute",
@@ -25647,7 +25645,7 @@ const ChoiceIcon = function (props) {
25647
25645
  } = props;
25648
25646
  const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
25649
25647
  return /*#__PURE__*/React__namespace.createElement("div", {
25650
- className: aphrodite.css(styles$u.iconWrapper)
25648
+ className: aphrodite.css(styles$t.iconWrapper)
25651
25649
  }, /*#__PURE__*/React__namespace.createElement(FocusRing, {
25652
25650
  color: wonderBlocksTokens.color.blue,
25653
25651
  visible: focused || hovered,
@@ -25655,13 +25653,13 @@ const ChoiceIcon = function (props) {
25655
25653
  }, /*#__PURE__*/React__namespace.createElement("div", {
25656
25654
  style: dynamicStyles,
25657
25655
  "data-testid": "choice-icon__library-choice-icon",
25658
- className: aphrodite.css(styles$s.circle, showCorrectness && correct && styles$s.circleCorrect, showCorrectness && !correct && styles$s.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$s.circleIncorrectAnswered)
25656
+ className: aphrodite.css(styles$r.circle, showCorrectness && correct && styles$r.circleCorrect, showCorrectness && !correct && styles$r.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$r.circleIncorrectAnswered)
25659
25657
  // used in BaseRadio editMode to check
25660
25658
  // if we actually clicked on the radio icon
25661
25659
  ,
25662
25660
  "data-is-radio-icon": true
25663
25661
  }, /*#__PURE__*/React__namespace.createElement("div", {
25664
- className: aphrodite.css(styles$s.innerWrapper)
25662
+ className: aphrodite.css(styles$r.innerWrapper)
25665
25663
  }, /*#__PURE__*/React__namespace.createElement(ChoiceInner, {
25666
25664
  pos: pos,
25667
25665
  showCorrectness: showCorrectness,
@@ -25670,7 +25668,7 @@ const ChoiceIcon = function (props) {
25670
25668
  color: dynamicStyles.borderColor
25671
25669
  }));
25672
25670
  };
25673
- const styles$s = aphrodite.StyleSheet.create({
25671
+ const styles$r = aphrodite.StyleSheet.create({
25674
25672
  innerWrapper: {
25675
25673
  width: CHOICE_ICON_SIZE,
25676
25674
  height: CHOICE_ICON_SIZE,
@@ -25765,19 +25763,19 @@ const OptionStatus = function (props) {
25765
25763
  }
25766
25764
  let textStyle;
25767
25765
  if (correct) {
25768
- textStyle = styles$r.correct;
25766
+ textStyle = styles$q.correct;
25769
25767
  } else {
25770
25768
  if (checked || previouslyAnswered) {
25771
- textStyle = styles$r.incorrectAnswered;
25769
+ textStyle = styles$q.incorrectAnswered;
25772
25770
  } else {
25773
- textStyle = styles$r.incorrect;
25771
+ textStyle = styles$q.incorrect;
25774
25772
  }
25775
25773
  }
25776
25774
  return /*#__PURE__*/React__namespace.createElement("div", {
25777
- className: aphrodite.css(styles$r.text, textStyle)
25775
+ className: aphrodite.css(styles$q.text, textStyle)
25778
25776
  }, renderText(checked, correct, crossedOut, strings));
25779
25777
  };
25780
- const styles$r = aphrodite.StyleSheet.create({
25778
+ const styles$q = aphrodite.StyleSheet.create({
25781
25779
  text: {
25782
25780
  alignItems: "center",
25783
25781
  display: "flex",
@@ -25846,8 +25844,8 @@ const Choice = function (props) {
25846
25844
  crossedOut: updatedCrossedOut
25847
25845
  });
25848
25846
  }
25849
- const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$q.description));
25850
- const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$q.rationale));
25847
+ const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$p.description));
25848
+ const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$p.rationale));
25851
25849
 
25852
25850
  // We want to show the choices as dimmed out when the choices are disabled.
25853
25851
  // However, we don't want to do this when we're in review mode in the
@@ -26014,7 +26012,7 @@ const Choice = function (props) {
26014
26012
  "data-testid": `perseus-radio-rationale-content-${pos}`
26015
26013
  }, rationale));
26016
26014
  };
26017
- const styles$q = aphrodite.StyleSheet.create({
26015
+ const styles$p = aphrodite.StyleSheet.create({
26018
26016
  description: {
26019
26017
  display: "inline-block",
26020
26018
  width: "100%"
@@ -26205,10 +26203,10 @@ const BaseRadio = function (_ref) {
26205
26203
  const isMobile = apiOptions.isMobile;
26206
26204
  const firstChoiceHighlighted = choices[0].highlighted;
26207
26205
  const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
26208
- const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$p.radio, styles$p.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$p.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$p.radioContainerLastHighlighted));
26209
- const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$p.instructions, isMobile && styles$p.instructionsMobile));
26206
+ const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$o.radio, styles$o.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$o.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$o.radioContainerLastHighlighted));
26207
+ const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$o.instructions, isMobile && styles$o.instructionsMobile));
26210
26208
  const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
26211
- const responsiveClassName = aphrodite.css(styles$p.responsiveFieldset);
26209
+ const responsiveClassName = aphrodite.css(styles$o.responsiveFieldset);
26212
26210
  const fieldset = /*#__PURE__*/React__namespace.createElement("fieldset", {
26213
26211
  className: `perseus-widget-radio-fieldset ${responsiveClassName}`
26214
26212
  }, /*#__PURE__*/React__namespace.createElement("legend", {
@@ -26259,7 +26257,7 @@ const BaseRadio = function (_ref) {
26259
26257
  const aphroditeClassName = checked => {
26260
26258
  // Whether or not to show correctness borders
26261
26259
  // for this choice and the next choice.
26262
- return aphrodite.css(sharedStyles.aboveScratchpad, styles$p.item, styles$p.responsiveItem, checked && styles$p.selectedItem, checked && choice.highlighted && styles$p.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$p.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$p.nextHighlighted);
26260
+ return aphrodite.css(sharedStyles.aboveScratchpad, styles$o.item, styles$o.responsiveItem, checked && styles$o.selectedItem, checked && choice.highlighted && styles$o.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$o.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$o.nextHighlighted);
26263
26261
  };
26264
26262
 
26265
26263
  // HACK(abdulrahman): Preloads the selection-state
@@ -26324,10 +26322,10 @@ const BaseRadio = function (_ref) {
26324
26322
  // Allow for horizontal scrolling if content is too wide, which may be
26325
26323
  // an issue especially on phones.
26326
26324
  return /*#__PURE__*/React__namespace.createElement("div", {
26327
- className: aphrodite.css(styles$p.responsiveContainer)
26325
+ className: aphrodite.css(styles$o.responsiveContainer)
26328
26326
  }, fieldset);
26329
26327
  };
26330
- const styles$p = aphrodite.StyleSheet.create({
26328
+ const styles$o = aphrodite.StyleSheet.create({
26331
26329
  instructions: {
26332
26330
  display: "block",
26333
26331
  color: gray17,
@@ -27059,9 +27057,9 @@ class Categorizer extends React__namespace.Component {
27059
27057
  indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
27060
27058
  }
27061
27059
  const table = /*#__PURE__*/React__namespace.createElement("table", {
27062
- className: "categorizer-table " + aphrodite.css(styles$o.mobileTable)
27060
+ className: "categorizer-table " + aphrodite.css(styles$n.mobileTable)
27063
27061
  }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, /*#__PURE__*/React__namespace.createElement("td", {
27064
- className: aphrodite.css(styles$o.emptyHeaderCell)
27062
+ className: aphrodite.css(styles$n.emptyHeaderCell)
27065
27063
  }), this.props.categories.map((category, i) => {
27066
27064
  // Array index is the correct key here, as that's
27067
27065
  // how category grading actually works -- no way
@@ -27069,7 +27067,7 @@ class Categorizer extends React__namespace.Component {
27069
27067
  // middle. (If we later add that, this should be
27070
27068
  // fixed.)
27071
27069
  return /*#__PURE__*/React__namespace.createElement("th", {
27072
- className: aphrodite.css(styles$o.header),
27070
+ className: aphrodite.css(styles$n.header),
27073
27071
  key: i
27074
27072
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
27075
27073
  content: category,
@@ -27091,7 +27089,7 @@ class Categorizer extends React__namespace.Component {
27091
27089
  })), self.props.categories.map((catName, catNum) => {
27092
27090
  const selected = self.props.values[itemNum] === catNum;
27093
27091
  return /*#__PURE__*/React__namespace.createElement("td", {
27094
- className: "category " + aphrodite.css(styles$o.cell),
27092
+ className: "category " + aphrodite.css(styles$n.cell),
27095
27093
  key: catNum
27096
27094
  }, /*#__PURE__*/React__namespace.createElement("div", {
27097
27095
  className: ClassNames.INTERACTIVE,
@@ -27106,7 +27104,7 @@ class Categorizer extends React__namespace.Component {
27106
27104
  onChange: () => this.onChange(itemNum, catNum),
27107
27105
  onClick: e => e.stopPropagation()
27108
27106
  }), !isMobile && /*#__PURE__*/React__namespace.createElement("span", {
27109
- className: aphrodite.css(styles$o.radioSpan, selected && styles$o.checkedRadioSpan, this.props.static && selected && styles$o.staticCheckedRadioSpan)
27107
+ className: aphrodite.css(styles$n.radioSpan, selected && styles$n.checkedRadioSpan, this.props.static && selected && styles$n.staticCheckedRadioSpan)
27110
27108
  }, selected ? /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleThin))));
27111
27109
  }));
27112
27110
  /* eslint-enable max-len */
@@ -27118,7 +27116,7 @@ class Categorizer extends React__namespace.Component {
27118
27116
  "categorizer-container": true,
27119
27117
  "static-mode": this.props.static
27120
27118
  });
27121
- const inlineStyles = this.props.apiOptions.isMobile ? [styles$o.fullBleedContainer] : [];
27119
+ const inlineStyles = this.props.apiOptions.isMobile ? [styles$n.fullBleedContainer] : [];
27122
27120
  return /*#__PURE__*/React__namespace.createElement("div", {
27123
27121
  className: extraClassNames + " " + aphrodite.css(...inlineStyles)
27124
27122
  }, table);
@@ -27130,7 +27128,7 @@ const pageMargin = 16;
27130
27128
 
27131
27129
  // Stylesheets aren't directly testable
27132
27130
  /* c8 ignore next */
27133
- const styles$o = aphrodite.StyleSheet.create({
27131
+ const styles$n = aphrodite.StyleSheet.create({
27134
27132
  mobileTable: {
27135
27133
  [mediaQueries.smOrSmaller]: {
27136
27134
  minWidth: "auto"
@@ -27399,7 +27397,7 @@ class CSProgram extends React__namespace.Component {
27399
27397
  // creator "went wild".
27400
27398
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
27401
27399
  return /*#__PURE__*/React__namespace.createElement("div", {
27402
- className: aphrodite.css(styles$n.widthOverride, styleContainer && styles$n.container)
27400
+ className: aphrodite.css(styles$m.widthOverride, styleContainer && styles$m.container)
27403
27401
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
27404
27402
  sandbox: sandboxOptions,
27405
27403
  src: url,
@@ -27409,7 +27407,7 @@ class CSProgram extends React__namespace.Component {
27409
27407
  }));
27410
27408
  }
27411
27409
  }
27412
- const styles$n = aphrodite.StyleSheet.create({
27410
+ const styles$m = aphrodite.StyleSheet.create({
27413
27411
  // Override the inherited width from the perseus paragraph class
27414
27412
  // 820 is minimum width for 420px editor and 400px canvas
27415
27413
  widthOverride: {
@@ -27460,7 +27458,7 @@ class Definition extends React__namespace.Component {
27460
27458
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
27461
27459
  content: /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
27462
27460
  color: "white",
27463
- style: styles$m.tooltipBody,
27461
+ style: styles$l.tooltipBody,
27464
27462
  closeButtonVisible: true
27465
27463
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
27466
27464
  apiOptions: this.props.apiOptions,
@@ -27492,7 +27490,7 @@ class Definition extends React__namespace.Component {
27492
27490
  });
27493
27491
  }
27494
27492
  }
27495
- const styles$m = {
27493
+ const styles$l = {
27496
27494
  tooltipBody: {
27497
27495
  color: wonderBlocksTokens.color.offBlack,
27498
27496
  fontSize: 20,
@@ -27761,7 +27759,7 @@ class Explanation extends React__namespace.Component {
27761
27759
  marginRight: "-6px",
27762
27760
  "white-space": "normal"
27763
27761
  };
27764
- const contentStyling = [styles$l.content, this.state.expanded ? styles$l.contentExpanded : styles$l.contentCollapsed, allowTransition && (this.state.expanded ? styles$l.transitionExpanded : styles$l.transitionCollapsed)];
27762
+ const contentStyling = [styles$k.content, this.state.expanded ? styles$k.contentExpanded : styles$k.contentCollapsed, allowTransition && (this.state.expanded ? styles$k.transitionExpanded : styles$k.transitionCollapsed)];
27765
27763
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
27766
27764
  mockOnFirstRender: true,
27767
27765
  scope: "explanation-widget"
@@ -27780,7 +27778,7 @@ class Explanation extends React__namespace.Component {
27780
27778
  "aria-hidden": !this.state.expanded,
27781
27779
  testId: "content-container"
27782
27780
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
27783
- style: styles$l.contentWrapper
27781
+ style: styles$k.contentWrapper
27784
27782
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
27785
27783
  apiOptions: this.props.apiOptions,
27786
27784
  content: this.props.explanation,
@@ -27793,7 +27791,7 @@ class Explanation extends React__namespace.Component {
27793
27791
  const leftBorderSpacing = 23;
27794
27792
  const verticalContentPadding = 10;
27795
27793
  const arrowHeight = 14;
27796
- const styles$l = aphrodite.StyleSheet.create({
27794
+ const styles$k = aphrodite.StyleSheet.create({
27797
27795
  content: {
27798
27796
  borderLeft: "0px solid #ccc",
27799
27797
  display: "inline-grid",
@@ -27879,15 +27877,15 @@ class GradedGroupAnswerBar extends React__namespace.Component {
27879
27877
  nextQuestion
27880
27878
  } = this.context.strings;
27881
27879
  const answerBarStyle = {
27882
- ...styles$k.answerBar,
27880
+ ...styles$j.answerBar,
27883
27881
  backgroundColor: answerBarState === "CORRECT" ? wonderBlocksTokens.color.offWhite : "white",
27884
27882
  // Center the "Correct!" message only when there's no next question
27885
27883
  justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
27886
27884
  };
27887
27885
  const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React__namespace.createElement("span", {
27888
- style: styles$k.text
27886
+ style: styles$j.text
27889
27887
  }, /*#__PURE__*/React__namespace.createElement("span", {
27890
- style: styles$k.tryAgainIcon
27888
+ style: styles$j.tryAgainIcon
27891
27889
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React__namespace.createElement("span", {
27892
27890
  style: {
27893
27891
  marginLeft: 8
@@ -27906,7 +27904,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
27906
27904
  return /*#__PURE__*/React__namespace.createElement("div", {
27907
27905
  style: answerBarStyle
27908
27906
  }, /*#__PURE__*/React__namespace.createElement("span", {
27909
- style: styles$k.text
27907
+ style: styles$j.text
27910
27908
  }, /*#__PURE__*/React__namespace.createElement("span", {
27911
27909
  style: {
27912
27910
  fontSize: 28,
@@ -27928,7 +27926,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
27928
27926
  }
27929
27927
  }
27930
27928
  const fontSize = 17;
27931
- const styles$k = {
27929
+ const styles$j = {
27932
27930
  answerBar: {
27933
27931
  display: "flex",
27934
27932
  alignItems: "center",
@@ -28121,7 +28119,7 @@ class GradedGroup extends React__namespace.Component {
28121
28119
  }));
28122
28120
  gradeStatus = this.context.strings.incorrect;
28123
28121
  }
28124
- const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$j.gradedGroupInSet) : aphrodite.css(styles$j.gradedGroup);
28122
+ const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$i.gradedGroupInSet) : aphrodite.css(styles$i.gradedGroup);
28125
28123
  const classes = classNames__default["default"]({
28126
28124
  [mobileClass]: apiOptions.isMobile,
28127
28125
  "perseus-graded-group": true,
@@ -28140,7 +28138,7 @@ class GradedGroup extends React__namespace.Component {
28140
28138
  return /*#__PURE__*/React__namespace.createElement("div", {
28141
28139
  className: classes
28142
28140
  }, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
28143
- className: aphrodite.css(styles$j.title)
28141
+ className: aphrodite.css(styles$i.title)
28144
28142
  }, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends({}, this.props, {
28145
28143
  ref: this.rendererRef,
28146
28144
  apiOptions: {
@@ -28173,7 +28171,7 @@ class GradedGroup extends React__namespace.Component {
28173
28171
  }, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
28174
28172
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
28175
28173
  tabIndex: "0",
28176
- className: aphrodite.css(styles$j.explanationTitle),
28174
+ className: aphrodite.css(styles$i.explanationTitle),
28177
28175
  onClick: () => this.setState({
28178
28176
  showHint: false
28179
28177
  }),
@@ -28205,7 +28203,7 @@ class GradedGroup extends React__namespace.Component {
28205
28203
  showHint: true
28206
28204
  });
28207
28205
  },
28208
- className: aphrodite.css(styles$j.showHintLink)
28206
+ className: aphrodite.css(styles$i.showHintLink)
28209
28207
  }, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React__namespace.createElement(GradedGroupAnswerBar, {
28210
28208
  apiOptions: apiOptions,
28211
28209
  answerBarState: answerBarState,
@@ -28217,7 +28215,7 @@ class GradedGroup extends React__namespace.Component {
28217
28215
  const traverseChildWidgets$2 = function (props, traverseRenderer) {
28218
28216
  return ___default["default"].extend({}, props, traverseRenderer(props));
28219
28217
  };
28220
- const styles$j = aphrodite.StyleSheet.create({
28218
+ const styles$i = aphrodite.StyleSheet.create({
28221
28219
  gradedGroupInSet: {
28222
28220
  // Reset a few desktop-only styles that come from graded-group.less
28223
28221
  marginLeft: 0,
@@ -28298,20 +28296,20 @@ class Indicators extends React__namespace.Component {
28298
28296
  return /*#__PURE__*/React__namespace.createElement("ul", {
28299
28297
  // reduntantly add class name for use in .less files--
28300
28298
  // the styles object key gets hashed
28301
- className: classNames__default["default"](aphrodite.css(styles$i.indicatorContainer), "indicatorContainer")
28299
+ className: classNames__default["default"](aphrodite.css(styles$h.indicatorContainer), "indicatorContainer")
28302
28300
  }, this.props.gradedGroups.map((_ref, i) => {
28303
28301
  let {
28304
28302
  title
28305
28303
  } = _ref;
28306
28304
  return /*#__PURE__*/React__namespace.createElement("li", {
28307
- className: aphrodite.css(styles$i.indicator),
28305
+ className: aphrodite.css(styles$h.indicator),
28308
28306
  key: title
28309
28307
  }, /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
28310
28308
  role: "button",
28311
28309
  "aria-label": this.context.strings.skipToTitle({
28312
28310
  title
28313
28311
  }),
28314
- style: styles$i.indicatorButton,
28312
+ style: styles$h.indicatorButton,
28315
28313
  onClick: () => this.props.onChangeCurrentGroup(i),
28316
28314
  onKeyDown: e => this.handleKeyDown(e, i)
28317
28315
  }, _ref2 => {
@@ -28321,9 +28319,9 @@ class Indicators extends React__namespace.Component {
28321
28319
  pressed
28322
28320
  } = _ref2;
28323
28321
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
28324
- style: [styles$i.indicatorDot, (hovered || focused || pressed) && styles$i.indicatorDotFocused]
28322
+ style: [styles$h.indicatorDot, (hovered || focused || pressed) && styles$h.indicatorDotFocused]
28325
28323
  }, i === this.props.currentGroup && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
28326
- style: styles$i.indicatorDotActive
28324
+ style: styles$h.indicatorDotActive
28327
28325
  }, /*#__PURE__*/React__namespace.createElement("span", {
28328
28326
  className: aphrodite.css(a11y.srOnly)
28329
28327
  }, this.context.strings.current)));
@@ -28403,7 +28401,7 @@ class GradedGroupSet extends React__namespace.Component {
28403
28401
  } = getDependencies();
28404
28402
  if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
28405
28403
  return /*#__PURE__*/React__namespace.createElement("div", {
28406
- className: aphrodite.css(styles$i.container)
28404
+ className: aphrodite.css(styles$h.container)
28407
28405
  }, this.props.gradedGroups.map((gradedGroup, i) => {
28408
28406
  return (
28409
28407
  /*#__PURE__*/
@@ -28426,13 +28424,13 @@ class GradedGroupSet extends React__namespace.Component {
28426
28424
  const numGroups = this.props.gradedGroups.length;
28427
28425
  const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
28428
28426
  return /*#__PURE__*/React__namespace.createElement("div", {
28429
- className: aphrodite.css(styles$i.container)
28427
+ className: aphrodite.css(styles$h.container)
28430
28428
  }, /*#__PURE__*/React__namespace.createElement("div", {
28431
- className: aphrodite.css(styles$i.top)
28429
+ className: aphrodite.css(styles$h.top)
28432
28430
  }, /*#__PURE__*/React__namespace.createElement("div", {
28433
- className: aphrodite.css(styles$i.title)
28431
+ className: aphrodite.css(styles$h.title)
28434
28432
  }, currentGroup.title), /*#__PURE__*/React__namespace.createElement("div", {
28435
- className: aphrodite.css(styles$i.spacer)
28433
+ className: aphrodite.css(styles$h.spacer)
28436
28434
  }), /*#__PURE__*/React__namespace.createElement(Indicators, {
28437
28435
  currentGroup: this.state.currentGroup,
28438
28436
  gradedGroups: this.props.gradedGroups,
@@ -28470,7 +28468,7 @@ var GradedGroupSet$1 = {
28470
28468
  tracking: "all",
28471
28469
  isLintable: true
28472
28470
  };
28473
- const styles$i = aphrodite.StyleSheet.create({
28471
+ const styles$h = aphrodite.StyleSheet.create({
28474
28472
  top: {
28475
28473
  display: "flex",
28476
28474
  flexDirection: "row"
@@ -28576,7 +28574,7 @@ class ButtonGroup extends React__namespace.Component {
28576
28574
  id: "" + i,
28577
28575
  ref: "button" + i,
28578
28576
  key: "" + i,
28579
- className: aphrodite.css(styles$h.buttonStyle, button.value === value && styles$h.selectedStyle),
28577
+ className: aphrodite.css(styles$g.buttonStyle, button.value === value && styles$g.selectedStyle),
28580
28578
  onClick: () => this.toggleSelect(button.value)
28581
28579
  }, button.content || "" + button.value);
28582
28580
  });
@@ -28589,7 +28587,7 @@ class ButtonGroup extends React__namespace.Component {
28589
28587
  }, buttons);
28590
28588
  }
28591
28589
  }
28592
- const styles$h = aphrodite.StyleSheet.create({
28590
+ const styles$g = aphrodite.StyleSheet.create({
28593
28591
  buttonStyle: {
28594
28592
  backgroundColor: "white",
28595
28593
  border: "1px solid #ccc",
@@ -31967,7 +31965,7 @@ const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
31967
31965
  width: "24",
31968
31966
  height: "24",
31969
31967
  viewBox: "0 0 24 24",
31970
- className: aphrodite.css(styles$g.icon)
31968
+ className: aphrodite.css(styles$f.icon)
31971
31969
  }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
31972
31970
  id: "a",
31973
31971
  d: "M7.401 10.035c-1.424.748-2.599 1.905-3.544 " + "3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 " + "12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 " + "1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-" + "3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 " + "0 0 0 0 6z"
@@ -31998,7 +31996,7 @@ const HiddenIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
31998
31996
  width: "24",
31999
31997
  height: "24",
32000
31998
  viewBox: "0 0 24 24",
32001
- className: aphrodite.css(styles$g.icon)
31999
+ className: aphrodite.css(styles$f.icon)
32002
32000
  }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
32003
32001
  id: "a",
32004
32002
  d: "M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 " + "7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 " + "1.028c-.945-1.574-2.12-2.73-3.544-3.48.258." + "604.401 1.268.401 1.966 0 1.02-.305 " + "1.967-.828 2.757l2.535 2.536a1 1 0 0 " + "1-1.414 1.414l-12-12a1 1 0 0 1 " + "1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 " + "0-4.001-4.001l4 4.001zM6.072 8.486l2.976 " + "2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 " + "0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 " + "3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 " + "2.363-3.085 3.929-4z"
@@ -32037,20 +32035,20 @@ const HUD = _ref => {
32037
32035
  let state;
32038
32036
  let icon;
32039
32037
  if (enabled) {
32040
- state = styles$g.enabled;
32038
+ state = styles$f.enabled;
32041
32039
  icon = /*#__PURE__*/React__namespace.createElement(VisibleIcon, null);
32042
32040
  } else {
32043
- state = styles$g.disabled;
32041
+ state = styles$f.disabled;
32044
32042
  icon = /*#__PURE__*/React__namespace.createElement(HiddenIcon, null);
32045
32043
  }
32046
32044
  return /*#__PURE__*/React__namespace.createElement("button", {
32047
- className: aphrodite.css(styles$g.hud, fixedPosition && styles$g.hudFixedPosition, state),
32045
+ className: aphrodite.css(styles$f.hud, fixedPosition && styles$f.hudFixedPosition, state),
32048
32046
  onClick: e => {
32049
32047
  onClick();
32050
32048
  }
32051
32049
  }, icon, message);
32052
32050
  };
32053
- const styles$g = aphrodite.StyleSheet.create({
32051
+ const styles$f = aphrodite.StyleSheet.create({
32054
32052
  hud: {
32055
32053
  boxSizing: "border-box",
32056
32054
  height: 36,
@@ -32103,16 +32101,16 @@ const styles$g = aphrodite.StyleSheet.create({
32103
32101
  const InfoTipBase = props => {
32104
32102
  return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
32105
32103
  content: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.Body, {
32106
- style: styles$f.body
32104
+ style: styles$e.body
32107
32105
  }, props.children),
32108
32106
  placement: "right"
32109
32107
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
32110
32108
  size: "small",
32111
32109
  icon: questionIcon__default["default"],
32112
- style: styles$f.spacingLeft
32110
+ style: styles$e.spacingLeft
32113
32111
  }));
32114
32112
  };
32115
- const styles$f = aphrodite.StyleSheet.create({
32113
+ const styles$e = aphrodite.StyleSheet.create({
32116
32114
  spacingLeft: {
32117
32115
  marginInlineStart: wonderBlocksTokens.spacing.xxxSmall_4
32118
32116
  },
@@ -32188,7 +32186,7 @@ class MultiButtonGroup extends React__namespace.Component {
32188
32186
  id: "" + i,
32189
32187
  key: "" + i,
32190
32188
  ref: "button" + i,
32191
- className: aphrodite.css(styles$e.buttonStyle, selected && styles$e.selectedStyle),
32189
+ className: aphrodite.css(styles$d.buttonStyle, selected && styles$d.selectedStyle),
32192
32190
  onClick: () => this.toggleSelect(button.value)
32193
32191
  }, button.content || "" + button.value);
32194
32192
  });
@@ -32201,7 +32199,7 @@ class MultiButtonGroup extends React__namespace.Component {
32201
32199
  }, buttons);
32202
32200
  }
32203
32201
  }
32204
- const styles$e = aphrodite.StyleSheet.create({
32202
+ const styles$d = aphrodite.StyleSheet.create({
32205
32203
  buttonStyle: {
32206
32204
  backgroundColor: "white",
32207
32205
  border: "1px solid #ccc",
@@ -32605,14 +32603,6 @@ const LegacyGrid = _ref => {
32605
32603
  * A "PerseusArticle" is an item that is meant to be rendered as an article.
32606
32604
  * This item is never scored and is rendered by the `ArticleRenderer`.
32607
32605
  */
32608
- /**
32609
- * A "MultiItem" is an advanced Perseus item. It is rendered by the
32610
- * `MultiRenderer` and you can control the layout of individual parts of the
32611
- * item.
32612
- *
32613
- * @deprecated MultiItem support is slated for removal in a future Perseus
32614
- * release.
32615
- */
32616
32606
  const ItemExtras = [
32617
32607
  // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
32618
32608
  "calculator",
@@ -39071,7 +39061,7 @@ const HideAnswersToggle = props => {
39071
39061
  strings
39072
39062
  } = usePerseusI18n();
39073
39063
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
39074
- style: styles$d.switchWrapper
39064
+ style: styles$c.switchWrapper
39075
39065
  }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
39076
39066
  id: switchId,
39077
39067
  checked: props.areAnswersHidden,
@@ -39083,7 +39073,7 @@ const HideAnswersToggle = props => {
39083
39073
  tag: "label"
39084
39074
  }, strings.hideAnswersToggleLabel));
39085
39075
  };
39086
- const styles$d = aphrodite.StyleSheet.create({
39076
+ const styles$c = aphrodite.StyleSheet.create({
39087
39077
  switchWrapper: {
39088
39078
  display: "flex",
39089
39079
  flexDirection: "row",
@@ -39141,7 +39131,7 @@ const AnswerPill = props => {
39141
39131
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
39142
39132
  onClick: correct ? undefined : onClick,
39143
39133
  ref: ref,
39144
- style: [style, popperStyle, styles$c.pill, correct && styles$c.correct, incorrect && styles$c.incorrect, (focused || hovered) && BringToFront]
39134
+ style: [style, popperStyle, styles$b.pill, correct && styles$b.correct, incorrect && styles$b.incorrect, (focused || hovered) && BringToFront]
39145
39135
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
39146
39136
  content: answerString,
39147
39137
  strings: strings,
@@ -39149,7 +39139,7 @@ const AnswerPill = props => {
39149
39139
  }));
39150
39140
  });
39151
39141
  };
39152
- const styles$c = aphrodite.StyleSheet.create({
39142
+ const styles$b = aphrodite.StyleSheet.create({
39153
39143
  correct: {
39154
39144
  // WB green darkened by 18%
39155
39145
  backgroundColor: "#00880b"
@@ -39215,25 +39205,25 @@ class Marker extends React__namespace.Component {
39215
39205
  icon: iconNull
39216
39206
  };
39217
39207
  if (showCorrectness) {
39218
- iconStyles = [styles$b.markerGraded, showCorrectness === "correct" ? styles$b.markerCorrect : styles$b.markerIncorrect, isOpen && styles$b.markerSelected];
39208
+ iconStyles = [styles$a.markerGraded, showCorrectness === "correct" ? styles$a.markerCorrect : styles$a.markerIncorrect, isOpen && styles$a.markerSelected];
39219
39209
  args = {
39220
39210
  ...args,
39221
39211
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
39222
39212
  };
39223
39213
  } else if (selectedAnswers && selectedAnswers.length > 0) {
39224
- iconStyles = [styles$b.markerFilled, isOpen && styles$b.markerSelected];
39214
+ iconStyles = [styles$a.markerFilled, isOpen && styles$a.markerSelected];
39225
39215
  } else if (isOpen) {
39226
- iconStyles = [styles$b.markerSelected];
39216
+ iconStyles = [styles$a.markerSelected];
39227
39217
  args = {
39228
39218
  ...args,
39229
39219
  icon: iconChevronDown,
39230
39220
  size: 8
39231
39221
  };
39232
39222
  } else if (showPulsate) {
39233
- iconStyles = [styles$b.markerPulsateBase, this._mounted && shouldReduceMotion() ? showPulsate && styles$b.markerUnfilledPulsateOnce : showPulsate && styles$b.markerUnfilledPulsateInfinite];
39223
+ iconStyles = [styles$a.markerPulsateBase, this._mounted && shouldReduceMotion() ? showPulsate && styles$a.markerUnfilledPulsateOnce : showPulsate && styles$a.markerUnfilledPulsateInfinite];
39234
39224
  }
39235
39225
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
39236
- style: [styles$b.markerIcon, iconStyles],
39226
+ style: [styles$a.markerIcon, iconStyles],
39237
39227
  ref: node => this._icon = node
39238
39228
  }, /*#__PURE__*/React__namespace.createElement(Icon, args));
39239
39229
  }
@@ -39254,7 +39244,7 @@ class Marker extends React__namespace.Component {
39254
39244
  const markerDisabled = showCorrectness === "correct";
39255
39245
  const active = hovered || focused;
39256
39246
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
39257
- style: [styles$b.marker, active && !markerDisabled && styles$b.markerActive],
39247
+ style: [styles$a.marker, active && !markerDisabled && styles$a.markerActive],
39258
39248
  "aria-label": markerDisabled ? this.context.strings.correctExcited : label
39259
39249
  }, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React__namespace.createElement(AnswerPill, {
39260
39250
  selectedAnswers: selected,
@@ -39267,7 +39257,7 @@ class Marker extends React__namespace.Component {
39267
39257
  }));
39268
39258
  }
39269
39259
  }
39270
- const styles$b = aphrodite.StyleSheet.create({
39260
+ const styles$a = aphrodite.StyleSheet.create({
39271
39261
  marker: {
39272
39262
  position: "absolute",
39273
39263
  backgroundColor: wonderBlocksTokens.color.white,
@@ -39861,13 +39851,13 @@ class LabelImage extends React__namespace.Component {
39861
39851
  const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
39862
39852
  const choicesString = strings.choices;
39863
39853
  return /*#__PURE__*/React__namespace.createElement("div", {
39864
- className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$a.instructions))
39854
+ className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$9.instructions))
39865
39855
  }, /*#__PURE__*/React__namespace.createElement("div", {
39866
- className: aphrodite.css(styles$a.instructionsCaption)
39856
+ className: aphrodite.css(styles$9.instructionsCaption)
39867
39857
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React__namespace.createElement("div", {
39868
- className: aphrodite.css(styles$a.instructionsChoices)
39858
+ className: aphrodite.css(styles$9.instructionsChoices)
39869
39859
  }, choices.map((choice, index) => /*#__PURE__*/React__namespace.createElement("div", {
39870
- className: aphrodite.css(styles$a.instructionsChoice),
39860
+ className: aphrodite.css(styles$9.instructionsChoice),
39871
39861
  key: index
39872
39862
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
39873
39863
  content: choice,
@@ -39885,20 +39875,20 @@ class LabelImage extends React__namespace.Component {
39885
39875
  activeMarkerIndex
39886
39876
  } = this.state;
39887
39877
  return /*#__PURE__*/React__namespace.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React__namespace.createElement("div", {
39888
- className: aphrodite.css(styles$a.markersCanvas),
39878
+ className: aphrodite.css(styles$9.markersCanvas),
39889
39879
  style: {
39890
39880
  maxWidth: imageWidth,
39891
39881
  maxHeight: imageHeight
39892
39882
  }
39893
39883
  }, /*#__PURE__*/React__namespace.createElement("div", {
39894
- className: aphrodite.css(styles$a.imageContainer,
39884
+ className: aphrodite.css(styles$9.imageContainer,
39895
39885
  // Ensure image interaction is disabled while answer
39896
39886
  // choices popup is visible. This addresses specific
39897
39887
  // case where user may click on question image to
39898
39888
  // dismiss the popup. If the image is larger in size
39899
39889
  // than its rendered in the widget, this would
39900
39890
  // result in a zoom of the image.
39901
- activeMarkerIndex !== -1 && styles$a.imageInteractionDisabled)
39891
+ activeMarkerIndex !== -1 && styles$9.imageInteractionDisabled)
39902
39892
  }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref3 => {
39903
39893
  let {
39904
39894
  setAssetStatus
@@ -39924,7 +39914,7 @@ class LabelImage extends React__namespace.Component {
39924
39914
  }));
39925
39915
  }
39926
39916
  }
39927
- const styles$a = aphrodite.StyleSheet.create({
39917
+ const styles$9 = aphrodite.StyleSheet.create({
39928
39918
  instructions: {
39929
39919
  paddingBottom: 16
39930
39920
  },
@@ -40012,7 +40002,7 @@ class Placeholder extends React__namespace.Component {
40012
40002
  const {
40013
40003
  layout
40014
40004
  } = this.props;
40015
- const className = aphrodite.css(styles$9.card, styles$9.placeholder, layout === "horizontal" && styles$9.horizontalCard);
40005
+ const className = aphrodite.css(styles$8.card, styles$8.placeholder, layout === "horizontal" && styles$8.horizontalCard);
40016
40006
  const style = {
40017
40007
  width: this.props.width,
40018
40008
  height: this.props.height
@@ -40219,7 +40209,7 @@ class Draggable extends React__namespace.Component {
40219
40209
  // We need to keep backwards compatbility with rules specified directly
40220
40210
  // in CSS. Hence the hacky tacking on of manual classNames.
40221
40211
  // See sortable.less for details.
40222
- let className = aphrodite.css(styles$9.card, styles$9.draggable, layout === "horizontal" && styles$9.horizontalCard, layout === "vertical" && styles$9.verticalCard, type === ItemState.DRAGGING && styles$9.dragging, type === ItemState.DISABLED && styles$9.disabled, !includePadding && styles$9.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
40212
+ let className = aphrodite.css(styles$8.card, styles$8.draggable, layout === "horizontal" && styles$8.horizontalCard, layout === "vertical" && styles$8.verticalCard, type === ItemState.DRAGGING && styles$8.dragging, type === ItemState.DISABLED && styles$8.disabled, !includePadding && styles$8.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
40223
40213
  if (!includePadding) {
40224
40214
  className += " perseus-sortable-draggable-unpadded";
40225
40215
  }
@@ -40557,7 +40547,7 @@ class Sortable extends React__namespace.Component {
40557
40547
  } = this.props;
40558
40548
  // We need to keep backwards compatbility with rules specified directly
40559
40549
  // in CSS. See sortable.less for details.
40560
- const className = aphrodite.css(styles$9.sortable) + " perseus-sortable";
40550
+ const className = aphrodite.css(styles$8.sortable) + " perseus-sortable";
40561
40551
  const syncWidth = this.props.constraints?.width || layout === "vertical";
40562
40552
  const syncHeight = this.props.constraints?.height || layout === "horizontal";
40563
40553
  ___default["default"].each(this.state.items, function (item, i, items) {
@@ -40643,7 +40633,7 @@ class Sortable extends React__namespace.Component {
40643
40633
  }, cards);
40644
40634
  }
40645
40635
  }
40646
- const styles$9 = aphrodite.StyleSheet.create({
40636
+ const styles$8 = aphrodite.StyleSheet.create({
40647
40637
  sortable: {
40648
40638
  boxSizing: "border-box",
40649
40639
  float: "left",
@@ -40839,25 +40829,25 @@ class Matcher extends React__namespace.Component {
40839
40829
  };
40840
40830
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
40841
40831
  return /*#__PURE__*/React__namespace.createElement("table", {
40842
- className: aphrodite.css(styles$8.widget) + " " + HACKY_CSS_CLASSNAME
40832
+ className: aphrodite.css(styles$7.widget) + " " + HACKY_CSS_CLASSNAME
40843
40833
  }, /*#__PURE__*/React__namespace.createElement("tbody", null, showLabels && /*#__PURE__*/React__namespace.createElement("tr", {
40844
- className: aphrodite.css(styles$8.row)
40834
+ className: aphrodite.css(styles$7.row)
40845
40835
  }, /*#__PURE__*/React__namespace.createElement("th", {
40846
- className: aphrodite.css(styles$8.column, styles$8.columnLabel)
40836
+ className: aphrodite.css(styles$7.column, styles$7.columnLabel)
40847
40837
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
40848
40838
  content: this.props.labels[0] || "...",
40849
40839
  linterContext: this.props.linterContext,
40850
40840
  strings: this.context.strings
40851
40841
  })), /*#__PURE__*/React__namespace.createElement("th", {
40852
- className: aphrodite.css(styles$8.column, styles$8.columnRight, styles$8.columnLabel)
40842
+ className: aphrodite.css(styles$7.column, styles$7.columnRight, styles$7.columnLabel)
40853
40843
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
40854
40844
  content: this.props.labels[1] || "...",
40855
40845
  linterContext: this.props.linterContext,
40856
40846
  strings: this.context.strings
40857
40847
  }))), /*#__PURE__*/React__namespace.createElement("tr", {
40858
- className: aphrodite.css(styles$8.row)
40848
+ className: aphrodite.css(styles$7.row)
40859
40849
  }, /*#__PURE__*/React__namespace.createElement("td", {
40860
- className: aphrodite.css(styles$8.column)
40850
+ className: aphrodite.css(styles$7.column)
40861
40851
  }, /*#__PURE__*/React__namespace.createElement(Sortable, {
40862
40852
  options: left,
40863
40853
  layout: "vertical",
@@ -40872,7 +40862,7 @@ class Matcher extends React__namespace.Component {
40872
40862
  ,
40873
40863
  ref: "left"
40874
40864
  })), /*#__PURE__*/React__namespace.createElement("td", {
40875
- className: aphrodite.css(styles$8.column, styles$8.columnRight)
40865
+ className: aphrodite.css(styles$7.column, styles$7.columnRight)
40876
40866
  }, /*#__PURE__*/React__namespace.createElement(Sortable, {
40877
40867
  options: right,
40878
40868
  layout: "vertical",
@@ -40890,7 +40880,7 @@ class Matcher extends React__namespace.Component {
40890
40880
  }
40891
40881
  const padding = 5;
40892
40882
  const border = "1px solid #444";
40893
- const styles$8 = aphrodite.StyleSheet.create({
40883
+ const styles$7 = aphrodite.StyleSheet.create({
40894
40884
  widget: {
40895
40885
  paddingTop: padding,
40896
40886
  maxWidth: "100%",
@@ -41581,9 +41571,9 @@ function drawText(ctx, item) {
41581
41571
  if (item.value === null) {
41582
41572
  return;
41583
41573
  }
41584
- ctx.fillStyle = styles$7.fgColor;
41585
- ctx.font = styles$7.font;
41586
- ctx.fillText(item.value, item.pos[0] - styles$7.fontSizePx / 2 + 1, item.pos[1] + styles$7.fontSizePx / 2);
41574
+ ctx.fillStyle = styles$6.fgColor;
41575
+ ctx.font = styles$6.font;
41576
+ ctx.fillText(item.value, item.pos[0] - styles$6.fontSizePx / 2 + 1, item.pos[1] + styles$6.fontSizePx / 2);
41587
41577
  }
41588
41578
 
41589
41579
  /**
@@ -41604,16 +41594,16 @@ function drawText(ctx, item) {
41604
41594
  function drawDoubleLine(ctx, item) {
41605
41595
  // Outer line that forms both of the bond lines.
41606
41596
  let path = new Path2D();
41607
- ctx.lineWidth = 5 * styles$7.lineWidth;
41608
- ctx.strokeStyle = styles$7.fgColor;
41597
+ ctx.lineWidth = 5 * styles$6.lineWidth;
41598
+ ctx.strokeStyle = styles$6.fgColor;
41609
41599
  path.moveTo(item.startPos[0], item.startPos[1]);
41610
41600
  path.lineTo(item.endPos[0], item.endPos[1]);
41611
41601
  ctx.stroke(path);
41612
41602
 
41613
41603
  // Inner white line that separates the two bond lines.
41614
41604
  path = new Path2D();
41615
- ctx.lineWidth = 3 * styles$7.lineWidth;
41616
- ctx.strokeStyle = styles$7.bgColor;
41605
+ ctx.lineWidth = 3 * styles$6.lineWidth;
41606
+ ctx.strokeStyle = styles$6.bgColor;
41617
41607
  path.moveTo(item.startPos[0], item.startPos[1]);
41618
41608
  path.lineTo(item.endPos[0], item.endPos[1]);
41619
41609
  ctx.stroke(path);
@@ -41640,16 +41630,16 @@ function drawTripleLine(ctx, item) {
41640
41630
 
41641
41631
  // Outer line that will form the two outer bond lines.
41642
41632
  let path = new Path2D();
41643
- ctx.lineWidth = 7 * styles$7.lineWidth;
41644
- ctx.strokeStyle = styles$7.fgColor;
41633
+ ctx.lineWidth = 7 * styles$6.lineWidth;
41634
+ ctx.strokeStyle = styles$6.fgColor;
41645
41635
  path.moveTo(item.startPos[0], item.startPos[1]);
41646
41636
  path.lineTo(item.endPos[0], item.endPos[1]);
41647
41637
  ctx.stroke(path);
41648
41638
 
41649
41639
  // Middle white line that separates the bonds
41650
41640
  path = new Path2D();
41651
- ctx.lineWidth = 5 * styles$7.lineWidth;
41652
- ctx.strokeStyle = styles$7.bgColor;
41641
+ ctx.lineWidth = 5 * styles$6.lineWidth;
41642
+ ctx.strokeStyle = styles$6.bgColor;
41653
41643
  path.moveTo(item.startPos[0], item.startPos[1]);
41654
41644
  path.lineTo(item.endPos[0], item.endPos[1]);
41655
41645
  ctx.stroke(path);
@@ -41671,8 +41661,8 @@ function drawTripleLine(ctx, item) {
41671
41661
  */
41672
41662
  function drawLine(ctx, item) {
41673
41663
  const path = new Path2D();
41674
- ctx.lineWidth = styles$7.lineWidth;
41675
- ctx.strokeStyle = styles$7.fgColor;
41664
+ ctx.lineWidth = styles$6.lineWidth;
41665
+ ctx.strokeStyle = styles$6.fgColor;
41676
41666
  path.moveTo(item.startPos[0], item.startPos[1]);
41677
41667
  path.lineTo(item.endPos[0], item.endPos[1]);
41678
41668
  ctx.stroke(path);
@@ -41724,7 +41714,7 @@ function compareElements(item0, item1) {
41724
41714
  function draw(ctx, items) {
41725
41715
  items.sort(compareElements).forEach(drawItem(ctx));
41726
41716
  }
41727
- const styles$7 = {
41717
+ const styles$6 = {
41728
41718
  bgColor: "rgb(255, 255, 255)",
41729
41719
  fgColor: "rgb(0, 0, 0)",
41730
41720
  fontSizePx: 12,
@@ -43851,7 +43841,7 @@ class PhetSimulation extends React__namespace.Component {
43851
43841
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43852
43842
  const sandboxProperties = "allow-same-origin allow-scripts";
43853
43843
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
43854
- style: styles$6.widgetContainer
43844
+ style: styles$5.widgetContainer
43855
43845
  }, this.state.banner !== null &&
43856
43846
  /*#__PURE__*/
43857
43847
  // TODO(anna): Make this banner focusable
@@ -43864,12 +43854,12 @@ class PhetSimulation extends React__namespace.Component {
43864
43854
  kind: this.state.banner.kind,
43865
43855
  text: this.state.banner.message
43866
43856
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
43867
- style: styles$6.iframeContainer
43857
+ style: styles$5.iframeContainer
43868
43858
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
43869
43859
  ref: this.iframeRef,
43870
43860
  title: this.props.description,
43871
43861
  sandbox: sandboxProperties,
43872
- className: aphrodite.css(styles$6.iframeResponsive),
43862
+ className: aphrodite.css(styles$5.iframeResponsive),
43873
43863
  src: this.state.url?.toString(),
43874
43864
  allow: "fullscreen"
43875
43865
  })), this.state.url !== null && /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
@@ -43900,7 +43890,7 @@ const makeSafeUrl = (urlString, locale) => {
43900
43890
  url.searchParams.set("locale", locale);
43901
43891
  return url;
43902
43892
  };
43903
- const styles$6 = aphrodite.StyleSheet.create({
43893
+ const styles$5 = aphrodite.StyleSheet.create({
43904
43894
  widgetContainer: {
43905
43895
  borderRadius: 6,
43906
43896
  borderWidth: 1,
@@ -44823,7 +44813,7 @@ class PythonProgram extends React__namespace.Component {
44823
44813
  // creator "went wild".
44824
44814
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
44825
44815
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
44826
- style: styles$5.container
44816
+ style: styles$4.container
44827
44817
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
44828
44818
  sandbox: sandboxOptions,
44829
44819
  src: url,
@@ -44832,7 +44822,7 @@ class PythonProgram extends React__namespace.Component {
44832
44822
  }));
44833
44823
  }
44834
44824
  }
44835
- const styles$5 = aphrodite.StyleSheet.create({
44825
+ const styles$4 = aphrodite.StyleSheet.create({
44836
44826
  container: {
44837
44827
  margin: "auto",
44838
44828
  width: "100%"
@@ -45318,7 +45308,7 @@ const VideoTranscriptLink = props => {
45318
45308
  {
45319
45309
  const video = result.data?.video;
45320
45310
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
45321
- style: styles$4.transcriptLink
45311
+ style: styles$3.transcriptLink
45322
45312
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.Text, null, video?.title), /*#__PURE__*/React__namespace.createElement(wonderBlocksLayout.Strut, {
45323
45313
  size: 10
45324
45314
  }), /*#__PURE__*/React__namespace.createElement(Link__default["default"], {
@@ -45335,7 +45325,7 @@ const VideoTranscriptLink = props => {
45335
45325
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, strings.somethingWrong);
45336
45326
  }
45337
45327
  };
45338
- const styles$4 = aphrodite.StyleSheet.create({
45328
+ const styles$3 = aphrodite.StyleSheet.create({
45339
45329
  transcriptLink: {
45340
45330
  flexDirection: "row",
45341
45331
  width: "100%",
@@ -45456,7 +45446,7 @@ const init = function () {
45456
45446
 
45457
45447
  // This file is processed by a Rollup plugin (replace) to inject the production
45458
45448
  const libName = "@khanacademy/perseus";
45459
- const libVersion = "46.0.0";
45449
+ const libVersion = "47.0.0";
45460
45450
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45461
45451
 
45462
45452
  const apiVersion = {
@@ -45673,7 +45663,7 @@ class HintRenderer extends React__namespace.Component {
45673
45663
  const {
45674
45664
  isMobile
45675
45665
  } = apiOptions;
45676
- const classNames = classNames__default["default"]("hint", !isMobile && "perseus-hint-renderer", isMobile && aphrodite.css(styles$3.newHint), isMobile && lastRendered && aphrodite.css(styles$3.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
45666
+ const classNames = classNames__default["default"]("hint", !isMobile && "perseus-hint-renderer", isMobile && aphrodite.css(styles$2.newHint), isMobile && lastRendered && aphrodite.css(styles$2.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
45677
45667
 
45678
45668
  // TODO(charlie): Allowing `customKeypad` would require that we
45679
45669
  // extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
@@ -45715,7 +45705,7 @@ class HintRenderer extends React__namespace.Component {
45715
45705
  );
45716
45706
  }
45717
45707
  }
45718
- const styles$3 = aphrodite.StyleSheet.create({
45708
+ const styles$2 = aphrodite.StyleSheet.create({
45719
45709
  newHint: {
45720
45710
  marginBottom: 1.5 * baseUnitPx,
45721
45711
  borderLeftColor: gray97,
@@ -45892,14 +45882,14 @@ class HintsRenderer extends React__namespace.Component {
45892
45882
  } = apiOptions;
45893
45883
  const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
45894
45884
  const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
45895
- const classNames = classNames__default["default"](this.props.className, apiOptions.isMobile && hintsVisible > 0 && aphrodite.css(styles$2.mobileHintStylesHintsRenderer));
45885
+ const classNames = classNames__default["default"](this.props.className, apiOptions.isMobile && hintsVisible > 0 && aphrodite.css(styles$1.mobileHintStylesHintsRenderer));
45896
45886
  return /*#__PURE__*/React__namespace.createElement("div", {
45897
45887
  className: classNames
45898
45888
  }, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React__namespace.createElement("div", {
45899
- className: aphrodite.css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
45889
+ className: aphrodite.css(styles$1.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
45900
45890
  }, this.context.strings.hints), hints, showGetAnotherHint && /*#__PURE__*/React__namespace.createElement("button", {
45901
45891
  rel: "button",
45902
- className: aphrodite.css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
45892
+ className: aphrodite.css(styles$1.linkButton, styles$1.getAnotherHintButton, apiOptions.isMobile && styles$1.mobileHintStylesGetAnotherHintButton),
45903
45893
  onClick: evt => {
45904
45894
  evt.preventDefault();
45905
45895
  evt.stopPropagation();
@@ -45908,14 +45898,14 @@ class HintsRenderer extends React__namespace.Component {
45908
45898
  }
45909
45899
  }
45910
45900
  }, /*#__PURE__*/React__namespace.createElement("span", {
45911
- className: aphrodite.css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
45901
+ className: aphrodite.css(styles$1.plusText, apiOptions.isMobile && styles$1.mobileHintStylesPlusText)
45912
45902
  }, "+"), /*#__PURE__*/React__namespace.createElement("span", {
45913
- className: aphrodite.css(styles$2.getAnotherHintText)
45903
+ className: aphrodite.css(styles$1.getAnotherHintText)
45914
45904
  }, this.context.strings.getAnotherHint, " ", hintRatioCopy)));
45915
45905
  }
45916
45906
  }
45917
45907
  const hintIndentation = baseUnitPx + hintBorderWidth;
45918
- const styles$2 = aphrodite.StyleSheet.create({
45908
+ const styles$1 = aphrodite.StyleSheet.create({
45919
45909
  // eslint-disable-next-line react-native/no-unused-styles
45920
45910
  rendererMargins: {
45921
45911
  marginTop: baseUnitPx
@@ -46335,11 +46325,11 @@ class ServerItemRenderer extends React__namespace.Component {
46335
46325
  // mobile hint styles, which are flush to the left.
46336
46326
  // NOTE(charlie): We may still want to apply this
46337
46327
  // padding for desktop exercises.
46338
- apiOptions.isMobile ? undefined : aphrodite.css(styles$1.hintsContainer)
46328
+ apiOptions.isMobile ? undefined : aphrodite.css(styles.hintsContainer)
46339
46329
  }, hintsRenderer)));
46340
46330
  }
46341
46331
  }
46342
- const styles$1 = aphrodite.StyleSheet.create({
46332
+ const styles = aphrodite.StyleSheet.create({
46343
46333
  hintsContainer: {
46344
46334
  marginLeft: 50
46345
46335
  }
@@ -46446,1148 +46436,6 @@ const traverse = function (rendererOptions, contentCallback, widgetCallback, opt
46446
46436
  return traverseRenderer$1(rendererOptions, contentCallback, deepCallbackFor(contentCallback, widgetCallback, optionsCallback), optionsCallback);
46447
46437
  };
46448
46438
 
46449
- /**
46450
- * Utility functions for constructing and inferring multi-item shapes.
46451
- *
46452
- * A shape is an object that serves as a runtime type declaration: it specifies
46453
- * a tree structure for a particular class of multi-item. See shape-types.js
46454
- * for further discussion.
46455
- *
46456
- * This module allows you to construct arbitrary Shape trees, by combining
46457
- * leaf node shapes like `content` and `hint` into composite shapes like
46458
- * `arrayOf(shape({foo: content, bar: hint}))`.
46459
- */
46460
-
46461
- /**
46462
- * These tools allow you to construct arbirtary shapes, by combining simple
46463
- * leaf shapes like `content` and `hint` into composite shapes like
46464
- * `arrayOf(shape({question: content, hints: arrayOf(hint)}))`.
46465
- */
46466
- const contentShape = {
46467
- type: "content"
46468
- };
46469
- const hintShape = {
46470
- type: "hint"
46471
- };
46472
- const tagsShape = {
46473
- type: "tags"
46474
- };
46475
- const buildArrayShape = elementShape => ({
46476
- type: "array",
46477
- elementShape
46478
- });
46479
- const buildObjectShape = shape => ({
46480
- type: "object",
46481
- shape
46482
- });
46483
- const hintsShape = buildArrayShape(hintShape);
46484
- var shapes = {
46485
- content: contentShape,
46486
- hint: hintShape,
46487
- hints: hintsShape,
46488
- tags: tagsShape,
46489
- arrayOf: buildArrayShape,
46490
- shape: buildObjectShape
46491
- };
46492
-
46493
- /**
46494
- * Utility functions for manipulating multi-item-shaped trees.
46495
- *
46496
- * Multi-items are trees! But we also often have other trees that are shaped
46497
- * like multi-items - for example, if we map a multi-item tree into a tree of
46498
- * renderer info and state, and then map that again into a tree of just the
46499
- * renderer nodes, like we do in MultiRenderer. See tree-types.js for further
46500
- * discussion.
46501
- *
46502
- * These functions enable us to manipulate generic multi-item-shaped trees,
46503
- * regardless of what type of data they contain at their leaves. You can use
46504
- * the mapper functions to transform a tree into another tree of the same
46505
- * shape, or to discover all the nodes of a particular type.
46506
- *
46507
- * We expose two simple mapper functions (mapContentNodes and mapHintNodes),
46508
- * and also a more complex interface for creating a mapping over all of a
46509
- * tree's node types simultaneously:
46510
- *
46511
- * `buildMapper()` returns a TreeMapper object that allows you to build your
46512
- * mapper object one node type at a time. Then, you can execute your mapping by
46513
- * calling the `mapTree` method.
46514
- *
46515
- * For example:
46516
- * const renderers = buildMapper()
46517
- * .setContentMapper(this.renderContentNode)
46518
- * .setHintMapper(this.renderHintNode)
46519
- * .setTagsMapper(this.renderTagsNode)
46520
- * .setArrayMapper(this.hideSkippedQuestions)
46521
- * .mapTree(tree, shape);
46522
- *
46523
- * This will copy the given tree, apply the given transformations to the
46524
- * content, hint, and array nodes respectively, and return the resulting tree.
46525
- *
46526
- * For node types whose mappers aren't specified, we default to the identity
46527
- * function. (This builder interface enables us to implement that default
46528
- * behavior in a provably type-safe way, while not requiring the call site to
46529
- * be aware of all the node types. Hooray!)
46530
- *
46531
- * The call to `setArrayMapper` must come last, because the array mapper's
46532
- * argument types depend on the other mappers' types. See ArrayMapper for more
46533
- * details.
46534
- *
46535
- * WARNING: These functions trust that the provided tree conforms to the
46536
- * provided shape. If not, behavior is undefined and may not respect the type
46537
- * signatures specified here.
46538
- */
46539
-
46540
- /**
46541
- * The sequence of edges that lead to a particular node in a Tree.
46542
- * Elements can be `string` to correspond to an ObjectNode key, or `number` to
46543
- * correspond to an ArrayNode index.
46544
- */
46545
-
46546
- /**
46547
- * These are function interfaces for mapping over various types of tree nodes.
46548
- *
46549
- * ArrayMapper is a bit more complicated than the leaf node mappers. It's
46550
- * executed in the context of a `mapTree` call, after we've finished mapping
46551
- * its child nodes, so the function has access to both the resulting array
46552
- * (with mapped elements) and the original array (with the original untouched
46553
- * elements).
46554
- *
46555
- * The ArrayMapper then has the opportunity to apply a final transformation to
46556
- * the resulting array, like filtering certain elements or (in the hacky
46557
- * MultiRenderer case) attaching a `renderHints` method to arrays of hint
46558
- * renderers :)
46559
- *
46560
- * This is why `TreeMapper#setArrayMapper` must be called last: ArrayMapper's
46561
- * types depend on the ContentMapper and HintMapper's types. And, since you can
46562
- * only specify one mapper at a time in this builder interface (which is
46563
- * necessary to provide default mappers in a type-safe way), you need your
46564
- * dependencies to already be in place by the time you call `setArrayMapper`.
46565
- * Otherwise, we'd have to set the ArrayMapper and *hope* that you *eventually*
46566
- * provide a compatible ContentMapper and HintMapper, which is difficult to
46567
- * prove at compile time.
46568
- *
46569
- * There's no ObjectMapper here, but not for any particular reason. We just
46570
- * don't have a use case for it yet, so we haven't built it yet.
46571
- */
46572
-
46573
- /**
46574
- * A TreeMapper is a collection of node mappers, which, together, compose the
46575
- * behavior for mapping over an entire tree.
46576
- *
46577
- * This serves as the interface for the two TreeMapper classes, including both
46578
- * the internal mapper properties that we care about, and the `mapTree`
46579
- * function that the call site will use.
46580
- */
46581
-
46582
- /**
46583
- * This is a TreeMapper that only has mappers specified for its leaf nodes; its
46584
- * array mapper is the identity function.
46585
- *
46586
- * This is the TreeMapper initially returned by `buildMapper`. It allows you to
46587
- * change the types of your ContentMapper and HintMapper, which is safe because
46588
- * none of the other mappers that depend on those types (aka ArrayMapper) have
46589
- * been specified yet. (Or, more specifically, the ArrayMapper is currently
46590
- * `identity`, which can trivially vary with the ContentMapper and HintMapper's
46591
- * types.)
46592
- *
46593
- * Once you call `setArrayMapper`, however, we move to the other class:
46594
- * TreeMapperForLeavesAndCollections.
46595
- */
46596
- class TreeMapperJustForLeaves {
46597
- content;
46598
- hint;
46599
- tags;
46600
- array;
46601
- constructor(content, hint, tags) {
46602
- this.content = content;
46603
- this.hint = hint;
46604
- this.tags = tags;
46605
- this.array = identity;
46606
- }
46607
- setContentMapper(newContentMapper) {
46608
- return new TreeMapperJustForLeaves(newContentMapper, this.hint, this.tags);
46609
- }
46610
- setHintMapper(newHintMapper) {
46611
- return new TreeMapperJustForLeaves(this.content, newHintMapper, this.tags);
46612
- }
46613
- setTagsMapper(newTagsMapper) {
46614
- return new TreeMapperJustForLeaves(this.content, this.hint, newTagsMapper);
46615
- }
46616
- setArrayMapper(newArrayMapper) {
46617
- return new TreeMapperForLeavesAndCollections(this.content, this.hint, this.tags, newArrayMapper);
46618
- }
46619
-
46620
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic. | TS2315 - Type 'Tree' is not generic.
46621
- mapTree(tree, shape) {
46622
- return mapTree(tree, shape, [], this);
46623
- }
46624
- }
46625
-
46626
- /**
46627
- * This is a TreeMapper that already has an ArrayMapper specified, so its
46628
- * ContentMapper and HintMapper are now locked in.
46629
- */
46630
- class TreeMapperForLeavesAndCollections {
46631
- content;
46632
- hint;
46633
- tags;
46634
- array;
46635
- constructor(content, hint, tags, array) {
46636
- this.content = content;
46637
- this.hint = hint;
46638
- this.tags = tags;
46639
- this.array = array;
46640
- }
46641
- setArrayMapper(newArrayMapper) {
46642
- return new TreeMapperForLeavesAndCollections(this.content, this.hint, this.tags, newArrayMapper);
46643
- }
46644
-
46645
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic. | TS2315 - Type 'Tree' is not generic.
46646
- mapTree(tree, shape) {
46647
- return mapTree(tree, shape, [], this);
46648
- }
46649
- }
46650
- function identity(x) {
46651
- return x;
46652
- }
46653
-
46654
- /**
46655
- * Return a new TreeMapper that will perform a no-op transformation on an input
46656
- * tree. To make it useful, chain any combination of `setContentMapper`,
46657
- * `setHintMapper`, `setTagMapper`, and `setArrayMapper` to specify
46658
- * transformations for the individual node types.
46659
- */
46660
- // @ts-expect-error - TS2300 - Duplicate identifier 'C'. | TS2300 - Duplicate identifier 'H'. | TS2300 - Duplicate identifier 'T'.
46661
- function buildMapper() {
46662
- return new TreeMapperJustForLeaves(identity, identity, identity);
46663
- }
46664
-
46665
- /**
46666
- * Copy the given tree, apply the corresponding transformation specified in the
46667
- * TreeMapper to each node, and return the resulting tree.
46668
- */
46669
- function mapTree(
46670
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46671
- tree, shape, path, mappers
46672
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46673
- ) {
46674
- // We trust the shape of the multi-item to match the shape provided at
46675
- // runtime. Therefore, in each shape branch, we cast the node to `any` and
46676
- // reinterpret it as the expected node type.
46677
- if (shape.type === "content") {
46678
- const content = tree;
46679
- return mappers.content(content, shape, path);
46680
- }
46681
- if (shape.type === "hint") {
46682
- const hint = tree;
46683
- return mappers.hint(hint, shape, path);
46684
- }
46685
- if (shape.type === "tags") {
46686
- const tags = tree;
46687
- return mappers.tags(tags, shape, path);
46688
- }
46689
- if (shape.type === "array") {
46690
- // @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
46691
- const array = tree;
46692
- if (!Array.isArray(array)) {
46693
- throw new perseusCore.PerseusError(`Invalid object of type "${typeof array}" found at path ` +
46694
- // @ts-expect-error - TS2769 - No overload matches this call.
46695
- `${["<root>"].concat(path).join(".")}. Expected array.`, perseusCore.Errors.Internal);
46696
- }
46697
- const elementShape = shape.elementShape;
46698
- // @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
46699
- const mappedElements = array.map((inner, i) => mapTree(inner, elementShape, path.concat(i), mappers));
46700
- return mappers.array(mappedElements, array, shape, path);
46701
- }
46702
- if (shape.type === "object") {
46703
- const object = tree;
46704
- if (object && typeof object !== "object") {
46705
- throw new perseusCore.PerseusError(`Invalid object of type "${typeof object}" found at ` +
46706
- // @ts-expect-error - TS2769 - No overload matches this call.
46707
- `path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, perseusCore.Errors.InvalidInput);
46708
- }
46709
- const valueShapes = shape.shape;
46710
- if (!valueShapes) {
46711
- throw new perseusCore.PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
46712
- // @ts-expect-error - TS2769 - No overload matches this call.
46713
- `${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
46714
- }
46715
- const newObject = {};
46716
- Object.keys(valueShapes).forEach(key => {
46717
- if (!(key in object)) {
46718
- throw new perseusCore.PerseusError(`Key "${key}" is missing from shape at path ` +
46719
- // @ts-expect-error - TS2769 - No overload matches this call.
46720
- `${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
46721
- }
46722
- newObject[key] = mapTree(object[key], valueShapes[key], path.concat(key), mappers);
46723
- });
46724
- return newObject;
46725
- }
46726
- throw new perseusCore.PerseusError(
46727
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
46728
- `unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
46729
- }
46730
-
46731
- /**
46732
- * Utility functions for constructing and manipulating multi-items.
46733
- *
46734
- * These functions apply *specifically* to Items and ItemTrees - things that
46735
- * actually semantically *are* multi-items. For more general functions for
46736
- * traversing and manipulating *anything* shaped like a multi-item (like a
46737
- * renderer tree or a score tree or, well, a multi-item), see trees.js.
46738
- */
46739
- /**
46740
- * Return a semantically empty ItemTree that conforms to the given shape.
46741
- *
46742
- * - An empty content node has an empty content string and no widgets/images.
46743
- * - An empty hint node has an empty content string and no widgets/images.
46744
- * - An empty array node has no elements.
46745
- * - An empty object node has a semantically empty node for each of its keys.
46746
- * (That is, we recursively call buildEmptyItemTreeForShape for each key.)
46747
- */
46748
- function buildEmptyItemTreeForShape(shape) {
46749
- if (shape.type === "content") {
46750
- return {
46751
- __type: "content",
46752
- content: "",
46753
- images: {},
46754
- widgets: {}
46755
- };
46756
- }
46757
- if (shape.type === "hint") {
46758
- return {
46759
- __type: "hint",
46760
- replace: false,
46761
- content: "",
46762
- images: {},
46763
- widgets: {}
46764
- };
46765
- }
46766
- if (shape.type === "tags") {
46767
- return [];
46768
- }
46769
- if (shape.type === "array") {
46770
- return [];
46771
- }
46772
- if (shape.type === "object") {
46773
- const valueShapes = shape.shape;
46774
- const object = {};
46775
- Object.keys(valueShapes).forEach(key => {
46776
- object[key] = buildEmptyItemTreeForShape(valueShapes[key]);
46777
- });
46778
- return object;
46779
- }
46780
- throw new perseusCore.PerseusError(
46781
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
46782
- `unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
46783
- }
46784
-
46785
- /**
46786
- * Return a semantically empty Item that conforms to the given shape.
46787
- *
46788
- * - An empty content node has an empty content string and no widgets/images.
46789
- * - An empty hint node has an empty content string and no widgets/images.
46790
- * - An empty array node has no elements.
46791
- * - An empty object node has a semantically empty node for each of its keys.
46792
- * (That is, we recursively call buildEmptyItemTreeForShape for each key.)
46793
- */
46794
- function buildEmptyItemForShape(shape) {
46795
- return treeToItem(buildEmptyItemTreeForShape(shape));
46796
- }
46797
-
46798
- /**
46799
- * Given an Item and its Shape, yield all of its content nodes to the callback.
46800
- */
46801
- function findContentNodesInItem$2(item, shape, callback) {
46802
- const itemTree = itemToTree(item);
46803
- buildMapper().setContentMapper(callback).mapTree(itemTree, shape);
46804
- }
46805
-
46806
- /**
46807
- * Given an Item and its Shape, yield all of its hint nodes to the callback.
46808
- */
46809
- function findHintNodesInItem(item, shape, callback) {
46810
- const itemTree = itemToTree(item);
46811
- buildMapper().setHintMapper(callback).mapTree(itemTree, shape);
46812
- }
46813
-
46814
- /**
46815
- * Given an ItemTree, return a Shape that it conforms to.
46816
- *
46817
- * The Shape might not be complete or correct Shape that this Item was designed
46818
- * for. If you have access to the intended Shape, use that instead.
46819
- */
46820
- function inferItemShape$2(item) {
46821
- const itemTree = itemToTree(item);
46822
- return inferItemTreeShape(itemTree);
46823
- }
46824
- function inferItemTreeShape(node) {
46825
- if (Array.isArray(node)) {
46826
- if (node.length) {
46827
- if (typeof node[0] === "string") {
46828
- // There's no ItemTree that can manifest as a string.
46829
- // So, an array of strings must be a TagsNode, not ArrayNode.
46830
- return shapes.tags;
46831
- }
46832
- // Otherwise, assume that this is a valid ArrayNode, and
46833
- // therefore the shape of the first element applies to all
46834
- // elements in the array.
46835
- return shapes.arrayOf(inferItemTreeShape(node[0]));
46836
- }
46837
- // The array is empty, so we arbitrarily guess that it's a content
46838
- // array. As discussed in the docstring, this might be incorrect,
46839
- // and you shouldn't depend on it.
46840
- return shapes.arrayOf(shapes.content);
46841
- }
46842
- if (
46843
- // TODO(mdr): Remove #LegacyContentNode support.
46844
- typeof node === "object" && (node.__type === "content" || node.__type === "item")) {
46845
- return shapes.content;
46846
- }
46847
- if (typeof node === "object" && node.__type === "hint") {
46848
- return shapes.hint;
46849
- }
46850
- if (typeof node === "object") {
46851
- const valueShapes = {};
46852
- Object.keys(node).forEach(key => {
46853
- valueShapes[key] = inferItemTreeShape(node[key]);
46854
- });
46855
- return shapes.shape(valueShapes);
46856
- }
46857
- throw new perseusCore.PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, perseusCore.Errors.InvalidInput);
46858
- }
46859
-
46860
- /**
46861
- * Convert the given Item to an ItemTree, by unwrapping the `_multi` key.
46862
- */
46863
- function itemToTree(item) {
46864
- return item._multi;
46865
- }
46866
-
46867
- /**
46868
- * Convert the given ItemTree to an Item, by wrapping it in the `_multi` key.
46869
- */
46870
- function treeToItem(node) {
46871
- return {
46872
- _multi: node
46873
- };
46874
- }
46875
-
46876
- var isObject$1 = function (obj) {
46877
- return obj === Object(obj);
46878
- };
46879
- var merge = function () {
46880
- var obj = {};
46881
- for (var i = 0; i < arguments.length; i++) {
46882
- var source = arguments[i];
46883
- if (source) {
46884
- for (var prop in source) {
46885
- obj[prop] = source[prop];
46886
- }
46887
- }
46888
- }
46889
- return obj;
46890
- };
46891
- var clone = function (obj) {
46892
- if (!isObject$1(obj)) {
46893
- return obj;
46894
- }
46895
- return Array.isArray(obj) ? obj.slice() : merge(obj);
46896
- };
46897
-
46898
- /* TODO batch *all* mutations
46899
- * idea: freeze / thaw implementations for all types
46900
- * lens constructor thaws, freeze delegates to type's freeze
46901
- */
46902
-
46903
- // equivalents, without requiring it
46904
- // find the implementation to use for a given object
46905
- var dispatch = function (x) {
46906
- if (Array.isArray(x)) {
46907
- return arr;
46908
- } else if (isObject$1(x)) {
46909
- return obj;
46910
- } else if (typeof x === "string") {
46911
- return str;
46912
- }
46913
- };
46914
-
46915
- // This is underscore with a different name
46916
- var lens = function (obj) {
46917
- if (obj instanceof lens) {
46918
- return obj;
46919
- }
46920
- if (!(this instanceof lens)) {
46921
- return new lens(obj);
46922
- }
46923
- var ops = dispatch(obj);
46924
- this._wrapped = ops.thaw ? ops.thaw(obj) : obj;
46925
- };
46926
- lens.prototype.freeze = function () {
46927
- var obj = this._wrapped;
46928
- var ops = dispatch(obj);
46929
- return ops.freeze ? ops.freeze(obj) : obj;
46930
- };
46931
- lens.prototype.zoom = function (lensArr) {
46932
- if (this._zoomStack === undefined) {
46933
- this._zoomStack = [];
46934
- }
46935
- this._zoomStack.push({
46936
- zoom: lensArr,
46937
- wrapped: this._wrapped
46938
- });
46939
- this._wrapped = lens(this._wrapped).get(lensArr);
46940
- return this;
46941
- };
46942
- lens.prototype.deZoom = function () {
46943
- var frame = this._zoomStack.pop();
46944
- this._wrapped = lens(frame.wrapped).set(frame.zoom, this._wrapped).freeze();
46945
- return this;
46946
- };
46947
- lens.prototype.get = function (lensArr) {
46948
- var obj = this._wrapped;
46949
- for (var i = 0; i < lensArr.length; i++) {
46950
- obj = dispatch(obj).get(obj, lensArr[i]);
46951
- }
46952
- return obj;
46953
- };
46954
- lens.prototype.mod = function (lensArr, f) {
46955
- var obj = this._wrapped;
46956
- var newObj = clone(obj);
46957
- var ops = dispatch(obj);
46958
- if (lensArr.length === 0) {
46959
- this._wrapped = f(this._wrapped);
46960
- } else if (lensArr.length === 1) {
46961
- this._wrapped = ops.mod(newObj, lensArr[0], f);
46962
- } else {
46963
- var monocle = lensArr[0];
46964
- var shortLens = lensArr.slice(1);
46965
-
46966
- // newObj = ops.mod(obj[monocle], shortLens, f);
46967
-
46968
- newObj[monocle] = lens(obj[monocle]).mod(shortLens, f).freeze();
46969
- this._wrapped = newObj;
46970
- }
46971
- return this;
46972
- };
46973
-
46974
- // TODO - move to individual files
46975
- lens.prototype.merge = function (lensArr, props) {
46976
- this._wrapped = lens(this._wrapped).mod(lensArr, function (oldProps) {
46977
- return merge(oldProps, props);
46978
- }).freeze();
46979
- return this;
46980
- };
46981
-
46982
- // Lens must have length >= 1 or there would be nothing to return
46983
- lens.prototype.del = function (lensArr) {
46984
- var obj = this._wrapped;
46985
- var ops = dispatch(obj);
46986
- if (lensArr.length === 1) {
46987
- this._wrapped = ops.del(obj, lensArr[0]);
46988
- } else {
46989
- var monocle = lensArr[0];
46990
- var shortLens = lensArr.slice(1);
46991
- var newObj = clone(obj);
46992
- newObj[monocle] = lens(obj[monocle]).del(shortLens).freeze();
46993
- this._wrapped = newObj;
46994
- }
46995
- return this;
46996
- };
46997
- lens.prototype.set = function (lensArr, set) {
46998
- return this.mod(lensArr, function () {
46999
- return set;
47000
- });
47001
- };
47002
-
47003
- // ARRAY FUNCTIONS
47004
-
47005
- const arr = {
47006
- get: function (arr, monocle) {
47007
- return arr[monocle];
47008
- },
47009
- set: function (arr, monocle, val) {
47010
- var newArr = arr.splice();
47011
- newArr[monocle] = val;
47012
- return newArr;
47013
- },
47014
- mod: function (arr, monocle, f) {
47015
- var newArr = arr.slice();
47016
- newArr[monocle] = f(arr[monocle]);
47017
- return newArr;
47018
- },
47019
- del: function (arr, monocle) {
47020
- var newArr = arr.slice();
47021
- newArr.splice(monocle, 1);
47022
- return newArr;
47023
- }
47024
- };
47025
-
47026
- /*
47027
- // Lens must point to a member of an array. We'll insert into that array.
47028
- lens.prototype.insertAt = function(lensArr, toInsert) {
47029
- var obj = this._wrapped;
47030
-
47031
- var arrLens = lensArr.slice(0, -1);
47032
- var arr = lens(obj).get(arrLens).slice(); // slice to copy
47033
-
47034
- var arrIdx = lensArr[lensArr.length-1];
47035
- arr.splice(arrIdx, 0, toInsert);
47036
- return lens(obj).set(arrLens, arr);
47037
- };
47038
-
47039
- lens.prototype.insertBefore = lens.prototype.insertAt;
47040
- lens.prototype.insertAfter = function(lensArr, toInsert) {
47041
- var newLens = lensArr.slice();
47042
- newLens[newLens.length-1] += 1;
47043
- return lens(this._wrapped).insertAt(newLens, toInsert);
47044
- };
47045
- */
47046
-
47047
- // OBJECT FUNCTIONS
47048
-
47049
- const obj = {
47050
- get: function (obj, monocle) {
47051
- return obj[monocle];
47052
- },
47053
- set: function (obj, monocle, val) {
47054
- var newObj = clone(obj);
47055
- newObj[monocle] = val;
47056
- return newObj;
47057
- },
47058
- mod: function (obj, monocle, f) {
47059
- var newObj = clone(obj);
47060
- newObj[monocle] = f(obj[monocle]);
47061
- return newObj;
47062
- },
47063
- del: function (obj, monocle) {
47064
- var newObj = clone(obj);
47065
- delete newObj[monocle];
47066
- return newObj;
47067
- }
47068
- };
47069
-
47070
- // STRING FUNCTIONS
47071
-
47072
- const str = {
47073
- get: function (arr, monocle) {
47074
- return arr[monocle];
47075
- },
47076
- set: function (arr, monocle, val) {
47077
- var newArr = arr.splice();
47078
- newArr[monocle] = val;
47079
- return newArr;
47080
- },
47081
- mod: function (arr, monocle, f) {
47082
- var newArr = arr.splice();
47083
- newArr[monocle] = f(arr[monocle]);
47084
- return newArr;
47085
- },
47086
- del: function (arr, monocle) {
47087
- var newArr = arr.slice();
47088
- newArr.splice(monocle);
47089
- return newArr;
47090
- }
47091
- };
47092
-
47093
- // TODO(mdr)
47094
- // TODO(mdr)
47095
- // TODO(mdr)
47096
-
47097
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
47098
-
47099
- /**
47100
- * TODO(somewhatabstract, JIRA-XXXX):
47101
- * Some usage of this type somewhere is causing TypeScript to believe that these
47102
- * elements should be components. Don't know where that is, to fix it up
47103
- * properly. In reality, these types are just too hard to use and aren't
47104
- * really helping us out as I now have to suppress this rather than
47105
- * get value from the type. :(
47106
- */ // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
47107
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
47108
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
47109
- class MultiRenderer extends React__namespace.Component {
47110
- static contextType = PerseusI18nContext;
47111
- rendererDataTreeMapper;
47112
- getRenderersMapper;
47113
- constructor(props) {
47114
- super(props);
47115
- this.rendererDataTreeMapper = buildMapper()
47116
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ContentNode'.
47117
- .setContentMapper((c, _, p) => this._makeContentRendererData(c, p))
47118
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'HintNode'.
47119
- .setHintMapper(h => this._makeHintRendererData(h)).setTagsMapper(t => null);
47120
-
47121
- // @ts-expect-error - TS2322 - Type 'TreeMapperForLeavesAndCollections<unknown, any, unknown, any, unknown, unknown>' is not assignable to type 'TreeMapper<ContentRendererData, ContentRendererElement, HintRendererData, HintRendererElement, null, null>'.
47122
- this.getRenderersMapper = buildMapper()
47123
- // @ts-expect-error - TS2571 - Object is of type 'unknown'.
47124
- .setContentMapper(c => c.makeRenderer())
47125
- // @ts-expect-error - TS2571 - Object is of type 'unknown'.
47126
- .setHintMapper(h => h.makeRenderer()).setArrayMapper((renderers, data, shape) => this._annotateRendererArray(renderers, data, shape));
47127
-
47128
- // Keep state in sync with props.
47129
- this.state = this._tryMakeRendererState(this.props);
47130
- }
47131
- UNSAFE_componentWillReceiveProps(nextProps) {
47132
- // Keep state in sync with props.
47133
- if (nextProps.item !== this.props.item) {
47134
- this.setState(this._tryMakeRendererState(nextProps));
47135
- }
47136
- }
47137
-
47138
- /**
47139
- * Attempt to build a State that includes a renderer tree corresponding to
47140
- * the item provided in props. On error, return a state with `renderError`
47141
- * set instead.
47142
- */
47143
- _tryMakeRendererState(props) {
47144
- try {
47145
- return {
47146
- rendererDataTree: this._makeRendererDataTree(props.item, props.shape),
47147
- renderError: null
47148
- };
47149
- } catch (e) {
47150
- Log.error("Error building tree state", perseusCore.Errors.Internal, {
47151
- cause: e
47152
- });
47153
- return {
47154
- rendererDataTree: null,
47155
- renderError: e
47156
- };
47157
- }
47158
- }
47159
- _handleSerializedStateUpdated = (path, newState) => {
47160
- const {
47161
- onSerializedStateUpdated
47162
- } = this.props;
47163
- if (onSerializedStateUpdated) {
47164
- const oldState = this._getSerializedState(this.props.serializedState);
47165
- onSerializedStateUpdated(lens(oldState).set(path, newState).freeze());
47166
- }
47167
- };
47168
-
47169
- /**
47170
- * Props that aren't directly used by the MultiRenderer are delegated to
47171
- * the underlying Renderers.
47172
- */
47173
- _getRendererProps() {
47174
- // `item`, `children`, and others are unused. I'm
47175
- // explicitly pulling them out of `this.props` so I don't pass them to
47176
- // `<Renderer>`. I'm not sure how else to do this.
47177
- const {
47178
- item: _,
47179
- children: __,
47180
- shape: ___,
47181
- serializedState: ____,
47182
- onSerializedStateUpdated: _____,
47183
- ...otherProps
47184
- } = this.props;
47185
- return {
47186
- ...otherProps,
47187
- strings: this.context.strings
47188
- };
47189
- }
47190
-
47191
- /**
47192
- * Construct a Renderer and a ref placeholder for the given ContentNode.
47193
- */
47194
- _makeContentRendererData(content, path) {
47195
- // NOTE(emily): The `findExternalWidgets` function here is computed
47196
- // inline and thus changes each time we run this function. If it
47197
- // were to change every render, it would cause the Renderer to
47198
- // re-render a lot more than is necessary. Don't re-compute this
47199
- // element unless it is necessary!
47200
- // HACK(mdr): TypeScript can't prove that this is a ContentRendererData,
47201
- // because of how we awkwardly construct it in order to obtain a
47202
- // circular reference. But it is, I promise.
47203
- const data = {
47204
- ref: null,
47205
- makeRenderer: null
47206
- };
47207
- const refFunc = e => data.ref = e;
47208
- const findExternalWidgets = criterion => this._findWidgets(data, criterion);
47209
- const handleSerializedState = state => this._handleSerializedStateUpdated(path, state);
47210
- data.makeRenderer = () =>
47211
- /*#__PURE__*/
47212
- /**
47213
- * TODO(somewhatabstract, JIRA-XXXX):
47214
- * `content` contains props that Renderer doesn't have. However,
47215
- * since the type for `content` is not exact, it's hard to know
47216
- * if this spread is including undocumented props so mapping
47217
- * one to one could introduce a bug. Need to work out the exact
47218
- * type for ContentNode and then fix this.
47219
- */
47220
- // @ts-expect-error - TS2322 - Type '{ ref: (e: any) => any; findExternalWidgets: (criterion: any) => readonly (Widget | null | undefined)[]; serializedState: any; onSerializedStateUpdated: (state: any) => void; __type: "content" | "item"; ... 9 more ...; reviewMode?: boolean | ... 1 more ... | undefined; }' is not assignable to type 'InexactPartial<Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "content" | "images" | "onRender" | "linterContext" | "widgets" | "alwaysUpdate" | ... 6 more ... | "serializedState">>'.
47221
- React__namespace.createElement(Renderer, _extends({}, this._getRendererProps(), content, {
47222
- ref: refFunc,
47223
- findExternalWidgets: findExternalWidgets,
47224
- serializedState: this.props.serializedState ? lens(this.props.serializedState).get(path) : null,
47225
- onSerializedStateUpdated: handleSerializedState
47226
- }));
47227
- return data;
47228
- }
47229
-
47230
- /**
47231
- * Construct a Renderer for the given HintNode, and keep track of the hint
47232
- * itself for future use, too.
47233
- */
47234
- _makeHintRendererData(hint) {
47235
- // TODO(mdr): Once HintsRenderer supports inter-widget communication,
47236
- // give it a ref. Until then, leave the ref null forever, to avoid
47237
- // confusing the findWidgets functions.
47238
- //
47239
- // NOTE(davidflanagan): As a partial step toward inter-widget
47240
- // communication we're going to pass a findExternalWidgets function
47241
- // (using a dummy data object). This allows passage-ref widgets in
47242
- // hints to use findWidget() to find the passage widgets they reference.
47243
- // Note that this is one-way only, however. It does not allow
47244
- // widgets in the question to find widgets in the hints, for example.
47245
- const findExternalWidgets = criterion => this._findWidgets({}, criterion);
47246
- return {
47247
- hint,
47248
- findExternalWidgets,
47249
- // _annotateRendererArray() needs this
47250
- ref: null,
47251
- makeRenderer: () => /*#__PURE__*/React__namespace.createElement(HintsRenderer, _extends({}, this._getRendererProps(), {
47252
- findExternalWidgets: findExternalWidgets
47253
- // Note(Jeremy): The MultiRenderer codebase types are
47254
- // slightly different from the rest of the codebase.
47255
- // Ideally `HintNode` would spread the `Hint` type into it,
47256
- // but there is a difference in optionality of `widgets`
47257
- // and `images` and that causes a huge cascade of type
47258
- // errors (they are truly optional, but most of our code
47259
- // assumes they're provided/set). Ignoring this for now.
47260
- // @ts-expect-error - TS2769 - Type 'HintNode' is not assignable to type 'Hint'.
47261
- ,
47262
- hints: [hint]
47263
- }))
47264
- };
47265
- }
47266
-
47267
- /**
47268
- * Construct a tree of interconnected RendererDatas, corresponding to the
47269
- * given item. Called in `_tryMakeRendererState`, in order to store this
47270
- * tree in the component state.
47271
- */
47272
- _makeRendererDataTree(item, shape) {
47273
- const itemTree = itemToTree(item);
47274
- return this.rendererDataTreeMapper.mapTree(itemTree, shape);
47275
- }
47276
-
47277
- /**
47278
- * Return all widgets that meet the given criterion, from all Renderers
47279
- * except the Renderer that triggered this call.
47280
- *
47281
- * This function is provided to each Renderer's `findExternalWidgets` prop,
47282
- * which enables widgets in different Renderers to discover each other and
47283
- * communicate.
47284
- */
47285
- _findWidgets(callingData, filterCriterion) {
47286
- const results = [];
47287
- this._mapRenderers(data => {
47288
- if (callingData !== data && data.ref) {
47289
- results.push(...data.ref.findInternalWidgets(filterCriterion));
47290
- }
47291
- });
47292
- return results;
47293
- }
47294
-
47295
- /**
47296
- * Copy the renderer tree, apply the given transformation to the leaf nodes
47297
- * and the optional given transformation to the array nodes, and return the
47298
- * result.
47299
- *
47300
- * Used to provide structured data to the call site (the Renderer tree on
47301
- * `render`, the Score tree on `getScores`, etc.), and to traverse the
47302
- * renderer tree even when we disregard the output (like in
47303
- * `_findWidgets`).
47304
- */
47305
- _mapRenderers(
47306
- // eslint-disable-next-line no-restricted-syntax
47307
- leafMapper
47308
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
47309
- ) {
47310
- const {
47311
- rendererDataTree
47312
- } = this.state;
47313
- if (!rendererDataTree) {
47314
- return null;
47315
- }
47316
- const mapper = buildMapper().setContentMapper(leafMapper).setHintMapper(leafMapper);
47317
- return mapper.mapTree(rendererDataTree, this.props.shape);
47318
- }
47319
- _scoreFromRef(ref) {
47320
- if (!ref) {
47321
- return null;
47322
- }
47323
- const [guess, score] = ref.guessAndScore();
47324
- let state;
47325
- if (ref.getSerializedState) {
47326
- state = ref.getSerializedState();
47327
- }
47328
- return keScoreFromPerseusScore(score, guess, state);
47329
- }
47330
-
47331
- /**
47332
- * Return a tree in the shape of the multi-item, with scores at each of
47333
- * the content nodes and `null` at the other leaf nodes.
47334
- */
47335
- getScores() {
47336
- return this._mapRenderers(data => this._scoreFromRef(data.ref));
47337
- }
47338
-
47339
- /**
47340
- * Return a single composite score for all rendered content nodes.
47341
- * The `guess` is a tree in the shape of the multi-item, with an individual
47342
- * guess at each content node and `null` at the other leaf nodes.
47343
- */
47344
- score() {
47345
- const scores = [];
47346
- const state = [];
47347
- const guess = this._mapRenderers(data => {
47348
- if (!data.ref) {
47349
- return null;
47350
- }
47351
- if (data.ref.getSerializedState) {
47352
- state.push(data.ref.getSerializedState());
47353
- }
47354
- scores.push(data.ref.score());
47355
- return data.ref?.getUserInput();
47356
- });
47357
- const combinedScore = scores.reduce(combineScores);
47358
- return keScoreFromPerseusScore(combinedScore, guess, state);
47359
- }
47360
-
47361
- /**
47362
- * Return a tree in the shape of the multi-item, with serialized state at
47363
- * each of the content nodes and `null` at the other leaf nodes.
47364
- *
47365
- * If the lastSerializedState argument is supplied, this function will fill
47366
- * in the state of not-currently-rendered content and hint nodes with the
47367
- * values from the previous serialized state. If no lastSerializedState is
47368
- * supplied, `null` will be returned for not-currently-rendered content and
47369
- * hint nodes.
47370
- */
47371
- _getSerializedState(lastSerializedState) {
47372
- return this._mapRenderers((data, _, path) => {
47373
- if (data.ref) {
47374
- return data.ref.getSerializedState();
47375
- }
47376
- if (lastSerializedState) {
47377
- return lens(lastSerializedState).get(path);
47378
- }
47379
- return null;
47380
- });
47381
- }
47382
-
47383
- /**
47384
- * Given a tree in the shape of the multi-item, with serialized state at
47385
- * each of the content nodes, restore each state to the corresponding
47386
- * renderer if currently mounted.
47387
- */
47388
- restoreSerializedState(serializedState, callback) {
47389
- // We want to call our async callback only once all of the childrens'
47390
- // callbacks have run. We add one to this counter before we call out to
47391
- // each renderer and decrement it when it runs our callback.
47392
- let numCallbacks = 0;
47393
- const countCallback = () => {
47394
- numCallbacks--;
47395
- if (callback && numCallbacks === 0) {
47396
- callback();
47397
- }
47398
- };
47399
- this._mapRenderers((data, _, path) => {
47400
- if (!data.ref) {
47401
- return;
47402
- }
47403
- const state = lens(serializedState).get(path);
47404
- if (!state) {
47405
- return;
47406
- }
47407
- numCallbacks++;
47408
- data.ref?.restoreSerializedState(state, countCallback);
47409
- });
47410
- }
47411
-
47412
- /**
47413
- * Given an array of renderers, if it happens to be an array of *hint*
47414
- * renderers, then attach a `firstN` method to the array, which allows the
47415
- * layout to render the hints together in one HintsRenderer.
47416
- */
47417
- _annotateRendererArray(renderers, rendererDatas, shape) {
47418
- if (shape.elementShape.type === "hint") {
47419
- // The shape says that these are HintRendererDatas, even though
47420
- // it's not provable at compile time, so perform a cast.
47421
- const hintRendererDatas = rendererDatas;
47422
- renderers = [...renderers];
47423
- renderers.firstN = n => /*#__PURE__*/React__namespace.createElement(HintsRenderer, _extends({}, this._getRendererProps(), {
47424
- findExternalWidgets: hintRendererDatas[0] ? hintRendererDatas[0].findExternalWidgets : undefined,
47425
- hints: hintRendererDatas.map(d => d.hint),
47426
- hintsVisible: n
47427
- }));
47428
- }
47429
- return renderers;
47430
- }
47431
-
47432
- /**
47433
- * Return a tree in the shape of the multi-item, with a Renderer at each
47434
- * content node and a HintRenderer at each hint node.
47435
- *
47436
- * This is generated by running each of the `makeRenderer` functions at the
47437
- * leaf nodes.
47438
- */
47439
- _getRenderers() {
47440
- return this.getRenderersMapper.mapTree(this.state.rendererDataTree, this.props.shape);
47441
- }
47442
- render() {
47443
- if (this.state.renderError) {
47444
- return /*#__PURE__*/React__namespace.createElement("div", {
47445
- className: aphrodite.css(styles.error)
47446
- }, this.context.strings.errorRendering({
47447
- error: String(this.state.renderError)
47448
- }));
47449
- }
47450
-
47451
- // Pass the renderer tree to the `children` function, which will
47452
- // determine the actual content of this component.
47453
- return /*#__PURE__*/React__namespace.createElement(DependenciesContext.Provider, {
47454
- value: this.props.dependencies
47455
- }, this.props.children({
47456
- renderers: this._getRenderers()
47457
- }));
47458
- }
47459
- }
47460
- const styles = aphrodite.StyleSheet.create({
47461
- error: {
47462
- color: "red"
47463
- }
47464
- });
47465
-
47466
- /**
47467
- * Utility functions to build React PropTypes for multi-items and shapes.
47468
- *
47469
- * If you're writing new components, though, consider using the Item and Shape
47470
- * types instead.
47471
- */
47472
- /**
47473
- * Return a PropType that accepts Items of the given shape, and rejects other
47474
- * objects.
47475
- *
47476
- * Usage: `propTypes: {item: buildPropTypeForShape(myShape)}`
47477
- */
47478
- function buildPropTypeForShape(shape) {
47479
- return PropTypes__default["default"].oneOfType([PropTypes__default["default"].shape({
47480
- _multi: buildTreePropTypeForShape(shape)
47481
- }), PropTypes__default["default"].oneOf([null, undefined])]);
47482
- }
47483
-
47484
- /**
47485
- * Return a PropType that accepts ItemTrees of the given shape, and rejects
47486
- * other objects.
47487
- */
47488
- function buildTreePropTypeForShape(shape) {
47489
- if (shape.type === "content") {
47490
- return PropTypes__default["default"].shape({
47491
- // TODO(mdr): Remove #LegacyContentNode support.
47492
- __type: PropTypes__default["default"].oneOf(["content", "item"]).isRequired,
47493
- content: PropTypes__default["default"].string,
47494
- images: PropTypes__default["default"].objectOf(PropTypes__default["default"].any),
47495
- widgets: PropTypes__default["default"].objectOf(PropTypes__default["default"].any)
47496
- });
47497
- }
47498
- if (shape.type === "hint") {
47499
- return PropTypes__default["default"].shape({
47500
- __type: PropTypes__default["default"].oneOf(["hint"]).isRequired,
47501
- content: PropTypes__default["default"].string,
47502
- images: PropTypes__default["default"].objectOf(PropTypes__default["default"].any),
47503
- widgets: PropTypes__default["default"].objectOf(PropTypes__default["default"].any),
47504
- replace: PropTypes__default["default"].bool
47505
- });
47506
- }
47507
- if (shape.type === "tags") {
47508
- return PropTypes__default["default"].arrayOf(PropTypes__default["default"].string.isRequired);
47509
- }
47510
- if (shape.type === "array") {
47511
- const elementPropType = buildTreePropTypeForShape(shape.elementShape);
47512
- return PropTypes__default["default"].arrayOf(elementPropType.isRequired);
47513
- }
47514
- if (shape.type === "object") {
47515
- const valueShapes = shape.shape;
47516
- const propTypeShape = {};
47517
- Object.keys(valueShapes).forEach(key => {
47518
- propTypeShape[key] = buildTreePropTypeForShape(valueShapes[key]).isRequired;
47519
- });
47520
- return PropTypes__default["default"].shape(propTypeShape);
47521
- }
47522
- throw new perseusCore.PerseusError(
47523
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
47524
- `unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
47525
- }
47526
-
47527
- /**
47528
- * This library provides support for Perseus multi-items: structured Perseus
47529
- * content that content creators can easily create, and that applications can
47530
- * easily render into different parts of the layout.
47531
- *
47532
- * For more details about application and motivation, see:
47533
- * https://sites.google.com/a/khanacademy.org/forge/for-developers/perseus-items-and-multi-items
47534
- *
47535
- * This file primarily exposes the `MultiRenderer` component, which performs
47536
- * multi-rendering. To multi-render a question, pass in the content of the item
47537
- * to the `MultiRenderer` component as a props. Then, pass in a function which
47538
- * takes an object of renderers (in the same structure as the content), and
47539
- * return a render tree. The `MultiRenderer` component will allow you to
47540
- * combine scores, serialized state, etc. without having to manually call on
47541
- * each of the functions. It also handles inter-widgets requests between the
47542
- * different renderers.
47543
- * For more details, see `multi-items/multi-renderer.jsx`.
47544
- *
47545
- * Example:
47546
- *
47547
- * item = {_multi: {
47548
- * left: <content data>,
47549
- * right: [<content data>, <content data>],
47550
- * }}
47551
- * shape = shapes.shape({
47552
- * left: shapes.content,
47553
- * right: shapes.arrayOf(shapes.content),
47554
- * })
47555
- *
47556
- * <MultiRenderer item={item} shape={shape}>
47557
- * {({renderers}) =>
47558
- * <div>
47559
- * <div id="left">{renderers.left}</div>
47560
- * <ul id="right">
47561
- * {renderers.right.map(r => <li>{r}</li>)}
47562
- * </ul>
47563
- * </div>
47564
- * }
47565
- * </MultiRenderer>
47566
- *
47567
- * This file also exposes `shapes`, which helps you construct a runtime type
47568
- * declaration for your particular class of multi-item. This can then be used
47569
- * to create a MultirendererEditor for your multi-item shape, and to validate
47570
- * that a multi-item conforms to the shape via `buildPropTypeForShape`.
47571
- * For more details, see `multi-items/shapes.js`.
47572
- *
47573
- * This file also exposes some utility functions for working with generic
47574
- * multi-items, like `findContentNodesInItem`, `findHintNodesInItem`,
47575
- * `inferItemShape`, and `buildEmptyItemForShape`.
47576
- * For more details, see `multi-items/items.js`.
47577
- */
47578
- var MultiItems = {
47579
- // Tools for rendering your multi-items
47580
- MultiRenderer,
47581
- // Tools for declaring your multi-item shapes
47582
- shapes,
47583
- buildPropTypeForShape,
47584
- // Tools for generically manipulating multi-items
47585
- buildEmptyItemForShape,
47586
- findContentNodesInItem: findContentNodesInItem$2,
47587
- findHintNodesInItem,
47588
- inferItemShape: inferItemShape$2
47589
- };
47590
-
47591
46439
  /**
47592
46440
  * Calculates whether a perseus item is renderable by a specific
47593
46441
  * perseus-item-data version.
@@ -47597,10 +46445,6 @@ var MultiItems = {
47597
46445
  * This supports widgets that contain renderers, such as the
47598
46446
  * group or sequence widgets.
47599
46447
  */
47600
- const {
47601
- findContentNodesInItem: findContentNodesInItem$1,
47602
- inferItemShape: inferItemShape$1
47603
- } = MultiItems;
47604
46448
  const isUpgradedWidgetInfoRenderableBy = function (widgetInfo, widgetRendererVersion) {
47605
46449
  if (widgetRendererVersion == null) {
47606
46450
  // If the widget does not exist in this version, this will
@@ -47646,17 +46490,6 @@ const isItemRenderableByVersion = function (itemData, rendererContentVersion) {
47646
46490
  if (itemData == null || rendererContentVersion == null) {
47647
46491
  throw new perseusCore.PerseusError("missing parameter to Perseus.isRenderable.item", perseusCore.Errors.InvalidInput);
47648
46492
  }
47649
- if (itemData._multi) {
47650
- const shape = inferItemShape$1(itemData);
47651
- let isRenderable = true;
47652
- findContentNodesInItem$1(itemData, shape, node => {
47653
- const nodeIsRenderable = isRendererContentRenderableBy(node, rendererContentVersion);
47654
- if (!nodeIsRenderable) {
47655
- isRenderable = false;
47656
- }
47657
- });
47658
- return isRenderable;
47659
- }
47660
46493
  return isRendererContentRenderableBy(itemData.question, rendererContentVersion);
47661
46494
  };
47662
46495
 
@@ -47664,10 +46497,6 @@ const isItemRenderableByVersion = function (itemData, rendererContentVersion) {
47664
46497
  * Identifies whether or not a given perseus item requires the use of a mouse
47665
46498
  * or screen, based on the widgets it contains.
47666
46499
  */
47667
- const {
47668
- findContentNodesInItem,
47669
- inferItemShape
47670
- } = MultiItems;
47671
46500
 
47672
46501
  // Iterate over a single Perseus renderer, mutating `widgets` by appending
47673
46502
  // violating widget types discovered in this item.
@@ -47688,12 +46517,7 @@ function traverseRenderer(itemData, widgets) {
47688
46517
  function violatingWidgets(itemData) {
47689
46518
  // TODO(jordan): Hints as well
47690
46519
  const widgets = [];
47691
- if (itemData._multi) {
47692
- const shape = inferItemShape(itemData);
47693
- findContentNodesInItem(itemData, shape, content => traverseRenderer(content, widgets));
47694
- } else {
47695
- traverseRenderer(itemData.question, widgets);
47696
- }
46520
+ traverseRenderer(itemData.question, widgets);
47697
46521
 
47698
46522
  // Uniquify the list of widgets (by type)
47699
46523
  return ___default["default"].uniq(widgets);
@@ -50216,6 +49040,10 @@ const ScoringUtil = {
50216
49040
  keScoreFromPerseusScore
50217
49041
  };
50218
49042
 
49043
+ /**
49044
+ * Types
49045
+ */
49046
+
50219
49047
  exports.ApiOptions = ApiOptions;
50220
49048
  exports.ArticleRenderer = ArticleRenderer;
50221
49049
  exports.BaseRadio = BaseRadio;
@@ -50238,7 +49066,6 @@ exports.KhanMath = KhanMath;
50238
49066
  exports.LoadingContext = context;
50239
49067
  exports.Log = Log;
50240
49068
  exports.MatrixWidget = Matrix$1;
50241
- exports.MultiItems = MultiItems;
50242
49069
  exports.NumericInput = NumericInput$1;
50243
49070
  exports.PerseusExpressionAnswerFormConsidered = PerseusExpressionAnswerFormConsidered;
50244
49071
  exports.PerseusI18nContext = PerseusI18nContext;
@@ -50257,8 +49084,6 @@ exports.Widgets = widgets$1;
50257
49084
  exports.addWidget = addWidget;
50258
49085
  exports.apiVersion = apiVersion;
50259
49086
  exports.bodyXsmallBold = bodyXsmallBold;
50260
- exports.buildEmptyItemTreeForShape = buildEmptyItemTreeForShape;
50261
- exports.buildMapper = buildMapper;
50262
49087
  exports.components = components;
50263
49088
  exports.containerSizeClass = containerSizeClass;
50264
49089
  exports.contentHasWidgetType = contentHasWidgetType;
@@ -50302,7 +49127,6 @@ exports.isItemRenderableByVersion = isItemRenderableByVersion;
50302
49127
  exports.isWidgetIdInContent = isWidgetIdInContent;
50303
49128
  exports.isWrongAnswerSupported = isWrongAnswerSupported;
50304
49129
  exports.itemDataVersion = itemDataVersion;
50305
- exports.itemToTree = itemToTree;
50306
49130
  exports.itemVersion = ItemVersion;
50307
49131
  exports.libVersion = libVersion;
50308
49132
  exports.lockedFigureColors = lockedFigureColors;
@@ -50315,7 +49139,6 @@ exports.plotterPlotTypes = plotterPlotTypes;
50315
49139
  exports.preprocessTex = preprocessTex;
50316
49140
  exports.registerAllWidgetsForTesting = registerAllWidgetsForTesting;
50317
49141
  exports.scorePerseusItem = scorePerseusItem;
50318
- exports.shapes = shapes;
50319
49142
  exports.shouldHaveIndividualAnswer = shouldHaveIndividualAnswer;
50320
49143
  exports.traverse = traverse;
50321
49144
  exports.usePerseusI18n = usePerseusI18n;