@khanacademy/perseus 1.3.5 → 1.4.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/es/index.css +3 -2
  3. package/dist/es/index.js +82 -61
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.css +3 -2
  6. package/dist/index.js +78 -51
  7. package/dist/index.js.map +1 -1
  8. package/package.json +33 -33
  9. package/src/components/__stories__/tex.stories.jsx +8 -2
  10. package/src/index.js +1 -1
  11. package/src/interactive2/movable-point.jsx +2 -4
  12. package/src/item-renderer.jsx +3 -6
  13. package/src/mixins/__tests__/{widget-prop-blacklist_test.js → widget-prop-denylist_test.js} +1 -1
  14. package/src/mixins/changeable.jsx +2 -2
  15. package/src/mixins/editor-jsonify.jsx +2 -2
  16. package/src/mixins/provide-keypad.jsx +3 -3
  17. package/src/mixins/widget-jsonify-deprecated.jsx +3 -3
  18. package/src/mixins/{widget-prop-blacklist.js → widget-prop-denylist.js} +2 -3
  19. package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +0 -10
  20. package/src/styles/perseus-renderer.less +0 -3
  21. package/src/styles/widgets/radio.less +4 -0
  22. package/src/types.js +1 -7
  23. package/src/util/react-render.js +27 -0
  24. package/src/util.js +1 -1
  25. package/src/widget-container.jsx +1 -1
  26. package/src/widgets/__stories__/on-screen-keypad.stories.jsx +118 -0
  27. package/src/widgets/__tests__/__snapshots__/categorizer_test.jsx.snap +6 -6
  28. package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +0 -2
  29. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt_test.jsx.snap +3 -6
  30. package/src/widgets/__tests__/__snapshots__/graded-group-set_test.jsx.snap +15 -13
  31. package/src/widgets/__tests__/__snapshots__/graded-group_test.jsx.snap +6 -7
  32. package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +0 -10
  33. package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +0 -104
  34. package/src/widgets/__tests__/__snapshots__/video_test.jsx.snap +2 -4
  35. package/src/widgets/__tests__/graded-group-set_test.jsx +29 -9
  36. package/src/widgets/categorizer.jsx +6 -1
  37. package/src/widgets/cs-program.jsx +1 -1
  38. package/src/widgets/graded-group-set.jsx +43 -39
  39. package/src/widgets/graded-group.jsx +3 -3
  40. package/src/widgets/iframe.jsx +1 -1
  41. package/src/widgets/input-number.jsx +2 -2
  42. package/src/widgets/passage-ref.jsx +2 -2
  43. package/src/widgets/radio/widget.jsx +7 -6
  44. package/src/widgets/radio.jsx +2 -2
package/dist/index.css CHANGED
@@ -2310,8 +2310,6 @@ img.zoom-img {
2310
2310
  font-size: 14px;
2311
2311
  line-height: 19.6px;
2312
2312
  padding-left: 35px;
2313
- }
2314
- .framework-perseus .paragraph ul:not(.perseus-widget-radio) li {
2315
2313
  list-style-type: disc;
2316
2314
  }
2317
2315
  .framework-perseus .paragraph ol {
@@ -3190,6 +3188,9 @@ body.sat-section .perseus-widget-passage {
3190
3188
  .perseus-widget-radio li table {
3191
3189
  border: 1px solid #ccc;
3192
3190
  }
3191
+ .perseus-widget-radio-fieldset .instructions {
3192
+ font-family: "Lato", sans-serif;
3193
+ }
3193
3194
  .reaction {
3194
3195
  display: table-row;
3195
3196
  }
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ var ReactDOM = require('react-dom');
15
15
  var wonderBlocksProgressSpinner = require('@khanacademy/wonder-blocks-progress-spinner');
16
16
  var kmath = require('@khanacademy/kmath');
17
17
  var createReactClass = require('create-react-class');
18
+ var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
18
19
  var SimpleMarkdown = require('@khanacademy/simple-markdown');
19
20
  var pureMarkdown = require('@khanacademy/pure-markdown');
20
21
  var aphrodite = require('aphrodite');
@@ -25,7 +26,6 @@ var Tooltip$1 = require('@khanacademy/wonder-blocks-tooltip');
25
26
  var Button = require('@khanacademy/wonder-blocks-button');
26
27
  var Clickable = require('@khanacademy/wonder-blocks-clickable');
27
28
  var Color = require('@khanacademy/wonder-blocks-color');
28
- var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
29
29
  var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
30
30
  var wonderBlocksPopover = require('@khanacademy/wonder-blocks-popover');
31
31
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
@@ -2185,7 +2185,7 @@ function widgetShouldHighlight(widget) {
2185
2185
 
2186
2186
  switch (widget.type) {
2187
2187
  /**
2188
- * Highlight bar blacklist
2188
+ * Highlight bar denylist
2189
2189
  */
2190
2190
  case "measurer":
2191
2191
  case "protractor":
@@ -14539,6 +14539,26 @@ var iconPaths = /*#__PURE__*/Object.freeze({
14539
14539
  iconMinus: iconMinus
14540
14540
  });
14541
14541
 
14542
+ function render(element, container, callback) {
14543
+ // TODO(LP-11406): Replace this, or callers, with React Portal
14544
+ // eslint-disable-next-line no-restricted-syntax
14545
+ return ReactDOM__default["default"].render(
14546
+ /*#__PURE__*/
14547
+
14548
+ /**
14549
+ * `RenderStateRoot` is responsible for tracking whether it's
14550
+ * the initial render or subsequent renders. It's used by
14551
+ * `useUniqueId` and will be used by `UniqueIDProvider` and
14552
+ * `WithSSRPlaceholder` in the future. We're placing it as
14553
+ * high up in the render tree as possible to ensure that any
14554
+ * components using that hook or those components will function
14555
+ * correctly.
14556
+ */
14557
+ React__namespace.createElement(wonderBlocksCore.RenderStateRoot, {
14558
+ throwIfNested: false
14559
+ }, element), container, callback);
14560
+ }
14561
+
14542
14562
  /* eslint-disable @babel/no-invalid-this */
14543
14563
  const add$1 = {
14544
14564
  constrain: function () {
@@ -14866,9 +14886,7 @@ ___default["default"].extend(MovablePoint$5.prototype, {
14866
14886
 
14867
14887
  const showTrashTooltip = () => {
14868
14888
  this._showTooltip(container => {
14869
- // TODO(LP-11406): Replace with React Portal
14870
- // eslint-disable-next-line no-restricted-syntax
14871
- ReactDOM__namespace.render( /*#__PURE__*/React__namespace.createElement("span", {
14889
+ render( /*#__PURE__*/React__namespace.createElement("span", {
14872
14890
  style: {
14873
14891
  fontSize: "2em"
14874
14892
  }
@@ -19201,7 +19219,7 @@ class WidgetContainer extends React__namespace.Component {
19201
19219
  highlightLint: false
19202
19220
  }; // Note: if you add more props here, please consider whether or not
19203
19221
  // it should be auto-serialized (e.g. used in scoreInput()). See
19204
- // widget-jsonify-deprecated.jsx and widget-prop-blacklist.jsx
19222
+ // widget-jsonify-deprecated.jsx and widget-prop-denylist.jsx
19205
19223
  // We default to an empty object for style instead of null
19206
19224
  // because of a strange bug where the static styles aren't applied
19207
19225
  // after toggling static mode.
@@ -22156,9 +22174,7 @@ _defineProperty(InputWithExamples, "defaultProps", {
22156
22174
  * automatically serializing schemaless list of attributes causes issues (e.g.
22157
22175
  * circular JSON structures sometimes).
22158
22176
  *
22159
- * This blacklists things that we know don't need to be serialized.
22160
- *
22161
- * TODO(TB): Go through and update usage of BLACKLIST to DENYLIST: https://khanacademy.atlassian.net/browse/LP-13149?atlOrigin=eyJpIjoiNTI0Y2UwNzQ0MzA4NDYzOGI1YWRmNjEwY2E5YzZlZWUiLCJwIjoiaiJ9
22177
+ * This blocks things that we know don't need to be serialized.
22162
22178
  */
22163
22179
  const denylist = [// standard props "added" by react
22164
22180
  // (technically the renderer still adds them)
@@ -23141,12 +23157,12 @@ class InputNumber extends React__namespace.Component {
23141
23157
 
23142
23158
  const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign]; // Correct
23143
23159
 
23144
- if (rubric && correct && this.props.currentValue) {
23160
+ if (rubric && correct === true && this.props.currentValue) {
23145
23161
  inputStyles.push(styles$z.answerStateCorrect);
23146
23162
  } // Incorrect
23147
23163
 
23148
23164
 
23149
- if (rubric && !correct && this.props.currentValue) {
23165
+ if (rubric && correct === false && this.props.currentValue) {
23150
23166
  inputStyles.push(styles$z.answerStateIncorrect);
23151
23167
  } // Unanswered
23152
23168
 
@@ -26209,7 +26225,7 @@ class PassageRef extends React__namespace.Component {
26209
26225
 
26210
26226
  shouldComponentUpdate(nextProps, nextState) {
26211
26227
  return !___default["default"].isEqual(this.props, nextProps) || !___default["default"].isEqual(this.state, nextState);
26212
- } // TODO(TB): getUserInput needs to be updated to only return
26228
+ } // TODO(tamarab): getUserInput needs to be updated to only return
26213
26229
  // props input by the user. Currently returns all the widget's props.
26214
26230
 
26215
26231
 
@@ -28530,7 +28546,9 @@ class Categorizer extends React__namespace.Component {
28530
28546
 
28531
28547
  const table = /*#__PURE__*/React__namespace.createElement("table", {
28532
28548
  className: "categorizer-table " + aphrodite.css(styles$m.mobileTable)
28533
- }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, /*#__PURE__*/React__namespace.createElement("th", null, "\xA0"), this.props.categories.map((category, i) => {
28549
+ }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, /*#__PURE__*/React__namespace.createElement("td", {
28550
+ className: aphrodite.css(styles$m.emptyHeaderCell)
28551
+ }), this.props.categories.map((category, i) => {
28534
28552
  // Array index is the correct key here, as that's
28535
28553
  // how category grading actually works -- no way
28536
28554
  // to add or remove categories or items in the
@@ -28658,6 +28676,10 @@ const styles$m = aphrodite.StyleSheet.create({
28658
28676
  color: "#ccc",
28659
28677
  verticalAlign: "middle"
28660
28678
  },
28679
+ emptyHeaderCell: {
28680
+ backgroundColor: "inherit",
28681
+ borderBottom: "2px solid #ccc"
28682
+ },
28661
28683
  radioSpan: {
28662
28684
  fontSize: 30,
28663
28685
  paddingRight: 3,
@@ -28893,7 +28915,7 @@ class CSProgram extends React__namespace.Component {
28893
28915
  url = updateQueryString$1(url, "settings", JSON.stringify(settings));
28894
28916
  }
28895
28917
 
28896
- const sandboxOptions = ["allow-popups", "allow-same-origin", "allow-scripts", "allow-top-navigation"].join(" "); // We sandbox the iframe so that we whitelist only the functionality
28918
+ const sandboxOptions = ["allow-popups", "allow-same-origin", "allow-scripts", "allow-top-navigation"].join(" "); // We sandbox the iframe so that we allowlist only the functionality
28897
28919
  // that we need. This makes it a bit safer in case some content
28898
28920
  // creator "went wild".
28899
28921
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
@@ -29771,7 +29793,7 @@ const styles$h = aphrodite.StyleSheet.create({
29771
29793
  padding: 0,
29772
29794
  border: "none",
29773
29795
  marginTop: 20,
29774
- color: kaGreen$1,
29796
+ color: Color__default["default"].blue,
29775
29797
  cursor: "pointer",
29776
29798
  display: "block",
29777
29799
  clear: "both"
@@ -29779,7 +29801,7 @@ const styles$h = aphrodite.StyleSheet.create({
29779
29801
  explanationTitle: {
29780
29802
  backgroundColor: "unset",
29781
29803
  marginTop: 20,
29782
- color: kaGreen$1,
29804
+ color: Color__default["default"].blue,
29783
29805
  marginBottom: 10,
29784
29806
  cursor: "pointer",
29785
29807
  fontSize: 14,
@@ -29809,29 +29831,38 @@ var GradedGroup$2 = {
29809
29831
 
29810
29832
  const GradedGroup = GradedGroup$2.widget;
29811
29833
 
29812
- // TODO(jeremy): This indicator panel is not accessible for keyboard
29813
- // navigation. Add in keyboard handling and tab indexes to make accessible.
29814
29834
  class Indicators extends React__namespace.Component {
29815
- render() {
29816
- const items = [];
29835
+ constructor() {
29836
+ super(...arguments);
29837
+
29838
+ _defineProperty(this, "handleKeyDown", (e, i) => {
29839
+ if (e.key === "Enter" || e.key === " ") {
29840
+ this.props.onChangeCurrentGroup(i);
29841
+ }
29842
+ });
29843
+ }
29817
29844
 
29818
- for (let i = 0; i < this.props.numGroups; i++) {
29819
- items.push( /*#__PURE__*/React__namespace.createElement("div", {
29845
+ render() {
29846
+ return /*#__PURE__*/React__namespace.createElement("ul", {
29847
+ className: aphrodite.css(styles$g.indicatorContainer)
29848
+ }, this.props.gradedGroups.map((_ref, i) => {
29849
+ let {
29850
+ title
29851
+ } = _ref;
29852
+ return /*#__PURE__*/React__namespace.createElement("li", {
29820
29853
  role: "button",
29821
29854
  "aria-label": i18n__namespace._("Skip to %(title)s", {
29822
- title: this.props.groupTitles[i]
29855
+ title
29823
29856
  }),
29824
- key: i,
29857
+ key: title,
29825
29858
  className: aphrodite.css(styles$g.indicator, i === this.props.currentGroup && styles$g.selectedIndicator),
29826
- onClick: () => this.props.onChangeCurrentGroup(i)
29859
+ tabIndex: 0,
29860
+ onClick: () => this.props.onChangeCurrentGroup(i),
29861
+ onKeyDown: e => this.handleKeyDown(e, i)
29827
29862
  }, i === this.props.currentGroup && /*#__PURE__*/React__namespace.createElement("span", {
29828
29863
  className: aphrodite.css(a11y.srOnly)
29829
- }, i18n__namespace._("Current"))));
29830
- }
29831
-
29832
- return /*#__PURE__*/React__namespace.createElement("div", {
29833
- className: aphrodite.css(styles$g.indicatorContainer)
29834
- }, items);
29864
+ }, i18n__namespace._("Current")));
29865
+ }));
29835
29866
  }
29836
29867
 
29837
29868
  }
@@ -29945,9 +29976,8 @@ class GradedGroupSet extends React__namespace.Component {
29945
29976
  }, currentGroup.title), /*#__PURE__*/React__namespace.createElement("div", {
29946
29977
  className: aphrodite.css(styles$g.spacer)
29947
29978
  }), /*#__PURE__*/React__namespace.createElement(Indicators, {
29948
- numGroups: numGroups,
29949
29979
  currentGroup: this.state.currentGroup,
29950
- groupTitles: this.props.gradedGroups.map(g => g.title),
29980
+ gradedGroups: this.props.gradedGroups,
29951
29981
  onChangeCurrentGroup: currentGroup => this.setState({
29952
29982
  currentGroup
29953
29983
  })
@@ -30000,25 +30030,28 @@ const styles$g = aphrodite.StyleSheet.create({
30000
30030
  },
30001
30031
  title: {
30002
30032
  fontSize: 12,
30003
- color: gray76,
30033
+ color: Color__default["default"].offBlack64,
30004
30034
  textTransform: "uppercase",
30005
30035
  marginBottom: 11,
30006
30036
  letterSpacing: 0.8
30007
30037
  },
30008
30038
  indicatorContainer: {
30009
30039
  display: "flex",
30010
- flexDirection: "row"
30040
+ flexDirection: "row",
30041
+ listStyle: "none",
30042
+ margin: "unset"
30011
30043
  },
30012
30044
  indicator: {
30013
30045
  width: 10,
30014
30046
  height: 10,
30015
- borderRadius: 5,
30016
- backgroundColor: grayLight$1,
30047
+ borderRadius: "100%",
30048
+ border: "3px solid",
30049
+ borderColor: Color__default["default"].blue,
30017
30050
  marginLeft: 5,
30018
30051
  cursor: "pointer"
30019
30052
  },
30020
30053
  selectedIndicator: {
30021
- backgroundColor: kaGreen$1
30054
+ backgroundColor: Color__default["default"].blue
30022
30055
  },
30023
30056
  container: {
30024
30057
  borderTop: "1px solid ".concat(gray76),
@@ -31492,7 +31525,7 @@ class Iframe extends React__namespace.Component {
31492
31525
  sandboxProperties += " allow-top-navigation"; // if (this.props.allowTopNavigation === true) {
31493
31526
  // sandboxProperties += " allow-top-navigation";
31494
31527
  // }
31495
- // We sandbox the iframe so that we whitelist only the functionality
31528
+ // We sandbox the iframe so that we allowlist only the functionality
31496
31529
  // that we need. This makes it a bit safer in case some content
31497
31530
  // creator "went wild".
31498
31531
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
@@ -48287,10 +48320,8 @@ const ProvideKeypad = {
48287
48320
  // React tree. We may also want to add this keypad asynchronously
48288
48321
  // or on-demand in the future.
48289
48322
  _this._keypadContainer = document.createElement("div");
48290
- (_document$body = document.body) === null || _document$body === void 0 ? void 0 : _document$body.appendChild(_this._keypadContainer); // TODO(LP-11406): Replace with React Portal
48291
- // eslint-disable-next-line no-restricted-syntax
48292
-
48293
- ReactDOM__default["default"].render( /*#__PURE__*/React__namespace.createElement(mathInput.Keypad, {
48323
+ (_document$body = document.body) === null || _document$body === void 0 ? void 0 : _document$body.appendChild(_this._keypadContainer);
48324
+ render( /*#__PURE__*/React__namespace.createElement(mathInput.Keypad, {
48294
48325
  onElementMounted: element => {
48295
48326
  // NOTE(kevinb): The reason why this setState works is
48296
48327
  // b/c we're calling it manually from item-renderer.jsx
@@ -48986,11 +49017,9 @@ class ItemRenderer extends React__namespace.Component {
48986
49017
  // that have completely different places in the DOM, we have to do this
48987
49018
  // strangeness instead of relying on React's normal render() method.
48988
49019
  // TODO(alpert): Figure out how to clean this up somehow
48989
- // TODO(LP-11406): Replace with React Portal
48990
- // eslint-disable-next-line no-restricted-syntax
48991
49020
 
48992
49021
 
48993
- ReactDOM__namespace.render(
49022
+ render(
48994
49023
  /*#__PURE__*/
48995
49024
  // metadata (from item.question, aka PerseusRenderer)
48996
49025
  // replace (also item.question, aka PerseusRenderer)
@@ -49025,10 +49054,8 @@ class ItemRenderer extends React__namespace.Component {
49025
49054
  linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "question")
49026
49055
  }, this.props.item.question, {
49027
49056
  legacyPerseusLint: this.props.legacyPerseusLint
49028
- })), workArea); // TODO(LP-11406): Replace with React Portal
49029
- // eslint-disable-next-line no-restricted-syntax
49030
-
49031
- ReactDOM__namespace.render( /*#__PURE__*/React__namespace.createElement(HintsRenderer, {
49057
+ })), workArea);
49058
+ render( /*#__PURE__*/React__namespace.createElement(HintsRenderer, {
49032
49059
  ref: node => this.hintsRenderer = node,
49033
49060
  hints: this.props.item.hints,
49034
49061
  hintsVisible: this.state.hintsVisible,
@@ -51378,7 +51405,7 @@ exports.SizingUtils = sizingUtils;
51378
51405
  exports.TableWidget = Table$1;
51379
51406
  exports.TransformerWidget = Transformer$1;
51380
51407
  exports.Util = Util;
51381
- exports.WIDGET_PROP_BLACKLIST = denylist;
51408
+ exports.WIDGET_PROP_DENYLIST = denylist;
51382
51409
  exports.WidgetJsonifyDeprecated = WidgetJsonifyDeprecated;
51383
51410
  exports.Widgets = widgets$1;
51384
51411
  exports.apiVersion = apiVersion;