@khanacademy/perseus 46.0.1 → 47.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -508,7 +508,7 @@ class InnerMathInput extends React.Component {
508
508
  className = className + " " + this.props.className;
509
509
  }
510
510
  return /*#__PURE__*/React.createElement(View, {
511
- style: [styles$E.outerWrapper, this.state.focused && styles$E.wrapperFocused, this.props.hasError && styles$E.wrapperError]
511
+ style: [styles$D.outerWrapper, this.state.focused && styles$D.wrapperFocused, this.props.hasError && styles$D.wrapperError]
512
512
  }, /*#__PURE__*/React.createElement("div", {
513
513
  style: {
514
514
  display: "flex",
@@ -546,7 +546,7 @@ class InnerMathInput extends React.Component {
546
546
  style: a11y.srOnly
547
547
  }, this.context.strings.mathInputDescription), /*#__PURE__*/React.createElement(PopoverContentCore, {
548
548
  closeButtonVisible: true,
549
- style: styles$E.popoverContent
549
+ style: styles$D.popoverContent
550
550
  }, /*#__PURE__*/React.createElement(DesktopKeypad, _extends({
551
551
  onAnalyticsEvent: this.props.onAnalyticsEvent,
552
552
  extraKeys: this.props.extraKeys,
@@ -622,9 +622,9 @@ const MathInputIcon = ({
622
622
  fillColor = color.offBlack;
623
623
  break;
624
624
  }
625
- const dynamicClass = active || focused ? styles$E.iconActive : styles$E.iconInactive;
625
+ const dynamicClass = active || focused ? styles$D.iconActive : styles$D.iconInactive;
626
626
  return /*#__PURE__*/React.createElement(View, {
627
- style: [styles$E.iconContainer, dynamicClass]
627
+ style: [styles$D.iconContainer, dynamicClass]
628
628
  }, /*#__PURE__*/React.createElement("svg", {
629
629
  xmlns: "http://www.w3.org/2000/svg",
630
630
  width: "16",
@@ -669,7 +669,7 @@ const inputFocused = {
669
669
  borderColor: color.blue,
670
670
  margin: -1
671
671
  };
672
- const styles$E = StyleSheet.create({
672
+ const styles$D = StyleSheet.create({
673
673
  iconContainer: {
674
674
  display: "flex",
675
675
  justifyContent: "center",
@@ -2469,7 +2469,7 @@ class Expression extends React.Component {
2469
2469
  var _this$props$keypadCon, _this$props$analytics2, _this$props$analytics3;
2470
2470
  if (this.props.apiOptions.customKeypad) {
2471
2471
  return /*#__PURE__*/React.createElement(View, {
2472
- className: css(styles$D.mobileLabelInputWrapper)
2472
+ className: css(styles$C.mobileLabelInputWrapper)
2473
2473
  }, !!this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelSmall, {
2474
2474
  htmlFor: this._textareaId,
2475
2475
  tag: "label"
@@ -2504,7 +2504,7 @@ class Expression extends React.Component {
2504
2504
  ERROR_TITLE
2505
2505
  } = this.context.strings;
2506
2506
  return /*#__PURE__*/React.createElement(View, {
2507
- className: css(styles$D.desktopLabelInputWrapper)
2507
+ className: css(styles$C.desktopLabelInputWrapper)
2508
2508
  }, !!this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelSmall, {
2509
2509
  htmlFor: this._textareaId,
2510
2510
  tag: "label"
@@ -2554,7 +2554,7 @@ Expression.defaultProps = {
2554
2554
  apiOptions: ApiOptions.defaults,
2555
2555
  linterContext: linterContextDefault
2556
2556
  };
2557
- const styles$D = StyleSheet.create({
2557
+ const styles$C = StyleSheet.create({
2558
2558
  mobileLabelInputWrapper: {
2559
2559
  padding: "15px 4px 0"
2560
2560
  },
@@ -17930,33 +17930,33 @@ class Lint extends React.Component {
17930
17930
  let warningText;
17931
17931
  let warningTextStyle;
17932
17932
  if (this.props.severity === Severity.Error) {
17933
- severityStyle = styles$C.indicatorError;
17933
+ severityStyle = styles$B.indicatorError;
17934
17934
  warningText = "Error";
17935
- warningTextStyle = styles$C.publishBlockingError;
17935
+ warningTextStyle = styles$B.publishBlockingError;
17936
17936
  } else if (this.props.severity === Severity.Warning) {
17937
- severityStyle = styles$C.indicatorWarning;
17937
+ severityStyle = styles$B.indicatorWarning;
17938
17938
  warningText = "Warning";
17939
- warningTextStyle = styles$C.warning;
17939
+ warningTextStyle = styles$B.warning;
17940
17940
  } else {
17941
- severityStyle = styles$C.indicatorGuideline;
17941
+ severityStyle = styles$B.indicatorGuideline;
17942
17942
  warningText = "Recommendation";
17943
- warningTextStyle = styles$C.warning;
17943
+ warningTextStyle = styles$B.warning;
17944
17944
  }
17945
17945
  return /*#__PURE__*/React.createElement("a", {
17946
17946
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
17947
17947
  target: "lint-help-window",
17948
17948
  className: css(style)
17949
17949
  }, /*#__PURE__*/React.createElement("span", {
17950
- className: css(styles$C.indicator, severityStyle)
17950
+ className: css(styles$B.indicator, severityStyle)
17951
17951
  }, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React.createElement("div", {
17952
- className: css(styles$C.tooltip, tooltipAbove && styles$C.tooltipAbove)
17952
+ className: css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
17953
17953
  }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
17954
17954
  key: i,
17955
- className: css(styles$C.tooltipParagraph)
17955
+ className: css(styles$B.tooltipParagraph)
17956
17956
  }, /*#__PURE__*/React.createElement("span", {
17957
17957
  className: css(warningTextStyle)
17958
17958
  }, warningText, ":", " "), m)), /*#__PURE__*/React.createElement("div", {
17959
- className: css(styles$C.tail, tooltipAbove && styles$C.tailAbove)
17959
+ className: css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
17960
17960
  })));
17961
17961
  };
17962
17962
  }
@@ -17994,20 +17994,20 @@ class Lint extends React.Component {
17994
17994
  }
17995
17995
  if (blockHighlight) {
17996
17996
  return /*#__PURE__*/React.createElement("span", {
17997
- className: css(styles$C.lintContainer, styles$C.lintContainerBlock)
17998
- }, this.renderLink(styles$C.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17997
+ className: css(styles$B.lintContainer, styles$B.lintContainerBlock)
17998
+ }, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
17999
17999
  }
18000
18000
  if (inline) {
18001
18001
  return /*#__PURE__*/React.createElement("span", {
18002
- className: css(styles$C.lintContainer)
18003
- }, this.renderLink(styles$C.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
18002
+ className: css(styles$B.lintContainer)
18003
+ }, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
18004
18004
  }
18005
18005
  return /*#__PURE__*/React.createElement("div", {
18006
- className: css(styles$C.lintContainer)
18007
- }, this.renderLink(styles$C.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
18006
+ className: css(styles$B.lintContainer)
18007
+ }, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
18008
18008
  }
18009
18009
  }
18010
- const styles$C = StyleSheet.create({
18010
+ const styles$B = StyleSheet.create({
18011
18011
  // This is the class of the outermost element.
18012
18012
  // We use relative positioning so that the lint indicator can be
18013
18013
  // positioned absolutely relative to the position of the linty container.
@@ -18814,8 +18814,6 @@ function getWidgetFromWidgetMap(widgetId, widgetMap) {
18814
18814
 
18815
18815
  /**
18816
18816
  * Get select widgets from a widget map.
18817
- * Useful for multi-items that needs to split
18818
- * one PerseusItem into several
18819
18817
  *
18820
18818
  * @param {ReadonlyArray<string>} widgetIds to extract
18821
18819
  * @param {PerseusWidgetsMap} widgetMap to extract from
@@ -20200,7 +20198,7 @@ class Renderer extends React.Component {
20200
20198
  paddingLeft: margin,
20201
20199
  paddingRight: margin
20202
20200
  };
20203
- const mobileInnerStyle = _extends({}, innerStyle, styles$B.mobileZoomableParentFix);
20201
+ const mobileInnerStyle = _extends({}, innerStyle, styles$A.mobileZoomableParentFix);
20204
20202
  return /*#__PURE__*/React.createElement("div", {
20205
20203
  key: state.key,
20206
20204
  className: "perseus-block-math",
@@ -20324,7 +20322,7 @@ class Renderer extends React.Component {
20324
20322
  paddingLeft: 0,
20325
20323
  paddingRight: 0
20326
20324
  };
20327
- const mobileInnerStyle = _extends({}, innerStyle, styles$B.mobileZoomableParentFix);
20325
+ const mobileInnerStyle = _extends({}, innerStyle, styles$A.mobileZoomableParentFix);
20328
20326
  const wrappedOutput = /*#__PURE__*/React.createElement("div", {
20329
20327
  style: _extends({}, mobileInnerStyle, {
20330
20328
  overflowX: "auto"
@@ -20965,7 +20963,7 @@ Renderer.defaultProps = {
20965
20963
  onSerializedStateUpdated: () => {},
20966
20964
  linterContext: PerseusLinter.linterContextDefault
20967
20965
  };
20968
- const styles$B = {
20966
+ const styles$A = {
20969
20967
  mobileZoomableParentFix: {
20970
20968
  // NOTE(abdul): There is an issue where transform animations will
20971
20969
  // cause the Zoomable component to disappear when running on the
@@ -21073,7 +21071,7 @@ function _objectWithoutPropertiesLoose(r, e) {
21073
21071
  return t;
21074
21072
  }
21075
21073
 
21076
- const _excluded$8 = ["position", "visibility", "left", "top"];
21074
+ const _excluded$7 = ["position", "visibility", "left", "top"];
21077
21075
  const zIndex = 10;
21078
21076
  let HorizontalDirection = /*#__PURE__*/function (HorizontalDirection) {
21079
21077
  HorizontalDirection["Left"] = "left";
@@ -21124,7 +21122,7 @@ const TooltipArrow = _ref => {
21124
21122
  left = 100,
21125
21123
  top = 0
21126
21124
  } = _ref,
21127
- props = _objectWithoutPropertiesLoose(_ref, _excluded$8);
21125
+ props = _objectWithoutPropertiesLoose(_ref, _excluded$7);
21128
21126
  // TODO(aria): Think about adding a box-shadow to the triangle here
21129
21127
  // See http://css-tricks.com/triangle-with-shadow/
21130
21128
 
@@ -21498,7 +21496,7 @@ InputWithExamples.defaultProps = {
21498
21496
  className: ""
21499
21497
  };
21500
21498
 
21501
- const _excluded$7 = ["keypadElement", "onFocus", "value"];
21499
+ const _excluded$6 = ["keypadElement", "onFocus", "value"];
21502
21500
  class SimpleKeypadInput extends React.Component {
21503
21501
  constructor(...args) {
21504
21502
  super(...args);
@@ -21543,7 +21541,7 @@ class SimpleKeypadInput extends React.Component {
21543
21541
  onFocus,
21544
21542
  value
21545
21543
  } = _this$props,
21546
- rest = _objectWithoutPropertiesLoose(_this$props, _excluded$7);
21544
+ rest = _objectWithoutPropertiesLoose(_this$props, _excluded$6);
21547
21545
  return (
21548
21546
  /*#__PURE__*/
21549
21547
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -21948,10 +21946,10 @@ class InputNumber extends React.Component {
21948
21946
  // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21949
21947
  // you modify this, double-check if you also need to modify that
21950
21948
  // component.
21951
- const inputStyles = [styles$A.default, this.props.size === "small" ? styles$A.small : null, this.props.rightAlign ? styles$A.rightAlign : styles$A.leftAlign];
21949
+ const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
21952
21950
  // Unanswered
21953
21951
  if (this.props.reviewMode && !this.props.currentValue) {
21954
- inputStyles.push(styles$A.answerStateUnanswered);
21952
+ inputStyles.push(styles$z.answerStateUnanswered);
21955
21953
  }
21956
21954
  return /*#__PURE__*/React.createElement(InputWithExamples
21957
21955
  // eslint-disable-next-line react/no-string-refs
@@ -21981,7 +21979,7 @@ InputNumber.defaultProps = {
21981
21979
  apiOptions: ApiOptions.defaults,
21982
21980
  linterContext: linterContextDefault
21983
21981
  };
21984
- const styles$A = StyleSheet.create({
21982
+ const styles$z = StyleSheet.create({
21985
21983
  default: {
21986
21984
  width: 80,
21987
21985
  height: "auto"
@@ -23152,7 +23150,7 @@ class HighlightRenderer extends React.PureComponent {
23152
23150
  const rects = this.state.cachedHighlightRects;
23153
23151
  return /*#__PURE__*/React.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React.createElement("div", {
23154
23152
  key: index,
23155
- className: css(styles$z.highlightRect),
23153
+ className: css(styles$y.highlightRect),
23156
23154
  style: {
23157
23155
  // NOTE(mdr): We apply `position: absolute` here
23158
23156
  // rather than in Aphrodite styles, because
@@ -23171,7 +23169,7 @@ class HighlightRenderer extends React.PureComponent {
23171
23169
  })));
23172
23170
  }
23173
23171
  }
23174
- const styles$z = StyleSheet.create({
23172
+ const styles$y = StyleSheet.create({
23175
23173
  highlightRect: {
23176
23174
  background: "#fffabe" // highlighter yellow :)
23177
23175
  }
@@ -23252,7 +23250,7 @@ class HighlightTooltip extends React.PureComponent {
23252
23250
  // TooltipContent wouldn't let me overwrite
23253
23251
  // user-select and onClick
23254
23252
  const content = /*#__PURE__*/React.createElement("div", {
23255
- className: css(styles$y.tooltipLabel),
23253
+ className: css(styles$x.tooltipLabel),
23256
23254
  onClick: this.props.onClick
23257
23255
  }, this.props.label);
23258
23256
  const style = {
@@ -23272,7 +23270,7 @@ class HighlightTooltip extends React.PureComponent {
23272
23270
  }, /*#__PURE__*/React.createElement("div", null)));
23273
23271
  }
23274
23272
  }
23275
- const styles$y = StyleSheet.create({
23273
+ const styles$x = StyleSheet.create({
23276
23274
  tooltipLabel: {
23277
23275
  // Unlike most tooltip contents, we don't want this label to be
23278
23276
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -23823,7 +23821,7 @@ class HighlightableContent extends React.PureComponent {
23823
23821
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
23824
23822
  const buildHighlight = r => this._buildHighlight(r);
23825
23823
  return /*#__PURE__*/React.createElement("div", {
23826
- className: css(styles$x.container),
23824
+ className: css(styles$w.container),
23827
23825
  ref: container => this._container = container
23828
23826
  }, /*#__PURE__*/React.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React.createElement(HighlightingUI, {
23829
23827
  buildHighlight: buildHighlight,
@@ -23844,14 +23842,14 @@ class HighlightableContent extends React.PureComponent {
23844
23842
  onAddHighlight: this._handleAddHighlight,
23845
23843
  onRemoveHighlight: this._handleRemoveHighlight
23846
23844
  })), /*#__PURE__*/React.createElement("div", {
23847
- className: css(styles$x.content),
23845
+ className: css(styles$w.content),
23848
23846
  ref: content => this._content = content
23849
23847
  }, /*#__PURE__*/React.createElement(WordIndexer, {
23850
23848
  onWordsUpdate: this._handleWordsUpdate
23851
23849
  }, this.props.children)));
23852
23850
  }
23853
23851
  }
23854
- const styles$x = StyleSheet.create({
23852
+ const styles$w = StyleSheet.create({
23855
23853
  // We render content with z-index 1, and highlights with z-index 0, so that
23856
23854
  // content will receive the browser's native pointer events. (Highlights
23857
23855
  // have their own magic code to manage hover detection, despite being
@@ -24277,7 +24275,7 @@ class LineHeightMeasurer extends React.Component {
24277
24275
  }
24278
24276
  render() {
24279
24277
  return /*#__PURE__*/React.createElement("div", {
24280
- className: css(styles$w.measurer),
24278
+ className: css(styles$v.measurer),
24281
24279
  "aria-hidden": "true"
24282
24280
  }, /*#__PURE__*/React.createElement("div", {
24283
24281
  ref: ref => this._line = ref,
@@ -24285,7 +24283,7 @@ class LineHeightMeasurer extends React.Component {
24285
24283
  }, "Line Height Measurement"));
24286
24284
  }
24287
24285
  }
24288
- const styles$w = StyleSheet.create({
24286
+ const styles$v = StyleSheet.create({
24289
24287
  measurer: {
24290
24288
  position: "absolute",
24291
24289
  top: 0,
@@ -25262,11 +25260,11 @@ const FocusRing = function FocusRing({
25262
25260
  };
25263
25261
  return /*#__PURE__*/React.createElement("span", {
25264
25262
  "data-testid": "focus-ring",
25265
- className: css(styles$v.ring),
25263
+ className: css(styles$u.ring),
25266
25264
  style: style
25267
25265
  }, children);
25268
25266
  };
25269
- const styles$v = StyleSheet.create({
25267
+ const styles$u = StyleSheet.create({
25270
25268
  ring: {
25271
25269
  margin: "auto",
25272
25270
  display: "inline-block",
@@ -25293,7 +25291,7 @@ function getChoiceLetter(pos, strings) {
25293
25291
  }
25294
25292
 
25295
25293
  const CHOICE_ICON_SIZE = 24;
25296
- const styles$u = StyleSheet.create({
25294
+ const styles$t = StyleSheet.create({
25297
25295
  iconWrapper: {
25298
25296
  display: "inline-block",
25299
25297
  position: "relative"
@@ -25316,7 +25314,7 @@ const CrossOutLine = function CrossOutLine(props) {
25316
25314
  width: CROSS_OUT_LINE_SIZE,
25317
25315
  height: CROSS_OUT_LINE_SIZE,
25318
25316
  viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
25319
- className: css(styles$t.crossOutLine),
25317
+ className: css(styles$s.crossOutLine),
25320
25318
  "data-testid": "choice-icon__cross-out-line"
25321
25319
  }, /*#__PURE__*/React.createElement("line", {
25322
25320
  // The line stretches from the bottom-left to top-right.
@@ -25331,7 +25329,7 @@ const CrossOutLine = function CrossOutLine(props) {
25331
25329
  strokeLinecap: "round"
25332
25330
  }));
25333
25331
  };
25334
- const styles$t = StyleSheet.create({
25332
+ const styles$s = StyleSheet.create({
25335
25333
  crossOutLine: {
25336
25334
  // Center the icon within the container.
25337
25335
  position: "absolute",
@@ -25415,7 +25413,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
25415
25413
  } = props;
25416
25414
  const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
25417
25415
  return /*#__PURE__*/React.createElement("div", {
25418
- className: css(styles$u.iconWrapper)
25416
+ className: css(styles$t.iconWrapper)
25419
25417
  }, /*#__PURE__*/React.createElement(FocusRing, {
25420
25418
  color: color.blue,
25421
25419
  visible: focused || hovered,
@@ -25423,13 +25421,13 @@ const ChoiceIcon = function ChoiceIcon(props) {
25423
25421
  }, /*#__PURE__*/React.createElement("div", {
25424
25422
  style: dynamicStyles,
25425
25423
  "data-testid": "choice-icon__library-choice-icon",
25426
- className: css(styles$s.circle, showCorrectness && correct && styles$s.circleCorrect, showCorrectness && !correct && styles$s.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$s.circleIncorrectAnswered)
25424
+ className: css(styles$r.circle, showCorrectness && correct && styles$r.circleCorrect, showCorrectness && !correct && styles$r.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$r.circleIncorrectAnswered)
25427
25425
  // used in BaseRadio editMode to check
25428
25426
  // if we actually clicked on the radio icon
25429
25427
  ,
25430
25428
  "data-is-radio-icon": true
25431
25429
  }, /*#__PURE__*/React.createElement("div", {
25432
- className: css(styles$s.innerWrapper)
25430
+ className: css(styles$r.innerWrapper)
25433
25431
  }, /*#__PURE__*/React.createElement(ChoiceInner, {
25434
25432
  pos: pos,
25435
25433
  showCorrectness: showCorrectness,
@@ -25438,7 +25436,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
25438
25436
  color: dynamicStyles.borderColor
25439
25437
  }));
25440
25438
  };
25441
- const styles$s = StyleSheet.create({
25439
+ const styles$r = StyleSheet.create({
25442
25440
  innerWrapper: {
25443
25441
  width: CHOICE_ICON_SIZE,
25444
25442
  height: CHOICE_ICON_SIZE,
@@ -25533,19 +25531,19 @@ const OptionStatus = function OptionStatus(props) {
25533
25531
  }
25534
25532
  let textStyle;
25535
25533
  if (correct) {
25536
- textStyle = styles$r.correct;
25534
+ textStyle = styles$q.correct;
25537
25535
  } else {
25538
25536
  if (checked || previouslyAnswered) {
25539
- textStyle = styles$r.incorrectAnswered;
25537
+ textStyle = styles$q.incorrectAnswered;
25540
25538
  } else {
25541
- textStyle = styles$r.incorrect;
25539
+ textStyle = styles$q.incorrect;
25542
25540
  }
25543
25541
  }
25544
25542
  return /*#__PURE__*/React.createElement("div", {
25545
- className: css(styles$r.text, textStyle)
25543
+ className: css(styles$q.text, textStyle)
25546
25544
  }, renderText(checked, correct, crossedOut, strings));
25547
25545
  };
25548
- const styles$r = StyleSheet.create({
25546
+ const styles$q = StyleSheet.create({
25549
25547
  text: {
25550
25548
  alignItems: "center",
25551
25549
  display: "flex",
@@ -25615,8 +25613,8 @@ const Choice = function Choice(props) {
25615
25613
  crossedOut: updatedCrossedOut
25616
25614
  });
25617
25615
  }
25618
- const descriptionClassName = classNames$1("description", css(styles$q.description));
25619
- const rationaleClassName = classNames$1("perseus-radio-rationale-content", css(styles$q.rationale));
25616
+ const descriptionClassName = classNames$1("description", css(styles$p.description));
25617
+ const rationaleClassName = classNames$1("perseus-radio-rationale-content", css(styles$p.rationale));
25620
25618
 
25621
25619
  // We want to show the choices as dimmed out when the choices are disabled.
25622
25620
  // However, we don't want to do this when we're in review mode in the
@@ -25776,7 +25774,7 @@ const Choice = function Choice(props) {
25776
25774
  "data-testid": `perseus-radio-rationale-content-${pos}`
25777
25775
  }, rationale));
25778
25776
  };
25779
- const styles$q = StyleSheet.create({
25777
+ const styles$p = StyleSheet.create({
25780
25778
  description: {
25781
25779
  display: "inline-block",
25782
25780
  width: "100%"
@@ -25797,14 +25795,14 @@ var Choice$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.
25797
25795
  forwardedRef: ref
25798
25796
  })));
25799
25797
 
25800
- const _excluded$6 = ["content", "forwardedRef", "showContent"];
25798
+ const _excluded$5 = ["content", "forwardedRef", "showContent"];
25801
25799
  const ChoiceNoneAbove = function ChoiceNoneAbove(_ref) {
25802
25800
  let {
25803
25801
  content,
25804
25802
  forwardedRef,
25805
25803
  showContent = true
25806
25804
  } = _ref,
25807
- rest = _objectWithoutPropertiesLoose(_ref, _excluded$6);
25805
+ rest = _objectWithoutPropertiesLoose(_ref, _excluded$5);
25808
25806
  const {
25809
25807
  strings
25810
25808
  } = usePerseusI18n();
@@ -25966,10 +25964,10 @@ const BaseRadio = function BaseRadio({
25966
25964
  const isMobile = apiOptions.isMobile;
25967
25965
  const firstChoiceHighlighted = choices[0].highlighted;
25968
25966
  const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
25969
- const className = classNames$1("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$p.radio, styles$p.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$p.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$p.radioContainerLastHighlighted));
25970
- const instructionsClassName = classNames$1("instructions", css(styles$p.instructions, isMobile && styles$p.instructionsMobile));
25967
+ const className = classNames$1("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$o.radio, styles$o.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$o.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$o.radioContainerLastHighlighted));
25968
+ const instructionsClassName = classNames$1("instructions", css(styles$o.instructions, isMobile && styles$o.instructionsMobile));
25971
25969
  const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
25972
- const responsiveClassName = css(styles$p.responsiveFieldset);
25970
+ const responsiveClassName = css(styles$o.responsiveFieldset);
25973
25971
  const fieldset = /*#__PURE__*/React.createElement("fieldset", {
25974
25972
  className: `perseus-widget-radio-fieldset ${responsiveClassName}`
25975
25973
  }, /*#__PURE__*/React.createElement("legend", {
@@ -26020,7 +26018,7 @@ const BaseRadio = function BaseRadio({
26020
26018
  const aphroditeClassName = checked => {
26021
26019
  // Whether or not to show correctness borders
26022
26020
  // for this choice and the next choice.
26023
- return 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);
26021
+ return 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);
26024
26022
  };
26025
26023
 
26026
26024
  // HACK(abdulrahman): Preloads the selection-state
@@ -26085,10 +26083,10 @@ const BaseRadio = function BaseRadio({
26085
26083
  // Allow for horizontal scrolling if content is too wide, which may be
26086
26084
  // an issue especially on phones.
26087
26085
  return /*#__PURE__*/React.createElement("div", {
26088
- className: css(styles$p.responsiveContainer)
26086
+ className: css(styles$o.responsiveContainer)
26089
26087
  }, fieldset);
26090
26088
  };
26091
- const styles$p = StyleSheet.create({
26089
+ const styles$o = StyleSheet.create({
26092
26090
  instructions: {
26093
26091
  display: "block",
26094
26092
  color: gray17,
@@ -26580,7 +26578,7 @@ Radio$1.defaultProps = {
26580
26578
  showSolutions: "none"
26581
26579
  };
26582
26580
 
26583
- const _excluded$5 = ["noneOfTheAbove"];
26581
+ const _excluded$4 = ["noneOfTheAbove"];
26584
26582
  const {
26585
26583
  shuffle: shuffle$2,
26586
26584
  random
@@ -26672,7 +26670,7 @@ const propUpgrades$1 = {
26672
26670
  const {
26673
26671
  noneOfTheAbove
26674
26672
  } = v0props,
26675
- rest = _objectWithoutPropertiesLoose(v0props, _excluded$5);
26673
+ rest = _objectWithoutPropertiesLoose(v0props, _excluded$4);
26676
26674
  if (noneOfTheAbove) {
26677
26675
  throw new Error("radio widget v0 no longer supports auto noneOfTheAbove");
26678
26676
  }
@@ -26795,9 +26793,9 @@ class Categorizer extends React.Component {
26795
26793
  indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
26796
26794
  }
26797
26795
  const table = /*#__PURE__*/React.createElement("table", {
26798
- className: "categorizer-table " + css(styles$o.mobileTable)
26796
+ className: "categorizer-table " + css(styles$n.mobileTable)
26799
26797
  }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
26800
- className: css(styles$o.emptyHeaderCell)
26798
+ className: css(styles$n.emptyHeaderCell)
26801
26799
  }), this.props.categories.map((category, i) => {
26802
26800
  // Array index is the correct key here, as that's
26803
26801
  // how category grading actually works -- no way
@@ -26805,7 +26803,7 @@ class Categorizer extends React.Component {
26805
26803
  // middle. (If we later add that, this should be
26806
26804
  // fixed.)
26807
26805
  return /*#__PURE__*/React.createElement("th", {
26808
- className: css(styles$o.header),
26806
+ className: css(styles$n.header),
26809
26807
  key: i
26810
26808
  }, /*#__PURE__*/React.createElement(Renderer, {
26811
26809
  content: category,
@@ -26827,7 +26825,7 @@ class Categorizer extends React.Component {
26827
26825
  })), self.props.categories.map((catName, catNum) => {
26828
26826
  const selected = self.props.values[itemNum] === catNum;
26829
26827
  return /*#__PURE__*/React.createElement("td", {
26830
- className: "category " + css(styles$o.cell),
26828
+ className: "category " + css(styles$n.cell),
26831
26829
  key: catNum
26832
26830
  }, /*#__PURE__*/React.createElement("div", {
26833
26831
  className: ClassNames.INTERACTIVE,
@@ -26842,7 +26840,7 @@ class Categorizer extends React.Component {
26842
26840
  onChange: () => this.onChange(itemNum, catNum),
26843
26841
  onClick: e => e.stopPropagation()
26844
26842
  }), !isMobile && /*#__PURE__*/React.createElement("span", {
26845
- className: css(styles$o.radioSpan, selected && styles$o.checkedRadioSpan, this.props.static && selected && styles$o.staticCheckedRadioSpan)
26843
+ className: css(styles$n.radioSpan, selected && styles$n.checkedRadioSpan, this.props.static && selected && styles$n.staticCheckedRadioSpan)
26846
26844
  }, selected ? /*#__PURE__*/React.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React.createElement(InlineIcon, iconCircleThin))));
26847
26845
  }));
26848
26846
  /* eslint-enable max-len */
@@ -26854,7 +26852,7 @@ class Categorizer extends React.Component {
26854
26852
  "categorizer-container": true,
26855
26853
  "static-mode": this.props.static
26856
26854
  });
26857
- const inlineStyles = this.props.apiOptions.isMobile ? [styles$o.fullBleedContainer] : [];
26855
+ const inlineStyles = this.props.apiOptions.isMobile ? [styles$n.fullBleedContainer] : [];
26858
26856
  return /*#__PURE__*/React.createElement("div", {
26859
26857
  className: extraClassNames + " " + css(...inlineStyles)
26860
26858
  }, table);
@@ -26873,7 +26871,7 @@ const pageMargin = 16;
26873
26871
 
26874
26872
  // Stylesheets aren't directly testable
26875
26873
  /* c8 ignore next */
26876
- const styles$o = StyleSheet.create({
26874
+ const styles$n = StyleSheet.create({
26877
26875
  mobileTable: {
26878
26876
  [mediaQueries.smOrSmaller]: {
26879
26877
  minWidth: "auto"
@@ -27131,7 +27129,7 @@ class CSProgram extends React.Component {
27131
27129
  // creator "went wild".
27132
27130
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
27133
27131
  return /*#__PURE__*/React.createElement("div", {
27134
- className: css(styles$n.widthOverride, styleContainer && styles$n.container)
27132
+ className: css(styles$m.widthOverride, styleContainer && styles$m.container)
27135
27133
  }, /*#__PURE__*/React.createElement("iframe", {
27136
27134
  sandbox: sandboxOptions,
27137
27135
  src: url,
@@ -27148,7 +27146,7 @@ CSProgram.defaultProps = {
27148
27146
  // optional message
27149
27147
  message: null
27150
27148
  };
27151
- const styles$n = StyleSheet.create({
27149
+ const styles$m = StyleSheet.create({
27152
27150
  // Override the inherited width from the perseus paragraph class
27153
27151
  // 820 is minimum width for 420px editor and 400px canvas
27154
27152
  widthOverride: {
@@ -27194,7 +27192,7 @@ class Definition extends React.Component {
27194
27192
  }) => /*#__PURE__*/React.createElement(Popover, {
27195
27193
  content: /*#__PURE__*/React.createElement(PopoverContentCore, {
27196
27194
  color: "white",
27197
- style: styles$m.tooltipBody,
27195
+ style: styles$l.tooltipBody,
27198
27196
  closeButtonVisible: true
27199
27197
  }, /*#__PURE__*/React.createElement(Renderer, {
27200
27198
  apiOptions: this.props.apiOptions,
@@ -27227,7 +27225,7 @@ Definition.defaultProps = {
27227
27225
  togglePrompt: "define me",
27228
27226
  definition: "definition goes here"
27229
27227
  };
27230
- const styles$m = {
27228
+ const styles$l = {
27231
27229
  tooltipBody: {
27232
27230
  color: color.offBlack,
27233
27231
  fontSize: 20,
@@ -27352,7 +27350,7 @@ class Dropdown extends React.Component {
27352
27350
  key: "placeholder",
27353
27351
  value: "0",
27354
27352
  disabled: true,
27355
- label: this.props.placeholder
27353
+ label: this.props.placeholder || " "
27356
27354
  }), ...this.props.choices.map((choice, i) => /*#__PURE__*/React.createElement(OptionItem, {
27357
27355
  key: String(i + 1),
27358
27356
  value: String(i + 1),
@@ -27373,15 +27371,14 @@ class Dropdown extends React.Component {
27373
27371
  }
27374
27372
  }, this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelLarge, {
27375
27373
  tag: "label",
27376
- id: ids.get("dropdown-label")
27374
+ htmlFor: ids.get("dropdown")
27377
27375
  }, this.props.visibleLabel), /*#__PURE__*/React.createElement(SingleSelect, {
27378
27376
  id: ids.get("dropdown"),
27379
27377
  placeholder: "",
27380
27378
  onChange: value => this._handleChange(parseInt(value)),
27381
27379
  selectedValue: String(this.props.selected),
27382
27380
  disabled: this.props.apiOptions.readOnly,
27383
- "aria-label": this.props.ariaLabel || this.context.strings.selectAnAnswer,
27384
- "aria-labelledby": ids.get("dropdown-label")
27381
+ "aria-label": this.props.ariaLabel || this.props.visibleLabel || this.context.strings.selectAnAnswer
27385
27382
  // This is currently necessary for SRs to read the labels properly.
27386
27383
  // However, WB is working on a change to add the "combobox" role to
27387
27384
  // all dropdowns.
@@ -27490,7 +27487,7 @@ class Explanation extends React.Component {
27490
27487
  marginRight: "-6px",
27491
27488
  "white-space": "normal"
27492
27489
  };
27493
- const contentStyling = [styles$l.content, this.state.expanded ? styles$l.contentExpanded : styles$l.contentCollapsed, allowTransition && (this.state.expanded ? styles$l.transitionExpanded : styles$l.transitionCollapsed)];
27490
+ const contentStyling = [styles$k.content, this.state.expanded ? styles$k.contentExpanded : styles$k.contentCollapsed, allowTransition && (this.state.expanded ? styles$k.transitionExpanded : styles$k.transitionCollapsed)];
27494
27491
  return /*#__PURE__*/React.createElement(UniqueIDProvider, {
27495
27492
  mockOnFirstRender: true,
27496
27493
  scope: "explanation-widget"
@@ -27509,7 +27506,7 @@ class Explanation extends React.Component {
27509
27506
  "aria-hidden": !this.state.expanded,
27510
27507
  testId: "content-container"
27511
27508
  }, /*#__PURE__*/React.createElement(View, {
27512
- style: styles$l.contentWrapper
27509
+ style: styles$k.contentWrapper
27513
27510
  }, /*#__PURE__*/React.createElement(Renderer, {
27514
27511
  apiOptions: this.props.apiOptions,
27515
27512
  content: this.props.explanation,
@@ -27530,7 +27527,7 @@ Explanation.defaultProps = {
27530
27527
  const leftBorderSpacing = 23;
27531
27528
  const verticalContentPadding = 10;
27532
27529
  const arrowHeight = 14;
27533
- const styles$l = StyleSheet.create({
27530
+ const styles$k = StyleSheet.create({
27534
27531
  content: {
27535
27532
  borderLeft: "0px solid #ccc",
27536
27533
  display: "inline-grid",
@@ -27613,15 +27610,15 @@ class GradedGroupAnswerBar extends React.Component {
27613
27610
  correctExcited,
27614
27611
  nextQuestion
27615
27612
  } = this.context.strings;
27616
- const answerBarStyle = _extends({}, styles$k.answerBar, {
27613
+ const answerBarStyle = _extends({}, styles$j.answerBar, {
27617
27614
  backgroundColor: answerBarState === "CORRECT" ? color.offWhite : "white",
27618
27615
  // Center the "Correct!" message only when there's no next question
27619
27616
  justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
27620
27617
  });
27621
27618
  const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React.createElement("span", {
27622
- style: styles$k.text
27619
+ style: styles$j.text
27623
27620
  }, /*#__PURE__*/React.createElement("span", {
27624
- style: styles$k.tryAgainIcon
27621
+ style: styles$j.tryAgainIcon
27625
27622
  }, /*#__PURE__*/React.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React.createElement("span", {
27626
27623
  style: {
27627
27624
  marginLeft: 8
@@ -27640,7 +27637,7 @@ class GradedGroupAnswerBar extends React.Component {
27640
27637
  return /*#__PURE__*/React.createElement("div", {
27641
27638
  style: answerBarStyle
27642
27639
  }, /*#__PURE__*/React.createElement("span", {
27643
- style: styles$k.text
27640
+ style: styles$j.text
27644
27641
  }, /*#__PURE__*/React.createElement("span", {
27645
27642
  style: {
27646
27643
  fontSize: 28,
@@ -27663,7 +27660,7 @@ class GradedGroupAnswerBar extends React.Component {
27663
27660
  }
27664
27661
  GradedGroupAnswerBar.contextType = PerseusI18nContext;
27665
27662
  const fontSize = 17;
27666
- const styles$k = {
27663
+ const styles$j = {
27667
27664
  answerBar: {
27668
27665
  display: "flex",
27669
27666
  alignItems: "center",
@@ -27848,7 +27845,7 @@ class GradedGroup extends React.Component {
27848
27845
  }));
27849
27846
  gradeStatus = this.context.strings.incorrect;
27850
27847
  }
27851
- const mobileClass = this.props.inGradedGroupSet ? css(styles$j.gradedGroupInSet) : css(styles$j.gradedGroup);
27848
+ const mobileClass = this.props.inGradedGroupSet ? css(styles$i.gradedGroupInSet) : css(styles$i.gradedGroup);
27852
27849
  const classes = classNames$1({
27853
27850
  [mobileClass]: apiOptions.isMobile,
27854
27851
  "perseus-graded-group": true,
@@ -27867,7 +27864,7 @@ class GradedGroup extends React.Component {
27867
27864
  return /*#__PURE__*/React.createElement("div", {
27868
27865
  className: classes
27869
27866
  }, !!this.props.title && /*#__PURE__*/React.createElement("div", {
27870
- className: css(styles$j.title)
27867
+ className: css(styles$i.title)
27871
27868
  }, this.props.title), /*#__PURE__*/React.createElement(Renderer, _extends({}, this.props, {
27872
27869
  ref: this.rendererRef,
27873
27870
  apiOptions: _extends({}, apiOptions, {
@@ -27899,7 +27896,7 @@ class GradedGroup extends React.Component {
27899
27896
  }, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
27900
27897
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
27901
27898
  tabIndex: "0",
27902
- className: css(styles$j.explanationTitle),
27899
+ className: css(styles$i.explanationTitle),
27903
27900
  onClick: () => this.setState({
27904
27901
  showHint: false
27905
27902
  }),
@@ -27931,7 +27928,7 @@ class GradedGroup extends React.Component {
27931
27928
  showHint: true
27932
27929
  });
27933
27930
  },
27934
- className: css(styles$j.showHintLink)
27931
+ className: css(styles$i.showHintLink)
27935
27932
  }, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React.createElement(GradedGroupAnswerBar, {
27936
27933
  apiOptions: apiOptions,
27937
27934
  answerBarState: answerBarState,
@@ -27953,7 +27950,7 @@ GradedGroup.defaultProps = {
27953
27950
  const traverseChildWidgets$2 = function traverseChildWidgets(props, traverseRenderer) {
27954
27951
  return _.extend({}, props, traverseRenderer(props));
27955
27952
  };
27956
- const styles$j = StyleSheet.create({
27953
+ const styles$i = StyleSheet.create({
27957
27954
  gradedGroupInSet: {
27958
27955
  // Reset a few desktop-only styles that come from graded-group.less
27959
27956
  marginLeft: 0,
@@ -28036,18 +28033,18 @@ class Indicators extends React.Component {
28036
28033
  return /*#__PURE__*/React.createElement("ul", {
28037
28034
  // reduntantly add class name for use in .less files--
28038
28035
  // the styles object key gets hashed
28039
- className: classNames$1(css(styles$i.indicatorContainer), "indicatorContainer")
28036
+ className: classNames$1(css(styles$h.indicatorContainer), "indicatorContainer")
28040
28037
  }, this.props.gradedGroups.map(({
28041
28038
  title
28042
28039
  }, i) => /*#__PURE__*/React.createElement("li", {
28043
- className: css(styles$i.indicator),
28040
+ className: css(styles$h.indicator),
28044
28041
  key: title
28045
28042
  }, /*#__PURE__*/React.createElement(Clickable, {
28046
28043
  role: "button",
28047
28044
  "aria-label": this.context.strings.skipToTitle({
28048
28045
  title
28049
28046
  }),
28050
- style: styles$i.indicatorButton,
28047
+ style: styles$h.indicatorButton,
28051
28048
  onClick: () => this.props.onChangeCurrentGroup(i),
28052
28049
  onKeyDown: e => this.handleKeyDown(e, i)
28053
28050
  }, ({
@@ -28055,9 +28052,9 @@ class Indicators extends React.Component {
28055
28052
  focused,
28056
28053
  pressed
28057
28054
  }) => /*#__PURE__*/React.createElement(View, {
28058
- style: [styles$i.indicatorDot, (hovered || focused || pressed) && styles$i.indicatorDotFocused]
28055
+ style: [styles$h.indicatorDot, (hovered || focused || pressed) && styles$h.indicatorDotFocused]
28059
28056
  }, i === this.props.currentGroup && /*#__PURE__*/React.createElement(View, {
28060
- style: styles$i.indicatorDotActive
28057
+ style: styles$h.indicatorDotActive
28061
28058
  }, /*#__PURE__*/React.createElement("span", {
28062
28059
  className: css(a11y.srOnly)
28063
28060
  }, this.context.strings.current)))))));
@@ -28125,7 +28122,7 @@ class GradedGroupSet extends React.Component {
28125
28122
  } = getDependencies();
28126
28123
  if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
28127
28124
  return /*#__PURE__*/React.createElement("div", {
28128
- className: css(styles$i.container)
28125
+ className: css(styles$h.container)
28129
28126
  }, this.props.gradedGroups.map((gradedGroup, i) => {
28130
28127
  return (
28131
28128
  /*#__PURE__*/
@@ -28148,13 +28145,13 @@ class GradedGroupSet extends React.Component {
28148
28145
  const numGroups = this.props.gradedGroups.length;
28149
28146
  const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
28150
28147
  return /*#__PURE__*/React.createElement("div", {
28151
- className: css(styles$i.container)
28148
+ className: css(styles$h.container)
28152
28149
  }, /*#__PURE__*/React.createElement("div", {
28153
- className: css(styles$i.top)
28150
+ className: css(styles$h.top)
28154
28151
  }, /*#__PURE__*/React.createElement("div", {
28155
- className: css(styles$i.title)
28152
+ className: css(styles$h.title)
28156
28153
  }, currentGroup.title), /*#__PURE__*/React.createElement("div", {
28157
- className: css(styles$i.spacer)
28154
+ className: css(styles$h.spacer)
28158
28155
  }), /*#__PURE__*/React.createElement(Indicators, {
28159
28156
  currentGroup: this.state.currentGroup,
28160
28157
  gradedGroups: this.props.gradedGroups,
@@ -28196,7 +28193,7 @@ var GradedGroupSet$1 = {
28196
28193
  tracking: "all",
28197
28194
  isLintable: true
28198
28195
  };
28199
- const styles$i = StyleSheet.create({
28196
+ const styles$h = StyleSheet.create({
28200
28197
  top: {
28201
28198
  display: "flex",
28202
28199
  flexDirection: "row"
@@ -28301,7 +28298,7 @@ class ButtonGroup extends React.Component {
28301
28298
  id: "" + i,
28302
28299
  ref: "button" + i,
28303
28300
  key: "" + i,
28304
- className: css(styles$h.buttonStyle, button.value === value && styles$h.selectedStyle),
28301
+ className: css(styles$g.buttonStyle, button.value === value && styles$g.selectedStyle),
28305
28302
  onClick: () => this.toggleSelect(button.value)
28306
28303
  }, button.content || "" + button.value);
28307
28304
  });
@@ -28318,7 +28315,7 @@ ButtonGroup.defaultProps = {
28318
28315
  value: null,
28319
28316
  allowEmpty: true
28320
28317
  };
28321
- const styles$h = StyleSheet.create({
28318
+ const styles$g = StyleSheet.create({
28322
28319
  buttonStyle: {
28323
28320
  backgroundColor: "white",
28324
28321
  border: "1px solid #ccc",
@@ -31659,7 +31656,7 @@ const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
31659
31656
  width: "24",
31660
31657
  height: "24",
31661
31658
  viewBox: "0 0 24 24",
31662
- className: css(styles$g.icon)
31659
+ className: css(styles$f.icon)
31663
31660
  }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
31664
31661
  id: "a",
31665
31662
  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"
@@ -31690,7 +31687,7 @@ const HiddenIcon = () => /*#__PURE__*/React.createElement("svg", {
31690
31687
  width: "24",
31691
31688
  height: "24",
31692
31689
  viewBox: "0 0 24 24",
31693
- className: css(styles$g.icon)
31690
+ className: css(styles$f.icon)
31694
31691
  }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
31695
31692
  id: "a",
31696
31693
  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"
@@ -31728,20 +31725,20 @@ const HUD = ({
31728
31725
  let state;
31729
31726
  let icon;
31730
31727
  if (enabled) {
31731
- state = styles$g.enabled;
31728
+ state = styles$f.enabled;
31732
31729
  icon = /*#__PURE__*/React.createElement(VisibleIcon, null);
31733
31730
  } else {
31734
- state = styles$g.disabled;
31731
+ state = styles$f.disabled;
31735
31732
  icon = /*#__PURE__*/React.createElement(HiddenIcon, null);
31736
31733
  }
31737
31734
  return /*#__PURE__*/React.createElement("button", {
31738
- className: css(styles$g.hud, _fixedPosition && styles$g.hudFixedPosition, state),
31735
+ className: css(styles$f.hud, _fixedPosition && styles$f.hudFixedPosition, state),
31739
31736
  onClick: e => {
31740
31737
  onClick();
31741
31738
  }
31742
31739
  }, icon, message);
31743
31740
  };
31744
- const styles$g = StyleSheet.create({
31741
+ const styles$f = StyleSheet.create({
31745
31742
  hud: {
31746
31743
  boxSizing: "border-box",
31747
31744
  height: 36,
@@ -31794,16 +31791,16 @@ const styles$g = StyleSheet.create({
31794
31791
  const InfoTipBase = props => {
31795
31792
  return /*#__PURE__*/React.createElement(Tooltip$1, {
31796
31793
  content: /*#__PURE__*/React.createElement(Body, {
31797
- style: styles$f.body
31794
+ style: styles$e.body
31798
31795
  }, props.children),
31799
31796
  placement: "right"
31800
31797
  }, /*#__PURE__*/React.createElement(PhosphorIcon, {
31801
31798
  size: "small",
31802
31799
  icon: questionIcon,
31803
- style: styles$f.spacingLeft
31800
+ style: styles$e.spacingLeft
31804
31801
  }));
31805
31802
  };
31806
- const styles$f = StyleSheet.create({
31803
+ const styles$e = StyleSheet.create({
31807
31804
  spacingLeft: {
31808
31805
  marginInlineStart: spacing.xxxSmall_4
31809
31806
  },
@@ -31882,7 +31879,7 @@ class MultiButtonGroup extends React.Component {
31882
31879
  id: "" + i,
31883
31880
  key: "" + i,
31884
31881
  ref: "button" + i,
31885
- className: css(styles$e.buttonStyle, selected && styles$e.selectedStyle),
31882
+ className: css(styles$d.buttonStyle, selected && styles$d.selectedStyle),
31886
31883
  onClick: () => this.toggleSelect(button.value)
31887
31884
  }, button.content || "" + button.value);
31888
31885
  });
@@ -31899,7 +31896,7 @@ MultiButtonGroup.defaultProps = {
31899
31896
  values: [],
31900
31897
  allowEmpty: true
31901
31898
  };
31902
- const styles$e = StyleSheet.create({
31899
+ const styles$d = StyleSheet.create({
31903
31900
  buttonStyle: {
31904
31901
  backgroundColor: "white",
31905
31902
  border: "1px solid #ccc",
@@ -31932,7 +31929,7 @@ const styles$e = StyleSheet.create({
31932
31929
  }
31933
31930
  });
31934
31931
 
31935
- const _excluded$4 = ["onFormatChange", "checkValidity", "useArrowKeys"];
31932
+ const _excluded$3 = ["onFormatChange", "checkValidity", "useArrowKeys"];
31936
31933
  const {
31937
31934
  firstNumericalParse,
31938
31935
  captureScratchpadTouchStart
@@ -32086,7 +32083,7 @@ class NumberInput extends React.Component {
32086
32083
  classes = classes + " " + this.props.className;
32087
32084
  }
32088
32085
  const _this$props = this.props,
32089
- restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$4);
32086
+ restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$3);
32090
32087
  return /*#__PURE__*/React.createElement("input", _extends({}, restProps, {
32091
32088
  className: classes,
32092
32089
  type: "text",
@@ -32225,11 +32222,39 @@ const LegacyGrid = ({
32225
32222
  return null;
32226
32223
  };
32227
32224
 
32225
+ /**
32226
+ * The Perseus "data schema" file.
32227
+ *
32228
+ * This file, and the types in it, represents the "data schema" that Perseus
32229
+ * uses. The @khanacademy/perseus-editor package edits and produces objects
32230
+ * that conform to the types in this file. Similarly, the top-level renderers
32231
+ * in @khanacademy/perseus, consume objects that conform to these types.
32232
+ *
32233
+ * WARNING: This file should not import any types from elsewhere so that it is
32234
+ * easy to reason about changes that alter the Perseus schema. This helps
32235
+ * ensure that it is not changed accidentally when upgrading a dependant
32236
+ * package or other part of Perseus code. Note that TypeScript does type
32237
+ * checking via something called "structural typing". This means that as long
32238
+ * as the shape of a type matches, the name it goes by doesn't matter. As a
32239
+ * result, a `Coord` type that looks like this `[x: number, y: number]` is
32240
+ * _identical_, in TypeScript's eyes, to this `Vector2` type `[x: number, y:
32241
+ * number]`. Also, with tuples, the labels for each entry is ignored, so `[x:
32242
+ * number, y: number]` is compatible with `[min: number, max: number]`. The
32243
+ * labels are for humans, not TypeScript. :)
32244
+ *
32245
+ * If you make changes to types in this file, be very sure that:
32246
+ *
32247
+ * a) the changes are backwards compatible. If they are not, old data from
32248
+ * previous versions of the "schema" could become unrenderable, or worse,
32249
+ * introduce hard-to-diagnose bugs.
32250
+ * b) the parsing code (`util/parse-perseus-json/`) is updated to handle
32251
+ * the new format _as well as_ the old format.
32252
+ */
32253
+
32228
32254
  // TODO(FEI-4010): Remove `Perseus` prefix for all types here
32229
- // TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
32230
32255
 
32231
- // Range is replaced within this file with Interval, but it is used elsewhere
32232
- // and exported from the package, so we need to keep it around.
32256
+ // Same name as Mafs
32257
+
32233
32258
  /**
32234
32259
  * Our core set of Perseus widgets.
32235
32260
  *
@@ -32273,6 +32298,7 @@ const LegacyGrid = ({
32273
32298
  *
32274
32299
  * @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
32275
32300
  */
32301
+
32276
32302
  /**
32277
32303
  * A map of widget IDs to widget options. This is most often used as the type
32278
32304
  * for a set of widgets defined in a `PerseusItem` but can also be useful to
@@ -32285,6 +32311,7 @@ const LegacyGrid = ({
32285
32311
  * @see {@link PerseusWidgetTypes} additional widgets can be added to this map type
32286
32312
  * by augmenting the PerseusWidgetTypes with new widget types!
32287
32313
  */
32314
+
32288
32315
  /**
32289
32316
  * A "PerseusItem" is a classic Perseus item. It is rendered by the
32290
32317
  * `ServerItemRenderer` and the layout is pre-set.
@@ -32292,18 +32319,12 @@ const LegacyGrid = ({
32292
32319
  * To render more complex Perseus items, see the `Item` type in the multi item
32293
32320
  * area.
32294
32321
  */
32322
+
32295
32323
  /**
32296
32324
  * A "PerseusArticle" is an item that is meant to be rendered as an article.
32297
32325
  * This item is never scored and is rendered by the `ArticleRenderer`.
32298
32326
  */
32299
- /**
32300
- * A "MultiItem" is an advanced Perseus item. It is rendered by the
32301
- * `MultiRenderer` and you can control the layout of individual parts of the
32302
- * item.
32303
- *
32304
- * @deprecated MultiItem support is slated for removal in a future Perseus
32305
- * release.
32306
- */
32327
+
32307
32328
  const ItemExtras = [
32308
32329
  // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
32309
32330
  "calculator",
@@ -33076,12 +33097,12 @@ const MafsCssTransformWrapper = ({
33076
33097
  }
33077
33098
  }, children);
33078
33099
 
33079
- const _excluded$3 = ["children"];
33100
+ const _excluded$2 = ["children"];
33080
33101
  const TextLabel = _ref => {
33081
33102
  let {
33082
33103
  children
33083
33104
  } = _ref,
33084
- rest = _objectWithoutPropertiesLoose(_ref, _excluded$3);
33105
+ rest = _objectWithoutPropertiesLoose(_ref, _excluded$2);
33085
33106
  return /*#__PURE__*/React__default.createElement(Text$1, _extends({
33086
33107
  size: 16,
33087
33108
  svgTextProps: {
@@ -38711,7 +38732,7 @@ const HideAnswersToggle = props => {
38711
38732
  strings
38712
38733
  } = usePerseusI18n();
38713
38734
  return /*#__PURE__*/React.createElement(View, {
38714
- style: styles$d.switchWrapper
38735
+ style: styles$c.switchWrapper
38715
38736
  }, /*#__PURE__*/React.createElement(Switch, {
38716
38737
  id: switchId,
38717
38738
  checked: props.areAnswersHidden,
@@ -38723,7 +38744,7 @@ const HideAnswersToggle = props => {
38723
38744
  tag: "label"
38724
38745
  }, strings.hideAnswersToggleLabel));
38725
38746
  };
38726
- const styles$d = StyleSheet.create({
38747
+ const styles$c = StyleSheet.create({
38727
38748
  switchWrapper: {
38728
38749
  display: "flex",
38729
38750
  flexDirection: "row",
@@ -38779,14 +38800,14 @@ const AnswerPill = props => {
38779
38800
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
38780
38801
  onClick: correct ? undefined : onClick,
38781
38802
  ref: ref,
38782
- style: [style, popperStyle, styles$c.pill, correct && styles$c.correct, incorrect && styles$c.incorrect, (focused || hovered) && BringToFront]
38803
+ style: [style, popperStyle, styles$b.pill, correct && styles$b.correct, incorrect && styles$b.incorrect, (focused || hovered) && BringToFront]
38783
38804
  }, /*#__PURE__*/React.createElement(Renderer, {
38784
38805
  content: answerString,
38785
38806
  strings: strings,
38786
38807
  inline: true
38787
38808
  })));
38788
38809
  };
38789
- const styles$c = StyleSheet.create({
38810
+ const styles$b = StyleSheet.create({
38790
38811
  correct: {
38791
38812
  // WB green darkened by 18%
38792
38813
  backgroundColor: "#00880b"
@@ -38850,23 +38871,23 @@ class Marker extends React.Component {
38850
38871
  icon: iconNull
38851
38872
  };
38852
38873
  if (showCorrectness) {
38853
- iconStyles = [styles$b.markerGraded, showCorrectness === "correct" ? styles$b.markerCorrect : styles$b.markerIncorrect, isOpen && styles$b.markerSelected];
38874
+ iconStyles = [styles$a.markerGraded, showCorrectness === "correct" ? styles$a.markerCorrect : styles$a.markerIncorrect, isOpen && styles$a.markerSelected];
38854
38875
  args = _extends({}, args, {
38855
38876
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
38856
38877
  });
38857
38878
  } else if (selectedAnswers && selectedAnswers.length > 0) {
38858
- iconStyles = [styles$b.markerFilled, isOpen && styles$b.markerSelected];
38879
+ iconStyles = [styles$a.markerFilled, isOpen && styles$a.markerSelected];
38859
38880
  } else if (isOpen) {
38860
- iconStyles = [styles$b.markerSelected];
38881
+ iconStyles = [styles$a.markerSelected];
38861
38882
  args = _extends({}, args, {
38862
38883
  icon: iconChevronDown,
38863
38884
  size: 8
38864
38885
  });
38865
38886
  } else if (showPulsate) {
38866
- iconStyles = [styles$b.markerPulsateBase, this._mounted && shouldReduceMotion() ? showPulsate && styles$b.markerUnfilledPulsateOnce : showPulsate && styles$b.markerUnfilledPulsateInfinite];
38887
+ iconStyles = [styles$a.markerPulsateBase, this._mounted && shouldReduceMotion() ? showPulsate && styles$a.markerUnfilledPulsateOnce : showPulsate && styles$a.markerUnfilledPulsateInfinite];
38867
38888
  }
38868
38889
  return /*#__PURE__*/React.createElement(View, {
38869
- style: [styles$b.markerIcon, iconStyles],
38890
+ style: [styles$a.markerIcon, iconStyles],
38870
38891
  ref: node => this._icon = node
38871
38892
  }, /*#__PURE__*/React.createElement(Icon, args));
38872
38893
  }
@@ -38888,7 +38909,7 @@ class Marker extends React.Component {
38888
38909
  const markerDisabled = showCorrectness === "correct";
38889
38910
  const active = hovered || focused;
38890
38911
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
38891
- style: [styles$b.marker, active && !markerDisabled && styles$b.markerActive],
38912
+ style: [styles$a.marker, active && !markerDisabled && styles$a.markerActive],
38892
38913
  "aria-label": markerDisabled ? this.context.strings.correctExcited : label
38893
38914
  }, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React.createElement(AnswerPill, {
38894
38915
  selectedAnswers: selected,
@@ -38905,7 +38926,7 @@ Marker.contextType = PerseusI18nContext;
38905
38926
  Marker.defaultProps = {
38906
38927
  selected: []
38907
38928
  };
38908
- const styles$b = StyleSheet.create({
38929
+ const styles$a = StyleSheet.create({
38909
38930
  marker: {
38910
38931
  position: "absolute",
38911
38932
  backgroundColor: color.white,
@@ -39490,13 +39511,13 @@ class LabelImage extends React.Component {
39490
39511
  const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
39491
39512
  const choicesString = strings.choices;
39492
39513
  return /*#__PURE__*/React.createElement("div", {
39493
- className: classNames$1("perseus-label-image-widget-instructions", css(styles$a.instructions))
39514
+ className: classNames$1("perseus-label-image-widget-instructions", css(styles$9.instructions))
39494
39515
  }, /*#__PURE__*/React.createElement("div", {
39495
- className: css(styles$a.instructionsCaption)
39516
+ className: css(styles$9.instructionsCaption)
39496
39517
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React.createElement("div", {
39497
- className: css(styles$a.instructionsChoices)
39518
+ className: css(styles$9.instructionsChoices)
39498
39519
  }, choices.map((choice, index) => /*#__PURE__*/React.createElement("div", {
39499
- className: css(styles$a.instructionsChoice),
39520
+ className: css(styles$9.instructionsChoice),
39500
39521
  key: index
39501
39522
  }, /*#__PURE__*/React.createElement(Renderer, {
39502
39523
  content: choice,
@@ -39514,20 +39535,20 @@ class LabelImage extends React.Component {
39514
39535
  activeMarkerIndex
39515
39536
  } = this.state;
39516
39537
  return /*#__PURE__*/React.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React.createElement("div", {
39517
- className: css(styles$a.markersCanvas),
39538
+ className: css(styles$9.markersCanvas),
39518
39539
  style: {
39519
39540
  maxWidth: imageWidth,
39520
39541
  maxHeight: imageHeight
39521
39542
  }
39522
39543
  }, /*#__PURE__*/React.createElement("div", {
39523
- className: css(styles$a.imageContainer,
39544
+ className: css(styles$9.imageContainer,
39524
39545
  // Ensure image interaction is disabled while answer
39525
39546
  // choices popup is visible. This addresses specific
39526
39547
  // case where user may click on question image to
39527
39548
  // dismiss the popup. If the image is larger in size
39528
39549
  // than its rendered in the widget, this would
39529
39550
  // result in a zoom of the image.
39530
- activeMarkerIndex !== -1 && styles$a.imageInteractionDisabled)
39551
+ activeMarkerIndex !== -1 && styles$9.imageInteractionDisabled)
39531
39552
  }, /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
39532
39553
  setAssetStatus
39533
39554
  }) => /*#__PURE__*/React.createElement(SvgImage, {
@@ -39552,7 +39573,7 @@ class LabelImage extends React.Component {
39552
39573
  }
39553
39574
  }
39554
39575
  LabelImage.contextType = PerseusI18nContext;
39555
- const styles$a = StyleSheet.create({
39576
+ const styles$9 = StyleSheet.create({
39556
39577
  instructions: {
39557
39578
  paddingBottom: 16
39558
39579
  },
@@ -39638,7 +39659,7 @@ class Placeholder extends React.Component {
39638
39659
  const {
39639
39660
  layout
39640
39661
  } = this.props;
39641
- const className = css(styles$9.card, styles$9.placeholder, layout === "horizontal" && styles$9.horizontalCard);
39662
+ const className = css(styles$8.card, styles$8.placeholder, layout === "horizontal" && styles$8.horizontalCard);
39642
39663
  const style = {
39643
39664
  width: this.props.width,
39644
39665
  height: this.props.height
@@ -39842,7 +39863,7 @@ class Draggable extends React.Component {
39842
39863
  // We need to keep backwards compatbility with rules specified directly
39843
39864
  // in CSS. Hence the hacky tacking on of manual classNames.
39844
39865
  // See sortable.less for details.
39845
- let className = 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";
39866
+ let className = 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";
39846
39867
  if (!includePadding) {
39847
39868
  className += " perseus-sortable-draggable-unpadded";
39848
39869
  }
@@ -40175,7 +40196,7 @@ class Sortable extends React.Component {
40175
40196
  } = this.props;
40176
40197
  // We need to keep backwards compatbility with rules specified directly
40177
40198
  // in CSS. See sortable.less for details.
40178
- const className = css(styles$9.sortable) + " perseus-sortable";
40199
+ const className = css(styles$8.sortable) + " perseus-sortable";
40179
40200
  const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === "vertical";
40180
40201
  const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === "horizontal";
40181
40202
  _.each(this.state.items, function (item, i, items) {
@@ -40272,7 +40293,7 @@ Sortable.defaultProps = {
40272
40293
  linterContext: PerseusLinter.linterContextDefault,
40273
40294
  waitForTexRendererToLoad: true
40274
40295
  };
40275
- const styles$9 = StyleSheet.create({
40296
+ const styles$8 = StyleSheet.create({
40276
40297
  sortable: {
40277
40298
  boxSizing: "border-box",
40278
40299
  float: "left",
@@ -40458,25 +40479,25 @@ class Matcher extends React.Component {
40458
40479
  };
40459
40480
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
40460
40481
  return /*#__PURE__*/React.createElement("table", {
40461
- className: css(styles$8.widget) + " " + HACKY_CSS_CLASSNAME
40482
+ className: css(styles$7.widget) + " " + HACKY_CSS_CLASSNAME
40462
40483
  }, /*#__PURE__*/React.createElement("tbody", null, showLabels && /*#__PURE__*/React.createElement("tr", {
40463
- className: css(styles$8.row)
40484
+ className: css(styles$7.row)
40464
40485
  }, /*#__PURE__*/React.createElement("th", {
40465
- className: css(styles$8.column, styles$8.columnLabel)
40486
+ className: css(styles$7.column, styles$7.columnLabel)
40466
40487
  }, /*#__PURE__*/React.createElement(Renderer, {
40467
40488
  content: this.props.labels[0] || "...",
40468
40489
  linterContext: this.props.linterContext,
40469
40490
  strings: this.context.strings
40470
40491
  })), /*#__PURE__*/React.createElement("th", {
40471
- className: css(styles$8.column, styles$8.columnRight, styles$8.columnLabel)
40492
+ className: css(styles$7.column, styles$7.columnRight, styles$7.columnLabel)
40472
40493
  }, /*#__PURE__*/React.createElement(Renderer, {
40473
40494
  content: this.props.labels[1] || "...",
40474
40495
  linterContext: this.props.linterContext,
40475
40496
  strings: this.context.strings
40476
40497
  }))), /*#__PURE__*/React.createElement("tr", {
40477
- className: css(styles$8.row)
40498
+ className: css(styles$7.row)
40478
40499
  }, /*#__PURE__*/React.createElement("td", {
40479
- className: css(styles$8.column)
40500
+ className: css(styles$7.column)
40480
40501
  }, /*#__PURE__*/React.createElement(Sortable, {
40481
40502
  options: left,
40482
40503
  layout: "vertical",
@@ -40491,7 +40512,7 @@ class Matcher extends React.Component {
40491
40512
  ,
40492
40513
  ref: "left"
40493
40514
  })), /*#__PURE__*/React.createElement("td", {
40494
- className: css(styles$8.column, styles$8.columnRight)
40515
+ className: css(styles$7.column, styles$7.columnRight)
40495
40516
  }, /*#__PURE__*/React.createElement(Sortable, {
40496
40517
  options: right,
40497
40518
  layout: "vertical",
@@ -40520,7 +40541,7 @@ Matcher.defaultProps = {
40520
40541
  };
40521
40542
  const padding = 5;
40522
40543
  const border = "1px solid #444";
40523
- const styles$8 = StyleSheet.create({
40544
+ const styles$7 = StyleSheet.create({
40524
40545
  widget: {
40525
40546
  paddingTop: padding,
40526
40547
  maxWidth: "100%",
@@ -41062,7 +41083,7 @@ const getPromptJSON$7 = () => {
41062
41083
  return getUnsupportedPromptJSON("measurer");
41063
41084
  };
41064
41085
 
41065
- const _excluded$2 = ["imageUrl", "imageTop", "imageLeft"];
41086
+ const _excluded$1 = ["imageUrl", "imageTop", "imageLeft"];
41066
41087
  const defaultImage = {
41067
41088
  url: null,
41068
41089
  top: 0,
@@ -41174,7 +41195,7 @@ const propUpgrades = {
41174
41195
  imageTop,
41175
41196
  imageLeft
41176
41197
  } = v0props,
41177
- rest = _objectWithoutPropertiesLoose(v0props, _excluded$2);
41198
+ rest = _objectWithoutPropertiesLoose(v0props, _excluded$1);
41178
41199
  return _extends({}, rest, {
41179
41200
  image: {
41180
41201
  url: imageUrl,
@@ -41214,9 +41235,9 @@ function drawText(ctx, item) {
41214
41235
  if (item.value === null) {
41215
41236
  return;
41216
41237
  }
41217
- ctx.fillStyle = styles$7.fgColor;
41218
- ctx.font = styles$7.font;
41219
- ctx.fillText(item.value, item.pos[0] - styles$7.fontSizePx / 2 + 1, item.pos[1] + styles$7.fontSizePx / 2);
41238
+ ctx.fillStyle = styles$6.fgColor;
41239
+ ctx.font = styles$6.font;
41240
+ ctx.fillText(item.value, item.pos[0] - styles$6.fontSizePx / 2 + 1, item.pos[1] + styles$6.fontSizePx / 2);
41220
41241
  }
41221
41242
 
41222
41243
  /**
@@ -41237,16 +41258,16 @@ function drawText(ctx, item) {
41237
41258
  function drawDoubleLine(ctx, item) {
41238
41259
  // Outer line that forms both of the bond lines.
41239
41260
  let path = new Path2D();
41240
- ctx.lineWidth = 5 * styles$7.lineWidth;
41241
- ctx.strokeStyle = styles$7.fgColor;
41261
+ ctx.lineWidth = 5 * styles$6.lineWidth;
41262
+ ctx.strokeStyle = styles$6.fgColor;
41242
41263
  path.moveTo(item.startPos[0], item.startPos[1]);
41243
41264
  path.lineTo(item.endPos[0], item.endPos[1]);
41244
41265
  ctx.stroke(path);
41245
41266
 
41246
41267
  // Inner white line that separates the two bond lines.
41247
41268
  path = new Path2D();
41248
- ctx.lineWidth = 3 * styles$7.lineWidth;
41249
- ctx.strokeStyle = styles$7.bgColor;
41269
+ ctx.lineWidth = 3 * styles$6.lineWidth;
41270
+ ctx.strokeStyle = styles$6.bgColor;
41250
41271
  path.moveTo(item.startPos[0], item.startPos[1]);
41251
41272
  path.lineTo(item.endPos[0], item.endPos[1]);
41252
41273
  ctx.stroke(path);
@@ -41273,16 +41294,16 @@ function drawTripleLine(ctx, item) {
41273
41294
 
41274
41295
  // Outer line that will form the two outer bond lines.
41275
41296
  let path = new Path2D();
41276
- ctx.lineWidth = 7 * styles$7.lineWidth;
41277
- ctx.strokeStyle = styles$7.fgColor;
41297
+ ctx.lineWidth = 7 * styles$6.lineWidth;
41298
+ ctx.strokeStyle = styles$6.fgColor;
41278
41299
  path.moveTo(item.startPos[0], item.startPos[1]);
41279
41300
  path.lineTo(item.endPos[0], item.endPos[1]);
41280
41301
  ctx.stroke(path);
41281
41302
 
41282
41303
  // Middle white line that separates the bonds
41283
41304
  path = new Path2D();
41284
- ctx.lineWidth = 5 * styles$7.lineWidth;
41285
- ctx.strokeStyle = styles$7.bgColor;
41305
+ ctx.lineWidth = 5 * styles$6.lineWidth;
41306
+ ctx.strokeStyle = styles$6.bgColor;
41286
41307
  path.moveTo(item.startPos[0], item.startPos[1]);
41287
41308
  path.lineTo(item.endPos[0], item.endPos[1]);
41288
41309
  ctx.stroke(path);
@@ -41304,8 +41325,8 @@ function drawTripleLine(ctx, item) {
41304
41325
  */
41305
41326
  function drawLine(ctx, item) {
41306
41327
  const path = new Path2D();
41307
- ctx.lineWidth = styles$7.lineWidth;
41308
- ctx.strokeStyle = styles$7.fgColor;
41328
+ ctx.lineWidth = styles$6.lineWidth;
41329
+ ctx.strokeStyle = styles$6.fgColor;
41309
41330
  path.moveTo(item.startPos[0], item.startPos[1]);
41310
41331
  path.lineTo(item.endPos[0], item.endPos[1]);
41311
41332
  ctx.stroke(path);
@@ -41357,7 +41378,7 @@ function compareElements(item0, item1) {
41357
41378
  function draw(ctx, items) {
41358
41379
  items.sort(compareElements).forEach(drawItem(ctx));
41359
41380
  }
41360
- const styles$7 = {
41381
+ const styles$6 = {
41361
41382
  bgColor: "rgb(255, 255, 255)",
41362
41383
  fgColor: "rgb(0, 0, 0)",
41363
41384
  fontSizePx: 12,
@@ -43477,7 +43498,7 @@ class PhetSimulation extends React.Component {
43477
43498
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43478
43499
  const sandboxProperties = "allow-same-origin allow-scripts";
43479
43500
  return /*#__PURE__*/React.createElement(View, {
43480
- style: styles$6.widgetContainer
43501
+ style: styles$5.widgetContainer
43481
43502
  }, this.state.banner !== null &&
43482
43503
  /*#__PURE__*/
43483
43504
  // TODO(anna): Make this banner focusable
@@ -43490,12 +43511,12 @@ class PhetSimulation extends React.Component {
43490
43511
  kind: this.state.banner.kind,
43491
43512
  text: this.state.banner.message
43492
43513
  })), /*#__PURE__*/React.createElement(View, {
43493
- style: styles$6.iframeContainer
43514
+ style: styles$5.iframeContainer
43494
43515
  }, /*#__PURE__*/React.createElement("iframe", {
43495
43516
  ref: this.iframeRef,
43496
43517
  title: this.props.description,
43497
43518
  sandbox: sandboxProperties,
43498
- className: css(styles$6.iframeResponsive),
43519
+ className: css(styles$5.iframeResponsive),
43499
43520
  src: (_this$state$url = this.state.url) == null ? void 0 : _this$state$url.toString(),
43500
43521
  allow: "fullscreen"
43501
43522
  })), this.state.url !== null && /*#__PURE__*/React.createElement(IconButton, {
@@ -43528,7 +43549,7 @@ const makeSafeUrl = (urlString, locale) => {
43528
43549
  url.searchParams.set("locale", locale);
43529
43550
  return url;
43530
43551
  };
43531
- const styles$6 = StyleSheet.create({
43552
+ const styles$5 = StyleSheet.create({
43532
43553
  widgetContainer: {
43533
43554
  borderRadius: 6,
43534
43555
  borderWidth: 1,
@@ -44446,7 +44467,7 @@ class PythonProgram extends React.Component {
44446
44467
  // creator "went wild".
44447
44468
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
44448
44469
  return /*#__PURE__*/React.createElement(View, {
44449
- style: styles$5.container
44470
+ style: styles$4.container
44450
44471
  }, /*#__PURE__*/React.createElement("iframe", {
44451
44472
  sandbox: sandboxOptions,
44452
44473
  src: url,
@@ -44458,7 +44479,7 @@ class PythonProgram extends React.Component {
44458
44479
  PythonProgram.defaultProps = {
44459
44480
  height: 400
44460
44481
  };
44461
- const styles$5 = StyleSheet.create({
44482
+ const styles$4 = StyleSheet.create({
44462
44483
  container: {
44463
44484
  margin: "auto",
44464
44485
  width: "100%"
@@ -44951,7 +44972,7 @@ const VideoTranscriptLink = props => {
44951
44972
  var _result$data;
44952
44973
  const video = (_result$data = result.data) == null ? void 0 : _result$data.video;
44953
44974
  return /*#__PURE__*/React.createElement(View, {
44954
- style: styles$4.transcriptLink
44975
+ style: styles$3.transcriptLink
44955
44976
  }, /*#__PURE__*/React.createElement(Text$2, null, video == null ? void 0 : video.title), /*#__PURE__*/React.createElement(Strut, {
44956
44977
  size: 10
44957
44978
  }), /*#__PURE__*/React.createElement(Link, {
@@ -44968,7 +44989,7 @@ const VideoTranscriptLink = props => {
44968
44989
  return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
44969
44990
  }
44970
44991
  };
44971
- const styles$4 = StyleSheet.create({
44992
+ const styles$3 = StyleSheet.create({
44972
44993
  transcriptLink: {
44973
44994
  flexDirection: "row",
44974
44995
  width: "100%",
@@ -45086,7 +45107,7 @@ const init = function init() {
45086
45107
 
45087
45108
  // This file is processed by a Rollup plugin (replace) to inject the production
45088
45109
  const libName = "@khanacademy/perseus";
45089
- const libVersion = "46.0.1";
45110
+ const libVersion = "47.0.1";
45090
45111
  addLibraryVersionToPerseusDebug(libName, libVersion);
45091
45112
 
45092
45113
  const apiVersion = {
@@ -45298,7 +45319,7 @@ class HintRenderer extends React.Component {
45298
45319
  const {
45299
45320
  isMobile
45300
45321
  } = apiOptions;
45301
- const classNames = classNames$1("hint", !isMobile && "perseus-hint-renderer", isMobile && css(styles$3.newHint), isMobile && lastRendered && css(styles$3.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
45322
+ const classNames = classNames$1("hint", !isMobile && "perseus-hint-renderer", isMobile && css(styles$2.newHint), isMobile && lastRendered && css(styles$2.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
45302
45323
 
45303
45324
  // TODO(charlie): Allowing `customKeypad` would require that we
45304
45325
  // extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
@@ -45343,7 +45364,7 @@ HintRenderer.contextType = PerseusI18nContext;
45343
45364
  HintRenderer.defaultProps = {
45344
45365
  linterContext: PerseusLinter.linterContextDefault
45345
45366
  };
45346
- const styles$3 = StyleSheet.create({
45367
+ const styles$2 = StyleSheet.create({
45347
45368
  newHint: {
45348
45369
  marginBottom: 1.5 * baseUnitPx,
45349
45370
  borderLeftColor: gray97,
@@ -45516,14 +45537,14 @@ class HintsRenderer extends React.Component {
45516
45537
  } = apiOptions;
45517
45538
  const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
45518
45539
  const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
45519
- const classNames = classNames$1(this.props.className, apiOptions.isMobile && hintsVisible > 0 && css(styles$2.mobileHintStylesHintsRenderer));
45540
+ const classNames = classNames$1(this.props.className, apiOptions.isMobile && hintsVisible > 0 && css(styles$1.mobileHintStylesHintsRenderer));
45520
45541
  return /*#__PURE__*/React.createElement("div", {
45521
45542
  className: classNames
45522
45543
  }, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React.createElement("div", {
45523
- className: css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
45544
+ className: css(styles$1.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
45524
45545
  }, this.context.strings.hints), hints, showGetAnotherHint && /*#__PURE__*/React.createElement("button", {
45525
45546
  rel: "button",
45526
- className: css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
45547
+ className: css(styles$1.linkButton, styles$1.getAnotherHintButton, apiOptions.isMobile && styles$1.mobileHintStylesGetAnotherHintButton),
45527
45548
  onClick: evt => {
45528
45549
  evt.preventDefault();
45529
45550
  evt.stopPropagation();
@@ -45532,9 +45553,9 @@ class HintsRenderer extends React.Component {
45532
45553
  }
45533
45554
  }
45534
45555
  }, /*#__PURE__*/React.createElement("span", {
45535
- className: css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
45556
+ className: css(styles$1.plusText, apiOptions.isMobile && styles$1.mobileHintStylesPlusText)
45536
45557
  }, "+"), /*#__PURE__*/React.createElement("span", {
45537
- className: css(styles$2.getAnotherHintText)
45558
+ className: css(styles$1.getAnotherHintText)
45538
45559
  }, this.context.strings.getAnotherHint, " ", hintRatioCopy)));
45539
45560
  }
45540
45561
  }
@@ -45543,7 +45564,7 @@ HintsRenderer.defaultProps = {
45543
45564
  linterContext: PerseusLinter.linterContextDefault
45544
45565
  };
45545
45566
  const hintIndentation = baseUnitPx + hintBorderWidth;
45546
- const styles$2 = StyleSheet.create({
45567
+ const styles$1 = StyleSheet.create({
45547
45568
  // eslint-disable-next-line react-native/no-unused-styles
45548
45569
  rendererMargins: {
45549
45570
  marginTop: baseUnitPx
@@ -45952,7 +45973,7 @@ class ServerItemRenderer extends React.Component {
45952
45973
  // mobile hint styles, which are flush to the left.
45953
45974
  // NOTE(charlie): We may still want to apply this
45954
45975
  // padding for desktop exercises.
45955
- apiOptions.isMobile ? undefined : css(styles$1.hintsContainer)
45976
+ apiOptions.isMobile ? undefined : css(styles.hintsContainer)
45956
45977
  }, hintsRenderer)));
45957
45978
  }
45958
45979
  }
@@ -45963,7 +45984,7 @@ ServerItemRenderer.defaultProps = {
45963
45984
  linterContext: PerseusLinter.linterContextDefault,
45964
45985
  onRendered: isRendered => {}
45965
45986
  };
45966
- const styles$1 = StyleSheet.create({
45987
+ const styles = StyleSheet.create({
45967
45988
  hintsContainer: {
45968
45989
  marginLeft: 50
45969
45990
  }
@@ -46068,1144 +46089,6 @@ const traverse = function traverse(rendererOptions, contentCallback, widgetCallb
46068
46089
  return traverseRenderer$1(rendererOptions, contentCallback, deepCallbackFor(contentCallback, widgetCallback, optionsCallback), optionsCallback);
46069
46090
  };
46070
46091
 
46071
- /**
46072
- * Utility functions for constructing and inferring multi-item shapes.
46073
- *
46074
- * A shape is an object that serves as a runtime type declaration: it specifies
46075
- * a tree structure for a particular class of multi-item. See shape-types.js
46076
- * for further discussion.
46077
- *
46078
- * This module allows you to construct arbitrary Shape trees, by combining
46079
- * leaf node shapes like `content` and `hint` into composite shapes like
46080
- * `arrayOf(shape({foo: content, bar: hint}))`.
46081
- */
46082
-
46083
- /**
46084
- * These tools allow you to construct arbirtary shapes, by combining simple
46085
- * leaf shapes like `content` and `hint` into composite shapes like
46086
- * `arrayOf(shape({question: content, hints: arrayOf(hint)}))`.
46087
- */
46088
- const contentShape = {
46089
- type: "content"
46090
- };
46091
- const hintShape = {
46092
- type: "hint"
46093
- };
46094
- const tagsShape = {
46095
- type: "tags"
46096
- };
46097
- const buildArrayShape = elementShape => ({
46098
- type: "array",
46099
- elementShape
46100
- });
46101
- const buildObjectShape = shape => ({
46102
- type: "object",
46103
- shape
46104
- });
46105
- const hintsShape = buildArrayShape(hintShape);
46106
- var shapes = {
46107
- content: contentShape,
46108
- hint: hintShape,
46109
- hints: hintsShape,
46110
- tags: tagsShape,
46111
- arrayOf: buildArrayShape,
46112
- shape: buildObjectShape
46113
- };
46114
-
46115
- /**
46116
- * Utility functions for manipulating multi-item-shaped trees.
46117
- *
46118
- * Multi-items are trees! But we also often have other trees that are shaped
46119
- * like multi-items - for example, if we map a multi-item tree into a tree of
46120
- * renderer info and state, and then map that again into a tree of just the
46121
- * renderer nodes, like we do in MultiRenderer. See tree-types.js for further
46122
- * discussion.
46123
- *
46124
- * These functions enable us to manipulate generic multi-item-shaped trees,
46125
- * regardless of what type of data they contain at their leaves. You can use
46126
- * the mapper functions to transform a tree into another tree of the same
46127
- * shape, or to discover all the nodes of a particular type.
46128
- *
46129
- * We expose two simple mapper functions (mapContentNodes and mapHintNodes),
46130
- * and also a more complex interface for creating a mapping over all of a
46131
- * tree's node types simultaneously:
46132
- *
46133
- * `buildMapper()` returns a TreeMapper object that allows you to build your
46134
- * mapper object one node type at a time. Then, you can execute your mapping by
46135
- * calling the `mapTree` method.
46136
- *
46137
- * For example:
46138
- * const renderers = buildMapper()
46139
- * .setContentMapper(this.renderContentNode)
46140
- * .setHintMapper(this.renderHintNode)
46141
- * .setTagsMapper(this.renderTagsNode)
46142
- * .setArrayMapper(this.hideSkippedQuestions)
46143
- * .mapTree(tree, shape);
46144
- *
46145
- * This will copy the given tree, apply the given transformations to the
46146
- * content, hint, and array nodes respectively, and return the resulting tree.
46147
- *
46148
- * For node types whose mappers aren't specified, we default to the identity
46149
- * function. (This builder interface enables us to implement that default
46150
- * behavior in a provably type-safe way, while not requiring the call site to
46151
- * be aware of all the node types. Hooray!)
46152
- *
46153
- * The call to `setArrayMapper` must come last, because the array mapper's
46154
- * argument types depend on the other mappers' types. See ArrayMapper for more
46155
- * details.
46156
- *
46157
- * WARNING: These functions trust that the provided tree conforms to the
46158
- * provided shape. If not, behavior is undefined and may not respect the type
46159
- * signatures specified here.
46160
- */
46161
-
46162
- /**
46163
- * The sequence of edges that lead to a particular node in a Tree.
46164
- * Elements can be `string` to correspond to an ObjectNode key, or `number` to
46165
- * correspond to an ArrayNode index.
46166
- */
46167
-
46168
- /**
46169
- * These are function interfaces for mapping over various types of tree nodes.
46170
- *
46171
- * ArrayMapper is a bit more complicated than the leaf node mappers. It's
46172
- * executed in the context of a `mapTree` call, after we've finished mapping
46173
- * its child nodes, so the function has access to both the resulting array
46174
- * (with mapped elements) and the original array (with the original untouched
46175
- * elements).
46176
- *
46177
- * The ArrayMapper then has the opportunity to apply a final transformation to
46178
- * the resulting array, like filtering certain elements or (in the hacky
46179
- * MultiRenderer case) attaching a `renderHints` method to arrays of hint
46180
- * renderers :)
46181
- *
46182
- * This is why `TreeMapper#setArrayMapper` must be called last: ArrayMapper's
46183
- * types depend on the ContentMapper and HintMapper's types. And, since you can
46184
- * only specify one mapper at a time in this builder interface (which is
46185
- * necessary to provide default mappers in a type-safe way), you need your
46186
- * dependencies to already be in place by the time you call `setArrayMapper`.
46187
- * Otherwise, we'd have to set the ArrayMapper and *hope* that you *eventually*
46188
- * provide a compatible ContentMapper and HintMapper, which is difficult to
46189
- * prove at compile time.
46190
- *
46191
- * There's no ObjectMapper here, but not for any particular reason. We just
46192
- * don't have a use case for it yet, so we haven't built it yet.
46193
- */
46194
-
46195
- /**
46196
- * A TreeMapper is a collection of node mappers, which, together, compose the
46197
- * behavior for mapping over an entire tree.
46198
- *
46199
- * This serves as the interface for the two TreeMapper classes, including both
46200
- * the internal mapper properties that we care about, and the `mapTree`
46201
- * function that the call site will use.
46202
- */
46203
-
46204
- /**
46205
- * This is a TreeMapper that only has mappers specified for its leaf nodes; its
46206
- * array mapper is the identity function.
46207
- *
46208
- * This is the TreeMapper initially returned by `buildMapper`. It allows you to
46209
- * change the types of your ContentMapper and HintMapper, which is safe because
46210
- * none of the other mappers that depend on those types (aka ArrayMapper) have
46211
- * been specified yet. (Or, more specifically, the ArrayMapper is currently
46212
- * `identity`, which can trivially vary with the ContentMapper and HintMapper's
46213
- * types.)
46214
- *
46215
- * Once you call `setArrayMapper`, however, we move to the other class:
46216
- * TreeMapperForLeavesAndCollections.
46217
- */
46218
- class TreeMapperJustForLeaves {
46219
- constructor(content, hint, tags) {
46220
- this.content = void 0;
46221
- this.hint = void 0;
46222
- this.tags = void 0;
46223
- this.array = void 0;
46224
- this.content = content;
46225
- this.hint = hint;
46226
- this.tags = tags;
46227
- this.array = identity;
46228
- }
46229
- setContentMapper(newContentMapper) {
46230
- return new TreeMapperJustForLeaves(newContentMapper, this.hint, this.tags);
46231
- }
46232
- setHintMapper(newHintMapper) {
46233
- return new TreeMapperJustForLeaves(this.content, newHintMapper, this.tags);
46234
- }
46235
- setTagsMapper(newTagsMapper) {
46236
- return new TreeMapperJustForLeaves(this.content, this.hint, newTagsMapper);
46237
- }
46238
- setArrayMapper(newArrayMapper) {
46239
- return new TreeMapperForLeavesAndCollections(this.content, this.hint, this.tags, newArrayMapper);
46240
- }
46241
-
46242
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic. | TS2315 - Type 'Tree' is not generic.
46243
- mapTree(tree, shape) {
46244
- return mapTree(tree, shape, [], this);
46245
- }
46246
- }
46247
-
46248
- /**
46249
- * This is a TreeMapper that already has an ArrayMapper specified, so its
46250
- * ContentMapper and HintMapper are now locked in.
46251
- */
46252
- class TreeMapperForLeavesAndCollections {
46253
- constructor(content, hint, tags, array) {
46254
- this.content = void 0;
46255
- this.hint = void 0;
46256
- this.tags = void 0;
46257
- this.array = void 0;
46258
- this.content = content;
46259
- this.hint = hint;
46260
- this.tags = tags;
46261
- this.array = array;
46262
- }
46263
- setArrayMapper(newArrayMapper) {
46264
- return new TreeMapperForLeavesAndCollections(this.content, this.hint, this.tags, newArrayMapper);
46265
- }
46266
-
46267
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic. | TS2315 - Type 'Tree' is not generic.
46268
- mapTree(tree, shape) {
46269
- return mapTree(tree, shape, [], this);
46270
- }
46271
- }
46272
- function identity(x) {
46273
- return x;
46274
- }
46275
-
46276
- /**
46277
- * Return a new TreeMapper that will perform a no-op transformation on an input
46278
- * tree. To make it useful, chain any combination of `setContentMapper`,
46279
- * `setHintMapper`, `setTagMapper`, and `setArrayMapper` to specify
46280
- * transformations for the individual node types.
46281
- */
46282
- // @ts-expect-error - TS2300 - Duplicate identifier 'C'. | TS2300 - Duplicate identifier 'H'. | TS2300 - Duplicate identifier 'T'.
46283
- function buildMapper() {
46284
- return new TreeMapperJustForLeaves(identity, identity, identity);
46285
- }
46286
-
46287
- /**
46288
- * Copy the given tree, apply the corresponding transformation specified in the
46289
- * TreeMapper to each node, and return the resulting tree.
46290
- */
46291
- function mapTree(
46292
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46293
- tree, shape, path, mappers
46294
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46295
- ) {
46296
- // We trust the shape of the multi-item to match the shape provided at
46297
- // runtime. Therefore, in each shape branch, we cast the node to `any` and
46298
- // reinterpret it as the expected node type.
46299
- if (shape.type === "content") {
46300
- const content = tree;
46301
- return mappers.content(content, shape, path);
46302
- }
46303
- if (shape.type === "hint") {
46304
- const hint = tree;
46305
- return mappers.hint(hint, shape, path);
46306
- }
46307
- if (shape.type === "tags") {
46308
- const tags = tree;
46309
- return mappers.tags(tags, shape, path);
46310
- }
46311
- if (shape.type === "array") {
46312
- // @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
46313
- const array = tree;
46314
- if (!Array.isArray(array)) {
46315
- throw new PerseusError(`Invalid object of type "${typeof array}" found at path ` +
46316
- // @ts-expect-error - TS2769 - No overload matches this call.
46317
- `${["<root>"].concat(path).join(".")}. Expected array.`, Errors.Internal);
46318
- }
46319
- const elementShape = shape.elementShape;
46320
- // @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
46321
- const mappedElements = array.map((inner, i) => mapTree(inner, elementShape, path.concat(i), mappers));
46322
- return mappers.array(mappedElements, array, shape, path);
46323
- }
46324
- if (shape.type === "object") {
46325
- const object = tree;
46326
- if (object && typeof object !== "object") {
46327
- throw new PerseusError(`Invalid object of type "${typeof object}" found at ` +
46328
- // @ts-expect-error - TS2769 - No overload matches this call.
46329
- `path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, Errors.InvalidInput);
46330
- }
46331
- const valueShapes = shape.shape;
46332
- if (!valueShapes) {
46333
- throw new PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
46334
- // @ts-expect-error - TS2769 - No overload matches this call.
46335
- `${["<root>"].concat(path).join(".")}.`, Errors.InvalidInput);
46336
- }
46337
- const newObject = {};
46338
- Object.keys(valueShapes).forEach(key => {
46339
- if (!(key in object)) {
46340
- throw new PerseusError(`Key "${key}" is missing from shape at path ` +
46341
- // @ts-expect-error - TS2769 - No overload matches this call.
46342
- `${["<root>"].concat(path).join(".")}.`, Errors.InvalidInput);
46343
- }
46344
- newObject[key] = mapTree(object[key], valueShapes[key], path.concat(key), mappers);
46345
- });
46346
- return newObject;
46347
- }
46348
- throw new PerseusError(
46349
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
46350
- `unexpected shape type ${shape.type}`, Errors.InvalidInput);
46351
- }
46352
-
46353
- /**
46354
- * Utility functions for constructing and manipulating multi-items.
46355
- *
46356
- * These functions apply *specifically* to Items and ItemTrees - things that
46357
- * actually semantically *are* multi-items. For more general functions for
46358
- * traversing and manipulating *anything* shaped like a multi-item (like a
46359
- * renderer tree or a score tree or, well, a multi-item), see trees.js.
46360
- */
46361
- /**
46362
- * Return a semantically empty ItemTree that conforms to the given shape.
46363
- *
46364
- * - An empty content node has an empty content string and no widgets/images.
46365
- * - An empty hint node has an empty content string and no widgets/images.
46366
- * - An empty array node has no elements.
46367
- * - An empty object node has a semantically empty node for each of its keys.
46368
- * (That is, we recursively call buildEmptyItemTreeForShape for each key.)
46369
- */
46370
- function buildEmptyItemTreeForShape(shape) {
46371
- if (shape.type === "content") {
46372
- return {
46373
- __type: "content",
46374
- content: "",
46375
- images: {},
46376
- widgets: {}
46377
- };
46378
- }
46379
- if (shape.type === "hint") {
46380
- return {
46381
- __type: "hint",
46382
- replace: false,
46383
- content: "",
46384
- images: {},
46385
- widgets: {}
46386
- };
46387
- }
46388
- if (shape.type === "tags") {
46389
- return [];
46390
- }
46391
- if (shape.type === "array") {
46392
- return [];
46393
- }
46394
- if (shape.type === "object") {
46395
- const valueShapes = shape.shape;
46396
- const object = {};
46397
- Object.keys(valueShapes).forEach(key => {
46398
- object[key] = buildEmptyItemTreeForShape(valueShapes[key]);
46399
- });
46400
- return object;
46401
- }
46402
- throw new PerseusError(
46403
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
46404
- `unexpected shape type ${shape.type}`, Errors.InvalidInput);
46405
- }
46406
-
46407
- /**
46408
- * Return a semantically empty Item that conforms to the given shape.
46409
- *
46410
- * - An empty content node has an empty content string and no widgets/images.
46411
- * - An empty hint node has an empty content string and no widgets/images.
46412
- * - An empty array node has no elements.
46413
- * - An empty object node has a semantically empty node for each of its keys.
46414
- * (That is, we recursively call buildEmptyItemTreeForShape for each key.)
46415
- */
46416
- function buildEmptyItemForShape(shape) {
46417
- return treeToItem(buildEmptyItemTreeForShape(shape));
46418
- }
46419
-
46420
- /**
46421
- * Given an Item and its Shape, yield all of its content nodes to the callback.
46422
- */
46423
- function findContentNodesInItem$2(item, shape, callback) {
46424
- const itemTree = itemToTree(item);
46425
- buildMapper().setContentMapper(callback).mapTree(itemTree, shape);
46426
- }
46427
-
46428
- /**
46429
- * Given an Item and its Shape, yield all of its hint nodes to the callback.
46430
- */
46431
- function findHintNodesInItem(item, shape, callback) {
46432
- const itemTree = itemToTree(item);
46433
- buildMapper().setHintMapper(callback).mapTree(itemTree, shape);
46434
- }
46435
-
46436
- /**
46437
- * Given an ItemTree, return a Shape that it conforms to.
46438
- *
46439
- * The Shape might not be complete or correct Shape that this Item was designed
46440
- * for. If you have access to the intended Shape, use that instead.
46441
- */
46442
- function inferItemShape$2(item) {
46443
- const itemTree = itemToTree(item);
46444
- return inferItemTreeShape(itemTree);
46445
- }
46446
- function inferItemTreeShape(node) {
46447
- if (Array.isArray(node)) {
46448
- if (node.length) {
46449
- if (typeof node[0] === "string") {
46450
- // There's no ItemTree that can manifest as a string.
46451
- // So, an array of strings must be a TagsNode, not ArrayNode.
46452
- return shapes.tags;
46453
- }
46454
- // Otherwise, assume that this is a valid ArrayNode, and
46455
- // therefore the shape of the first element applies to all
46456
- // elements in the array.
46457
- return shapes.arrayOf(inferItemTreeShape(node[0]));
46458
- }
46459
- // The array is empty, so we arbitrarily guess that it's a content
46460
- // array. As discussed in the docstring, this might be incorrect,
46461
- // and you shouldn't depend on it.
46462
- return shapes.arrayOf(shapes.content);
46463
- }
46464
- if (
46465
- // TODO(mdr): Remove #LegacyContentNode support.
46466
- typeof node === "object" && (node.__type === "content" || node.__type === "item")) {
46467
- return shapes.content;
46468
- }
46469
- if (typeof node === "object" && node.__type === "hint") {
46470
- return shapes.hint;
46471
- }
46472
- if (typeof node === "object") {
46473
- const valueShapes = {};
46474
- Object.keys(node).forEach(key => {
46475
- valueShapes[key] = inferItemTreeShape(node[key]);
46476
- });
46477
- return shapes.shape(valueShapes);
46478
- }
46479
- throw new PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, Errors.InvalidInput);
46480
- }
46481
-
46482
- /**
46483
- * Convert the given Item to an ItemTree, by unwrapping the `_multi` key.
46484
- */
46485
- function itemToTree(item) {
46486
- return item._multi;
46487
- }
46488
-
46489
- /**
46490
- * Convert the given ItemTree to an Item, by wrapping it in the `_multi` key.
46491
- */
46492
- function treeToItem(node) {
46493
- return {
46494
- _multi: node
46495
- };
46496
- }
46497
-
46498
- var isObject$1 = function isObject(obj) {
46499
- return obj === Object(obj);
46500
- };
46501
- var merge = function merge() {
46502
- var obj = {};
46503
- for (var i = 0; i < arguments.length; i++) {
46504
- var source = arguments[i];
46505
- if (source) {
46506
- for (var prop in source) {
46507
- obj[prop] = source[prop];
46508
- }
46509
- }
46510
- }
46511
- return obj;
46512
- };
46513
- var clone = function clone(obj) {
46514
- if (!isObject$1(obj)) {
46515
- return obj;
46516
- }
46517
- return Array.isArray(obj) ? obj.slice() : merge(obj);
46518
- };
46519
-
46520
- /* TODO batch *all* mutations
46521
- * idea: freeze / thaw implementations for all types
46522
- * lens constructor thaws, freeze delegates to type's freeze
46523
- */
46524
-
46525
- // equivalents, without requiring it
46526
- // find the implementation to use for a given object
46527
- var dispatch = function dispatch(x) {
46528
- if (Array.isArray(x)) {
46529
- return arr;
46530
- } else if (isObject$1(x)) {
46531
- return obj;
46532
- } else if (typeof x === "string") {
46533
- return str;
46534
- }
46535
- };
46536
-
46537
- // This is underscore with a different name
46538
- var lens = function lens(obj) {
46539
- if (obj instanceof lens) {
46540
- return obj;
46541
- }
46542
- if (!(this instanceof lens)) {
46543
- return new lens(obj);
46544
- }
46545
- var ops = dispatch(obj);
46546
- this._wrapped = ops.thaw ? ops.thaw(obj) : obj;
46547
- };
46548
- lens.prototype.freeze = function () {
46549
- var obj = this._wrapped;
46550
- var ops = dispatch(obj);
46551
- return ops.freeze ? ops.freeze(obj) : obj;
46552
- };
46553
- lens.prototype.zoom = function (lensArr) {
46554
- if (this._zoomStack === undefined) {
46555
- this._zoomStack = [];
46556
- }
46557
- this._zoomStack.push({
46558
- zoom: lensArr,
46559
- wrapped: this._wrapped
46560
- });
46561
- this._wrapped = lens(this._wrapped).get(lensArr);
46562
- return this;
46563
- };
46564
- lens.prototype.deZoom = function () {
46565
- var frame = this._zoomStack.pop();
46566
- this._wrapped = lens(frame.wrapped).set(frame.zoom, this._wrapped).freeze();
46567
- return this;
46568
- };
46569
- lens.prototype.get = function (lensArr) {
46570
- var obj = this._wrapped;
46571
- for (var i = 0; i < lensArr.length; i++) {
46572
- obj = dispatch(obj).get(obj, lensArr[i]);
46573
- }
46574
- return obj;
46575
- };
46576
- lens.prototype.mod = function (lensArr, f) {
46577
- var obj = this._wrapped;
46578
- var newObj = clone(obj);
46579
- var ops = dispatch(obj);
46580
- if (lensArr.length === 0) {
46581
- this._wrapped = f(this._wrapped);
46582
- } else if (lensArr.length === 1) {
46583
- this._wrapped = ops.mod(newObj, lensArr[0], f);
46584
- } else {
46585
- var monocle = lensArr[0];
46586
- var shortLens = lensArr.slice(1);
46587
-
46588
- // newObj = ops.mod(obj[monocle], shortLens, f);
46589
-
46590
- newObj[monocle] = lens(obj[monocle]).mod(shortLens, f).freeze();
46591
- this._wrapped = newObj;
46592
- }
46593
- return this;
46594
- };
46595
-
46596
- // TODO - move to individual files
46597
- lens.prototype.merge = function (lensArr, props) {
46598
- this._wrapped = lens(this._wrapped).mod(lensArr, function (oldProps) {
46599
- return merge(oldProps, props);
46600
- }).freeze();
46601
- return this;
46602
- };
46603
-
46604
- // Lens must have length >= 1 or there would be nothing to return
46605
- lens.prototype.del = function (lensArr) {
46606
- var obj = this._wrapped;
46607
- var ops = dispatch(obj);
46608
- if (lensArr.length === 1) {
46609
- this._wrapped = ops.del(obj, lensArr[0]);
46610
- } else {
46611
- var monocle = lensArr[0];
46612
- var shortLens = lensArr.slice(1);
46613
- var newObj = clone(obj);
46614
- newObj[monocle] = lens(obj[monocle]).del(shortLens).freeze();
46615
- this._wrapped = newObj;
46616
- }
46617
- return this;
46618
- };
46619
- lens.prototype.set = function (lensArr, set) {
46620
- return this.mod(lensArr, function () {
46621
- return set;
46622
- });
46623
- };
46624
-
46625
- // ARRAY FUNCTIONS
46626
-
46627
- const arr = {
46628
- get: function (arr, monocle) {
46629
- return arr[monocle];
46630
- },
46631
- set: function (arr, monocle, val) {
46632
- var newArr = arr.splice();
46633
- newArr[monocle] = val;
46634
- return newArr;
46635
- },
46636
- mod: function (arr, monocle, f) {
46637
- var newArr = arr.slice();
46638
- newArr[monocle] = f(arr[monocle]);
46639
- return newArr;
46640
- },
46641
- del: function (arr, monocle) {
46642
- var newArr = arr.slice();
46643
- newArr.splice(monocle, 1);
46644
- return newArr;
46645
- }
46646
- };
46647
-
46648
- /*
46649
- // Lens must point to a member of an array. We'll insert into that array.
46650
- lens.prototype.insertAt = function(lensArr, toInsert) {
46651
- var obj = this._wrapped;
46652
-
46653
- var arrLens = lensArr.slice(0, -1);
46654
- var arr = lens(obj).get(arrLens).slice(); // slice to copy
46655
-
46656
- var arrIdx = lensArr[lensArr.length-1];
46657
- arr.splice(arrIdx, 0, toInsert);
46658
- return lens(obj).set(arrLens, arr);
46659
- };
46660
-
46661
- lens.prototype.insertBefore = lens.prototype.insertAt;
46662
- lens.prototype.insertAfter = function(lensArr, toInsert) {
46663
- var newLens = lensArr.slice();
46664
- newLens[newLens.length-1] += 1;
46665
- return lens(this._wrapped).insertAt(newLens, toInsert);
46666
- };
46667
- */
46668
-
46669
- // OBJECT FUNCTIONS
46670
-
46671
- const obj = {
46672
- get: function (obj, monocle) {
46673
- return obj[monocle];
46674
- },
46675
- set: function (obj, monocle, val) {
46676
- var newObj = clone(obj);
46677
- newObj[monocle] = val;
46678
- return newObj;
46679
- },
46680
- mod: function (obj, monocle, f) {
46681
- var newObj = clone(obj);
46682
- newObj[monocle] = f(obj[monocle]);
46683
- return newObj;
46684
- },
46685
- del: function (obj, monocle) {
46686
- var newObj = clone(obj);
46687
- delete newObj[monocle];
46688
- return newObj;
46689
- }
46690
- };
46691
-
46692
- // STRING FUNCTIONS
46693
-
46694
- const str = {
46695
- get: function (arr, monocle) {
46696
- return arr[monocle];
46697
- },
46698
- set: function (arr, monocle, val) {
46699
- var newArr = arr.splice();
46700
- newArr[monocle] = val;
46701
- return newArr;
46702
- },
46703
- mod: function (arr, monocle, f) {
46704
- var newArr = arr.splice();
46705
- newArr[monocle] = f(arr[monocle]);
46706
- return newArr;
46707
- },
46708
- del: function (arr, monocle) {
46709
- var newArr = arr.slice();
46710
- newArr.splice(monocle);
46711
- return newArr;
46712
- }
46713
- };
46714
-
46715
- const _excluded$1 = ["item", "children", "shape", "serializedState", "onSerializedStateUpdated"];
46716
-
46717
- // TODO(mdr)
46718
- // TODO(mdr)
46719
- // TODO(mdr)
46720
-
46721
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46722
-
46723
- /**
46724
- * TODO(somewhatabstract, JIRA-XXXX):
46725
- * Some usage of this type somewhere is causing TypeScript to believe that these
46726
- * elements should be components. Don't know where that is, to fix it up
46727
- * properly. In reality, these types are just too hard to use and aren't
46728
- * really helping us out as I now have to suppress this rather than
46729
- * get value from the type. :(
46730
- */ // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46731
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46732
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46733
- class MultiRenderer extends React.Component {
46734
- constructor(props) {
46735
- super(props);
46736
- this.rendererDataTreeMapper = void 0;
46737
- this.getRenderersMapper = void 0;
46738
- this._handleSerializedStateUpdated = (path, newState) => {
46739
- const {
46740
- onSerializedStateUpdated
46741
- } = this.props;
46742
- if (onSerializedStateUpdated) {
46743
- const oldState = this._getSerializedState(this.props.serializedState);
46744
- onSerializedStateUpdated(lens(oldState).set(path, newState).freeze());
46745
- }
46746
- };
46747
- this.rendererDataTreeMapper = buildMapper()
46748
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ContentNode'.
46749
- .setContentMapper((c, _, p) => this._makeContentRendererData(c, p))
46750
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'HintNode'.
46751
- .setHintMapper(h => this._makeHintRendererData(h)).setTagsMapper(t => null);
46752
-
46753
- // @ts-expect-error - TS2322 - Type 'TreeMapperForLeavesAndCollections<unknown, any, unknown, any, unknown, unknown>' is not assignable to type 'TreeMapper<ContentRendererData, ContentRendererElement, HintRendererData, HintRendererElement, null, null>'.
46754
- this.getRenderersMapper = buildMapper()
46755
- // @ts-expect-error - TS2571 - Object is of type 'unknown'.
46756
- .setContentMapper(c => c.makeRenderer())
46757
- // @ts-expect-error - TS2571 - Object is of type 'unknown'.
46758
- .setHintMapper(h => h.makeRenderer()).setArrayMapper((renderers, data, shape) => this._annotateRendererArray(renderers, data, shape));
46759
-
46760
- // Keep state in sync with props.
46761
- this.state = this._tryMakeRendererState(this.props);
46762
- }
46763
- UNSAFE_componentWillReceiveProps(nextProps) {
46764
- // Keep state in sync with props.
46765
- if (nextProps.item !== this.props.item) {
46766
- this.setState(this._tryMakeRendererState(nextProps));
46767
- }
46768
- }
46769
-
46770
- /**
46771
- * Attempt to build a State that includes a renderer tree corresponding to
46772
- * the item provided in props. On error, return a state with `renderError`
46773
- * set instead.
46774
- */
46775
- _tryMakeRendererState(props) {
46776
- try {
46777
- return {
46778
- rendererDataTree: this._makeRendererDataTree(props.item, props.shape),
46779
- renderError: null
46780
- };
46781
- } catch (e) {
46782
- Log.error("Error building tree state", Errors.Internal, {
46783
- cause: e
46784
- });
46785
- return {
46786
- rendererDataTree: null,
46787
- renderError: e
46788
- };
46789
- }
46790
- }
46791
- /**
46792
- * Props that aren't directly used by the MultiRenderer are delegated to
46793
- * the underlying Renderers.
46794
- */
46795
- _getRendererProps() {
46796
- // `item`, `children`, and others are unused. I'm
46797
- // explicitly pulling them out of `this.props` so I don't pass them to
46798
- // `<Renderer>`. I'm not sure how else to do this.
46799
- const _this$props = this.props,
46800
- otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
46801
- return _extends({}, otherProps, {
46802
- strings: this.context.strings
46803
- });
46804
- }
46805
-
46806
- /**
46807
- * Construct a Renderer and a ref placeholder for the given ContentNode.
46808
- */
46809
- _makeContentRendererData(content, path) {
46810
- // NOTE(emily): The `findExternalWidgets` function here is computed
46811
- // inline and thus changes each time we run this function. If it
46812
- // were to change every render, it would cause the Renderer to
46813
- // re-render a lot more than is necessary. Don't re-compute this
46814
- // element unless it is necessary!
46815
- // HACK(mdr): TypeScript can't prove that this is a ContentRendererData,
46816
- // because of how we awkwardly construct it in order to obtain a
46817
- // circular reference. But it is, I promise.
46818
- const data = {
46819
- ref: null,
46820
- makeRenderer: null
46821
- };
46822
- const refFunc = e => data.ref = e;
46823
- const findExternalWidgets = criterion => this._findWidgets(data, criterion);
46824
- const handleSerializedState = state => this._handleSerializedStateUpdated(path, state);
46825
- data.makeRenderer = () =>
46826
- /*#__PURE__*/
46827
- /**
46828
- * TODO(somewhatabstract, JIRA-XXXX):
46829
- * `content` contains props that Renderer doesn't have. However,
46830
- * since the type for `content` is not exact, it's hard to know
46831
- * if this spread is including undocumented props so mapping
46832
- * one to one could introduce a bug. Need to work out the exact
46833
- * type for ContentNode and then fix this.
46834
- */
46835
- // @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">>'.
46836
- React.createElement(Renderer, _extends({}, this._getRendererProps(), content, {
46837
- ref: refFunc,
46838
- findExternalWidgets: findExternalWidgets,
46839
- serializedState: this.props.serializedState ? lens(this.props.serializedState).get(path) : null,
46840
- onSerializedStateUpdated: handleSerializedState
46841
- }));
46842
- return data;
46843
- }
46844
-
46845
- /**
46846
- * Construct a Renderer for the given HintNode, and keep track of the hint
46847
- * itself for future use, too.
46848
- */
46849
- _makeHintRendererData(hint) {
46850
- // TODO(mdr): Once HintsRenderer supports inter-widget communication,
46851
- // give it a ref. Until then, leave the ref null forever, to avoid
46852
- // confusing the findWidgets functions.
46853
- //
46854
- // NOTE(davidflanagan): As a partial step toward inter-widget
46855
- // communication we're going to pass a findExternalWidgets function
46856
- // (using a dummy data object). This allows passage-ref widgets in
46857
- // hints to use findWidget() to find the passage widgets they reference.
46858
- // Note that this is one-way only, however. It does not allow
46859
- // widgets in the question to find widgets in the hints, for example.
46860
- const findExternalWidgets = criterion => this._findWidgets({}, criterion);
46861
- return {
46862
- hint,
46863
- findExternalWidgets,
46864
- // _annotateRendererArray() needs this
46865
- ref: null,
46866
- makeRenderer: () => /*#__PURE__*/React.createElement(HintsRenderer, _extends({}, this._getRendererProps(), {
46867
- findExternalWidgets: findExternalWidgets
46868
- // Note(Jeremy): The MultiRenderer codebase types are
46869
- // slightly different from the rest of the codebase.
46870
- // Ideally `HintNode` would spread the `Hint` type into it,
46871
- // but there is a difference in optionality of `widgets`
46872
- // and `images` and that causes a huge cascade of type
46873
- // errors (they are truly optional, but most of our code
46874
- // assumes they're provided/set). Ignoring this for now.
46875
- // @ts-expect-error - TS2769 - Type 'HintNode' is not assignable to type 'Hint'.
46876
- ,
46877
- hints: [hint]
46878
- }))
46879
- };
46880
- }
46881
-
46882
- /**
46883
- * Construct a tree of interconnected RendererDatas, corresponding to the
46884
- * given item. Called in `_tryMakeRendererState`, in order to store this
46885
- * tree in the component state.
46886
- */
46887
- _makeRendererDataTree(item, shape) {
46888
- const itemTree = itemToTree(item);
46889
- return this.rendererDataTreeMapper.mapTree(itemTree, shape);
46890
- }
46891
-
46892
- /**
46893
- * Return all widgets that meet the given criterion, from all Renderers
46894
- * except the Renderer that triggered this call.
46895
- *
46896
- * This function is provided to each Renderer's `findExternalWidgets` prop,
46897
- * which enables widgets in different Renderers to discover each other and
46898
- * communicate.
46899
- */
46900
- _findWidgets(callingData, filterCriterion) {
46901
- const results = [];
46902
- this._mapRenderers(data => {
46903
- if (callingData !== data && data.ref) {
46904
- results.push(...data.ref.findInternalWidgets(filterCriterion));
46905
- }
46906
- });
46907
- return results;
46908
- }
46909
-
46910
- /**
46911
- * Copy the renderer tree, apply the given transformation to the leaf nodes
46912
- * and the optional given transformation to the array nodes, and return the
46913
- * result.
46914
- *
46915
- * Used to provide structured data to the call site (the Renderer tree on
46916
- * `render`, the Score tree on `getScores`, etc.), and to traverse the
46917
- * renderer tree even when we disregard the output (like in
46918
- * `_findWidgets`).
46919
- */
46920
- _mapRenderers(
46921
- // eslint-disable-next-line no-restricted-syntax
46922
- leafMapper
46923
- // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
46924
- ) {
46925
- const {
46926
- rendererDataTree
46927
- } = this.state;
46928
- if (!rendererDataTree) {
46929
- return null;
46930
- }
46931
- const mapper = buildMapper().setContentMapper(leafMapper).setHintMapper(leafMapper);
46932
- return mapper.mapTree(rendererDataTree, this.props.shape);
46933
- }
46934
- _scoreFromRef(ref) {
46935
- if (!ref) {
46936
- return null;
46937
- }
46938
- const [guess, score] = ref.guessAndScore();
46939
- let state;
46940
- if (ref.getSerializedState) {
46941
- state = ref.getSerializedState();
46942
- }
46943
- return keScoreFromPerseusScore(score, guess, state);
46944
- }
46945
-
46946
- /**
46947
- * Return a tree in the shape of the multi-item, with scores at each of
46948
- * the content nodes and `null` at the other leaf nodes.
46949
- */
46950
- getScores() {
46951
- return this._mapRenderers(data => this._scoreFromRef(data.ref));
46952
- }
46953
-
46954
- /**
46955
- * Return a single composite score for all rendered content nodes.
46956
- * The `guess` is a tree in the shape of the multi-item, with an individual
46957
- * guess at each content node and `null` at the other leaf nodes.
46958
- */
46959
- score() {
46960
- const scores = [];
46961
- const state = [];
46962
- const guess = this._mapRenderers(data => {
46963
- var _data$ref;
46964
- if (!data.ref) {
46965
- return null;
46966
- }
46967
- if (data.ref.getSerializedState) {
46968
- state.push(data.ref.getSerializedState());
46969
- }
46970
- scores.push(data.ref.score());
46971
- return (_data$ref = data.ref) == null ? void 0 : _data$ref.getUserInput();
46972
- });
46973
- const combinedScore = scores.reduce(combineScores);
46974
- return keScoreFromPerseusScore(combinedScore, guess, state);
46975
- }
46976
-
46977
- /**
46978
- * Return a tree in the shape of the multi-item, with serialized state at
46979
- * each of the content nodes and `null` at the other leaf nodes.
46980
- *
46981
- * If the lastSerializedState argument is supplied, this function will fill
46982
- * in the state of not-currently-rendered content and hint nodes with the
46983
- * values from the previous serialized state. If no lastSerializedState is
46984
- * supplied, `null` will be returned for not-currently-rendered content and
46985
- * hint nodes.
46986
- */
46987
- _getSerializedState(lastSerializedState) {
46988
- return this._mapRenderers((data, _, path) => {
46989
- if (data.ref) {
46990
- return data.ref.getSerializedState();
46991
- }
46992
- if (lastSerializedState) {
46993
- return lens(lastSerializedState).get(path);
46994
- }
46995
- return null;
46996
- });
46997
- }
46998
-
46999
- /**
47000
- * Given a tree in the shape of the multi-item, with serialized state at
47001
- * each of the content nodes, restore each state to the corresponding
47002
- * renderer if currently mounted.
47003
- */
47004
- restoreSerializedState(serializedState, callback) {
47005
- // We want to call our async callback only once all of the childrens'
47006
- // callbacks have run. We add one to this counter before we call out to
47007
- // each renderer and decrement it when it runs our callback.
47008
- let numCallbacks = 0;
47009
- const countCallback = () => {
47010
- numCallbacks--;
47011
- if (callback && numCallbacks === 0) {
47012
- callback();
47013
- }
47014
- };
47015
- this._mapRenderers((data, _, path) => {
47016
- var _data$ref2;
47017
- if (!data.ref) {
47018
- return;
47019
- }
47020
- const state = lens(serializedState).get(path);
47021
- if (!state) {
47022
- return;
47023
- }
47024
- numCallbacks++;
47025
- (_data$ref2 = data.ref) == null || _data$ref2.restoreSerializedState(state, countCallback);
47026
- });
47027
- }
47028
-
47029
- /**
47030
- * Given an array of renderers, if it happens to be an array of *hint*
47031
- * renderers, then attach a `firstN` method to the array, which allows the
47032
- * layout to render the hints together in one HintsRenderer.
47033
- */
47034
- _annotateRendererArray(renderers, rendererDatas, shape) {
47035
- if (shape.elementShape.type === "hint") {
47036
- // The shape says that these are HintRendererDatas, even though
47037
- // it's not provable at compile time, so perform a cast.
47038
- const hintRendererDatas = rendererDatas;
47039
- renderers = [...renderers];
47040
- renderers.firstN = n => /*#__PURE__*/React.createElement(HintsRenderer, _extends({}, this._getRendererProps(), {
47041
- findExternalWidgets: hintRendererDatas[0] ? hintRendererDatas[0].findExternalWidgets : undefined,
47042
- hints: hintRendererDatas.map(d => d.hint),
47043
- hintsVisible: n
47044
- }));
47045
- }
47046
- return renderers;
47047
- }
47048
-
47049
- /**
47050
- * Return a tree in the shape of the multi-item, with a Renderer at each
47051
- * content node and a HintRenderer at each hint node.
47052
- *
47053
- * This is generated by running each of the `makeRenderer` functions at the
47054
- * leaf nodes.
47055
- */
47056
- _getRenderers() {
47057
- return this.getRenderersMapper.mapTree(this.state.rendererDataTree, this.props.shape);
47058
- }
47059
- render() {
47060
- if (this.state.renderError) {
47061
- return /*#__PURE__*/React.createElement("div", {
47062
- className: css(styles.error)
47063
- }, this.context.strings.errorRendering({
47064
- error: String(this.state.renderError)
47065
- }));
47066
- }
47067
-
47068
- // Pass the renderer tree to the `children` function, which will
47069
- // determine the actual content of this component.
47070
- return /*#__PURE__*/React.createElement(DependenciesContext.Provider, {
47071
- value: this.props.dependencies
47072
- }, this.props.children({
47073
- renderers: this._getRenderers()
47074
- }));
47075
- }
47076
- }
47077
- MultiRenderer.contextType = PerseusI18nContext;
47078
- const styles = StyleSheet.create({
47079
- error: {
47080
- color: "red"
47081
- }
47082
- });
47083
-
47084
- /**
47085
- * Utility functions to build React PropTypes for multi-items and shapes.
47086
- *
47087
- * If you're writing new components, though, consider using the Item and Shape
47088
- * types instead.
47089
- */
47090
- /**
47091
- * Return a PropType that accepts Items of the given shape, and rejects other
47092
- * objects.
47093
- *
47094
- * Usage: `propTypes: {item: buildPropTypeForShape(myShape)}`
47095
- */
47096
- function buildPropTypeForShape(shape) {
47097
- return PropTypes.oneOfType([PropTypes.shape({
47098
- _multi: buildTreePropTypeForShape(shape)
47099
- }), PropTypes.oneOf([null, undefined])]);
47100
- }
47101
-
47102
- /**
47103
- * Return a PropType that accepts ItemTrees of the given shape, and rejects
47104
- * other objects.
47105
- */
47106
- function buildTreePropTypeForShape(shape) {
47107
- if (shape.type === "content") {
47108
- return PropTypes.shape({
47109
- // TODO(mdr): Remove #LegacyContentNode support.
47110
- __type: PropTypes.oneOf(["content", "item"]).isRequired,
47111
- content: PropTypes.string,
47112
- images: PropTypes.objectOf(PropTypes.any),
47113
- widgets: PropTypes.objectOf(PropTypes.any)
47114
- });
47115
- }
47116
- if (shape.type === "hint") {
47117
- return PropTypes.shape({
47118
- __type: PropTypes.oneOf(["hint"]).isRequired,
47119
- content: PropTypes.string,
47120
- images: PropTypes.objectOf(PropTypes.any),
47121
- widgets: PropTypes.objectOf(PropTypes.any),
47122
- replace: PropTypes.bool
47123
- });
47124
- }
47125
- if (shape.type === "tags") {
47126
- return PropTypes.arrayOf(PropTypes.string.isRequired);
47127
- }
47128
- if (shape.type === "array") {
47129
- const elementPropType = buildTreePropTypeForShape(shape.elementShape);
47130
- return PropTypes.arrayOf(elementPropType.isRequired);
47131
- }
47132
- if (shape.type === "object") {
47133
- const valueShapes = shape.shape;
47134
- const propTypeShape = {};
47135
- Object.keys(valueShapes).forEach(key => {
47136
- propTypeShape[key] = buildTreePropTypeForShape(valueShapes[key]).isRequired;
47137
- });
47138
- return PropTypes.shape(propTypeShape);
47139
- }
47140
- throw new PerseusError(
47141
- // @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
47142
- `unexpected shape type ${shape.type}`, Errors.InvalidInput);
47143
- }
47144
-
47145
- /**
47146
- * This library provides support for Perseus multi-items: structured Perseus
47147
- * content that content creators can easily create, and that applications can
47148
- * easily render into different parts of the layout.
47149
- *
47150
- * For more details about application and motivation, see:
47151
- * https://sites.google.com/a/khanacademy.org/forge/for-developers/perseus-items-and-multi-items
47152
- *
47153
- * This file primarily exposes the `MultiRenderer` component, which performs
47154
- * multi-rendering. To multi-render a question, pass in the content of the item
47155
- * to the `MultiRenderer` component as a props. Then, pass in a function which
47156
- * takes an object of renderers (in the same structure as the content), and
47157
- * return a render tree. The `MultiRenderer` component will allow you to
47158
- * combine scores, serialized state, etc. without having to manually call on
47159
- * each of the functions. It also handles inter-widgets requests between the
47160
- * different renderers.
47161
- * For more details, see `multi-items/multi-renderer.jsx`.
47162
- *
47163
- * Example:
47164
- *
47165
- * item = {_multi: {
47166
- * left: <content data>,
47167
- * right: [<content data>, <content data>],
47168
- * }}
47169
- * shape = shapes.shape({
47170
- * left: shapes.content,
47171
- * right: shapes.arrayOf(shapes.content),
47172
- * })
47173
- *
47174
- * <MultiRenderer item={item} shape={shape}>
47175
- * {({renderers}) =>
47176
- * <div>
47177
- * <div id="left">{renderers.left}</div>
47178
- * <ul id="right">
47179
- * {renderers.right.map(r => <li>{r}</li>)}
47180
- * </ul>
47181
- * </div>
47182
- * }
47183
- * </MultiRenderer>
47184
- *
47185
- * This file also exposes `shapes`, which helps you construct a runtime type
47186
- * declaration for your particular class of multi-item. This can then be used
47187
- * to create a MultirendererEditor for your multi-item shape, and to validate
47188
- * that a multi-item conforms to the shape via `buildPropTypeForShape`.
47189
- * For more details, see `multi-items/shapes.js`.
47190
- *
47191
- * This file also exposes some utility functions for working with generic
47192
- * multi-items, like `findContentNodesInItem`, `findHintNodesInItem`,
47193
- * `inferItemShape`, and `buildEmptyItemForShape`.
47194
- * For more details, see `multi-items/items.js`.
47195
- */
47196
- var MultiItems = {
47197
- // Tools for rendering your multi-items
47198
- MultiRenderer,
47199
- // Tools for declaring your multi-item shapes
47200
- shapes,
47201
- buildPropTypeForShape,
47202
- // Tools for generically manipulating multi-items
47203
- buildEmptyItemForShape,
47204
- findContentNodesInItem: findContentNodesInItem$2,
47205
- findHintNodesInItem,
47206
- inferItemShape: inferItemShape$2
47207
- };
47208
-
47209
46092
  /**
47210
46093
  * Calculates whether a perseus item is renderable by a specific
47211
46094
  * perseus-item-data version.
@@ -47215,10 +46098,6 @@ var MultiItems = {
47215
46098
  * This supports widgets that contain renderers, such as the
47216
46099
  * group or sequence widgets.
47217
46100
  */
47218
- const {
47219
- findContentNodesInItem: findContentNodesInItem$1,
47220
- inferItemShape: inferItemShape$1
47221
- } = MultiItems;
47222
46101
  const isUpgradedWidgetInfoRenderableBy = function isUpgradedWidgetInfoRenderableBy(widgetInfo, widgetRendererVersion) {
47223
46102
  if (widgetRendererVersion == null) {
47224
46103
  // If the widget does not exist in this version, this will
@@ -47264,17 +46143,6 @@ const isItemRenderableByVersion = function isItemRenderableByVersion(itemData, r
47264
46143
  if (itemData == null || rendererContentVersion == null) {
47265
46144
  throw new PerseusError("missing parameter to Perseus.isRenderable.item", Errors.InvalidInput);
47266
46145
  }
47267
- if (itemData._multi) {
47268
- const shape = inferItemShape$1(itemData);
47269
- let isRenderable = true;
47270
- findContentNodesInItem$1(itemData, shape, node => {
47271
- const nodeIsRenderable = isRendererContentRenderableBy(node, rendererContentVersion);
47272
- if (!nodeIsRenderable) {
47273
- isRenderable = false;
47274
- }
47275
- });
47276
- return isRenderable;
47277
- }
47278
46146
  return isRendererContentRenderableBy(itemData.question, rendererContentVersion);
47279
46147
  };
47280
46148
 
@@ -47282,10 +46150,6 @@ const isItemRenderableByVersion = function isItemRenderableByVersion(itemData, r
47282
46150
  * Identifies whether or not a given perseus item requires the use of a mouse
47283
46151
  * or screen, based on the widgets it contains.
47284
46152
  */
47285
- const {
47286
- findContentNodesInItem,
47287
- inferItemShape
47288
- } = MultiItems;
47289
46153
 
47290
46154
  // Iterate over a single Perseus renderer, mutating `widgets` by appending
47291
46155
  // violating widget types discovered in this item.
@@ -47306,12 +46170,7 @@ function traverseRenderer(itemData, widgets) {
47306
46170
  function violatingWidgets(itemData) {
47307
46171
  // TODO(jordan): Hints as well
47308
46172
  const widgets = [];
47309
- if (itemData._multi) {
47310
- const shape = inferItemShape(itemData);
47311
- findContentNodesInItem(itemData, shape, content => traverseRenderer(content, widgets));
47312
- } else {
47313
- traverseRenderer(itemData.question, widgets);
47314
- }
46173
+ traverseRenderer(itemData.question, widgets);
47315
46174
 
47316
46175
  // Uniquify the list of widgets (by type)
47317
46176
  return _.uniq(widgets);
@@ -49818,5 +48677,9 @@ const ScoringUtil = {
49818
48677
  keScoreFromPerseusScore
49819
48678
  };
49820
48679
 
49821
- export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, bodyXsmallBold, buildEmptyItemTreeForShape, buildMapper, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mathOnlyParser, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, scorePerseusItem, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48680
+ /**
48681
+ * Types
48682
+ */
48683
+
48684
+ export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mathOnlyParser, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, scorePerseusItem, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
49822
48685
  //# sourceMappingURL=index.js.map