@khanacademy/perseus 1.2.0 → 1.3.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.css CHANGED
@@ -3070,11 +3070,11 @@ body.mobile .perseus-matrix .math-output {
3070
3070
  margin: 0 0 10px;
3071
3071
  }
3072
3072
  .perseus-widget-passage-container .passage-text div.paragraph {
3073
- font-family: "Noto Serif", serif;
3074
3073
  font-weight: 400;
3075
- font-size: 20px;
3076
- line-height: 24px;
3074
+ font-size: 16px;
3075
+ line-height: 20px;
3077
3076
  text-indent: 20px;
3077
+ margin: 0;
3078
3078
  }
3079
3079
  .perseus-widget-passage-container .passage-text div.paragraph span {
3080
3080
  text-indent: 0;
package/dist/index.js CHANGED
@@ -25242,10 +25242,6 @@ const styles$w = aphrodite.StyleSheet.create({
25242
25242
  }
25243
25243
  });
25244
25244
 
25245
- const getLineHeightForNode = (line1, line2) => {
25246
- return $__default["default"](line2).offset().top - $__default["default"](line1).offset().top;
25247
- };
25248
-
25249
25245
  function getInitialParseState() {
25250
25246
  return {
25251
25247
  currentRef: [],
@@ -25613,65 +25609,40 @@ var PassageMarkdown = {
25613
25609
  getInitialParseState
25614
25610
  };
25615
25611
 
25616
- // A fake paragraph to measure the line height of the passage. In CSS we always
25617
- // set the line height to 22 pixels, but when using the browser zoom feature,
25618
- // the line height often ends up being a fractional number of pixels close to
25619
- // 22 pixels.
25612
+ // A fake paragraph to measure the line height of the passage,
25613
+ // so we can adapt to browser zoom
25620
25614
  class LineHeightMeasurer extends React__namespace.Component {
25621
25615
  constructor() {
25622
25616
  super(...arguments);
25623
25617
 
25624
- _defineProperty(this, "_cachedLineHeight", void 0);
25625
-
25626
- _defineProperty(this, "body", void 0);
25627
-
25628
- _defineProperty(this, "end", void 0);
25618
+ _defineProperty(this, "_line", void 0);
25629
25619
  }
25630
25620
 
25631
25621
  measureLineHeight() {
25632
- if (typeof this._cachedLineHeight !== "number") {
25633
- this.forceMeasureLineHeight();
25622
+ if (!this._line) {
25623
+ return 0;
25634
25624
  }
25635
25625
 
25636
- return this._cachedLineHeight;
25637
- }
25638
-
25639
- forceMeasureLineHeight() {
25640
- const body = this.body;
25641
- const end = this.end;
25642
-
25643
- if (!body || !end) {
25644
- return;
25645
- } // Add some text which magically fills an entire line.
25646
-
25647
-
25648
- body.textContent = " \u0080"; // Now, the line height is the difference between the top of the
25649
- // second line and the top of the first line.
25650
-
25651
- this._cachedLineHeight = getLineHeightForNode(body, end); // Clear out the first line so it doesn't overlap the passage.
25652
-
25653
- body.textContent = "";
25626
+ return this._line.clientHeight;
25654
25627
  }
25655
25628
 
25656
25629
  render() {
25657
25630
  return /*#__PURE__*/React__namespace.createElement("div", {
25658
- className: aphrodite.css(styles$v.measurer)
25659
- }, /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
25660
- ref: ref => this.body = ref,
25631
+ className: aphrodite.css(styles$v.measurer),
25632
+ "aria-hidden": "true"
25633
+ }, /*#__PURE__*/React__namespace.createElement("div", {
25634
+ ref: ref => this._line = ref,
25661
25635
  className: "paragraph"
25662
- }), /*#__PURE__*/React__namespace.createElement("div", {
25663
- ref: ref => this.end = ref
25664
- })));
25636
+ }, "Line Height Measurement"));
25665
25637
  }
25666
25638
 
25667
25639
  }
25668
-
25669
25640
  const styles$v = aphrodite.StyleSheet.create({
25670
25641
  measurer: {
25671
25642
  position: "absolute",
25672
- width: "100%",
25673
25643
  top: 0,
25674
25644
  left: 0,
25645
+ visibility: "hidden",
25675
25646
  // keep from blocking text selection
25676
25647
  zIndex: -1
25677
25648
  }
@@ -25718,7 +25689,7 @@ class Passage extends React__namespace.Component {
25718
25689
  // listen for resize events.
25719
25690
 
25720
25691
 
25721
- (_this$_lineHeightMeas = this._lineHeightMeasurerRef) === null || _this$_lineHeightMeas === void 0 ? void 0 : _this$_lineHeightMeas.forceMeasureLineHeight();
25692
+ (_this$_lineHeightMeas = this._lineHeightMeasurerRef) === null || _this$_lineHeightMeas === void 0 ? void 0 : _this$_lineHeightMeas.measureLineHeight();
25722
25693
 
25723
25694
  this._updateState();
25724
25695
  }, 500);
@@ -28046,6 +28017,129 @@ class Radio$1 extends React__namespace.Component {
28046
28017
  });
28047
28018
  }
28048
28019
 
28020
+ static validate(userInput, rubric) {
28021
+ const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
28022
+ return sum + (selected ? 1 : 0);
28023
+ }, 0);
28024
+
28025
+ if (numSelected === 0) {
28026
+ return {
28027
+ type: "invalid",
28028
+ message: null
28029
+ };
28030
+ }
28031
+
28032
+ if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
28033
+ return {
28034
+ type: "invalid",
28035
+ message: i18n__namespace._("Please choose the correct number of answers.")
28036
+ }; // If NOTA and some other answer are checked, ...
28037
+ }
28038
+
28039
+ if (userInput.noneOfTheAboveSelected && numSelected > 1) {
28040
+ return {
28041
+ type: "invalid",
28042
+ message: i18n__namespace._("'None of the above' may not be selected " + "when other answers are selected.")
28043
+ };
28044
+ }
28045
+
28046
+ const correct = userInput.choicesSelected.every((selected, i) => {
28047
+ let isCorrect;
28048
+
28049
+ if (userInput.noneOfTheAboveIndex === i) {
28050
+ isCorrect = rubric.choices.every((choice, j) => {
28051
+ return i === j || !choice.correct;
28052
+ });
28053
+ } else {
28054
+ isCorrect = !!rubric.choices[i].correct;
28055
+ }
28056
+
28057
+ return isCorrect === selected;
28058
+ });
28059
+ return {
28060
+ type: "points",
28061
+ earned: correct ? 1 : 0,
28062
+ total: 1,
28063
+ message: null
28064
+ };
28065
+ }
28066
+
28067
+ static getUserInputFromProps(props) {
28068
+ // Return checked inputs in the form {choicesSelected: [bool]}. (Dear
28069
+ // future timeline implementers: this used to be {value: i} before
28070
+ // multiple select was added)
28071
+ if (props.choiceStates) {
28072
+ let noneOfTheAboveIndex = null;
28073
+ let noneOfTheAboveSelected = false;
28074
+ const choiceStates = props.choiceStates;
28075
+ const choicesSelected = choiceStates.map(() => false);
28076
+ const countChoices = props.countChoices;
28077
+ const numCorrect = props.numCorrect;
28078
+
28079
+ for (let i = 0; i < choicesSelected.length; i++) {
28080
+ const index = props.choices[i].originalIndex;
28081
+ choicesSelected[index] = choiceStates[i].selected;
28082
+
28083
+ if (props.choices[i].isNoneOfTheAbove) {
28084
+ noneOfTheAboveIndex = index;
28085
+
28086
+ if (choicesSelected[i]) {
28087
+ noneOfTheAboveSelected = true;
28088
+ }
28089
+ }
28090
+ }
28091
+
28092
+ return {
28093
+ countChoices,
28094
+ choicesSelected,
28095
+ numCorrect,
28096
+ noneOfTheAboveIndex,
28097
+ noneOfTheAboveSelected
28098
+ }; // Support legacy choiceState implementation
28099
+ }
28100
+ /* istanbul ignore if - props.values is deprecated */
28101
+
28102
+
28103
+ const {
28104
+ values
28105
+ } = props;
28106
+
28107
+ if (values) {
28108
+ let noneOfTheAboveIndex = null;
28109
+ let noneOfTheAboveSelected = false;
28110
+ const choicesSelected = [...values];
28111
+ const countChoices = props.countChoices;
28112
+ const numCorrect = props.numCorrect;
28113
+ const valuesLength = values.length;
28114
+
28115
+ for (let i = 0; i < valuesLength; i++) {
28116
+ const index = props.choices[i].originalIndex;
28117
+ choicesSelected[index] = values[i];
28118
+
28119
+ if (props.choices[i].isNoneOfTheAbove) {
28120
+ noneOfTheAboveIndex = index;
28121
+
28122
+ if (choicesSelected[i]) {
28123
+ noneOfTheAboveSelected = true;
28124
+ }
28125
+ }
28126
+ }
28127
+
28128
+ return {
28129
+ choicesSelected,
28130
+ noneOfTheAboveIndex,
28131
+ noneOfTheAboveSelected,
28132
+ countChoices,
28133
+ numCorrect
28134
+ };
28135
+ } // Nothing checked
28136
+
28137
+
28138
+ return {
28139
+ choicesSelected: props.choices.map(() => false)
28140
+ };
28141
+ }
28142
+
28049
28143
  // TODO(LP-10672): I think this might be unused right now. I can't find anywhere
28050
28144
  // that we pass a value to `.focus()` and it seems to have been used for
28051
28145
  // adding hints when editing.
@@ -28176,129 +28270,6 @@ class Radio$1 extends React__namespace.Component {
28176
28270
  });
28177
28271
  }
28178
28272
 
28179
- static validate(userInput, rubric) {
28180
- const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
28181
- return sum + (selected ? 1 : 0);
28182
- }, 0);
28183
-
28184
- if (numSelected === 0) {
28185
- return {
28186
- type: "invalid",
28187
- message: null
28188
- };
28189
- }
28190
-
28191
- if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
28192
- return {
28193
- type: "invalid",
28194
- message: i18n__namespace._("Please choose the correct number of answers.")
28195
- }; // If NOTA and some other answer are checked, ...
28196
- }
28197
-
28198
- if (userInput.noneOfTheAboveSelected && numSelected > 1) {
28199
- return {
28200
- type: "invalid",
28201
- message: i18n__namespace._("'None of the above' may not be selected " + "when other answers are selected.")
28202
- };
28203
- }
28204
-
28205
- const correct = userInput.choicesSelected.every((selected, i) => {
28206
- let isCorrect;
28207
-
28208
- if (userInput.noneOfTheAboveIndex === i) {
28209
- isCorrect = rubric.choices.every((choice, j) => {
28210
- return i === j || !choice.correct;
28211
- });
28212
- } else {
28213
- isCorrect = !!rubric.choices[i].correct;
28214
- }
28215
-
28216
- return isCorrect === selected;
28217
- });
28218
- return {
28219
- type: "points",
28220
- earned: correct ? 1 : 0,
28221
- total: 1,
28222
- message: null
28223
- };
28224
- }
28225
-
28226
- static getUserInputFromProps(props) {
28227
- // Return checked inputs in the form {choicesSelected: [bool]}. (Dear
28228
- // future timeline implementers: this used to be {value: i} before
28229
- // multiple select was added)
28230
- if (props.choiceStates) {
28231
- let noneOfTheAboveIndex = null;
28232
- let noneOfTheAboveSelected = false;
28233
- const choiceStates = props.choiceStates;
28234
- const choicesSelected = choiceStates.map(() => false);
28235
- const countChoices = props.countChoices;
28236
- const numCorrect = props.numCorrect;
28237
-
28238
- for (let i = 0; i < choicesSelected.length; i++) {
28239
- const index = props.choices[i].originalIndex;
28240
- choicesSelected[index] = choiceStates[i].selected;
28241
-
28242
- if (props.choices[i].isNoneOfTheAbove) {
28243
- noneOfTheAboveIndex = index;
28244
-
28245
- if (choicesSelected[i]) {
28246
- noneOfTheAboveSelected = true;
28247
- }
28248
- }
28249
- }
28250
-
28251
- return {
28252
- countChoices,
28253
- choicesSelected,
28254
- numCorrect,
28255
- noneOfTheAboveIndex,
28256
- noneOfTheAboveSelected
28257
- }; // Support legacy choiceState implementation
28258
- }
28259
- /* istanbul ignore if - props.values is deprecated */
28260
-
28261
-
28262
- const {
28263
- values
28264
- } = props;
28265
-
28266
- if (values) {
28267
- let noneOfTheAboveIndex = null;
28268
- let noneOfTheAboveSelected = false;
28269
- const choicesSelected = [...values];
28270
- const countChoices = props.countChoices;
28271
- const numCorrect = props.numCorrect;
28272
- const valuesLength = values.length;
28273
-
28274
- for (let i = 0; i < valuesLength; i++) {
28275
- const index = props.choices[i].originalIndex;
28276
- choicesSelected[index] = values[i];
28277
-
28278
- if (props.choices[i].isNoneOfTheAbove) {
28279
- noneOfTheAboveIndex = index;
28280
-
28281
- if (choicesSelected[i]) {
28282
- noneOfTheAboveSelected = true;
28283
- }
28284
- }
28285
- }
28286
-
28287
- return {
28288
- choicesSelected,
28289
- noneOfTheAboveIndex,
28290
- noneOfTheAboveSelected,
28291
- countChoices,
28292
- numCorrect
28293
- };
28294
- } // Nothing checked
28295
-
28296
-
28297
- return {
28298
- choicesSelected: props.choices.map(() => false)
28299
- };
28300
- }
28301
-
28302
28273
  }
28303
28274
 
28304
28275
  _defineProperty(Radio$1, "defaultProps", {