@khanacademy/perseus 20.1.0 → 20.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.css CHANGED
@@ -4258,18 +4258,24 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4258
4258
  --mafs-bg: transparent;
4259
4259
  --mafs-fg: rgb(33, 36, 44); /* WB color.offBlack */
4260
4260
 
4261
- --mafs-line-color: rgb(33, 36, 44, 0.64); /* WB color.offBlack64 */
4262
- --grid-line-subdivision-color: rgba(33, 36, 44, 0.16);
4261
+ --mafs-line-color: rgba(33, 36, 44, 0.16); /* WB color.offBlack16*/
4263
4262
 
4264
4263
  --mafs-blue: #1865f2; /* WB color.blue */
4265
4264
  --mafs-red: #d92916; /* WB color.red */
4266
4265
  --mafs-green: #00a60e; /* WB color.green */
4267
4266
  --mafs-violet: #9059ff; /* WB color.purple */
4268
4267
  --mafs-yellow: #ffb100; /* WB color.gold */
4268
+
4269
+ /* overridden on a per-point basis */
4270
+ --movable-point-color: var(--mafs-blue);
4271
+ --movable-point-center-radius: 6px;
4272
+ --movable-point-ring-radius: calc(2px + var(--movable-point-center-radius));
4273
+ --movable-point-halo-radius: calc(3px + var(--movable-point-ring-radius));
4274
+ --movable-point-hover-expansion: 2px;
4269
4275
  }
4270
4276
 
4271
4277
  .MafsView .movable-segment {
4272
- --mafs-segment-stroke-color: var(--mafs-line-color);
4278
+ --mafs-segment-stroke-color: rgba(33, 36, 44, 0.64); /* offBlack64 */
4273
4279
  --mafs-segment-stroke-weight: 2px;
4274
4280
  }
4275
4281
 
@@ -4282,3 +4288,51 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
4282
4288
  .MafsView .movable-segment:focus {
4283
4289
  outline: none;
4284
4290
  }
4291
+
4292
+ .MafsView .movable-point-hitbox {
4293
+ fill: transparent;
4294
+ }
4295
+
4296
+ .MafsView :is(.movable-point-center, .movable-point-ring, .movable-point-halo) {
4297
+ transition: r 0.15s ease-out;
4298
+ }
4299
+
4300
+ .MafsView .movable-point-center {
4301
+ r: var(--movable-point-center-radius);
4302
+ }
4303
+
4304
+ .MafsView .movable-point-halo {
4305
+ r: var(--movable-point-halo-radius);
4306
+ fill: var(--movable-point-color);
4307
+ opacity: 0.25;
4308
+ filter: drop-shadow(0 5px 5px #0008);
4309
+ }
4310
+
4311
+ .MafsView .movable-point-ring {
4312
+ r: var(--movable-point-ring-radius);
4313
+ fill: #fff;
4314
+ }
4315
+
4316
+ .MafsView .movable-point:hover .movable-point-center {
4317
+ r: calc(
4318
+ var(--movable-point-hover-expansion) +
4319
+ var(--movable-point-center-radius)
4320
+ );
4321
+ }
4322
+
4323
+ .MafsView .movable-point:hover .movable-point-ring {
4324
+ r: calc(
4325
+ var(--movable-point-hover-expansion) + var(--movable-point-ring-radius)
4326
+ );
4327
+ }
4328
+
4329
+ .MafsView .movable-point:hover .movable-point-halo {
4330
+ r: calc(
4331
+ var(--movable-point-hover-expansion) + var(--movable-point-halo-radius)
4332
+ );
4333
+ }
4334
+
4335
+ .MafsView .movable-point:focus-visible .movable-point-halo {
4336
+ outline: 2px solid blue;
4337
+ border-radius: 99px;
4338
+ }
package/dist/index.d.ts CHANGED
@@ -83,7 +83,7 @@ export type { ILogger, LogErrorOptions, ErrorKind } from "./logging/log";
83
83
  export type { ServerItemRenderer as ServerItemRendererComponent } from "./server-item-renderer";
84
84
  export type { Alignment, APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, DomInsertCheckFn, EditorMode, FocusPath, Hint, ImageDict, ImageUploader, JiptLabelStore, JiptRenderer, PerseusDependencies, PerseusScore, Version, VideoData, VideoKind, WidgetDict, WidgetExports, } from "./types";
85
85
  export type { ParsedValue } from "./util";
86
- export type { PerseusAnswerArea, PerseusExpressionWidgetOptions, Range, Size, MathFormat, InputNumberWidget, // TODO(jeremy): remove?
86
+ export type { LockedFigure, LockedFigureType, LockedPoint, PerseusGraphType, PerseusAnswerArea, PerseusExpressionWidgetOptions, Range, Size, MathFormat, InputNumberWidget, // TODO(jeremy): remove?
87
87
  PerseusImageBackground, PerseusInputNumberWidgetOptions, PerseusInteractiveGraphWidgetOptions, PerseusItem, PerseusPlotterWidgetOptions, PerseusPythonProgramWidgetOptions, PerseusRadioWidgetOptions, PerseusExampleWidgetOptions, PerseusExampleGraphieWidgetOptions, PerseusSimpleMarkdownTesterWidgetOptions, PerseusRenderer, PerseusWidget, PerseusWidgetsMap, } from "./perseus-types";
88
88
  export type { Coord } from "./interactive2/types";
89
89
  export type { MarkerType } from "./widgets/label-image/types";
package/dist/index.js CHANGED
@@ -2705,11 +2705,14 @@ function combineScores(scoreA, scoreB) {
2705
2705
  }
2706
2706
  });
2707
2707
  }
2708
+ function isCorrect(score) {
2709
+ return score.type === "points" && score.earned >= score.total;
2710
+ }
2708
2711
  function keScoreFromPerseusScore(score, guess, state) {
2709
2712
  if (score.type === "points") {
2710
2713
  return {
2711
2714
  empty: false,
2712
- correct: score.earned >= score.total,
2715
+ correct: isCorrect(score),
2713
2716
  message: score.message,
2714
2717
  guess: guess,
2715
2718
  state: state
@@ -15001,7 +15004,7 @@ const DEFAULT_STATE$1 = {
15001
15004
  // TODO(benchristel): this is a memory leak. We add items to
15002
15005
  // tooltipResetFunctions, but never remove them.
15003
15006
  const tooltipResetFunctions = [];
15004
- class MovablePoint$4 {
15007
+ class MovablePoint$5 {
15005
15008
  // @ts-expect-error - TS2564: Property 'prevState' has no initializer and is not definitely assigned in the constructor.
15006
15009
 
15007
15010
  _listenerMap = {};
@@ -16129,10 +16132,10 @@ ___default["default"].extend(MovablePolygon.prototype, {
16129
16132
  });
16130
16133
 
16131
16134
  const Interactive2 = {
16132
- MovablePoint: MovablePoint$4,
16135
+ MovablePoint: MovablePoint$5,
16133
16136
  addMovablePoint: function (graphie, options) {
16134
16137
  const movable = new Movable(graphie, {});
16135
- return new MovablePoint$4(graphie, movable, options);
16138
+ return new MovablePoint$5(graphie, movable, options);
16136
16139
  },
16137
16140
  MovableLine: MovableLine$3,
16138
16141
  addMovableLine: function (graphie, options) {
@@ -16174,7 +16177,7 @@ const Interactive2 = {
16174
16177
  }
16175
16178
  };
16176
16179
 
16177
- const MovablePoint$3 = GraphieClasses.createClass({
16180
+ const MovablePoint$4 = GraphieClasses.createClass({
16178
16181
  displayName: "MovablePoint",
16179
16182
  movableProps: ["children"],
16180
16183
  _getProps: function () {
@@ -16232,7 +16235,7 @@ const MovablePoint$3 = GraphieClasses.createClass({
16232
16235
  });
16233
16236
 
16234
16237
  // Include helper methods, such as MovablePoint.constrain.snap()
16235
- ___default["default"].extend(MovablePoint$3, Interactive2.MovablePoint);
16238
+ ___default["default"].extend(MovablePoint$4, Interactive2.MovablePoint);
16236
16239
  const MovableLine$2 = GraphieClasses.createClass({
16237
16240
  displayName: "MovableLine",
16238
16241
  movableProps: ["children"],
@@ -16402,7 +16405,7 @@ var Movables = {
16402
16405
  Label: Label$1,
16403
16406
  Line: Line$2,
16404
16407
  MovableLine: MovableLine$2,
16405
- MovablePoint: MovablePoint$3,
16408
+ MovablePoint: MovablePoint$4,
16406
16409
  Parabola: Parabola,
16407
16410
  Path: Path,
16408
16411
  Plot: Plot$2,
@@ -26482,7 +26485,7 @@ var util = /*#__PURE__*/Object.freeze({
26482
26485
  });
26483
26486
 
26484
26487
  // @ts-expect-error - TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'.
26485
- const MovablePoint$2 = Graphie.MovablePoint;
26488
+ const MovablePoint$3 = Graphie.MovablePoint;
26486
26489
  // @ts-expect-error - TS2339 - Property 'MovableLine' does not exist on type 'typeof Graphie'.
26487
26490
  const MovableLine$1 = Graphie.MovableLine;
26488
26491
  function isFlipped(newCoord, oldCoord, line) {
@@ -26528,7 +26531,7 @@ class FunctionGrapher extends React__namespace.Component {
26528
26531
  })();
26529
26532
  render() {
26530
26533
  const pointForCoord = (coord, i) => {
26531
- return /*#__PURE__*/React__namespace.createElement(MovablePoint$2, {
26534
+ return /*#__PURE__*/React__namespace.createElement(MovablePoint$3, {
26532
26535
  key: i,
26533
26536
  coord: coord,
26534
26537
  static: this.props.static,
@@ -26665,7 +26668,7 @@ class FunctionGrapher extends React__namespace.Component {
26665
26668
  }],
26666
26669
  normalStyle: dashed,
26667
26670
  highlightStyle: dashed
26668
- }, ___default["default"].map(asymptote, (coord, i) => /*#__PURE__*/React__namespace.createElement(MovablePoint$2, {
26671
+ }, ___default["default"].map(asymptote, (coord, i) => /*#__PURE__*/React__namespace.createElement(MovablePoint$3, {
26669
26672
  key: `asymptoteCoord-${i}`,
26670
26673
  coord: coord,
26671
26674
  static: true,
@@ -27428,7 +27431,7 @@ const Label = Graphie.Label;
27428
27431
  // @ts-expect-error - TS2339 - Property 'Line' does not exist on type 'typeof Graphie'.
27429
27432
  const Line$1 = Graphie.Line;
27430
27433
  // @ts-expect-error - TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'.
27431
- const MovablePoint$1 = Graphie.MovablePoint;
27434
+ const MovablePoint$2 = Graphie.MovablePoint;
27432
27435
  // @ts-expect-error - TS2339 - Property 'MovableLine' does not exist on type 'typeof Graphie'.
27433
27436
  const MovableLine = Graphie.MovableLine;
27434
27437
  // @ts-expect-error - TS2339 - Property 'Plot' does not exist on type 'typeof Graphie'.
@@ -27682,7 +27685,7 @@ class Interaction extends React__namespace.Component {
27682
27685
  return [coordX, coordY];
27683
27686
  }];
27684
27687
  if (element.options.constraint === "snap") {
27685
- constraints.push(MovablePoint$1.constraints.snap(element.options.snap));
27688
+ constraints.push(MovablePoint$2.constraints.snap(element.options.snap));
27686
27689
  } else if (element.options.constraint === "x") {
27687
27690
  constraints.push(coord => {
27688
27691
  return [
@@ -27704,7 +27707,7 @@ class Interaction extends React__namespace.Component {
27704
27707
  // TODO(eater): foo_[xyz] are hacky non-props to
27705
27708
  // get the component to update when constraints
27706
27709
  // change
27707
- return /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
27710
+ return /*#__PURE__*/React__namespace.createElement(MovablePoint$2, {
27708
27711
  key: element.key,
27709
27712
  coord: [
27710
27713
  // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
@@ -27739,7 +27742,7 @@ class Interaction extends React__namespace.Component {
27739
27742
  return [coordX, coordY];
27740
27743
  }];
27741
27744
  if (element.options.constraint === "snap") {
27742
- constraints.push(MovablePoint$1.constraints.snap(element.options.snap));
27745
+ constraints.push(MovablePoint$2.constraints.snap(element.options.snap));
27743
27746
  } else if (element.options.constraint === "x") {
27744
27747
  constraints.push(coord => {
27745
27748
  return [
@@ -27780,14 +27783,14 @@ class Interaction extends React__namespace.Component {
27780
27783
  foo_x: element.options.constraint,
27781
27784
  foo_y: element.options.constraintFn,
27782
27785
  foo_z: element.options.snap
27783
- }, /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
27786
+ }, /*#__PURE__*/React__namespace.createElement(MovablePoint$2, {
27784
27787
  coord: start,
27785
27788
  static: true,
27786
27789
  normalStyle: {
27787
27790
  stroke: "none",
27788
27791
  fill: "none"
27789
27792
  }
27790
- }), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
27793
+ }), /*#__PURE__*/React__namespace.createElement(MovablePoint$2, {
27791
27794
  coord: end,
27792
27795
  static: true,
27793
27796
  normalStyle: {
@@ -28238,33 +28241,6 @@ class Graph extends React__namespace.Component {
28238
28241
  allowScratchpad: true,
28239
28242
  setDrawingAreaAvailable: this.props.setDrawingAreaAvailable
28240
28243
  });
28241
-
28242
- // Maybe move this out later
28243
- if (this.props.lockedFigures) {
28244
- for (const lockedFigure of this.props.lockedFigures) {
28245
- switch (lockedFigure.type) {
28246
- case "point":
28247
- graphie.circle(
28248
- // center
28249
- lockedFigure.coord,
28250
- // radius
28251
- 0.2,
28252
- // style
28253
- lockedFigure.style);
28254
- break;
28255
- default:
28256
- /**
28257
- * Devlopment-time future-proofing: This `never` should
28258
- * fail during type-checking if we add a new locked
28259
- * shape type and forget to handle it in any other
28260
- * switch case here.
28261
- */
28262
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
28263
- lockedFigure.type;
28264
- throw new Error(`Unknown locked shape type: ${lockedFigure.type}`);
28265
- }
28266
- }
28267
- }
28268
28244
  this._updateProtractor();
28269
28245
  this._updateRuler();
28270
28246
 
@@ -28357,6 +28333,35 @@ class Graph extends React__namespace.Component {
28357
28333
  }
28358
28334
  }
28359
28335
 
28336
+ const GraphLockedLayer = props => {
28337
+ const {
28338
+ lockedFigures
28339
+ } = props;
28340
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lockedFigures.map((figure, index) => {
28341
+ switch (figure.type) {
28342
+ case "point":
28343
+ const [x, y] = figure.coord;
28344
+ return /*#__PURE__*/React__namespace.createElement(mafs.Point, {
28345
+ key: `${figure.type}-${index}`,
28346
+ x: x,
28347
+ y: y,
28348
+ svgCircleProps: {
28349
+ style: figure.style
28350
+ }
28351
+ });
28352
+ }
28353
+
28354
+ /**
28355
+ * Devlopment-time future-proofing: This `never` should
28356
+ * fail during type-checking if we add a new locked
28357
+ * shape type and forget to handle it in any other
28358
+ * switch case here.
28359
+ */
28360
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28361
+ throw new wonderStuffCore.UnreachableCaseError(figure.type);
28362
+ }));
28363
+ };
28364
+
28360
28365
  const MOVE_CONTROL_POINT = "move-control-point";
28361
28366
  function moveControlPoint(objectIndex, pointIndex, destination) {
28362
28367
  return {
@@ -28375,6 +28380,59 @@ function moveSegment(segmentIndex, delta) {
28375
28380
  };
28376
28381
  }
28377
28382
 
28383
+ const MovablePoint$1 = props => {
28384
+ const hitboxRef = React.useRef(null);
28385
+ const {
28386
+ point,
28387
+ onMove
28388
+ } = props;
28389
+ const {
28390
+ dragging
28391
+ } = mafs.useMovable({
28392
+ gestureTarget: hitboxRef,
28393
+ point,
28394
+ onMove,
28395
+ constrain: p => p
28396
+ });
28397
+ const {
28398
+ viewTransform,
28399
+ userTransform
28400
+ } = mafs.useTransformContext();
28401
+ const transformToPx = mafs.vec.matrixMult(viewTransform, userTransform);
28402
+ const [x, y] = mafs.vec.transform(point, transformToPx);
28403
+ return /*#__PURE__*/React__namespace.createElement("g", {
28404
+ ref: hitboxRef,
28405
+ className: "movable-point",
28406
+ tabIndex: 0,
28407
+ style: {
28408
+ cursor: dragging ? "grabbing" : "grab",
28409
+ touchAction: "none",
28410
+ outline: "none",
28411
+ "--movable-point-color": Color__default["default"].blue
28412
+ }
28413
+ }, /*#__PURE__*/React__namespace.createElement("circle", {
28414
+ className: "movable-point-hitbox",
28415
+ r: 30,
28416
+ cx: x,
28417
+ cy: y
28418
+ }), /*#__PURE__*/React__namespace.createElement("circle", {
28419
+ className: "movable-point-halo",
28420
+ cx: x,
28421
+ cy: y
28422
+ }), /*#__PURE__*/React__namespace.createElement("circle", {
28423
+ className: "movable-point-ring",
28424
+ cx: x,
28425
+ cy: y
28426
+ }), /*#__PURE__*/React__namespace.createElement("circle", {
28427
+ className: "movable-point-center",
28428
+ cx: x,
28429
+ cy: y,
28430
+ style: {
28431
+ fill: Color__default["default"].blue
28432
+ }
28433
+ }));
28434
+ };
28435
+
28378
28436
  const SegmentGraph = props => {
28379
28437
  const {
28380
28438
  dispatch
@@ -28417,9 +28475,9 @@ const SegmentView = props => {
28417
28475
  viewTransform,
28418
28476
  userTransform
28419
28477
  } = mafs.useTransformContext();
28420
- const transform = mafs.vec.matrixMult(viewTransform, userTransform);
28421
- const scaledPoint1 = mafs.vec.transform(pt1, transform);
28422
- const scaledPoint2 = mafs.vec.transform(pt2, transform);
28478
+ const transformToPx = mafs.vec.matrixMult(viewTransform, userTransform);
28479
+ const pt1Px = mafs.vec.transform(pt1, transformToPx);
28480
+ const pt2Px = mafs.vec.transform(pt2, transformToPx);
28423
28481
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("g", {
28424
28482
  ref: segment,
28425
28483
  tabIndex: 0,
@@ -28428,28 +28486,26 @@ const SegmentView = props => {
28428
28486
  cursor: isDraggingSegment ? "grabbing" : "grab"
28429
28487
  }
28430
28488
  }, /*#__PURE__*/React__namespace.createElement(SVGLine, {
28431
- start: scaledPoint1,
28432
- end: scaledPoint2,
28489
+ start: pt1Px,
28490
+ end: pt2Px,
28433
28491
  style: {
28434
28492
  stroke: "transparent",
28435
28493
  strokeWidth: 30
28436
28494
  }
28437
28495
  }), /*#__PURE__*/React__namespace.createElement(SVGLine, {
28438
- start: scaledPoint1,
28439
- end: scaledPoint2,
28496
+ start: pt1Px,
28497
+ end: pt2Px,
28440
28498
  style: {
28441
28499
  stroke: "var(--mafs-segment-stroke-color)",
28442
28500
  strokeWidth: "var(--mafs-segment-stroke-weight)"
28443
28501
  }
28444
- })), /*#__PURE__*/React__namespace.createElement(mafs.MovablePoint, {
28502
+ })), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
28445
28503
  point: pt1,
28446
- color: Color__default["default"].blue,
28447
28504
  onMove: newPoint => {
28448
28505
  props.onMovePoint(0, newPoint);
28449
28506
  }
28450
- }), /*#__PURE__*/React__namespace.createElement(mafs.MovablePoint, {
28507
+ }), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
28451
28508
  point: pt2,
28452
- color: Color__default["default"].blue,
28453
28509
  onMove: newPoint => {
28454
28510
  props.onMovePoint(1, newPoint);
28455
28511
  }
@@ -29389,7 +29445,9 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
29389
29445
  zoom: false,
29390
29446
  width: width,
29391
29447
  height: height
29392
- }, !legacyGrid && /*#__PURE__*/React__namespace.createElement(Grid, props), renderGraph({
29448
+ }, !legacyGrid && /*#__PURE__*/React__namespace.createElement(Grid, props), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
29449
+ lockedFigures: props.lockedFigures
29450
+ }), renderGraph({
29393
29451
  state,
29394
29452
  dispatch
29395
29453
  }))));
@@ -29568,7 +29626,7 @@ class InteractiveGraph extends React__namespace.Component {
29568
29626
  this.sinusoid = null;
29569
29627
  // eslint-disable-next-line react/no-string-refs
29570
29628
  // @ts-expect-error - TS2339 - Property 'reset' does not exist on type 'ReactInstance'.
29571
- this.refs.graph.reset();
29629
+ this.refs.graph?.reset();
29572
29630
  };
29573
29631
  setupGraphie = () => {
29574
29632
  this.setTrashCanVisibility(0);
@@ -30644,8 +30702,7 @@ class InteractiveGraph extends React__namespace.Component {
30644
30702
  onMouseDown: onMouseDown,
30645
30703
  onGraphieUpdated: this.setGraphie,
30646
30704
  setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable,
30647
- isMobile: isMobile,
30648
- lockedFigures: this.props.lockedFigures
30705
+ isMobile: isMobile
30649
30706
  }));
30650
30707
  }
30651
30708
  static getQuadraticCoefficients(coords) {
@@ -41367,7 +41424,7 @@ const init = function (options) {
41367
41424
 
41368
41425
  // This file is processed by a Rollup plugin (replace) to inject the production
41369
41426
  const libName = "@khanacademy/perseus";
41370
- const libVersion = "20.1.0";
41427
+ const libVersion = "20.2.0";
41371
41428
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
41372
41429
 
41373
41430
  const apiVersion = {