@khanacademy/perseus 49.1.7 → 49.2.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
@@ -487,12 +487,12 @@ const mockStrings = {
487
487
  angleMeasure,
488
488
  vertexX,
489
489
  vertexY,
490
- isX,
491
- isY,
492
- tsX,
493
- tsY
490
+ startingSideX,
491
+ startingSideY,
492
+ endingSideX,
493
+ endingSideY
494
494
  } = _ref40;
495
- return `The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the initial side at ${isX} comma ${isY} and a point on the terminal side at ${tsX} comma ${tsY}.`;
495
+ return `The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the starting side at ${startingSideX} comma ${startingSideY} and a point on the ending side at ${endingSideX} comma ${endingSideY}.`;
496
496
  }
497
497
  // The above strings are used for interactive graph SR descriptions.
498
498
  };
@@ -897,6 +897,9 @@ const mapButtonSets = buttonSets => {
897
897
  case "trig":
898
898
  keypadButtonSets.trigonometry = true;
899
899
  break;
900
+ case "scientific":
901
+ keypadButtonSets.scientific = true;
902
+ break;
900
903
  }
901
904
  });
902
905
  return keypadButtonSets;
@@ -3971,7 +3974,9 @@ ZoomServiceClass.prototype._scrollHandler = function (e) {
3971
3974
  }
3972
3975
  };
3973
3976
  ZoomServiceClass.prototype._keyHandler = function (e) {
3974
- if (e.keyCode === 27) {
3977
+ // 27: Esc, 13: Enter, 32: Space
3978
+ const keyCodes = [27, 13, 32];
3979
+ if (keyCodes.includes(e.keyCode)) {
3975
3980
  this._activeZoomClose();
3976
3981
  }
3977
3982
  };
@@ -4060,6 +4065,7 @@ Zoom.prototype.zoomImage = function () {
4060
4065
  }.bind(this);
4061
4066
  img.src = this._targetImage.src;
4062
4067
  img.alt = this._targetImage.alt;
4068
+ img.tabIndex = 0;
4063
4069
  this.$zoomedImage = $zoomedImage;
4064
4070
  };
4065
4071
  Zoom.prototype._zoomOriginal = function () {
@@ -17242,6 +17248,7 @@ class ImageLoader extends React__namespace.Component {
17242
17248
  }
17243
17249
  const staticUrl = getDependencies().staticUrl;
17244
17250
  return /*#__PURE__*/React__namespace.createElement("img", _extends({
17251
+ tabIndex: 0,
17245
17252
  src: staticUrl(src),
17246
17253
  onKeyUp: onKeyUp,
17247
17254
  onKeyDown: onKeyDown
@@ -22456,7 +22463,7 @@ function scoreNumericInput(userInput, rubric, strings) {
22456
22463
  // We may have received TeX; try to parse it before grading.
22457
22464
  // If `currentValue` is not TeX, this should be a no-op.
22458
22465
  const currentValue = ParseTex(userInput.currentValue);
22459
- const normalizedAnswerExpected = rubric.answers.filter(answer => answer.status === "correct").every(answer => answer.value !== undefined && Math.abs(answer.value) <= 1);
22466
+ const normalizedAnswerExpected = rubric.answers.filter(answer => answer.status === "correct").every(answer => answer.value != null && Math.abs(answer.value) <= 1);
22460
22467
 
22461
22468
  // The coefficient is an attribute of the widget
22462
22469
  let localValue = currentValue;
@@ -27732,6 +27739,7 @@ class Dropdown extends React__namespace.Component {
27732
27739
  }, this.props.visibleLabel), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
27733
27740
  id: dropdownId,
27734
27741
  placeholder: "",
27742
+ className: "perseus-dropdown",
27735
27743
  onChange: value => this._handleChange(parseInt(value)),
27736
27744
  selectedValue: String(this.props.selected),
27737
27745
  disabled: this.props.apiOptions.readOnly,
@@ -34459,10 +34467,10 @@ function AngleGraph(props) {
34459
34467
  angleMeasure,
34460
34468
  vertexX: srFormatNumber(coords[1][X], locale),
34461
34469
  vertexY: srFormatNumber(coords[1][Y], locale),
34462
- isX: srFormatNumber(coords[2][X], locale),
34463
- isY: srFormatNumber(coords[2][Y], locale),
34464
- tsX: srFormatNumber(coords[0][X], locale),
34465
- tsY: srFormatNumber(coords[0][Y], locale)
34470
+ startingSideX: srFormatNumber(coords[2][X], locale),
34471
+ startingSideY: srFormatNumber(coords[2][Y], locale),
34472
+ endingSideX: srFormatNumber(coords[0][X], locale),
34473
+ endingSideY: srFormatNumber(coords[0][Y], locale)
34466
34474
  });
34467
34475
  const formatCoordinates = (x, y) => ({
34468
34476
  x: srFormatNumber(x, locale),
@@ -45936,7 +45944,7 @@ const init = function () {
45936
45944
 
45937
45945
  // This file is processed by a Rollup plugin (replace) to inject the production
45938
45946
  const libName = "@khanacademy/perseus";
45939
- const libVersion = "49.1.7";
45947
+ const libVersion = "49.2.0";
45940
45948
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45941
45949
 
45942
45950
  const apiVersion = {
@@ -48236,10 +48244,10 @@ class UnionBuilder {
48236
48244
  this.parser = parser;
48237
48245
  }
48238
48246
  or(newBranch) {
48239
- return new UnionBuilder(either(this.parser, newBranch));
48247
+ return new UnionBuilder(either$1(this.parser, newBranch));
48240
48248
  }
48241
48249
  }
48242
- function either(parseA, parseB) {
48250
+ function either$1(parseA, parseB) {
48243
48251
  return (rawValue, ctx) => {
48244
48252
  const resultA = parseA(rawValue, ctx);
48245
48253
  if (isSuccess(resultA)) {
@@ -48341,22 +48349,108 @@ const parseExplanationWidget = parseWidget(constant("explanation"), object({
48341
48349
  // We wrap parseWidgetsMap in a function here to make sure it is not
48342
48350
  // referenced before it is defined. There is an import cycle between
48343
48351
  // this file and widgets-map.ts that could cause it to be undefined.
48344
- widgets: (rawVal, ctx) => parseWidgetsMap(rawVal, ctx),
48345
- static: boolean
48352
+ widgets: defaulted((rawVal, ctx) => parseWidgetsMap(rawVal, ctx), () => ({})),
48353
+ static: defaulted(boolean, () => false)
48346
48354
  }));
48347
48355
 
48348
- const parseAnswerForm = object({
48349
- value: string,
48350
- form: boolean,
48351
- simplify: boolean,
48356
+ // Given a function, creates a PartialParser that converts one type to another
48357
+ // using that function. The returned parser never fails.
48358
+ function convert(f) {
48359
+ return (rawValue, ctx) => ctx.success(f(rawValue));
48360
+ }
48361
+
48362
+ /**
48363
+ * Creates a parser for a widget options type with multiple major versions. Old
48364
+ * versions are migrated to the latest version. The parse fails if the input
48365
+ * data does not match any of the versions.
48366
+ *
48367
+ * @example
48368
+ * const parseOptions = versionedWidgetOptions(parseOptionsV3)
48369
+ * .withMigrationFrom(parseOptionsV2, migrateV2ToV3)
48370
+ * .withMigrationFrom(parseOptionsV1, migrateV1ToV2)
48371
+ * .withMigrationFrom(parseOptionsV0, migrateV0ToV1)
48372
+ * .parser;
48373
+ *
48374
+ * @param parseLatest a {@link Parser} for the latest version of the widget
48375
+ * options. This should check version.major and fail if it's not the latest
48376
+ * version.
48377
+ * @returns a builder object, to which migrations from earlier versions can be
48378
+ * added. Migrations must be added in "reverse chronological" order as in the
48379
+ * example above.
48380
+ */
48381
+ function versionedWidgetOptions(parseLatest) {
48382
+ return new VersionedWidgetOptionsParserBuilder(parseLatest, latest => latest);
48383
+ }
48384
+ class VersionedWidgetOptionsParserBuilder {
48385
+ constructor(parser, migrate) {
48386
+ this.parser = parser;
48387
+ this.migrate = migrate;
48388
+ }
48389
+
48390
+ /**
48391
+ * Add a migration from an old version of the widget options.
48392
+ *
48393
+ * @returns a VersionedWidgetOptionsParserBuilder whose `parser` function
48394
+ * is capable of migrating the old version to the latest version. The parser
48395
+ * will always return the latest version of the widget options on a
48396
+ * successful parse.
48397
+ * @param parseOldVersion should be a {@link Parser} for the old options
48398
+ * type. It should fail if version.major isn't correct.
48399
+ * @param migrateToNextVersion should migrate the `Old` data to the
48400
+ * `Migratable` version of the current VersionedWidgetOptionsParserBuilder.
48401
+ * Usually, this means migrating to the next major version.
48402
+ */
48403
+ withMigrationFrom(parseOldVersion, migrateToNextVersion) {
48404
+ const parseLatestVersion = this.parser;
48405
+ const migrateToLatest = old => this.migrate(migrateToNextVersion(old));
48406
+ return new VersionedWidgetOptionsParserBuilder((raw, ctx) => {
48407
+ const resultOfParsingLatest = parseLatestVersion(raw, ctx);
48408
+ if (isSuccess(resultOfParsingLatest)) {
48409
+ return resultOfParsingLatest;
48410
+ }
48411
+ const resultOfParsingOld = parseOldVersion(raw, ctx);
48412
+ if (isSuccess(resultOfParsingOld)) {
48413
+ return success(migrateToLatest(resultOfParsingOld.value));
48414
+ }
48415
+
48416
+ // If we're here, neither parse succeeded. Return the failure.
48417
+ return resultOfParsingOld;
48418
+ }, migrateToLatest);
48419
+ }
48420
+ }
48421
+
48422
+ const parsePossiblyInvalidAnswerForm = object({
48423
+ // `value` is the possibly invalid part of this. It should always be a
48424
+ // string, but some answer forms don't have it. The Expression widget
48425
+ // ignores invalid values, so we can safely filter them out during parsing.
48426
+ value: optional(string),
48427
+ form: defaulted(boolean, () => false),
48428
+ simplify: defaulted(boolean, () => false),
48352
48429
  considered: enumeration("correct", "wrong", "ungraded"),
48353
48430
  key: pipeParsers(optional(union(string).or(number).parser)).then((key, ctx) => ctx.success(String(key))).parser
48354
48431
  });
48355
- const parseExpressionWidgetV1 = parseWidgetWithVersion(object({
48432
+ function removeInvalidAnswerForms(possiblyInvalid) {
48433
+ const valid = [];
48434
+ for (const answerForm of possiblyInvalid) {
48435
+ const {
48436
+ value
48437
+ } = answerForm;
48438
+ if (value != null) {
48439
+ // Copying the object seems to be needed to make TypeScript happy
48440
+ valid.push({
48441
+ ...answerForm,
48442
+ value
48443
+ });
48444
+ }
48445
+ }
48446
+ return valid;
48447
+ }
48448
+ const version1 = object({
48356
48449
  major: constant(1),
48357
48450
  minor: number
48358
- }), constant("expression"), object({
48359
- answerForms: array(parseAnswerForm),
48451
+ });
48452
+ const parseExpressionWidgetV1 = parseWidgetWithVersion(version1, constant("expression"), object({
48453
+ answerForms: pipeParsers(array(parsePossiblyInvalidAnswerForm)).then(convert(removeInvalidAnswerForms)).parser,
48360
48454
  functions: array(string),
48361
48455
  times: boolean,
48362
48456
  visibleLabel: optional(string),
@@ -48364,10 +48458,11 @@ const parseExpressionWidgetV1 = parseWidgetWithVersion(object({
48364
48458
  buttonSets: array(enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations")),
48365
48459
  buttonsVisible: optional(enumeration("always", "never", "focused"))
48366
48460
  }));
48367
- const parseExpressionWidgetV0 = parseWidgetWithVersion(optional(object({
48461
+ const version0 = optional(object({
48368
48462
  major: constant(0),
48369
48463
  minor: number
48370
- })), constant("expression"), object({
48464
+ }));
48465
+ const parseExpressionWidgetV0 = parseWidgetWithVersion(version0, constant("expression"), object({
48371
48466
  functions: array(string),
48372
48467
  times: boolean,
48373
48468
  visibleLabel: optional(string),
@@ -48378,11 +48473,11 @@ const parseExpressionWidgetV0 = parseWidgetWithVersion(optional(object({
48378
48473
  buttonSets: array(enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations")),
48379
48474
  buttonsVisible: optional(enumeration("always", "never", "focused"))
48380
48475
  }));
48381
- function migrateV0ToV1(widget, ctx) {
48476
+ function migrateV0ToV1(widget) {
48382
48477
  const {
48383
48478
  options
48384
48479
  } = widget;
48385
- return ctx.success({
48480
+ return {
48386
48481
  ...widget,
48387
48482
  version: {
48388
48483
  major: 1,
@@ -48402,9 +48497,9 @@ function migrateV0ToV1(widget, ctx) {
48402
48497
  value: options.value
48403
48498
  }]
48404
48499
  }
48405
- });
48500
+ };
48406
48501
  }
48407
- const parseExpressionWidget = union(parseExpressionWidgetV1).or(pipeParsers(parseExpressionWidgetV0).then(migrateV0ToV1).parser).parser;
48502
+ const parseExpressionWidget = versionedWidgetOptions(parseExpressionWidgetV1).withMigrationFrom(parseExpressionWidgetV0, migrateV0ToV1).parser;
48408
48503
 
48409
48504
  const parsePerseusRenderer = defaulted(object({
48410
48505
  // TODO(benchristel): content is also defaulted to empty string in
@@ -48450,31 +48545,70 @@ const parseGradedGroupSetWidget = parseWidget(constant("graded-group-set"), obje
48450
48545
  gradedGroups: array(parseGradedGroupWidgetOptions)
48451
48546
  }));
48452
48547
 
48548
+ // discriminatedUnion() should be preferred over union() when parsing a
48549
+ // discriminated union type, because discriminatedUnion() produces more
48550
+ // understandable failure messages. It takes the discriminant as the source of
48551
+ // truth for which variant is to be parsed, and expects the other data to match
48552
+ // that variant.
48553
+ function discriminatedUnion(narrow, parseVariant) {
48554
+ return new DiscriminatedUnionBuilder(pipeParsers(narrow).then(parseVariant).parser);
48555
+ }
48556
+ class DiscriminatedUnionBuilder {
48557
+ constructor(parser) {
48558
+ this.parser = parser;
48559
+ }
48560
+ or(narrow, parseVariant) {
48561
+ return new DiscriminatedUnionBuilder(either(narrow, parseVariant, this.parser));
48562
+ }
48563
+ }
48564
+ function either(narrowToA, parseA, parseB) {
48565
+ return (rawValue, ctx) => {
48566
+ if (isSuccess(narrowToA(rawValue, ctx))) {
48567
+ return parseA(rawValue, ctx);
48568
+ }
48569
+ return parseB(rawValue, ctx);
48570
+ };
48571
+ }
48572
+
48453
48573
  const pairOfNumbers$3 = pair(number, number);
48454
48574
  const pairOfPoints = pair(pairOfNumbers$3, pairOfNumbers$3);
48455
48575
  const parseGrapherWidget = parseWidget(constant("grapher"), object({
48456
48576
  availableTypes: array(enumeration("absolute_value", "exponential", "linear", "logarithm", "quadratic", "sinusoid", "tangent")),
48457
- correct: union(object({
48577
+ correct: discriminatedUnion(object({
48578
+ type: constant("absolute_value")
48579
+ }), object({
48458
48580
  type: constant("absolute_value"),
48459
48581
  coords: pairOfPoints
48460
48582
  })).or(object({
48583
+ type: constant("exponential")
48584
+ }), object({
48461
48585
  type: constant("exponential"),
48462
48586
  asymptote: pairOfPoints,
48463
48587
  coords: pairOfPoints
48464
48588
  })).or(object({
48589
+ type: constant("linear")
48590
+ }), object({
48465
48591
  type: constant("linear"),
48466
48592
  coords: pairOfPoints
48467
48593
  })).or(object({
48594
+ type: constant("logarithm")
48595
+ }), object({
48468
48596
  type: constant("logarithm"),
48469
48597
  asymptote: pairOfPoints,
48470
48598
  coords: pairOfPoints
48471
48599
  })).or(object({
48600
+ type: constant("quadratic")
48601
+ }), object({
48472
48602
  type: constant("quadratic"),
48473
48603
  coords: pairOfPoints
48474
48604
  })).or(object({
48605
+ type: constant("sinusoid")
48606
+ }), object({
48475
48607
  type: constant("sinusoid"),
48476
48608
  coords: pairOfPoints
48477
48609
  })).or(object({
48610
+ type: constant("tangent")
48611
+ }), object({
48478
48612
  type: constant("tangent"),
48479
48613
  coords: pairOfPoints
48480
48614
  })).parser,
@@ -48534,15 +48668,22 @@ const stringToNumber = (rawValue, ctx) => {
48534
48668
  return ctx.success(parsedNumber);
48535
48669
  };
48536
48670
 
48537
- const numericToNumber = pipeParsers(union(number).or(string).parser).then(stringToNumber).parser;
48671
+ function emptyToZero(x) {
48672
+ return x === "" ? 0 : x;
48673
+ }
48674
+ const imageDimensionToNumber = pipeParsers(union(number).or(string).parser)
48675
+ // In this specific case, empty string is equivalent to zero. An empty
48676
+ // string parses to either NaN (using parseInt) or 0 (using unary +) and
48677
+ // CSS will treat NaN as invalid and default to 0 instead.
48678
+ .then(convert(emptyToZero)).then(stringToNumber).parser;
48538
48679
  const parsePerseusImageBackground = object({
48539
48680
  url: optional(nullable(string)),
48540
- width: optional(numericToNumber),
48541
- height: optional(numericToNumber),
48542
- top: optional(numericToNumber),
48543
- left: optional(numericToNumber),
48544
- bottom: optional(numericToNumber),
48545
- scale: optional(numericToNumber)
48681
+ width: optional(imageDimensionToNumber),
48682
+ height: optional(imageDimensionToNumber),
48683
+ top: optional(imageDimensionToNumber),
48684
+ left: optional(imageDimensionToNumber),
48685
+ bottom: optional(imageDimensionToNumber),
48686
+ scale: optional(imageDimensionToNumber)
48546
48687
  });
48547
48688
 
48548
48689
  const pairOfNumbers$2 = pair(number, number);
@@ -48583,8 +48724,10 @@ const parseInputNumberWidget = parseWidget(constant("input-number"), object({
48583
48724
  }));
48584
48725
 
48585
48726
  const pairOfNumbers$1 = pair(number, number);
48727
+ const stringOrEmpty = defaulted(string, () => "");
48728
+ const parseFunctionType = constant("function");
48586
48729
  const parseFunctionElement = object({
48587
- type: constant("function"),
48730
+ type: parseFunctionType,
48588
48731
  key: string,
48589
48732
  options: object({
48590
48733
  value: string,
@@ -48596,8 +48739,9 @@ const parseFunctionElement = object({
48596
48739
  strokeWidth: number
48597
48740
  })
48598
48741
  });
48742
+ const parseLabelType = constant("label");
48599
48743
  const parseLabelElement = object({
48600
- type: constant("label"),
48744
+ type: parseLabelType,
48601
48745
  key: string,
48602
48746
  options: object({
48603
48747
  label: string,
@@ -48606,8 +48750,9 @@ const parseLabelElement = object({
48606
48750
  coordY: string
48607
48751
  })
48608
48752
  });
48753
+ const parseLineType = constant("line");
48609
48754
  const parseLineElement = object({
48610
- type: constant("line"),
48755
+ type: parseLineType,
48611
48756
  key: string,
48612
48757
  options: object({
48613
48758
  color: string,
@@ -48620,8 +48765,9 @@ const parseLineElement = object({
48620
48765
  arrows: string
48621
48766
  })
48622
48767
  });
48768
+ const parseMovableLineType = constant("movable-line");
48623
48769
  const parseMovableLineElement = object({
48624
- type: constant("movable-line"),
48770
+ type: parseMovableLineType,
48625
48771
  key: string,
48626
48772
  options: object({
48627
48773
  startX: string,
@@ -48639,8 +48785,9 @@ const parseMovableLineElement = object({
48639
48785
  constraintYMax: string
48640
48786
  })
48641
48787
  });
48788
+ const parseMovablePointType = constant("movable-point");
48642
48789
  const parseMovablePointElement = object({
48643
- type: constant("movable-point"),
48790
+ type: parseMovablePointType,
48644
48791
  key: string,
48645
48792
  options: object({
48646
48793
  startX: string,
@@ -48649,14 +48796,15 @@ const parseMovablePointElement = object({
48649
48796
  constraint: string,
48650
48797
  snap: number,
48651
48798
  constraintFn: string,
48652
- constraintXMin: string,
48653
- constraintXMax: string,
48654
- constraintYMin: string,
48655
- constraintYMax: string
48799
+ constraintXMin: stringOrEmpty,
48800
+ constraintXMax: stringOrEmpty,
48801
+ constraintYMin: stringOrEmpty,
48802
+ constraintYMax: stringOrEmpty
48656
48803
  })
48657
48804
  });
48805
+ const parseParametricType = constant("parametric");
48658
48806
  const parseParametricElement = object({
48659
- type: constant("parametric"),
48807
+ type: parseParametricType,
48660
48808
  key: string,
48661
48809
  options: object({
48662
48810
  x: string,
@@ -48668,8 +48816,9 @@ const parseParametricElement = object({
48668
48816
  strokeWidth: number
48669
48817
  })
48670
48818
  });
48819
+ const parsePointType = constant("point");
48671
48820
  const parsePointElement = object({
48672
- type: constant("point"),
48821
+ type: parsePointType,
48673
48822
  key: string,
48674
48823
  options: object({
48675
48824
  color: string,
@@ -48677,8 +48826,9 @@ const parsePointElement = object({
48677
48826
  coordY: string
48678
48827
  })
48679
48828
  });
48829
+ const parseRectangleType = constant("rectangle");
48680
48830
  const parseRectangleElement = object({
48681
- type: constant("rectangle"),
48831
+ type: parseRectangleType,
48682
48832
  key: string,
48683
48833
  options: object({
48684
48834
  color: string,
@@ -48689,7 +48839,7 @@ const parseRectangleElement = object({
48689
48839
  })
48690
48840
  });
48691
48841
  const parseInteractionWidget = parseWidget(constant("interaction"), object({
48692
- static: boolean,
48842
+ static: defaulted(boolean, () => false),
48693
48843
  graph: object({
48694
48844
  editableSettings: optional(array(enumeration("canvas", "graph"))),
48695
48845
  box: pairOfNumbers$1,
@@ -48706,7 +48856,23 @@ const parseInteractionWidget = parseWidget(constant("interaction"), object({
48706
48856
  rulerTicks: optional(number),
48707
48857
  tickStep: pairOfNumbers$1
48708
48858
  }),
48709
- elements: array(union(parseFunctionElement).or(parseLabelElement).or(parseLineElement).or(parseMovableLineElement).or(parseMovablePointElement).or(parseParametricElement).or(parsePointElement).or(parseRectangleElement).parser)
48859
+ elements: array(discriminatedUnion(object({
48860
+ type: parseFunctionType
48861
+ }), parseFunctionElement).or(object({
48862
+ type: parseLabelType
48863
+ }), parseLabelElement).or(object({
48864
+ type: parseLineType
48865
+ }), parseLineElement).or(object({
48866
+ type: parseMovableLineType
48867
+ }), parseMovableLineElement).or(object({
48868
+ type: parseMovablePointType
48869
+ }), parseMovablePointElement).or(object({
48870
+ type: parseParametricType
48871
+ }), parseParametricElement).or(object({
48872
+ type: parsePointType
48873
+ }), parsePointElement).or(object({
48874
+ type: parseRectangleType
48875
+ }), parseRectangleElement).parser)
48710
48876
  }));
48711
48877
 
48712
48878
  // Used to represent 2-D points and ranges
@@ -48929,10 +49095,11 @@ const parseMatcherWidget = parseWidget(constant("matcher"), object({
48929
49095
  padding: boolean
48930
49096
  }));
48931
49097
 
49098
+ const numeric = pipeParsers(union(number).or(string).parser).then(stringToNumber).parser;
48932
49099
  const parseMatrixWidget = parseWidget(defaulted(constant("matrix"), () => "matrix"), object({
48933
49100
  prefix: optional(string),
48934
49101
  suffix: optional(string),
48935
- answers: array(array(number)),
49102
+ answers: array(array(numeric)),
48936
49103
  cursorPosition: optional(array(number)),
48937
49104
  matrixBoardSize: array(number),
48938
49105
  static: optional(boolean)
@@ -48980,12 +49147,18 @@ const parseMathFormat = enumeration("integer", "mixed", "improper", "proper", "d
48980
49147
  const parseNumericInputWidget = parseWidget(constant("numeric-input"), object({
48981
49148
  answers: array(object({
48982
49149
  message: string,
48983
- value: optional(number),
49150
+ // TODO(benchristel): value should never be null or undefined,
49151
+ // but we have some content where it is anyway. If we backfill
49152
+ // the data, simplify this.
49153
+ value: optional(nullable(number)),
48984
49154
  status: string,
48985
49155
  answerForms: optional(array(parseMathFormat)),
48986
49156
  strict: boolean,
48987
49157
  maxError: optional(nullable(number)),
48988
- simplify: optional(nullable(string))
49158
+ // TODO(benchristel): simplify should never be `true`, but we
49159
+ // have some content where it is anyway. If we ever backfill
49160
+ // the data, we should simplify `simplify`.
49161
+ simplify: optional(nullable(union(string).or(pipeParsers(constant(true)).then(convert(String)).parser).parser))
48989
49162
  })),
48990
49163
  labelText: optional(string),
48991
49164
  size: string,
@@ -49021,7 +49194,7 @@ const parseOrdererWidget = parseWidget(constant("orderer"), object({
49021
49194
  const parsePassageRefWidget = parseWidget(constant("passage-ref"), object({
49022
49195
  passageNumber: number,
49023
49196
  referenceNumber: number,
49024
- summaryText: string
49197
+ summaryText: optional(string)
49025
49198
  }));
49026
49199
 
49027
49200
  const parsePassageWidget = parseWidget(constant("passage"), object({
@@ -49210,6 +49383,8 @@ const parseWidgetsMapEntry = (_ref, widgetMap, ctx) => {
49210
49383
  // sequence is a deprecated widget type, and the corresponding
49211
49384
  // widget component no longer exists.
49212
49385
  return parseAndAssign(`sequence ${id}`, parseDeprecatedWidget);
49386
+ case "lights-puzzle":
49387
+ return parseAndAssign(`lights-puzzle ${id}`, parseDeprecatedWidget);
49213
49388
  default:
49214
49389
  if (getWidget(type)) {
49215
49390
  // @ts-expect-error - 'type' is not a valid widget type