@khanacademy/perseus 21.0.0 → 21.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -25026,9 +25026,22 @@ class Explanation extends React__namespace.Component {
25026
25026
  // Special styling is needed to fit the button in a block of text without throwing off the line spacing.
25027
25027
  // While the button is not normally included in a block of text, it needs to be able to accommodate such a case.
25028
25028
  const buttonStyleOverrides = {
25029
- height: "22px",
25029
+ height: "auto",
25030
25030
  marginLeft: "-2px",
25031
- padding: "0 2px"
25031
+ // transfer space on the left side to the padding
25032
+ marginRight: "2px",
25033
+ // adds space between the right border and any text that follows
25034
+ paddingLeft: "2px" // adds space between the left border and the button text
25035
+ };
25036
+
25037
+ const labelStyle = {
25038
+ fontSize: "18px",
25039
+ lineHeight: "20px",
25040
+ // The following property adjusts the large space between the button text and the caret icon.
25041
+ // Since we are unable to adjust the styling of the icon (where the extra space exists),
25042
+ // we are adjusting it on the text label by using a negative margin.
25043
+ marginRight: "-6px",
25044
+ "white-space": "normal"
25032
25045
  };
25033
25046
  const contentStyling = [styles$p.content, this.state.expanded ? styles$p.contentExpanded : styles$p.contentCollapsed, allowTransition && (this.state.expanded ? styles$p.transitionExpanded : styles$p.transitionCollapsed)];
25034
25047
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
@@ -25039,8 +25052,9 @@ class Explanation extends React__namespace.Component {
25039
25052
  "aria-controls": ids.get("content"),
25040
25053
  endIcon: caretIcon,
25041
25054
  kind: "tertiary",
25055
+ labelStyle: labelStyle,
25042
25056
  onClick: this._onClick,
25043
- size: "large",
25057
+ size: "small",
25044
25058
  style: buttonStyleOverrides
25045
25059
  }, promptText), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
25046
25060
  id: ids.get("content"),
@@ -28342,6 +28356,14 @@ const moveAll = delta => ({
28342
28356
  type: MOVE_ALL,
28343
28357
  delta
28344
28358
  });
28359
+ const MOVE_POINT = "move-point";
28360
+ function movePoint(index, destination) {
28361
+ return {
28362
+ type: MOVE_POINT,
28363
+ index,
28364
+ destination
28365
+ };
28366
+ }
28345
28367
 
28346
28368
  /**
28347
28369
  * 44 is touch best practice and AAA compliant for WCAG
@@ -28567,7 +28589,9 @@ const SegmentGraph = props => {
28567
28589
  onMoveLine: delta => {
28568
28590
  dispatch(moveLine(i, delta));
28569
28591
  },
28570
- onMovePoint: (endpointIndex, destination) => dispatch(moveControlPoint(endpointIndex, destination, i)),
28592
+ onMovePoint: (endpointIndex, destination) => {
28593
+ dispatch(moveControlPoint(endpointIndex, destination, i));
28594
+ },
28571
28595
  "data-testid": "segment" + i
28572
28596
  })));
28573
28597
  };
@@ -28931,11 +28955,73 @@ const PolygonGraph = props => {
28931
28955
  }), points.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
28932
28956
  key: "point-" + i,
28933
28957
  point: point,
28934
- onMove: destination => dispatch(moveControlPoint(i, destination)),
28958
+ onMove: destination => dispatch(movePoint(i, destination)),
28935
28959
  "data-testid": type + i
28936
28960
  })));
28937
28961
  };
28938
28962
 
28963
+ function PointGraph(props) {
28964
+ const {
28965
+ dispatch
28966
+ } = props;
28967
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.graphState.coords.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
28968
+ key: i,
28969
+ point: point,
28970
+ onMove: destination => dispatch(movePoint(i, destination))
28971
+ })));
28972
+ }
28973
+
28974
+ const GraphStateContext = /*#__PURE__*/React.createContext({
28975
+ state: {},
28976
+ dispatch: () => {}
28977
+ });
28978
+ function useGraphState() {
28979
+ return React__default["default"].useContext(GraphStateContext);
28980
+ }
28981
+
28982
+ function Arrow(props) {
28983
+ const {
28984
+ userTransform,
28985
+ viewTransform
28986
+ } = mafs.useTransformContext();
28987
+ const point = [props.x, props.y];
28988
+ const userTransformedPoint = mafs.vec.transform(point, userTransform);
28989
+ const viewTransformedPoint = mafs.vec.transform(userTransformedPoint, viewTransform);
28990
+ return /*#__PURE__*/React__default["default"].createElement("g", {
28991
+ transform: `translate(${viewTransformedPoint[0]} ${viewTransformedPoint[1]}) rotate(${props.rotate}) scale(1.25)`
28992
+ }, /*#__PURE__*/React__default["default"].createElement("g", {
28993
+ transform: "translate(-1)"
28994
+ }, /*#__PURE__*/React__default["default"].createElement("path", {
28995
+ d: "M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4",
28996
+ fill: "none"
28997
+ })));
28998
+ }
28999
+ function AxisArrows() {
29000
+ const {
29001
+ state
29002
+ } = useGraphState();
29003
+ const range = state.range;
29004
+ const [xMin, xMax] = range[0];
29005
+ const [yMin, yMax] = range[1];
29006
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrow, {
29007
+ x: xMax,
29008
+ y: 0,
29009
+ rotate: 0
29010
+ }), /*#__PURE__*/React__default["default"].createElement(Arrow, {
29011
+ x: 0,
29012
+ y: yMin,
29013
+ rotate: 90
29014
+ }), /*#__PURE__*/React__default["default"].createElement(Arrow, {
29015
+ x: xMin,
29016
+ y: 0,
29017
+ rotate: 180
29018
+ }), /*#__PURE__*/React__default["default"].createElement(Arrow, {
29019
+ x: 0,
29020
+ y: yMax,
29021
+ rotate: 270
29022
+ }));
29023
+ }
29024
+
28939
29025
  const renderLineLabel = (n, _ref) => {
28940
29026
  let [min, max] = _ref;
28941
29027
  return n !== -1 && n !== min && n !== max;
@@ -28946,10 +29032,10 @@ const axisOptions = (props, index) => ({
28946
29032
  subdivisions: props.step[index] / props.gridStep[index],
28947
29033
  labels: n => renderLineLabel(n, props.range[index]) ? n : ""
28948
29034
  });
28949
- const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
29035
+ const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
28950
29036
  xAxis: axisOptions(props, 0),
28951
29037
  yAxis: axisOptions(props, 1)
28952
- });
29038
+ }), props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisArrows, null));
28953
29039
 
28954
29040
  // Displays a stylized open eye: lint warnings are visible
28955
29041
  const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
@@ -29647,22 +29733,32 @@ const LegacyGrid = _ref => {
29647
29733
  return null;
29648
29734
  };
29649
29735
 
29650
- /** Determine if coords is type CollinearTuple[] */
29651
- const isCollinearTuples = coords => Array.isArray(coords[0][0]);
29652
-
29653
- // Generic type makes returned state match input state
29654
29736
  function interactiveGraphReducer(state, action) {
29737
+ switch (action.type) {
29738
+ case MOVE_CONTROL_POINT:
29739
+ return doMoveControlPoint(state, action);
29740
+ case MOVE_LINE:
29741
+ return doMoveLine(state, action);
29742
+ case MOVE_ALL:
29743
+ return doMoveAll(state, action);
29744
+ case MOVE_POINT:
29745
+ return doMovePoint(state, action);
29746
+ default:
29747
+ throw new wonderStuffCore.UnreachableCaseError(action);
29748
+ }
29749
+ }
29750
+ function doMoveControlPoint(state, action) {
29655
29751
  const {
29656
29752
  snapStep,
29657
29753
  range
29658
29754
  } = state;
29659
- if (!state.coords) {
29660
- throw new Error("Graph state must have been initialized with coords");
29661
- }
29662
- switch (action.type) {
29663
- case MOVE_CONTROL_POINT:
29755
+ switch (state.type) {
29756
+ case "segment":
29757
+ case "linear":
29758
+ case "linear-system":
29759
+ case "ray":
29664
29760
  {
29665
- const newCoords = action.itemIndex !== undefined && state.coords && isCollinearTuples(state.coords) ? updateAtIndex({
29761
+ const newCoords = updateAtIndex({
29666
29762
  array: state.coords,
29667
29763
  index: action.itemIndex,
29668
29764
  update: tuple => setAtIndex({
@@ -29677,23 +29773,9 @@ function interactiveGraphReducer(state, action) {
29677
29773
  })
29678
29774
  })
29679
29775
  })
29680
- }) : setAtIndex({
29681
- array: state.coords,
29682
- index: action.pointIndex,
29683
- newValue: snap({
29684
- snapStep,
29685
- point: bound$1({
29686
- snapStep,
29687
- range,
29688
- point: action.destination
29689
- })
29690
- })
29691
29776
  });
29692
-
29693
- // Cannot type narrow both conditions within function parameters,
29694
- // so this may seem redundant, but it's necessary for type safety.
29695
- const coordsToCheck = isCollinearTuples(newCoords) && action.itemIndex !== undefined ? newCoords[action.itemIndex] : newCoords;
29696
- if (!isCollinearTuples(coordsToCheck) && coordsOverlap(coordsToCheck)) {
29777
+ const coordsToCheck = newCoords[action.itemIndex];
29778
+ if (coordsOverlap(coordsToCheck)) {
29697
29779
  return state;
29698
29780
  }
29699
29781
  return {
@@ -29702,15 +29784,30 @@ function interactiveGraphReducer(state, action) {
29702
29784
  coords: newCoords
29703
29785
  };
29704
29786
  }
29705
- case MOVE_LINE:
29787
+ case "circle":
29788
+ throw new Error("FIXME implement circle reducer");
29789
+ case "point":
29790
+ case "polygon":
29791
+ throw new Error(`Don't use moveControlPoint for ${state.type} graphs. Use movePoint instead!`);
29792
+ default:
29793
+ throw new wonderStuffCore.UnreachableCaseError(state);
29794
+ }
29795
+ }
29796
+ function doMoveLine(state, action) {
29797
+ const {
29798
+ snapStep,
29799
+ range
29800
+ } = state;
29801
+ switch (state.type) {
29802
+ case "segment":
29803
+ case "linear":
29804
+ case "linear-system":
29805
+ case "ray":
29706
29806
  {
29707
- if (!isCollinearTuples(state.coords)) {
29708
- throw new Error("Cannot call this action unless coords is array of CollinearTuple.");
29709
- }
29710
29807
  if (action.itemIndex === undefined) {
29711
29808
  throw new Error("Please provide index of line to move");
29712
29809
  }
29713
- const currentLine = state.coords?.[action.itemIndex];
29810
+ const currentLine = state.coords[action.itemIndex];
29714
29811
  if (!currentLine) {
29715
29812
  throw new Error("No line to move");
29716
29813
  }
@@ -29732,15 +29829,25 @@ function interactiveGraphReducer(state, action) {
29732
29829
  });
29733
29830
  return {
29734
29831
  ...state,
29832
+ type: state.type,
29735
29833
  hasBeenInteractedWith: true,
29736
29834
  coords: newCoords
29737
29835
  };
29738
29836
  }
29739
- case MOVE_ALL:
29837
+ default:
29838
+ // The MoveLine action doesn't make sense for other graph types;
29839
+ // ignore it if it somehow happens
29840
+ return state;
29841
+ }
29842
+ }
29843
+ function doMoveAll(state, action) {
29844
+ const {
29845
+ snapStep,
29846
+ range
29847
+ } = state;
29848
+ switch (state.type) {
29849
+ case "polygon":
29740
29850
  {
29741
- if (isCollinearTuples(state.coords)) {
29742
- throw new Error("Cannot call this action unless coords is array of vectors.");
29743
- }
29744
29851
  const change = getChange(state.coords, action.delta, {
29745
29852
  snapStep,
29746
29853
  range
@@ -29756,7 +29863,34 @@ function interactiveGraphReducer(state, action) {
29756
29863
  };
29757
29864
  }
29758
29865
  default:
29759
- throw new wonderStuffCore.UnreachableCaseError(action);
29866
+ // MoveAll is not supported for other state types; just ignore it.
29867
+ return state;
29868
+ }
29869
+ }
29870
+ function doMovePoint(state, action) {
29871
+ switch (state.type) {
29872
+ case "point":
29873
+ case "polygon":
29874
+ {
29875
+ return {
29876
+ ...state,
29877
+ hasBeenInteractedWith: true,
29878
+ coords: setAtIndex({
29879
+ array: state.coords,
29880
+ index: action.index,
29881
+ newValue: snap({
29882
+ snapStep: state.snapStep,
29883
+ point: bound$1({
29884
+ snapStep: state.snapStep,
29885
+ range: state.range,
29886
+ point: action.destination
29887
+ })
29888
+ })
29889
+ })
29890
+ };
29891
+ }
29892
+ default:
29893
+ throw new Error("The movePoint action is only for point and polygon graphs");
29760
29894
  }
29761
29895
  }
29762
29896
  const getChange = (coords, delta, constraintOpts) => {
@@ -29843,7 +29977,7 @@ function clamp(value, min, max) {
29843
29977
  const coordsOverlap = coords => coords.some((coord, i) => coords.some((c, j) => i !== j && kmath.vector.equal(coord, c)));
29844
29978
  function updateAtIndex(args) {
29845
29979
  const {
29846
- array = [],
29980
+ array,
29847
29981
  index,
29848
29982
  update
29849
29983
  } = args;
@@ -29856,13 +29990,12 @@ function updateAtIndex(args) {
29856
29990
  }
29857
29991
  function setAtIndex(args) {
29858
29992
  const {
29859
- array = [],
29993
+ array,
29860
29994
  index,
29861
29995
  newValue
29862
29996
  } = args;
29863
29997
  const copy = [...array];
29864
29998
  copy[index] = newValue;
29865
- // restoring readonly to array
29866
29999
  return copy;
29867
30000
  }
29868
30001
 
@@ -29904,18 +30037,31 @@ function initializeGraphState(params) {
29904
30037
  };
29905
30038
  case "polygon":
29906
30039
  return {
30040
+ type: "polygon",
29907
30041
  hasBeenInteractedWith: false,
29908
30042
  range,
29909
30043
  snapStep,
29910
- ...graph,
30044
+ showAngles: Boolean(graph.showAngles),
30045
+ showSides: Boolean(graph.showSides),
29911
30046
  coords: getPolygonCoords({
29912
30047
  graph,
29913
30048
  range,
29914
30049
  step
29915
30050
  })
29916
30051
  };
29917
- case "angle":
29918
30052
  case "point":
30053
+ return {
30054
+ type: graph.type,
30055
+ hasBeenInteractedWith: false,
30056
+ range,
30057
+ snapStep,
30058
+ coords: getDefaultPoints({
30059
+ graph,
30060
+ step,
30061
+ range
30062
+ })
30063
+ };
30064
+ case "angle":
29919
30065
  case "circle":
29920
30066
  case "sinusoid":
29921
30067
  case "quadratic":
@@ -29924,6 +30070,46 @@ function initializeGraphState(params) {
29924
30070
  throw new wonderStuffCore.UnreachableCaseError(graph);
29925
30071
  }
29926
30072
  }
30073
+ const getDefaultPoints = _ref => {
30074
+ let {
30075
+ graph,
30076
+ range,
30077
+ step
30078
+ } = _ref;
30079
+ const numPoints = graph.numPoints || 1;
30080
+ let coords = graph.coords?.slice();
30081
+ if (coords) {
30082
+ return coords;
30083
+ }
30084
+ switch (numPoints) {
30085
+ case 1:
30086
+ // Back in the day, one point's coords were in graph.coord
30087
+ coords = [graph.coord || [0, 0]];
30088
+ break;
30089
+ case 2:
30090
+ coords = [[-5, 0], [5, 0]];
30091
+ break;
30092
+ case 3:
30093
+ coords = [[-5, 0], [0, 0], [5, 0]];
30094
+ break;
30095
+ case 4:
30096
+ coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
30097
+ break;
30098
+ case 5:
30099
+ coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
30100
+ break;
30101
+ case 6:
30102
+ coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
30103
+ break;
30104
+ default:
30105
+ coords = [];
30106
+ break;
30107
+ }
30108
+ // Transform coords from their -10 to 10 space to 0 to 1
30109
+ // because of the old graph.coord, and also it's easier.
30110
+ const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
30111
+ return normalizePoints(range, step, newCoords);
30112
+ };
29927
30113
 
29928
30114
  // TS v4 doesn't narrow return types, while v5 does.
29929
30115
  // Instead of updating to v5, using generic type to relate input and output types.
@@ -29948,13 +30134,13 @@ function getGradableGraph(state, initialGraph) {
29948
30134
  if (state.type === "linear" && initialGraph.type === "linear") {
29949
30135
  return {
29950
30136
  ...initialGraph,
29951
- coords: state.coords?.[0]
30137
+ coords: state.coords[0]
29952
30138
  };
29953
30139
  }
29954
30140
  if (state.type === "ray" && initialGraph.type === "ray") {
29955
30141
  return {
29956
30142
  ...initialGraph,
29957
- coords: state.coords?.[0]
30143
+ coords: state.coords[0]
29958
30144
  };
29959
30145
  }
29960
30146
  if (state.type === "polygon" && initialGraph.type === "polygon") {
@@ -29963,14 +30149,20 @@ function getGradableGraph(state, initialGraph) {
29963
30149
  coords: state.coords
29964
30150
  };
29965
30151
  }
30152
+ if (state.type === "point" && initialGraph.type === "point") {
30153
+ return {
30154
+ ...initialGraph,
30155
+ coords: state.coords
30156
+ };
30157
+ }
29966
30158
  throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
29967
30159
  }
29968
- const getDefaultSegments = _ref => {
30160
+ const getDefaultSegments = _ref2 => {
29969
30161
  let {
29970
30162
  graph,
29971
30163
  range,
29972
30164
  step
29973
- } = _ref;
30165
+ } = _ref2;
29974
30166
  const ys = n => {
29975
30167
  switch (n) {
29976
30168
  case 2:
@@ -29996,24 +30188,24 @@ const getDefaultSegments = _ref => {
29996
30188
  });
29997
30189
  };
29998
30190
  const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
29999
- const getLineCoords = _ref2 => {
30191
+ const getLineCoords = _ref3 => {
30000
30192
  let {
30001
30193
  graph,
30002
30194
  range,
30003
30195
  step
30004
- } = _ref2;
30196
+ } = _ref3;
30005
30197
  return (
30006
30198
  // Return two lines for a linear system, one for a ray or linear
30007
30199
  graph.coords ?? graph.type === "linear-system" ? defaultLinearCoords.map(collinear => normalizePoints(range, step, collinear)) : [normalizePoints(range, step, defaultLinearCoords[0])]
30008
30200
  );
30009
30201
  };
30010
- const getPolygonCoords = _ref3 => {
30202
+ const getPolygonCoords = _ref4 => {
30011
30203
  let {
30012
30204
  graph,
30013
30205
  range,
30014
30206
  step
30015
- } = _ref3;
30016
- let coords = graph.coords;
30207
+ } = _ref4;
30208
+ let coords = graph.coords?.slice();
30017
30209
  if (coords) {
30018
30210
  return coords;
30019
30211
  }
@@ -30067,6 +30259,13 @@ const renderGraph = props => {
30067
30259
  graphState: state,
30068
30260
  dispatch: dispatch
30069
30261
  });
30262
+ case "point":
30263
+ return /*#__PURE__*/React__namespace.createElement(PointGraph, {
30264
+ graphState: state,
30265
+ dispatch: dispatch
30266
+ });
30267
+ case "circle":
30268
+ throw new Error("the circle graph type is not yet implemented");
30070
30269
  default:
30071
30270
  return new wonderStuffCore.UnreachableCaseError(type);
30072
30271
  }
@@ -30074,10 +30273,24 @@ const renderGraph = props => {
30074
30273
  const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30075
30274
  const [width, height] = props.box;
30076
30275
  const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
30276
+ const prevState = React.useRef(state);
30277
+ React.useEffect(() => {
30278
+ if (prevState.current !== state) {
30279
+ props.onChange({
30280
+ graph: state
30281
+ });
30282
+ }
30283
+ prevState.current = state;
30284
+ }, [props, state]);
30077
30285
  React__namespace.useImperativeHandle(ref, () => ({
30078
30286
  getUserInput: () => getGradableGraph(state, props.graph)
30079
30287
  }));
30080
- return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30288
+ return /*#__PURE__*/React__namespace.createElement(GraphStateContext.Provider, {
30289
+ value: {
30290
+ state,
30291
+ dispatch
30292
+ }
30293
+ }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
30081
30294
  style: {
30082
30295
  width,
30083
30296
  height,
@@ -30108,7 +30321,7 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
30108
30321
  }), renderGraph({
30109
30322
  state,
30110
30323
  dispatch
30111
- }))));
30324
+ })))));
30112
30325
  });
30113
30326
 
30114
30327
  const {
@@ -31275,6 +31488,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
31275
31488
  });
31276
31489
  $__default["default"](this.angle).on("move", () => {
31277
31490
  this.onChange({
31491
+ // @ts-expect-error Type '{ coords: any; type: "angle"; showAngles?: boolean | undefined; allowReflexAngles?: boolean | undefined; angleOffsetDeg?: number | undefined; snapDegrees?: number | undefined; match?: "congruent" | undefined; }' is not assignable to type 'InteractiveGraphState | undefined'.
31278
31492
  graph: {
31279
31493
  ...graph,
31280
31494
  coords: this.angle?.getClockwiseCoords()
@@ -31809,7 +32023,7 @@ class InteractiveGraph extends React__namespace.Component {
31809
32023
  }
31810
32024
  } else if (userInput.type === "point" && rubric.correct.type === "point" && userInput.coords != null) {
31811
32025
  let correct = InteractiveGraph.getPointCoords(rubric.correct, component);
31812
- const guess = userInput.coords?.slice();
32026
+ const guess = userInput.coords.slice();
31813
32027
  correct = correct.slice();
31814
32028
  // Everything's already rounded so we shouldn't need to do an
31815
32029
  // eq() comparison but _.isEqual(0, -0) is false, so we'll use
@@ -42115,7 +42329,7 @@ const init = function (options) {
42115
42329
 
42116
42330
  // This file is processed by a Rollup plugin (replace) to inject the production
42117
42331
  const libName = "@khanacademy/perseus";
42118
- const libVersion = "21.0.0";
42332
+ const libVersion = "21.1.0";
42119
42333
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
42120
42334
 
42121
42335
  const apiVersion = {
@@ -44617,7 +44831,7 @@ function getAnswersFromWidgets(widgets) {
44617
44831
  // E.g. 'item 1\nitem 2\nitem 3'
44618
44832
  const orderer = widget;
44619
44833
  if (orderer.options?.correctOptions) {
44620
- answers.push(orderer.options.correctOptions.map(option => option.content).join("\n"));
44834
+ answers.push(joinOptionContents(orderer.options.correctOptions));
44621
44835
  }
44622
44836
  break;
44623
44837
  case "sorter":
@@ -44676,6 +44890,31 @@ function getAnswersFromWidgets(widgets) {
44676
44890
  return answers;
44677
44891
  }
44678
44892
 
44893
+ /**
44894
+ * Join the content of the options together.
44895
+ * @param {Array<{content: string}>} options
44896
+ * @returns {string}
44897
+ */
44898
+ const joinOptionContents = options => options.map(_ref => {
44899
+ let {
44900
+ content
44901
+ } = _ref;
44902
+ return content;
44903
+ }).join("\n");
44904
+
44905
+ /**
44906
+ * Convert an index to an option letter.
44907
+ * @param {number} index
44908
+ * @returns {string}
44909
+ * @example
44910
+ * toOptionLetter(0) // 'A'
44911
+ * toOptionLetter(1) // 'B'
44912
+ * toOptionLetter(25) // 'Z'
44913
+ * // Once the index goes past 25, it will start returning special characters
44914
+ * toOptionLetter(26) // '['
44915
+ */
44916
+ const toOptionLetter = index => String.fromCharCode("A".charCodeAt(0) + index);
44917
+
44679
44918
  /**
44680
44919
  * Inject a string equivalent of the widgets into the content.
44681
44920
  *
@@ -44686,7 +44925,7 @@ function getAnswersFromWidgets(widgets) {
44686
44925
  * @param {PerseusRenderer["widgets"]} widgets
44687
44926
  * @returns
44688
44927
  */
44689
- function injectWidgets(content, widgets) {
44928
+ function injectWidgets(content, widgets, widgetProps) {
44690
44929
  // The types for taskProgress.itemData are not well defined,
44691
44930
  // so there is a chance that widgets or content could be undefined.
44692
44931
  // In that scenario, simply exit early and return the content as is.
@@ -44705,11 +44944,22 @@ function injectWidgets(content, widgets) {
44705
44944
  switch (widget.type) {
44706
44945
  case "radio":
44707
44946
  // Replace radio with the radio options
44708
- // '[[☃ Radio 1]]' -> 'option 1\noption 2\noption 3'
44947
+ // '[[☃ Radio 1]]' -> 'choice 1\nchoice 2\nchoice 3'
44948
+ // or if the current widget state is available with proper order,
44949
+ // '[[☃ Radio 1]]' ->
44950
+ // 'Option A: choice 1\nOption B: choice 2\nOption C: choice 3'
44709
44951
  const radio = widget;
44952
+ const radioProps = widgetProps?.[widgetID];
44710
44953
  if (radio.options?.choices?.length) {
44711
- let radioContext = radio.options.choices.map(choice => choice.content).join("\n");
44712
- if (radio.options?.randomize) {
44954
+ let radioContext = joinOptionContents(radioProps ? radioProps.choices.map((_ref2, i) => {
44955
+ let {
44956
+ content
44957
+ } = _ref2;
44958
+ return {
44959
+ content: `Option ${toOptionLetter(i)}: ${content}`
44960
+ };
44961
+ }) : radio.options.choices);
44962
+ if (!radioProps && radio.options?.randomize) {
44713
44963
  radioContext += "\nThose options are displayed in a different order to the user. If the user says the letter, number, or ordinal number, always ask them clarify which option they are referring to.\n";
44714
44964
  }
44715
44965
  context = context.replace(`[[☃ ${widgetID}]]`, radioContext);
@@ -44817,7 +45067,7 @@ function injectWidgets(content, widgets) {
44817
45067
  // '[[☃ Orderer 1]]' -> 'option 1\noption 2\noption 3'
44818
45068
  const orderer = widget;
44819
45069
  if (orderer.options?.options) {
44820
- context = context.replace(`[[☃ ${widgetID}]]`, orderer.options.options.map(option => option.content).join("\n"));
45070
+ context = context.replace(`[[☃ ${widgetID}]]`, joinOptionContents(orderer.options.options));
44821
45071
  }
44822
45072
  break;
44823
45073
  case "sorter":