@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.
package/dist/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/index.d.ts CHANGED
@@ -88,7 +88,7 @@ export type { ServerItemRenderer as ServerItemRendererComponent } from "./server
88
88
  export type { Alignment, APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, DomInsertCheckFn, EditorMode, FocusPath, ImageDict, ImageUploader, JiptLabelStore, JiptRenderer, PerseusDependencies, PerseusScore, Version, VideoData, VideoKind, WidgetDict, WidgetExports, } from "./types";
89
89
  export type { ParsedValue } from "./util";
90
90
  export type { Hint, LegacyButtonSets, LockedFigure, LockedFigureColor, LockedFigureFillType, LockedFigureType, LockedPointType, LockedLineType, LockedVectorType, LockedEllipseType, LockedPolygonType, LockedFunctionType, PerseusGraphType, PerseusAnswerArea, PerseusExpressionWidgetOptions, Range, Size, CollinearTuple, MathFormat, InputNumberWidget, // TODO(jeremy): remove?
91
- PerseusImageBackground, PerseusInputNumberWidgetOptions, PerseusInteractiveGraphWidgetOptions, PerseusItem, PerseusPlotterWidgetOptions, PerseusPythonProgramWidgetOptions, PerseusRadioWidgetOptions, PerseusExampleWidgetOptions, PerseusExampleGraphieWidgetOptions, PerseusSimpleMarkdownTesterWidgetOptions, PerseusRenderer, PerseusWidget, PerseusWidgetsMap, } from "./perseus-types";
91
+ PerseusImageBackground, PerseusInputNumberWidgetOptions, PerseusInteractiveGraphWidgetOptions, PerseusItem, PerseusPlotterWidgetOptions, PerseusPythonProgramWidgetOptions, PerseusRadioWidgetOptions, PerseusExampleWidgetOptions, PerseusExampleGraphieWidgetOptions, PerseusSimpleMarkdownTesterWidgetOptions, PerseusRenderer, PerseusWidget, PerseusWidgetsMap, MultiItem, } from "./perseus-types";
92
92
  export type { Coord } from "./interactive2/types";
93
93
  export type { MarkerType } from "./widgets/label-image/types";
94
94
  /**
package/dist/index.js CHANGED
@@ -869,7 +869,7 @@ const denylist = [
869
869
  // (technically the renderer still adds them)
870
870
  "key", "ref",
871
871
  // added by src/renderer.jsx
872
- "containerSizeClass", "widgetId", "onChange", "problemNum", "apiOptions", "questionCompleted", "findWidgets", "hintMode",
872
+ "containerSizeClass", "widgetId", "onChange", "problemNum", "apiOptions", "questionCompleted", "findWidgets",
873
873
  // added by src/editor.jsx, for widgets removing themselves
874
874
  // this is soooo not the right place for this, but alas.
875
875
  "onRemove",
@@ -1395,7 +1395,7 @@ const KhanMath = {
1395
1395
  * with an approx symbol if num had to be rounded, and trailing 0s
1396
1396
  */
1397
1397
  toFixedApprox: function (num, precision) {
1398
- // TODO(aria): Make this locale-dependent like KhanUtil.localeToFixed
1398
+ // TODO(aria): Make this locale-dependent
1399
1399
  const fixedStr = num.toFixed(precision);
1400
1400
  if (kmath.number.equal(+fixedStr, num)) {
1401
1401
  return fixedStr;
@@ -18331,39 +18331,10 @@ var Severity = /*#__PURE__*/function (Severity) {
18331
18331
  **/
18332
18332
  class Lint extends React__namespace.Component {
18333
18333
  _positionTimeout;
18334
- state = {
18335
- tooltipAbove: true
18336
- };
18337
- componentDidMount() {
18338
- // TODO(somewhatabstract): Use WB timing
18339
- // eslint-disable-next-line no-restricted-syntax
18340
- this._positionTimeout = window.setTimeout(this.getPosition);
18341
- }
18342
- componentWillUnmount() {
18343
- // TODO(somewhatabstract): Use WB timing
18344
- // eslint-disable-next-line no-restricted-syntax
18345
- window.clearTimeout(this._positionTimeout);
18346
- }
18347
-
18348
- // We can't call setState in componentDidMount without risking a render
18349
- // thrash, and we can't call getBoundingClientRect in render, so we
18350
- // borrow a timeout approach from learnstorm-dashboard.jsx and set our
18351
- // state once the component has mounted and we can get what we need.
18352
- getPosition = () => {
18353
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'getBoundingClientRect' does not exist on type 'Element | Text'.
18354
- const rect = ReactDOM__default["default"].findDOMNode(this).getBoundingClientRect();
18355
- // TODO(scottgrant): This is a magic number! We don't know the size
18356
- // of the tooltip at this point, so we're arbitrarily choosing a
18357
- // point at which to flip the tooltip's position.
18358
- this.setState({
18359
- tooltipAbove: rect.top > 100
18360
- });
18361
- };
18362
18334
 
18363
18335
  // Render the <a> element that holds the indicator icon and the tooltip
18364
18336
  // We pass different styles for the inline and block cases
18365
18337
  renderLink = style => {
18366
- const tooltipAbove = this.state.tooltipAbove;
18367
18338
  let severityStyle;
18368
18339
  let warningText;
18369
18340
  let warningTextStyle;
@@ -18380,22 +18351,21 @@ class Lint extends React__namespace.Component {
18380
18351
  warningText = "Recommendation";
18381
18352
  warningTextStyle = styles$B.warning;
18382
18353
  }
18383
- return /*#__PURE__*/React__namespace.createElement("a", {
18354
+ return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
18355
+ backgroundColor: "offBlack",
18356
+ content: /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React__namespace.createElement("p", {
18357
+ key: i,
18358
+ className: aphrodite.css(styles$B.tooltipParagraph)
18359
+ }, /*#__PURE__*/React__namespace.createElement("span", {
18360
+ className: aphrodite.css(warningTextStyle)
18361
+ }, warningText, ":", " "), m)))
18362
+ }, /*#__PURE__*/React__namespace.createElement("a", {
18384
18363
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
18385
18364
  target: "lint-help-window",
18386
18365
  className: aphrodite.css(style)
18387
18366
  }, /*#__PURE__*/React__namespace.createElement("span", {
18388
18367
  className: aphrodite.css(styles$B.indicator, severityStyle)
18389
- }, this.props.severity === 1 && /*#__PURE__*/React__namespace.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React__namespace.createElement("div", {
18390
- className: aphrodite.css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
18391
- }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React__namespace.createElement("p", {
18392
- key: i,
18393
- className: aphrodite.css(styles$B.tooltipParagraph)
18394
- }, /*#__PURE__*/React__namespace.createElement("span", {
18395
- className: aphrodite.css(warningTextStyle)
18396
- }, warningText, ":", " "), m)), /*#__PURE__*/React__namespace.createElement("div", {
18397
- className: aphrodite.css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
18398
- })));
18368
+ }, this.props.severity === 1 && /*#__PURE__*/React__namespace.createElement(InlineIcon, exclamationIcon))));
18399
18369
  };
18400
18370
 
18401
18371
  // The main render method surrounds linty content with a block or
@@ -18598,54 +18568,11 @@ const styles$B = aphrodite.StyleSheet.create({
18598
18568
  indicatorGuideline: {
18599
18569
  backgroundColor: "#ffbe26"
18600
18570
  },
18601
- // These are the styles for the tooltip
18602
- tooltip: {
18603
- // Absolute positioning relative to the lint indicator circle.
18604
- position: "absolute",
18605
- right: -12,
18606
- // The tooltip is hidden by default; only displayed on hover
18607
- display: "none",
18608
- // When it is displayed, it goes on top!
18609
- zIndex: 1000,
18610
- // These styles control what the tooltip looks like
18611
- color: white$1,
18612
- backgroundColor: gray17,
18613
- opacity: 0.9,
18614
- fontFamily: baseFontFamily$1,
18615
- fontSize: "12px",
18616
- lineHeight: "15px",
18617
- width: "320px",
18618
- borderRadius: "4px"
18619
- },
18620
- // If we're going to render the tooltip above the warning circle, we use
18621
- // the previous rules in tooltip, but change the position slightly.
18622
- tooltipAbove: {
18623
- bottom: 32
18624
- },
18625
- // We give the tooltip a little triangular "tail" that points down at
18626
- // the lint indicator circle. This is inside the tooltip and positioned
18627
- // relative to it. It also shares the opacity of the tooltip. We're using
18628
- // the standard CSS trick for drawing triangles with a thick border.
18629
- tail: {
18630
- position: "absolute",
18631
- top: -12,
18632
- right: 16,
18633
- width: 0,
18634
- height: 0,
18635
- // This is the CSS triangle trick
18636
- borderLeft: "8px solid transparent",
18637
- borderRight: "8px solid transparent",
18638
- borderBottom: "12px solid " + gray17
18639
- },
18640
- tailAbove: {
18641
- bottom: -12,
18642
- borderBottom: "none",
18643
- borderTop: "12px solid " + gray17,
18644
- top: "auto"
18645
- },
18646
18571
  // Each warning in the tooltip is its own <p>. They are 12 pixels from
18647
18572
  // the edges of the tooltip and 12 pixels from each other.
18648
18573
  tooltipParagraph: {
18574
+ fontFamily: wonderBlocksTokens.font.family.sans,
18575
+ color: wonderBlocksTokens.color.white,
18649
18576
  margin: 12
18650
18577
  },
18651
18578
  // The text "Warning" inside the tooltip is highlighted like this
@@ -19151,7 +19078,7 @@ const {
19151
19078
  // Note: these size cutoffs represent content-width cutoffs as specified in
19152
19079
  // http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
19153
19080
  // TODO(benkomalo): these values aren't used in JS outside of this file, but
19154
- // are coupled to the values in styles/articles.less - DRY it up at some point
19081
+ // are coupled to the values in styles/styles.less - DRY it up at some point
19155
19082
  const smMax = articleMaxWidthTableInPx;
19156
19083
  const mdMax = articleMaxWidthInPx;
19157
19084
  const containerSizeClass = {
@@ -19832,7 +19759,6 @@ class Renderer extends React__namespace.Component {
19832
19759
  findExternalWidgets: () => [],
19833
19760
  alwaysUpdate: false,
19834
19761
  reviewMode: false,
19835
- hintMode: false,
19836
19762
  serializedState: null,
19837
19763
  onSerializedStateUpdated: () => {},
19838
19764
  linterContext: PerseusLinter__namespace.linterContextDefault
@@ -20111,9 +20037,7 @@ class Renderer extends React__namespace.Component {
20111
20037
  ...widgetProps,
20112
20038
  widgetId: id,
20113
20039
  alignment: widgetInfo && widgetInfo.alignment,
20114
- // When determining if a widget is static, we verify that the widget is not an
20115
- // exercise question by verifying that it has no problem number.
20116
- static: widgetInfo && widgetInfo.static && !this.props.problemNum,
20040
+ static: widgetInfo?.static,
20117
20041
  problemNum: this.props.problemNum,
20118
20042
  apiOptions: this.getApiOptions(),
20119
20043
  keypadElement: this.props.keypadElement,
@@ -20123,7 +20047,6 @@ class Renderer extends React__namespace.Component {
20123
20047
  onBlur: ___default["default"].partial(this._onWidgetBlur, id),
20124
20048
  findWidgets: this.findWidgets,
20125
20049
  reviewModeRubric: reviewModeRubric,
20126
- hintMode: this.props.hintMode,
20127
20050
  onChange: function (newProps, cb) {
20128
20051
  let silent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
20129
20052
  _this._setWidgetProps(id, newProps, cb, silent);
@@ -20511,7 +20434,7 @@ class Renderer extends React__namespace.Component {
20511
20434
  }
20512
20435
  // Widgets can contain text nodes, so we don't center them with
20513
20436
  // markdown magic here.
20514
- // Instead, we center them with css magic in articles.less
20437
+ // Instead, we center them with css magic in styles.less
20515
20438
  // /cry(aria)
20516
20439
  this._foundTextNodes = true;
20517
20440
  if (___default["default"].contains(this.widgetIds, node.id)) {
@@ -22796,7 +22719,7 @@ var sharedStyles = aphrodite.StyleSheet.create({
22796
22719
  zIndex: zIndexAboveScratchpad
22797
22720
  },
22798
22721
  blankBackground: {
22799
- // TODO(emily): Use KhanUtil._BACKGROUND?
22722
+ // TODO(emily): Use WB colors?
22800
22723
  backgroundColor: "#FDFDFD"
22801
22724
  },
22802
22725
  perseusSrOnly: {
@@ -22811,7 +22734,7 @@ var sharedStyles = aphrodite.StyleSheet.create({
22811
22734
  },
22812
22735
  responsiveLabel: {
22813
22736
  // NOTE(charlie): The values used here should be kept in sync with the
22814
- // caption text sizing in Perseus' articles.less.
22737
+ // caption text sizing in Perseus' styles.less.
22815
22738
  // TODO(charlie): Migrate the captions over to using this style.
22816
22739
  [mediaQueries.smOrSmaller]: {
22817
22740
  fontSize: 14,
@@ -27186,7 +27109,7 @@ const propTransform$2 = editorProps => {
27186
27109
 
27187
27110
  // Note that in addition to the standard staticTransform, in static
27188
27111
  // mode we set static=true for the graph's handles in FunctionGrapher.
27189
- const staticTransform$3 = editorProps => {
27112
+ const staticTransform$4 = editorProps => {
27190
27113
  return {
27191
27114
  ...propTransform$2(editorProps),
27192
27115
  // Don't display graph type choices if we're in static mode
@@ -27200,7 +27123,7 @@ var Grapher$1 = {
27200
27123
  displayName: "Grapher",
27201
27124
  widget: Grapher,
27202
27125
  transform: propTransform$2,
27203
- staticTransform: staticTransform$3
27126
+ staticTransform: staticTransform$4
27204
27127
  };
27205
27128
 
27206
27129
  // exports has no 'transform'
@@ -30001,6 +29924,18 @@ const LegacyGrid = _ref => {
30001
29924
 
30002
29925
  // Range is replaced within this file with Interval, but it is used elsewhere
30003
29926
  // and exported from the package, so we need to keep it around.
29927
+ /**
29928
+ * A "PerseusItem" is a classic Perseus item. It is rendered by the
29929
+ * `ServerItemRenderer` and the layout is pre-set.
29930
+ *
29931
+ * To render more complex Perseus items, see the `Item` type in the multi item
29932
+ * area.
29933
+ */
29934
+ /**
29935
+ * A "MultiItem" is an advanced Perseus item. It is rendered by the
29936
+ * `MultiRenderer` and you can control the layout of individual parts of the
29937
+ * item.
29938
+ */
30004
29939
  const ItemExtras = [
30005
29940
  // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
30006
29941
  "calculator",
@@ -32195,7 +32130,6 @@ const MafsGraph = props => {
32195
32130
  state,
32196
32131
  dispatch,
32197
32132
  labels,
32198
- hintMode,
32199
32133
  readOnly
32200
32134
  } = props;
32201
32135
  const [width, height] = props.box;
@@ -32212,7 +32146,7 @@ const MafsGraph = props => {
32212
32146
  width,
32213
32147
  height,
32214
32148
  labels,
32215
- disableKeyboardInteraction: hintMode || readOnly
32149
+ disableKeyboardInteraction: readOnly || !!props.static
32216
32150
  }
32217
32151
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32218
32152
  className: "mafs-graph",
@@ -32224,7 +32158,8 @@ const MafsGraph = props => {
32224
32158
  boxSizing: "content-box",
32225
32159
  marginLeft: "20px",
32226
32160
  marginBottom: "20px",
32227
- pointerEvents: hintMode ? "none" : "auto"
32161
+ pointerEvents: props.static ? "none" : "auto",
32162
+ userSelect: "none"
32228
32163
  }
32229
32164
  }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32230
32165
  box: props.box,
@@ -33377,6 +33312,18 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
33377
33312
  dispatch(reinitialize(latestPropsRef.current));
33378
33313
  }
33379
33314
  }, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef, graph.startCoords]);
33315
+
33316
+ // If the graph is static, it always displays the correct answer. This is
33317
+ // standard behavior for Perseus widgets (e.g. compare the Radio widget).
33318
+ if (props.static) {
33319
+ return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, props, {
33320
+ state: initializeGraphState({
33321
+ ...props,
33322
+ graph: props.correct
33323
+ }),
33324
+ dispatch: dispatch
33325
+ }));
33326
+ }
33380
33327
  return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, props, {
33381
33328
  state: state,
33382
33329
  dispatch: dispatch
@@ -34680,7 +34627,6 @@ class InteractiveGraph extends React__namespace.Component {
34680
34627
  snapStep: snapStep,
34681
34628
  box: box,
34682
34629
  showTooltips: !!this.props.showTooltips,
34683
- hintMode: this.props.hintMode,
34684
34630
  readOnly: this.props.apiOptions?.readOnly
34685
34631
  }));
34686
34632
  }
@@ -35256,10 +35202,13 @@ function shouldUseMafs(mafsFlags, graph) {
35256
35202
  return Boolean(mafsFlags[graph.type]);
35257
35203
  }
35258
35204
  }
35205
+ // We don't need to change any of the original props for static mode
35206
+ const staticTransform$3 = ___default["default"].identity;
35259
35207
  var InteractiveGraph$1 = {
35260
35208
  name: "interactive-graph",
35261
35209
  displayName: "Interactive graph",
35262
- widget: InteractiveGraph
35210
+ widget: InteractiveGraph,
35211
+ staticTransform: staticTransform$3
35263
35212
  };
35264
35213
 
35265
35214
  const black = "#000000";
@@ -44603,7 +44552,7 @@ const init = function (options) {
44603
44552
 
44604
44553
  // This file is processed by a Rollup plugin (replace) to inject the production
44605
44554
  const libName = "@khanacademy/perseus";
44606
- const libVersion = "28.1.0";
44555
+ const libVersion = "29.0.0";
44607
44556
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
44608
44557
 
44609
44558
  const apiVersion = {
@@ -44851,7 +44800,6 @@ class HintRenderer extends React__namespace.Component {
44851
44800
  // eslint-disable-next-line react/no-string-refs
44852
44801
  , {
44853
44802
  ref: "renderer",
44854
- hintMode: true,
44855
44803
  widgets: hint.widgets,
44856
44804
  content: hint.content || "",
44857
44805
  images: hint.images,
@@ -48025,7 +47973,6 @@ const genericPerseusItemData = {
48025
47973
  minor: 1
48026
47974
  },
48027
47975
  hints: [],
48028
- _multi: null,
48029
47976
  answer: null
48030
47977
  };
48031
47978