@khanacademy/perseus 28.1.0 → 29.0.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.
@@ -14,9 +14,6 @@ type Props = {
14
14
  blockHighlight?: boolean;
15
15
  severity?: Severity;
16
16
  };
17
- type State = {
18
- tooltipAbove: boolean;
19
- };
20
17
  /**
21
18
  * This component renders "lint" nodes in a markdown parse tree. Lint nodes
22
19
  * are inserted into the tree by the Perseus linter (see
@@ -39,12 +36,8 @@ type State = {
39
36
  * that has a right margin (like anything blockquoted) the circle will appear
40
37
  * to the left of where it belongs. And if there is more
41
38
  **/
42
- declare class Lint extends React.Component<Props, State> {
39
+ declare class Lint extends React.Component<Props> {
43
40
  _positionTimeout: number | undefined;
44
- state: State;
45
- componentDidMount(): void;
46
- componentWillUnmount(): void;
47
- getPosition: () => void;
48
41
  renderLink: (arg1: any) => React.ReactElement;
49
42
  render(): React.ReactNode;
50
43
  }
package/dist/es/index.css CHANGED
@@ -1500,7 +1500,6 @@ body.mobile ul.inequalities-one-line-radios > li {
1500
1500
  .perseus-clearfix:after {
1501
1501
  clear: both;
1502
1502
  }
1503
- /* Fall back colors? Eg educator, talks & interviews */
1504
1503
  .framework-perseus code {
1505
1504
  font-family: Courier, monospace;
1506
1505
  }
@@ -2418,7 +2417,7 @@ img.zoom-img {
2418
2417
  width: 40px;
2419
2418
  }
2420
2419
  .framework-perseus .number-input.invalid-input {
2421
- background-color: #cf5044;
2420
+ background-color: #ffbaba;
2422
2421
  outline-color: red;
2423
2422
  }
2424
2423
  .framework-perseus .number-input.mini {
@@ -2604,7 +2603,7 @@ img.zoom-img {
2604
2603
  z-index: 2;
2605
2604
  }
2606
2605
  body.mobile .categorizer-container td.category input[type="radio"]:checked + span:before {
2607
- color: #005a88;
2606
+ color: #1c758a;
2608
2607
  }
2609
2608
  body.mobile .categorizer-container td.category input[type="radio"] + span:active:before {
2610
2609
  color: #666;
@@ -2677,7 +2676,7 @@ body.mobile .categorizer-container td.category input[type="radio"] + span:active
2677
2676
  margin-left: 0;
2678
2677
  }
2679
2678
  .framework-perseus .perseus-graded-group.answer-incorrect {
2680
- border-left: 3px solid #b2392e;
2679
+ border-left: 3px solid #ff8787;
2681
2680
  margin-left: 0;
2682
2681
  }
2683
2682
  .framework-perseus .perseus-graded-group .group-icon {
@@ -3490,7 +3489,7 @@ body.mobile .framework-perseus table.perseus-widget-table-of-values.non-markdown
3490
3489
  background-color: #fcc;
3491
3490
  }
3492
3491
  .perseus-error {
3493
- background: #cf5044;
3492
+ background: #ffbaba;
3494
3493
  border: 2px solid red;
3495
3494
  border-radius: 5px;
3496
3495
  padding: 20px;
package/dist/es/index.js CHANGED
@@ -15,7 +15,7 @@ import ReactDOM__default from 'react-dom';
15
15
  import _, { debounce as debounce$1 } from 'underscore';
16
16
  import Clickable from '@khanacademy/wonder-blocks-clickable';
17
17
  import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
18
- import { color, spacing } from '@khanacademy/wonder-blocks-tokens';
18
+ import { color, spacing, font } from '@khanacademy/wonder-blocks-tokens';
19
19
  import $ from 'jquery';
20
20
  import { v4 } from 'uuid';
21
21
  import PropTypes from 'prop-types';
@@ -766,7 +766,7 @@ const denylist = [
766
766
  // (technically the renderer still adds them)
767
767
  "key", "ref",
768
768
  // added by src/renderer.jsx
769
- "containerSizeClass", "widgetId", "onChange", "problemNum", "apiOptions", "questionCompleted", "findWidgets", "hintMode",
769
+ "containerSizeClass", "widgetId", "onChange", "problemNum", "apiOptions", "questionCompleted", "findWidgets",
770
770
  // added by src/editor.jsx, for widgets removing themselves
771
771
  // this is soooo not the right place for this, but alas.
772
772
  "onRemove",
@@ -1293,7 +1293,7 @@ const KhanMath = {
1293
1293
  * with an approx symbol if num had to be rounded, and trailing 0s
1294
1294
  */
1295
1295
  toFixedApprox: function (num, precision) {
1296
- // TODO(aria): Make this locale-dependent like KhanUtil.localeToFixed
1296
+ // TODO(aria): Make this locale-dependent
1297
1297
  const fixedStr = num.toFixed(precision);
1298
1298
  if (number.equal(+fixedStr, num)) {
1299
1299
  return fixedStr;
@@ -18171,27 +18171,9 @@ class Lint extends React.Component {
18171
18171
  constructor(...args) {
18172
18172
  super(...args);
18173
18173
  this._positionTimeout = void 0;
18174
- this.state = {
18175
- tooltipAbove: true
18176
- };
18177
- // We can't call setState in componentDidMount without risking a render
18178
- // thrash, and we can't call getBoundingClientRect in render, so we
18179
- // borrow a timeout approach from learnstorm-dashboard.jsx and set our
18180
- // state once the component has mounted and we can get what we need.
18181
- this.getPosition = () => {
18182
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'getBoundingClientRect' does not exist on type 'Element | Text'.
18183
- const rect = ReactDOM__default.findDOMNode(this).getBoundingClientRect();
18184
- // TODO(scottgrant): This is a magic number! We don't know the size
18185
- // of the tooltip at this point, so we're arbitrarily choosing a
18186
- // point at which to flip the tooltip's position.
18187
- this.setState({
18188
- tooltipAbove: rect.top > 100
18189
- });
18190
- };
18191
18174
  // Render the <a> element that holds the indicator icon and the tooltip
18192
18175
  // We pass different styles for the inline and block cases
18193
18176
  this.renderLink = style => {
18194
- const tooltipAbove = this.state.tooltipAbove;
18195
18177
  let severityStyle;
18196
18178
  let warningText;
18197
18179
  let warningTextStyle;
@@ -18208,34 +18190,23 @@ class Lint extends React.Component {
18208
18190
  warningText = "Recommendation";
18209
18191
  warningTextStyle = styles$B.warning;
18210
18192
  }
18211
- return /*#__PURE__*/React.createElement("a", {
18193
+ return /*#__PURE__*/React.createElement(Tooltip$1, {
18194
+ backgroundColor: "offBlack",
18195
+ content: /*#__PURE__*/React.createElement(React.Fragment, null, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
18196
+ key: i,
18197
+ className: css(styles$B.tooltipParagraph)
18198
+ }, /*#__PURE__*/React.createElement("span", {
18199
+ className: css(warningTextStyle)
18200
+ }, warningText, ":", " "), m)))
18201
+ }, /*#__PURE__*/React.createElement("a", {
18212
18202
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
18213
18203
  target: "lint-help-window",
18214
18204
  className: css(style)
18215
18205
  }, /*#__PURE__*/React.createElement("span", {
18216
18206
  className: css(styles$B.indicator, severityStyle)
18217
- }, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React.createElement("div", {
18218
- className: css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
18219
- }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
18220
- key: i,
18221
- className: css(styles$B.tooltipParagraph)
18222
- }, /*#__PURE__*/React.createElement("span", {
18223
- className: css(warningTextStyle)
18224
- }, warningText, ":", " "), m)), /*#__PURE__*/React.createElement("div", {
18225
- className: css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
18226
- })));
18207
+ }, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon))));
18227
18208
  };
18228
18209
  }
18229
- componentDidMount() {
18230
- // TODO(somewhatabstract): Use WB timing
18231
- // eslint-disable-next-line no-restricted-syntax
18232
- this._positionTimeout = window.setTimeout(this.getPosition);
18233
- }
18234
- componentWillUnmount() {
18235
- // TODO(somewhatabstract): Use WB timing
18236
- // eslint-disable-next-line no-restricted-syntax
18237
- window.clearTimeout(this._positionTimeout);
18238
- }
18239
18210
  // The main render method surrounds linty content with a block or
18240
18211
  // inline container and the link element that displays the indicator
18241
18212
  // and holds the tooltip.
@@ -18436,54 +18407,11 @@ const styles$B = StyleSheet.create({
18436
18407
  indicatorGuideline: {
18437
18408
  backgroundColor: "#ffbe26"
18438
18409
  },
18439
- // These are the styles for the tooltip
18440
- tooltip: {
18441
- // Absolute positioning relative to the lint indicator circle.
18442
- position: "absolute",
18443
- right: -12,
18444
- // The tooltip is hidden by default; only displayed on hover
18445
- display: "none",
18446
- // When it is displayed, it goes on top!
18447
- zIndex: 1000,
18448
- // These styles control what the tooltip looks like
18449
- color: white$1,
18450
- backgroundColor: gray17,
18451
- opacity: 0.9,
18452
- fontFamily: baseFontFamily$1,
18453
- fontSize: "12px",
18454
- lineHeight: "15px",
18455
- width: "320px",
18456
- borderRadius: "4px"
18457
- },
18458
- // If we're going to render the tooltip above the warning circle, we use
18459
- // the previous rules in tooltip, but change the position slightly.
18460
- tooltipAbove: {
18461
- bottom: 32
18462
- },
18463
- // We give the tooltip a little triangular "tail" that points down at
18464
- // the lint indicator circle. This is inside the tooltip and positioned
18465
- // relative to it. It also shares the opacity of the tooltip. We're using
18466
- // the standard CSS trick for drawing triangles with a thick border.
18467
- tail: {
18468
- position: "absolute",
18469
- top: -12,
18470
- right: 16,
18471
- width: 0,
18472
- height: 0,
18473
- // This is the CSS triangle trick
18474
- borderLeft: "8px solid transparent",
18475
- borderRight: "8px solid transparent",
18476
- borderBottom: "12px solid " + gray17
18477
- },
18478
- tailAbove: {
18479
- bottom: -12,
18480
- borderBottom: "none",
18481
- borderTop: "12px solid " + gray17,
18482
- top: "auto"
18483
- },
18484
18410
  // Each warning in the tooltip is its own <p>. They are 12 pixels from
18485
18411
  // the edges of the tooltip and 12 pixels from each other.
18486
18412
  tooltipParagraph: {
18413
+ fontFamily: font.family.sans,
18414
+ color: color.white,
18487
18415
  margin: 12
18488
18416
  },
18489
18417
  // The text "Warning" inside the tooltip is highlighted like this
@@ -18972,7 +18900,7 @@ const {
18972
18900
  // Note: these size cutoffs represent content-width cutoffs as specified in
18973
18901
  // http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
18974
18902
  // TODO(benkomalo): these values aren't used in JS outside of this file, but
18975
- // are coupled to the values in styles/articles.less - DRY it up at some point
18903
+ // are coupled to the values in styles/styles.less - DRY it up at some point
18976
18904
  const smMax = articleMaxWidthTableInPx;
18977
18905
  const mdMax = articleMaxWidthInPx;
18978
18906
  const containerSizeClass = {
@@ -19763,9 +19691,7 @@ class Renderer extends React.Component {
19763
19691
  return _extends({}, widgetProps, {
19764
19692
  widgetId: id,
19765
19693
  alignment: widgetInfo && widgetInfo.alignment,
19766
- // When determining if a widget is static, we verify that the widget is not an
19767
- // exercise question by verifying that it has no problem number.
19768
- static: widgetInfo && widgetInfo.static && !this.props.problemNum,
19694
+ static: widgetInfo == null ? void 0 : widgetInfo.static,
19769
19695
  problemNum: this.props.problemNum,
19770
19696
  apiOptions: this.getApiOptions(),
19771
19697
  keypadElement: this.props.keypadElement,
@@ -19775,7 +19701,6 @@ class Renderer extends React.Component {
19775
19701
  onBlur: _.partial(this._onWidgetBlur, id),
19776
19702
  findWidgets: this.findWidgets,
19777
19703
  reviewModeRubric: reviewModeRubric,
19778
- hintMode: this.props.hintMode,
19779
19704
  onChange: (newProps, cb, silent = false) => {
19780
19705
  this._setWidgetProps(id, newProps, cb, silent);
19781
19706
  },
@@ -20150,7 +20075,7 @@ class Renderer extends React.Component {
20150
20075
  }
20151
20076
  // Widgets can contain text nodes, so we don't center them with
20152
20077
  // markdown magic here.
20153
- // Instead, we center them with css magic in articles.less
20078
+ // Instead, we center them with css magic in styles.less
20154
20079
  // /cry(aria)
20155
20080
  this._foundTextNodes = true;
20156
20081
  if (_.contains(this.widgetIds, node.id)) {
@@ -20978,7 +20903,6 @@ Renderer.defaultProps = {
20978
20903
  findExternalWidgets: () => [],
20979
20904
  alwaysUpdate: false,
20980
20905
  reviewMode: false,
20981
- hintMode: false,
20982
20906
  serializedState: null,
20983
20907
  onSerializedStateUpdated: () => {},
20984
20908
  linterContext: PerseusLinter.linterContextDefault
@@ -22581,7 +22505,7 @@ var sharedStyles = StyleSheet.create({
22581
22505
  zIndex: zIndexAboveScratchpad
22582
22506
  },
22583
22507
  blankBackground: {
22584
- // TODO(emily): Use KhanUtil._BACKGROUND?
22508
+ // TODO(emily): Use WB colors?
22585
22509
  backgroundColor: "#FDFDFD"
22586
22510
  },
22587
22511
  perseusSrOnly: {
@@ -22596,7 +22520,7 @@ var sharedStyles = StyleSheet.create({
22596
22520
  },
22597
22521
  responsiveLabel: {
22598
22522
  // NOTE(charlie): The values used here should be kept in sync with the
22599
- // caption text sizing in Perseus' articles.less.
22523
+ // caption text sizing in Perseus' styles.less.
22600
22524
  // TODO(charlie): Migrate the captions over to using this style.
22601
22525
  [mediaQueries.smOrSmaller]: {
22602
22526
  fontSize: 14,
@@ -26915,7 +26839,7 @@ const propTransform$2 = editorProps => {
26915
26839
 
26916
26840
  // Note that in addition to the standard staticTransform, in static
26917
26841
  // mode we set static=true for the graph's handles in FunctionGrapher.
26918
- const staticTransform$3 = editorProps => {
26842
+ const staticTransform$4 = editorProps => {
26919
26843
  return _extends({}, propTransform$2(editorProps), {
26920
26844
  // Don't display graph type choices if we're in static mode
26921
26845
  availableTypes: [editorProps.correct.type],
@@ -26928,7 +26852,7 @@ var Grapher$1 = {
26928
26852
  displayName: "Grapher",
26929
26853
  widget: Grapher,
26930
26854
  transform: propTransform$2,
26931
- staticTransform: staticTransform$3
26855
+ staticTransform: staticTransform$4
26932
26856
  };
26933
26857
 
26934
26858
  // exports has no 'transform'
@@ -29696,6 +29620,18 @@ const LegacyGrid = ({
29696
29620
 
29697
29621
  // Range is replaced within this file with Interval, but it is used elsewhere
29698
29622
  // and exported from the package, so we need to keep it around.
29623
+ /**
29624
+ * A "PerseusItem" is a classic Perseus item. It is rendered by the
29625
+ * `ServerItemRenderer` and the layout is pre-set.
29626
+ *
29627
+ * To render more complex Perseus items, see the `Item` type in the multi item
29628
+ * area.
29629
+ */
29630
+ /**
29631
+ * A "MultiItem" is an advanced Perseus item. It is rendered by the
29632
+ * `MultiRenderer` and you can control the layout of individual parts of the
29633
+ * item.
29634
+ */
29699
29635
  const ItemExtras = [
29700
29636
  // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
29701
29637
  "calculator",
@@ -31868,7 +31804,6 @@ const MafsGraph = props => {
31868
31804
  state,
31869
31805
  dispatch,
31870
31806
  labels,
31871
- hintMode,
31872
31807
  readOnly
31873
31808
  } = props;
31874
31809
  const [width, height] = props.box;
@@ -31885,7 +31820,7 @@ const MafsGraph = props => {
31885
31820
  width,
31886
31821
  height,
31887
31822
  labels,
31888
- disableKeyboardInteraction: hintMode || readOnly
31823
+ disableKeyboardInteraction: readOnly || !!props.static
31889
31824
  }
31890
31825
  }, /*#__PURE__*/React.createElement(View, {
31891
31826
  className: "mafs-graph",
@@ -31897,7 +31832,8 @@ const MafsGraph = props => {
31897
31832
  boxSizing: "content-box",
31898
31833
  marginLeft: "20px",
31899
31834
  marginBottom: "20px",
31900
- pointerEvents: hintMode ? "none" : "auto"
31835
+ pointerEvents: props.static ? "none" : "auto",
31836
+ userSelect: "none"
31901
31837
  }
31902
31838
  }, /*#__PURE__*/React.createElement(LegacyGrid, {
31903
31839
  box: props.box,
@@ -33013,6 +32949,17 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
33013
32949
  dispatch(reinitialize(latestPropsRef.current));
33014
32950
  }
33015
32951
  }, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef, graph.startCoords]);
32952
+
32953
+ // If the graph is static, it always displays the correct answer. This is
32954
+ // standard behavior for Perseus widgets (e.g. compare the Radio widget).
32955
+ if (props.static) {
32956
+ return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, props, {
32957
+ state: initializeGraphState(_extends({}, props, {
32958
+ graph: props.correct
32959
+ })),
32960
+ dispatch: dispatch
32961
+ }));
32962
+ }
33016
32963
  return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, props, {
33017
32964
  state: state,
33018
32965
  dispatch: dispatch
@@ -34332,7 +34279,6 @@ class InteractiveGraph extends React.Component {
34332
34279
  snapStep: snapStep,
34333
34280
  box: box,
34334
34281
  showTooltips: !!this.props.showTooltips,
34335
- hintMode: this.props.hintMode,
34336
34282
  readOnly: (_this$props$apiOption2 = this.props.apiOptions) == null ? void 0 : _this$props$apiOption2.readOnly
34337
34283
  }));
34338
34284
  }
@@ -34922,10 +34868,13 @@ function shouldUseMafs(mafsFlags, graph) {
34922
34868
  return Boolean(mafsFlags[graph.type]);
34923
34869
  }
34924
34870
  }
34871
+ // We don't need to change any of the original props for static mode
34872
+ const staticTransform$3 = _.identity;
34925
34873
  var InteractiveGraph$1 = {
34926
34874
  name: "interactive-graph",
34927
34875
  displayName: "Interactive graph",
34928
- widget: InteractiveGraph
34876
+ widget: InteractiveGraph,
34877
+ staticTransform: staticTransform$3
34929
34878
  };
34930
34879
 
34931
34880
  const black = "#000000";
@@ -44252,7 +44201,7 @@ const init = function init(options) {
44252
44201
 
44253
44202
  // This file is processed by a Rollup plugin (replace) to inject the production
44254
44203
  const libName = "@khanacademy/perseus";
44255
- const libVersion = "28.1.0";
44204
+ const libVersion = "29.0.0";
44256
44205
  addLibraryVersionToPerseusDebug(libName, libVersion);
44257
44206
 
44258
44207
  const apiVersion = {
@@ -44494,7 +44443,6 @@ class HintRenderer extends React.Component {
44494
44443
  // eslint-disable-next-line react/no-string-refs
44495
44444
  , {
44496
44445
  ref: "renderer",
44497
- hintMode: true,
44498
44446
  widgets: hint.widgets,
44499
44447
  content: hint.content || "",
44500
44448
  images: hint.images,
@@ -47663,7 +47611,6 @@ const genericPerseusItemData = {
47663
47611
  minor: 1
47664
47612
  },
47665
47613
  hints: [],
47666
- _multi: null,
47667
47614
  answer: null
47668
47615
  };
47669
47616