@khanacademy/perseus 19.1.8 → 19.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.js CHANGED
@@ -278,7 +278,7 @@ class MathInput extends React__namespace.Component {
278
278
  className = className + " " + this.props.className;
279
279
  }
280
280
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
281
- style: [styles$B.outerWrapper, this.state.focused && styles$B.wrapperFocused, this.props.hasError && styles$B.wrapperError]
281
+ style: [styles$C.outerWrapper, this.state.focused && styles$C.wrapperFocused, this.props.hasError && styles$C.wrapperError]
282
282
  }, /*#__PURE__*/React__namespace.createElement("div", {
283
283
  style: {
284
284
  display: "flex",
@@ -309,7 +309,7 @@ class MathInput extends React__namespace.Component {
309
309
  dismissEnabled: true,
310
310
  content: () => /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
311
311
  closeButtonVisible: true,
312
- style: styles$B.popoverContent
312
+ style: styles$C.popoverContent
313
313
  }, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends({
314
314
  onAnalyticsEvent: this.props.analytics.onAnalyticsEvent,
315
315
  extraKeys: this.props.extraKeys,
@@ -349,9 +349,9 @@ const MathInputIcon = _ref => {
349
349
  color = Color__default["default"].offBlack;
350
350
  break;
351
351
  }
352
- const dynamicClass = active || focused ? styles$B.iconActive : styles$B.iconInactive;
352
+ const dynamicClass = active || focused ? styles$C.iconActive : styles$C.iconInactive;
353
353
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
354
- style: [styles$B.iconContainer, dynamicClass]
354
+ style: [styles$C.iconContainer, dynamicClass]
355
355
  }, /*#__PURE__*/React__namespace.createElement("svg", {
356
356
  xmlns: "http://www.w3.org/2000/svg",
357
357
  width: "16",
@@ -396,7 +396,7 @@ const inputFocused = {
396
396
  borderColor: Color__default["default"].blue,
397
397
  margin: -1
398
398
  };
399
- const styles$B = aphrodite.StyleSheet.create({
399
+ const styles$C = aphrodite.StyleSheet.create({
400
400
  iconContainer: {
401
401
  display: "flex",
402
402
  justifyContent: "center",
@@ -8692,6 +8692,11 @@ function polar(r, th) {
8692
8692
  class Graphie$1 {
8693
8693
  #bounds;
8694
8694
  #drawingTransform;
8695
+
8696
+ // The primary drawing layer
8697
+
8698
+ // The layer that all visuals with mouse handlers are drawn into
8699
+
8695
8700
  isMobile = false;
8696
8701
  // Set up some reasonable defaults
8697
8702
  currentStyle = {
@@ -9537,13 +9542,125 @@ class Graphie$1 {
9537
9542
  return processed;
9538
9543
  }
9539
9544
 
9540
- // This is a stub that's overridden in interactive.ts
9541
- getMouseCoord(event) {
9542
- throw new Error("getMouseCoord is a stub, and is not implemented");
9545
+ // Graphie puts text spans on top of the SVG, which looks good, but gets
9546
+ // in the way of mouse events. This adds another SVG element on top
9547
+ // of everything else where we can add invisible shapes with mouse
9548
+ // handlers wherever we want.
9549
+ addMouseLayer(options) {
9550
+ const localOptions = {
9551
+ allowScratchpad: false,
9552
+ setDrawingAreaAvailable: function () {},
9553
+ ...options
9554
+ };
9555
+ const mouselayerZIndex = 2;
9556
+ this.mouselayer = Raphael$1(this.el, this.xpixels, this.ypixels);
9557
+ $__default["default"](this.mouselayer.canvas).css("z-index", mouselayerZIndex);
9558
+ if (localOptions.onClick || localOptions.onMouseDown || localOptions.onMouseMove || localOptions.onMouseOver || localOptions.onMouseOut) {
9559
+ const canvasClickTarget = this.mouselayer.rect(0, 0, this.xpixels, this.ypixels).attr({
9560
+ fill: "#000",
9561
+ opacity: 0
9562
+ });
9563
+ let isClickingCanvas = false;
9564
+ $__default["default"](this.mouselayer.canvas).on("vmousedown", e => {
9565
+ if (e.target === canvasClickTarget[0]) {
9566
+ if (localOptions.onMouseDown) {
9567
+ localOptions.onMouseDown(this.getMouseCoord(e));
9568
+ }
9569
+ isClickingCanvas = true;
9570
+ if (localOptions.onMouseMove) {
9571
+ const handler = localOptions.onMouseMove;
9572
+ $__default["default"](document).bind("vmousemove.mouseLayer", e => {
9573
+ if (isClickingCanvas) {
9574
+ e.preventDefault();
9575
+ handler(this.getMouseCoord(e));
9576
+ }
9577
+ });
9578
+ }
9579
+ $__default["default"](document).bind("vmouseup.mouseLayer", e => {
9580
+ $__default["default"](document).unbind(".mouseLayer");
9581
+
9582
+ // Only register clicks that started on the canvas,
9583
+ // and not on another mouseLayer target
9584
+ if (isClickingCanvas && localOptions.onClick) {
9585
+ localOptions.onClick(this.getMouseCoord(e));
9586
+ }
9587
+ isClickingCanvas = false;
9588
+ });
9589
+ }
9590
+ });
9591
+ if (localOptions.onMouseOver) {
9592
+ const handler = localOptions.onMouseOver;
9593
+ $__default["default"](this.mouselayer.canvas).on("vmouseover", e => {
9594
+ handler(this.getMouseCoord(e));
9595
+ });
9596
+ }
9597
+ if (localOptions.onMouseOut) {
9598
+ const handler = localOptions.onMouseOut;
9599
+ $__default["default"](this.mouselayer.canvas).on("vmouseout", e => {
9600
+ handler(this.getMouseCoord(e));
9601
+ });
9602
+ }
9603
+ }
9604
+ if (!localOptions.allowScratchpad) {
9605
+ localOptions.setDrawingAreaAvailable?.(false);
9606
+ }
9607
+
9608
+ // Add mouse and visible wrapper layers for DOM-node-wrapped movables
9609
+ this._mouselayerWrapper = document.createElement("div");
9610
+ $__default["default"](this._mouselayerWrapper).css({
9611
+ position: "absolute",
9612
+ left: 0,
9613
+ top: 0,
9614
+ zIndex: mouselayerZIndex
9615
+ });
9616
+ this._visiblelayerWrapper = document.createElement("div");
9617
+ $__default["default"](this._visiblelayerWrapper).css({
9618
+ position: "absolute",
9619
+ left: 0,
9620
+ top: 0
9621
+ });
9622
+ const el = this.el;
9623
+ el.appendChild(this._visiblelayerWrapper);
9624
+ el.appendChild(this._mouselayerWrapper);
9625
+
9626
+ // Add functions for adding to wrappers
9627
+ this.addToMouseLayerWrapper = el => {
9628
+ this._mouselayerWrapper?.appendChild(el);
9629
+ };
9630
+ this.addToVisibleLayerWrapper = el => {
9631
+ this._visiblelayerWrapper?.appendChild(el);
9632
+ };
9633
+ }
9634
+ addToMouseLayerWrapper(el) {
9635
+ throw new Error("addToMouseLayerWrapper is not ready. Call addMouseLayer() first.");
9636
+ }
9637
+ addToVisibleLayerWrapper(el) {
9638
+ throw new Error("addToVisibleLayerWrapper is not ready. Call addMouseLayer() first.");
9639
+ }
9640
+ /**
9641
+ * Get mouse coordinates in pixels
9642
+ */
9643
+ getMousePx(event) {
9644
+ const offset = $__default["default"](this.el).offset();
9645
+ const mouseX =
9646
+ // @ts-expect-error - TS18048 - 'event.pageX' is possibly 'undefined'.
9647
+ event.pageX -
9648
+ // @ts-expect-error - TS2532 - Object is possibly 'undefined'.
9649
+ offset.left;
9650
+ const mouseY =
9651
+ // @ts-expect-error - TS18048 - 'event.pageY' is possibly 'undefined'.
9652
+ event.pageY -
9653
+ // @ts-expect-error - TS2532 - Object is possibly 'undefined'.
9654
+ offset.top;
9655
+ return [mouseX, mouseY];
9543
9656
  }
9544
9657
 
9545
- // This is a stub that's overridden in interactive.ts
9546
- addMouseLayer(options) {}
9658
+ /**
9659
+ * Get mouse coordinates in graph coordinates
9660
+ */
9661
+ getMouseCoord(event) {
9662
+ return this.unscalePoint(this.getMousePx(event));
9663
+ }
9547
9664
  }
9548
9665
  const labelDirections = {
9549
9666
  center: [-0.5, -0.5],
@@ -10095,89 +10212,45 @@ const GraphUtils = {
10095
10212
  }
10096
10213
  })($__default["default"], window, document);
10097
10214
 
10098
- /**
10099
- * A work-in-progress of _ methods for objects.
10100
- * That is, they take an object as a parameter,
10101
- * and return an object instead of an array.
10102
- *
10103
- * TODO(aria): Move this out of interactive2
10104
- */
10105
-
10106
- /**
10107
- * Does a pluck on keys inside objects in an object
10108
- *
10109
- * Ex:
10110
- * tools = {
10111
- * translation: {
10112
- * enabled: true
10113
- * },
10114
- * rotation: {
10115
- * enabled: false
10116
- * }
10117
- * };
10118
- * pluckObject(tools, "enabled") returns {
10119
- * translation: true
10120
- * rotation: false
10121
- * }
10122
- */
10123
- const pluck = function (table, subKey) {
10124
- return ___default["default"].object(___default["default"].map(table, function (value, key) {
10125
- return [key, value[subKey]];
10126
- }));
10127
- };
10128
-
10129
- /**
10130
- * Maps an object to an object
10131
- *
10132
- * > mapObject({a: '1', b: '2'}, (value, key) => {
10133
- * return value + 1;
10134
- * });
10135
- * {a: 2, b: 3}
10136
- */
10137
- const mapObject$2 = function (obj, lambda) {
10138
- const result = {};
10139
- ___default["default"].each(___default["default"].keys(obj), function (key) {
10140
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'K'.
10141
- result[key] = lambda(obj[key], key);
10142
- });
10143
- return result;
10144
- };
10215
+ // Given `coord` and `angle`, find the point where a line extended
10216
+ // from `coord` in the direction of `angle` would be clipped by the
10217
+ // edge of the graphie canvas.
10218
+ const getClipPoint = function (graph, coord, angle) {
10219
+ // Actually put the arrowheads 4px from the edge so they have
10220
+ // a bit of room
10221
+ const xExtent = graph.range[0][1] - graph.range[0][0];
10222
+ const yExtent = graph.range[1][1] - graph.range[1][0];
10145
10223
 
10146
- /**
10147
- * Maps an array to an object
10148
- *
10149
- * > mapObjectFromArray(['a', 'b'], function(elem) {
10150
- * return elem + elem;
10151
- * });
10152
- * {a: 'aa', b: 'bb'}
10153
- */
10154
- const mapObjectFromArray$1 = function (arr, lambda) {
10155
- const result = {};
10156
- ___default["default"].each(arr, function (elem) {
10157
- result[elem] = lambda(elem);
10158
- });
10159
- return result;
10160
- };
10161
- var objective_ = {
10162
- pluck: pluck,
10163
- mapObject: mapObject$2,
10164
- mapObjectFromArray: mapObjectFromArray$1
10224
+ // shoot a point off into the distance ...
10225
+ const distance = xExtent + yExtent;
10226
+ // we need to scale the point according to the scale of the axes
10227
+ const angleVec = graph.unscaleVector(kmath.vector.cartFromPolarDeg(1, angle));
10228
+ const distVec = kmath.vector.scale(kmath.vector.normalize(angleVec), distance);
10229
+ const farCoord = kmath.vector.add(coord, distVec);
10230
+ const scaledAngle = kmath.vector.polarDegFromCart(angleVec)[1];
10231
+ // ... and then bring it back
10232
+ const clipPoint = graph.constrainToBoundsOnAngle(farCoord, 4, scaledAngle * Math.PI / 180);
10233
+ return clipPoint;
10165
10234
  };
10166
10235
 
10167
10236
  /* eslint-disable @babel/no-invalid-this */
10168
10237
 
10169
10238
  /*
10170
- * These functions, when called on the wrapped object, simply pass the
10239
+ * attr() and animate() simply pass the
10171
10240
  * arguments to the underlying Raphael object.
10172
10241
  */
10173
- const PASS_TO_RAPHAEL = ["attr", "animate"];
10174
- const WrappedDefaults = ___default["default"].extend({
10175
- transform: function (transformation) {
10242
+
10243
+ class WrappedDrawing {
10244
+ constructor(graphie, initialPoint) {
10245
+ this.graphie = graphie;
10246
+ this.initialPoint = initialPoint;
10247
+ }
10248
+ transform(transformation) {
10176
10249
  const prefixedTransform = InteractiveUtil.getPrefixedTransform();
10177
10250
  // @ts-expect-error - TS2538 - Type 'null' cannot be used as an index type. | TS2538 - Type 'undefined' cannot be used as an index type.
10178
10251
  this.wrapper.style[prefixedTransform] = transformation;
10179
- },
10180
- toFront: function () {
10252
+ }
10253
+ toFront() {
10181
10254
  const parentNode = this.wrapper.parentNode;
10182
10255
  // TODO(emily): Sometimes, we call `.remove()` but then hold a
10183
10256
  // reference to this object, and sometimes call `.toFront` on it.
@@ -10186,152 +10259,205 @@ const WrappedDefaults = ___default["default"].extend({
10186
10259
  if (parentNode) {
10187
10260
  parentNode.appendChild(this.wrapper);
10188
10261
  }
10189
- },
10190
- toBack: function () {
10262
+ }
10263
+ toBack() {
10191
10264
  const parentNode = this.wrapper.parentNode;
10192
- if (parentNode.firstChild !== this.wrapper) {
10265
+ if (parentNode != null && parentNode.firstChild !== this.wrapper) {
10193
10266
  parentNode.insertBefore(this.wrapper, parentNode.firstChild);
10194
10267
  }
10195
- },
10196
- remove: function () {
10268
+ }
10269
+ remove() {
10197
10270
  this.visibleShape.remove();
10198
10271
  $__default["default"](this.wrapper).remove();
10199
- },
10200
- getMouseTarget: function () {
10272
+ }
10273
+ getMouseTarget() {
10201
10274
  return this.visibleShape[0];
10202
- },
10203
- moveTo: function (point) {
10275
+ }
10276
+ moveTo(point) {
10204
10277
  const delta = kmath.vector.subtract(this.graphie.scalePoint(point), this.graphie.scalePoint(this.initialPoint));
10205
10278
  const do3dTransform = InteractiveUtil.getCanUse3dTransform();
10206
10279
  const transformation = "translateX(" + delta[0] + "px) " + "translateY(" + delta[1] + "px)" + (do3dTransform ? " translateZ(0)" : "");
10207
10280
  this.transform(transformation);
10208
- },
10209
- hide: function () {
10281
+ }
10282
+ hide() {
10210
10283
  this.visibleShape.hide();
10211
- },
10212
- show: function () {
10284
+ }
10285
+ show() {
10213
10286
  this.visibleShape.show();
10214
10287
  }
10215
- }, objective_.mapObjectFromArray(PASS_TO_RAPHAEL, function (attribute) {
10216
- return function () {
10217
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10218
- this.visibleShape[attribute](...arguments);
10219
- };
10220
- }));
10288
+ attr() {
10289
+ this.visibleShape.attr(...arguments);
10290
+ }
10291
+ animate() {
10292
+ this.visibleShape.animate(...arguments);
10293
+ }
10294
+ }
10221
10295
 
10222
10296
  const DEFAULT_OPTIONS$2 = {
10223
- maxScale: 1,
10224
- mouselayer: false,
10225
- shadow: false,
10226
- disableMouseEventsOnWrapper: false
10297
+ center: null,
10298
+ // gets ignored in `graphie.fixedPath` if `null`
10299
+ createPath: null,
10300
+ // gets defaulted in `graphie.fixedPath` if `null`
10301
+ mouselayer: false
10227
10302
  };
10228
- const WrappedEllipse = function (graphie, center, radii, options) {
10229
- options = ___default["default"].extend({}, DEFAULT_OPTIONS$2, options);
10230
-
10231
- // Add `wrapper`, `visibleShape`, and remaining properties.
10232
- const fixedEllipse = graphie.fixedEllipse(center, radii, options.maxScale, options.padding);
10233
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10234
- ___default["default"].extend(this, fixedEllipse, {
10235
- graphie: graphie,
10236
- initialPoint: center
10237
- });
10238
- if (options.interactiveKindForTesting) {
10239
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10240
- this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10303
+ class WrappedPath extends WrappedDrawing {
10304
+ constructor(graphie, points, options) {
10305
+ const initialPoint = graphie.scalePoint(___default["default"].head(points));
10306
+ super(graphie, initialPoint);
10307
+ options = ___default["default"].extend({}, DEFAULT_OPTIONS$2, options);
10308
+ const fixedPath = graphie.fixedPath(points, options.center, options.createPath);
10309
+ this.wrapper = fixedPath.wrapper;
10310
+ this.visibleShape = fixedPath.visibleShape;
10311
+
10312
+ // Add to appropriate graphie layer
10313
+ if (options.mouselayer) {
10314
+ // Disable browser handling of all panning and zooming gestures on the
10315
+ // movable wrapper so that when moved the browser does not scroll page
10316
+ this.wrapper.style.touchAction = "none";
10317
+ this.graphie.addToMouseLayerWrapper(this.wrapper);
10318
+ } else {
10319
+ this.graphie.addToVisibleLayerWrapper(this.wrapper);
10320
+ }
10241
10321
  }
10322
+ }
10242
10323
 
10243
- // Add to appropriate graphie layer
10244
- if (options.mouselayer) {
10245
- // Disable browser handling of all panning and zooming gestures on the
10246
- // movable wrapper so that when moved the browser does not scroll page
10247
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10248
- this.wrapper.style.touchAction = "none";
10249
-
10250
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10251
- this.graphie.addToMouseLayerWrapper(this.wrapper);
10252
- } else {
10253
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10254
- this.graphie.addToVisibleLayerWrapper(this.wrapper);
10324
+ class Arrowhead extends WrappedPath {
10325
+ static scale = 1.4;
10326
+ constructor(graphie, style) {
10327
+ // Points that define the arrowhead
10328
+ const center = [0.75, 0];
10329
+ const points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]].map(point => {
10330
+ // Scale points by `Arrowhead.scale` around `center`
10331
+ const pv = kmath.vector.subtract(point, center);
10332
+ const pvScaled = kmath.vector.scale(pv, Arrowhead.scale);
10333
+ return kmath.vector.add(center, pvScaled);
10334
+ });
10335
+ const unscaledPoints = points.map(graphie.unscalePoint);
10336
+ super(graphie, unscaledPoints, {
10337
+ center: graphie.unscalePoint(center),
10338
+ createPath: createCubicPath
10339
+ });
10340
+ this.center = center;
10341
+ this.attr(___default["default"].extend({
10342
+ "stroke-linejoin": "round",
10343
+ "stroke-linecap": "round",
10344
+ "stroke-dasharray": ""
10345
+ }, style));
10255
10346
  }
10256
- if (options.shadow) {
10257
- const filter = "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
10258
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10259
- const wrapper = this.wrapper;
10260
- wrapper.style.filter = filter;
10261
-
10262
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10263
- this.moveTo = function (point) {
10264
- const delta = kmath.vector.subtract(this.graphie.scalePoint(point), this.graphie.scalePoint(this.initialPoint));
10265
- const do3dTransform = InteractiveUtil.getCanUse3dTransform();
10266
- const transform = "translateX(" + Math.round(delta[0]) + "px) " + "translateY(" + Math.round(delta[1]) + "px)" + (do3dTransform ? " translateZ(0)" : "");
10267
- this.transform(transform);
10268
- };
10347
+ toCoordAtAngle(coord, angle) {
10348
+ const clipPoint = this.graphie.scalePoint(getClipPoint(this.graphie, coord, angle));
10349
+ this.transform("translateX(" + (clipPoint[0] + Arrowhead.scale * this.center[0]) + "px) " + "translateY(" + (clipPoint[1] + Arrowhead.scale * this.center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
10269
10350
  }
10270
- if (options.disableMouseEventsOnWrapper) {
10271
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10272
- this.wrapper.style.pointerEvents = "none";
10273
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10274
- this.visibleShape.node.style.pointerEvents = "auto";
10351
+ }
10352
+
10353
+ // We can't just pass in a path to `graph.fixedPath` as we need to modify
10354
+ // the points in some way, so instead we provide a function for creating
10355
+ // the path once the points have been transformed
10356
+ const createCubicPath = function (points) {
10357
+ let path = "M" + points[0][0] + " " + points[0][1];
10358
+ for (let i = 1; i < points.length; i += 3) {
10359
+ path += "C" + points[i][0] + " " + points[i][1] + " " + points[i + 1][0] + " " + points[i + 1][1] + " " + points[i + 2][0] + " " + points[i + 2][1];
10275
10360
  }
10361
+ return path;
10276
10362
  };
10277
- ___default["default"].extend(WrappedEllipse.prototype, WrappedDefaults);
10278
10363
 
10279
10364
  const DEFAULT_OPTIONS$1 = {
10280
- thickness: 2,
10281
- mouselayer: false
10365
+ maxScale: 1,
10366
+ mouselayer: false,
10367
+ shadow: false,
10368
+ disableMouseEventsOnWrapper: false
10282
10369
  };
10283
- const WrappedLine = function (graphie, start, end, options) {
10284
- options = ___default["default"].extend({}, DEFAULT_OPTIONS$1, options);
10370
+ class WrappedEllipse extends WrappedDrawing {
10371
+ constructor(graphie, center, radii, options) {
10372
+ super(graphie, center);
10373
+ options = ___default["default"].extend({}, DEFAULT_OPTIONS$1, options);
10285
10374
 
10286
- // Always make the line as large as possible and horizontal; this
10287
- // simplifies a lot of the transforms, e.g., we can rotate by exactly the
10288
- // angle of the argument points in `moveTo`.
10289
- const initialStart = [graphie.range[0][0], 0];
10290
- const initialEnd = [graphie.range[0][1], 0];
10375
+ // Add `wrapper`, `visibleShape`, and remaining properties.
10376
+ const fixedEllipse = graphie.fixedEllipse(center, radii, options.maxScale, options.padding);
10377
+ this.visibleShape = fixedEllipse.visibleShape;
10378
+ this.wrapper = fixedEllipse.wrapper;
10379
+ this.graphie = graphie;
10380
+ this.initialPoint = center;
10381
+ if (options.interactiveKindForTesting) {
10382
+ this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10383
+ }
10291
10384
 
10292
- // Add `wrapper` and `visibleShape`
10293
- ___default["default"].extend(
10294
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10295
- this, graphie.fixedLine(initialStart, initialEnd, options.thickness));
10296
- if (options.interactiveKindForTesting) {
10297
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10298
- this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10385
+ // Add to appropriate graphie layer
10386
+ if (options.mouselayer) {
10387
+ // Disable browser handling of all panning and zooming gestures on the
10388
+ // movable wrapper so that when moved the browser does not scroll page
10389
+ this.wrapper.style.touchAction = "none";
10390
+ this.graphie.addToMouseLayerWrapper(this.wrapper);
10391
+ } else {
10392
+ this.graphie.addToVisibleLayerWrapper(this.wrapper);
10393
+ }
10394
+ if (options.shadow) {
10395
+ const filter = "drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.5))";
10396
+ const wrapper = this.wrapper;
10397
+ wrapper.style.filter = filter;
10398
+ this.moveTo = function (point) {
10399
+ const delta = kmath.vector.subtract(this.graphie.scalePoint(point), this.graphie.scalePoint(this.initialPoint));
10400
+ const do3dTransform = InteractiveUtil.getCanUse3dTransform();
10401
+ const transform = "translateX(" + Math.round(delta[0]) + "px) " + "translateY(" + Math.round(delta[1]) + "px)" + (do3dTransform ? " translateZ(0)" : "");
10402
+ this.transform(transform);
10403
+ };
10404
+ }
10405
+ if (options.disableMouseEventsOnWrapper) {
10406
+ this.wrapper.style.pointerEvents = "none";
10407
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10408
+ this.visibleShape.node.style.pointerEvents = "auto";
10409
+ }
10299
10410
  }
10411
+ }
10300
10412
 
10301
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10302
- this.visibleShape.attr(options.normalStyle);
10303
-
10304
- // Save properties for computing transformations
10305
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10306
- ___default["default"].extend(this, {
10307
- graphie: graphie,
10308
- initialPoint: graphie.scalePoint(initialStart),
10309
- initialLength: kmath.point.distanceToPoint(graphie.scalePoint(initialStart), graphie.scalePoint(initialEnd))
10310
- });
10311
-
10312
- // Add to appropriate graphie layer
10313
- if (options.mouselayer) {
10314
- // Disable browser handling of all panning and zooming gestures on the
10315
- // movable wrapper so that when moved the browser does not scroll page
10316
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10317
- this.wrapper.style.touchAction = "none";
10413
+ const DEFAULT_OPTIONS = {
10414
+ thickness: 2,
10415
+ mouselayer: false
10416
+ };
10417
+ class WrappedLine extends WrappedDrawing {
10418
+ constructor(graphie, start, end, options) {
10419
+ // Always make the line as large as possible and horizontal; this
10420
+ // simplifies a lot of the transforms, e.g., we can rotate by exactly the
10421
+ // angle of the argument points in `moveTo`.
10422
+ const initialStart = [graphie.range[0][0], 0];
10423
+ const initialEnd = [graphie.range[0][1], 0];
10424
+ const initialPoint = graphie.scalePoint(initialStart);
10425
+ super(graphie, initialPoint);
10426
+ options = ___default["default"].extend({}, DEFAULT_OPTIONS, options);
10427
+ const fixedLine = graphie.fixedLine(initialStart, initialEnd, options.thickness);
10428
+ this.wrapper = fixedLine.wrapper;
10429
+ this.visibleShape = fixedLine.visibleShape;
10430
+ if (options.interactiveKindForTesting) {
10431
+ this.wrapper.setAttribute("data-interactive-kind-for-testing", options.interactiveKindForTesting);
10432
+ }
10433
+ this.visibleShape.attr(options.normalStyle);
10434
+
10435
+ // Save properties for computing transformations
10436
+ this.initialPoint = initialPoint;
10437
+ this.initialLength = kmath.point.distanceToPoint(graphie.scalePoint(initialStart), graphie.scalePoint(initialEnd));
10438
+
10439
+ // Add to appropriate graphie layer
10440
+ if (options.mouselayer) {
10441
+ // Disable browser handling of all panning and zooming gestures on the
10442
+ // movable wrapper so that when moved the browser does not scroll page
10443
+ this.wrapper.style.touchAction = "none";
10444
+ this.graphie.addToMouseLayerWrapper(this.wrapper);
10445
+ } else {
10446
+ this.graphie.addToVisibleLayerWrapper(this.wrapper);
10447
+ }
10318
10448
 
10319
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10320
- this.graphie.addToMouseLayerWrapper(this.wrapper);
10321
- } else {
10322
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10323
- this.graphie.addToVisibleLayerWrapper(this.wrapper);
10449
+ // Move line to initial points
10450
+ this.moveTo(start, end);
10324
10451
  }
10325
-
10326
- // Move to argument points
10327
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10328
- this.moveTo(start, end);
10329
- };
10330
- ___default["default"].extend(WrappedLine.prototype, WrappedDefaults, {
10331
- getMouseTarget: function () {
10452
+ getMouseTarget() {
10332
10453
  return this.wrapper;
10333
- },
10334
- moveTo: function (start, end) {
10454
+ }
10455
+
10456
+ // TODO(benchristel): we need to suppress a type error here because moveTo
10457
+ // takes 2 parameters here, but only 1 parameter in the superclass's
10458
+ // definition. Rename this method after confirming it's safe to do so
10459
+ // @ts-expect-error - TS2416: Property 'moveTo' in type 'WrappedLine' is not assignable to the same property in base type 'WrappedDefaults'.
10460
+ moveTo(start, end) {
10335
10461
  const scaledStart = this.graphie.scalePoint(start);
10336
10462
  const scaledEnd = this.graphie.scalePoint(end);
10337
10463
 
@@ -10347,45 +10473,7 @@ ___default["default"].extend(WrappedLine.prototype, WrappedDefaults, {
10347
10473
  const transformation = "translateX(" + delta[0] + "px) " + "translateY(" + delta[1] + "px) " + (do3dTransform ? " translateZ(0)" : "") + "rotate(" + angle + "deg) " + "scaleX(" + scale + ") scaleY(1)";
10348
10474
  this.transform(transformation);
10349
10475
  }
10350
- });
10351
-
10352
- const DEFAULT_OPTIONS = {
10353
- center: null,
10354
- // gets ignored in `graphie.fixedPath` if `null`
10355
- createPath: null,
10356
- // gets defaulted in `graphie.fixedPath` if `null`
10357
- mouselayer: false
10358
- };
10359
- const WrappedPath = function (graphie, points, options) {
10360
- options = ___default["default"].extend({}, DEFAULT_OPTIONS, options);
10361
-
10362
- // Add `wrapper` and `visibleShape`
10363
- ___default["default"].extend(
10364
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10365
- this, graphie.fixedPath(points, options.center, options.createPath));
10366
-
10367
- // Add remaining properties
10368
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10369
- ___default["default"].extend(this, {
10370
- graphie: graphie,
10371
- initialPoint: graphie.scalePoint(___default["default"].head(points))
10372
- });
10373
-
10374
- // Add to appropriate graphie layer
10375
- if (options.mouselayer) {
10376
- // Disable browser handling of all panning and zooming gestures on the
10377
- // movable wrapper so that when moved the browser does not scroll page
10378
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10379
- this.wrapper.style.touchAction = "none";
10380
-
10381
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10382
- this.graphie.addToMouseLayerWrapper(this.wrapper);
10383
- } else {
10384
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
10385
- this.graphie.addToVisibleLayerWrapper(this.wrapper);
10386
- }
10387
- };
10388
- ___default["default"].extend(WrappedPath.prototype, WrappedDefaults);
10476
+ }
10389
10477
 
10390
10478
  /**
10391
10479
  * A collection of geomtry-related utility functions
@@ -10611,9 +10699,6 @@ firstPoints, secondPoints) {
10611
10699
  }
10612
10700
 
10613
10701
  /* eslint-disable @babel/no-invalid-this */
10614
- const {
10615
- getCanUse3dTransform
10616
- } = InteractiveUtil;
10617
10702
  function scaledDistanceFromAngle(angle) {
10618
10703
  const a = 3.51470560176242 * 20;
10619
10704
  const b = 0.5687298702748785 * 20;
@@ -10644,114 +10729,6 @@ const InteractiveUtils = {
10644
10729
  }
10645
10730
  };
10646
10731
  ___default["default"].extend(GraphUtils.Graphie.prototype, {
10647
- // graphie puts text spans on top of the SVG, which looks good, but gets
10648
- // in the way of mouse events. This adds another SVG element on top
10649
- // of everything else where we can add invisible shapes with mouse
10650
- // handlers wherever we want.
10651
- addMouseLayer: function (options) {
10652
- const graph = this;
10653
- options = ___default["default"].extend({
10654
- allowScratchpad: false,
10655
- setDrawingAreaAvailable: function () {}
10656
- }, options);
10657
- const mouselayerZIndex = 2;
10658
- graph.mouselayer = Raphael$1(graph.raphael.canvas.parentNode, graph.xpixels, graph.ypixels);
10659
- $__default["default"](graph.mouselayer.canvas).css("z-index", mouselayerZIndex);
10660
- if (options.onClick || options.onMouseDown || options.onMouseMove || options.onMouseOver || options.onMouseOut) {
10661
- const canvasClickTarget = graph.mouselayer.rect(0, 0, graph.xpixels, graph.ypixels).attr({
10662
- fill: "#000",
10663
- opacity: 0
10664
- });
10665
- let isClickingCanvas = false;
10666
- $__default["default"](graph.mouselayer.canvas).on("vmousedown", function (e) {
10667
- if (e.target === canvasClickTarget[0]) {
10668
- if (options.onMouseDown) {
10669
- options.onMouseDown(graph.getMouseCoord(e));
10670
- }
10671
- isClickingCanvas = true;
10672
- if (options.onMouseMove) {
10673
- const handler = options.onMouseMove;
10674
- $__default["default"](document).bind("vmousemove.mouseLayer", function (e) {
10675
- if (isClickingCanvas) {
10676
- e.preventDefault();
10677
- handler(graph.getMouseCoord(e));
10678
- }
10679
- });
10680
- }
10681
- $__default["default"](document).bind("vmouseup.mouseLayer", function (e) {
10682
- $__default["default"](document).unbind(".mouseLayer");
10683
-
10684
- // Only register clicks that started on the canvas,
10685
- // and not on another mouseLayer target
10686
- if (isClickingCanvas && options.onClick) {
10687
- options.onClick(graph.getMouseCoord(e));
10688
- }
10689
- isClickingCanvas = false;
10690
- });
10691
- }
10692
- });
10693
- if (options.onMouseOver) {
10694
- const handler = options.onMouseOver;
10695
- $__default["default"](graph.mouselayer.canvas).on("vmouseover", function (e) {
10696
- handler(graph.getMouseCoord(e));
10697
- });
10698
- }
10699
- if (options.onMouseOut) {
10700
- const handler = options.onMouseOut;
10701
- $__default["default"](graph.mouselayer.canvas).on("vmouseout", function (e) {
10702
- handler(graph.getMouseCoord(e));
10703
- });
10704
- }
10705
- }
10706
- if (!options.allowScratchpad) {
10707
- options.setDrawingAreaAvailable?.(false);
10708
- }
10709
-
10710
- // Add mouse and visible wrapper layers for DOM-node-wrapped movables
10711
- graph._mouselayerWrapper = document.createElement("div");
10712
- $__default["default"](graph._mouselayerWrapper).css({
10713
- position: "absolute",
10714
- left: 0,
10715
- top: 0,
10716
- zIndex: mouselayerZIndex
10717
- });
10718
- graph._visiblelayerWrapper = document.createElement("div");
10719
- $__default["default"](graph._visiblelayerWrapper).css({
10720
- position: "absolute",
10721
- left: 0,
10722
- top: 0
10723
- });
10724
- const el = graph.raphael.canvas.parentNode;
10725
- el.appendChild(graph._visiblelayerWrapper);
10726
- el.appendChild(graph._mouselayerWrapper);
10727
-
10728
- // Add functions for adding to wrappers
10729
- graph.addToMouseLayerWrapper = function (el) {
10730
- this._mouselayerWrapper.appendChild(el);
10731
- };
10732
- graph.addToVisibleLayerWrapper = function (el) {
10733
- this._visiblelayerWrapper.appendChild(el);
10734
- };
10735
- },
10736
- /**
10737
- * Get mouse coordinates in pixels
10738
- */
10739
- getMousePx: function (event) {
10740
- const graphie = this;
10741
- const mouseX =
10742
- // @ts-expect-error - TS2532 - Object is possibly 'undefined'.
10743
- event.pageX - $__default["default"](graphie.raphael.canvas.parentNode).offset().left;
10744
- const mouseY =
10745
- // @ts-expect-error - TS2532 - Object is possibly 'undefined'.
10746
- event.pageY - $__default["default"](graphie.raphael.canvas.parentNode).offset().top;
10747
- return [mouseX, mouseY];
10748
- },
10749
- /**
10750
- * Get mouse coordinates in graph coordinates
10751
- */
10752
- getMouseCoord: function (event) {
10753
- return this.unscalePoint(this.getMousePx(event));
10754
- },
10755
10732
  /**
10756
10733
  * Unlike all other Graphie-related code, the following three functions use
10757
10734
  * a lot of scaled coordinates (so that labels appear the same size
@@ -11605,52 +11582,15 @@ ___default["default"].extend(GraphUtils.Graphie.prototype, {
11605
11582
  ___default["default"].each(elements, function (element) {
11606
11583
  element.moveTo(start, end);
11607
11584
  });
11608
- const createArrow = function (graph, style) {
11609
- const center = [0.75, 0];
11610
- let points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]];
11611
- const scale = 1.4;
11612
- points = ___default["default"].map(points, function (point) {
11613
- const pv = kmath.vector.subtract(point, center);
11614
- const pvScaled = kmath.vector.scale(pv, scale);
11615
- return kmath.vector.add(center, pvScaled);
11616
- });
11617
- const createCubicPath = function (points) {
11618
- let path = "M" + points[0][0] + " " + points[0][1];
11619
- for (let i = 1; i < points.length; i += 3) {
11620
- path += "C" + points[i][0] + " " + points[i][1] + " " + points[i + 1][0] + " " + points[i + 1][1] + " " + points[i + 2][0] + " " + points[i + 2][1];
11621
- }
11622
- return path;
11623
- };
11624
- const unscaledPoints = ___default["default"].map(points, graph.unscalePoint);
11625
- const options = {
11626
- center: graph.unscalePoint(center),
11627
- createPath: createCubicPath
11628
- };
11629
- const arrowHead = new WrappedPath(graph, unscaledPoints, options);
11630
- arrowHead.attr(___default["default"].extend({
11631
- "stroke-linejoin": "round",
11632
- "stroke-linecap": "round",
11633
- "stroke-dasharray": ""
11634
- }, style));
11635
-
11636
- // Add custom function for transforming arrowheads that
11637
- // accounts for center, scaling, etc.
11638
- arrowHead.toCoordAtAngle = function (coord, angle) {
11639
- const clipPoint = graph.scalePoint(getClipPoint(graph, coord, angle));
11640
- const do3dTransform = getCanUse3dTransform();
11641
- arrowHead.transform("translateX(" + (clipPoint[0] + scale * center[0]) + "px) " + "translateY(" + (clipPoint[1] + scale * center[1]) + "px) " + (do3dTransform ? "translateZ(0) " : "") + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
11642
- };
11643
- return arrowHead;
11644
- };
11645
11585
 
11646
11586
  // Add arrows
11647
11587
  if (this._arrows == null) {
11648
11588
  this._arrows = [];
11649
11589
  if (this.extendLine) {
11650
- this._arrows.push(createArrow(graph, this.normalStyle));
11651
- this._arrows.push(createArrow(graph, this.normalStyle));
11590
+ this._arrows.push(new Arrowhead(graph, this.normalStyle));
11591
+ this._arrows.push(new Arrowhead(graph, this.normalStyle));
11652
11592
  } else if (this.extendRay) {
11653
- this._arrows.push(createArrow(graph, this.normalStyle));
11593
+ this._arrows.push(new Arrowhead(graph, this.normalStyle));
11654
11594
  }
11655
11595
  }
11656
11596
  const coordForArrow = [this.coordA, this.coordZ];
@@ -14091,78 +14031,6 @@ const getScaledAngle = function (line) {
14091
14031
  return kmath.vector.polarDegFromCart(kmath.vector.subtract(scaledZ, scaledA))[1];
14092
14032
  };
14093
14033
 
14094
- // Given `coord` and `angle`, find the point where a line extended
14095
- // from `coord` in the direction of `angle` would be clipped by the
14096
- // edge of the graphie canvas. Then draw an arrowhead at that point
14097
- // pointing in the direction of `angle`.
14098
- const getClipPoint = function (graph, coord, angle) {
14099
- // Actually put the arrowheads 4px from the edge so they have
14100
- // a bit of room
14101
- const xExtent = graph.range[0][1] - graph.range[0][0];
14102
- const yExtent = graph.range[1][1] - graph.range[1][0];
14103
-
14104
- // shoot a point off into the distance ...
14105
- const distance = xExtent + yExtent;
14106
- // we need to scale the point according to the scale of the axes
14107
- const angleVec = graph.unscaleVector(kmath.vector.cartFromPolarDeg(1, angle));
14108
- const distVec = kmath.vector.scale(kmath.vector.normalize(angleVec), distance);
14109
- const farCoord = kmath.vector.add(coord, distVec);
14110
- const scaledAngle = kmath.vector.polarDegFromCart(angleVec)[1];
14111
- // ... and then bring it back
14112
- const clipPoint = graph.constrainToBoundsOnAngle(farCoord, 4, scaledAngle * Math.PI / 180);
14113
- return clipPoint;
14114
- };
14115
-
14116
- // Given `coord` and `angle`, find the point where a line extended
14117
- // from `coord` in the direction of `angle` would be clipped by the
14118
- // edge of the graphie canvas. Then draw an arrowhead at that point
14119
- // pointing in the direction of `angle`.
14120
- const createArrow = function (graph, style) {
14121
- // Points that define the arrowhead
14122
- const center = [0.75, 0];
14123
- let points = [[-3, 4], [-2.75, 2.5], [0, 0.25], center, [0, -0.25], [-2.75, -2.5], [-3, -4]];
14124
-
14125
- // Scale points by 1.4 around (0.75, 0)
14126
- const scale = 1.4;
14127
- points = ___default["default"].map(points, function (point) {
14128
- const pv = kmath.vector.subtract(point, center);
14129
- const pvScaled = kmath.vector.scale(pv, scale);
14130
- return kmath.vector.add(center, pvScaled);
14131
- });
14132
-
14133
- // We can't just pass in a path to `graph.fixedPath` as we need to modify
14134
- // the points in some way, so instead we provide a function for creating
14135
- // the path once the points have been transformed
14136
- const createCubicPath = function (points) {
14137
- let path = "M" + points[0][0] + " " + points[0][1];
14138
- for (let i = 1; i < points.length; i += 3) {
14139
- path += "C" + points[i][0] + " " + points[i][1] + " " + points[i + 1][0] + " " + points[i + 1][1] + " " + points[i + 2][0] + " " + points[i + 2][1];
14140
- }
14141
- return path;
14142
- };
14143
-
14144
- // Create arrowhead
14145
- const unscaledPoints = ___default["default"].map(points, graph.unscalePoint);
14146
- const options = {
14147
- center: graph.unscalePoint(center),
14148
- createPath: createCubicPath
14149
- };
14150
- const arrowHead = new WrappedPath(graph, unscaledPoints, options);
14151
- arrowHead.attr(___default["default"].extend({
14152
- "stroke-linejoin": "round",
14153
- "stroke-linecap": "round",
14154
- "stroke-dasharray": ""
14155
- }, style));
14156
-
14157
- // Add custom function for transforming arrowheads that accounts for
14158
- // center, scaling, etc.
14159
- arrowHead.toCoordAtAngle = function (coord, angle) {
14160
- const clipPoint = graph.scalePoint(getClipPoint(graph, coord, angle));
14161
- arrowHead.transform("translateX(" + (clipPoint[0] + scale * center[0]) + "px) " + "translateY(" + (clipPoint[1] + scale * center[1]) + "px) " + "translateZ(0) " + "rotate(" + (360 - KhanMath.bound(angle)) + "deg)");
14162
- };
14163
- return arrowHead;
14164
- };
14165
-
14166
14034
  /**
14167
14035
  * MovableLine option functions
14168
14036
  */
@@ -14249,16 +14117,16 @@ const draw$3 = {
14249
14117
  // @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
14250
14118
  this._arrows.push(
14251
14119
  // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
14252
- createArrow(this.graphie, this.normalStyle()));
14120
+ new Arrowhead(this.graphie, this.normalStyle()));
14253
14121
  // @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
14254
14122
  this._arrows.push(
14255
14123
  // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
14256
- createArrow(this.graphie, this.normalStyle()));
14124
+ new Arrowhead(this.graphie, this.normalStyle()));
14257
14125
  } else if (state.extendRay) {
14258
14126
  // @ts-expect-error - TS2551 - Property '_arrows' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. Did you mean 'arrows'?
14259
14127
  this._arrows.push(
14260
14128
  // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'. | TS2339 - Property 'normalStyle' does not exist on type '{ readonly basic: (state: any) => void; readonly arrows: (state: any) => void; readonly highlight: (state: any, prevState: any) => void; }'.
14261
- createArrow(this.graphie, this.normalStyle()));
14129
+ new Arrowhead(this.graphie, this.normalStyle()));
14262
14130
  }
14263
14131
  }
14264
14132
 
@@ -14404,6 +14272,75 @@ var MovableLineOptions = {
14404
14272
  }
14405
14273
  };
14406
14274
 
14275
+ /**
14276
+ * A work-in-progress of _ methods for objects.
14277
+ * That is, they take an object as a parameter,
14278
+ * and return an object instead of an array.
14279
+ *
14280
+ * TODO(aria): Move this out of interactive2
14281
+ */
14282
+
14283
+ /**
14284
+ * Does a pluck on keys inside objects in an object
14285
+ *
14286
+ * Ex:
14287
+ * tools = {
14288
+ * translation: {
14289
+ * enabled: true
14290
+ * },
14291
+ * rotation: {
14292
+ * enabled: false
14293
+ * }
14294
+ * };
14295
+ * pluckObject(tools, "enabled") returns {
14296
+ * translation: true
14297
+ * rotation: false
14298
+ * }
14299
+ */
14300
+ const pluck = function (table, subKey) {
14301
+ return ___default["default"].object(___default["default"].map(table, function (value, key) {
14302
+ return [key, value[subKey]];
14303
+ }));
14304
+ };
14305
+
14306
+ /**
14307
+ * Maps an object to an object
14308
+ *
14309
+ * > mapObject({a: '1', b: '2'}, (value, key) => {
14310
+ * return value + 1;
14311
+ * });
14312
+ * {a: 2, b: 3}
14313
+ */
14314
+ const mapObject$2 = function (obj, lambda) {
14315
+ const result = {};
14316
+ ___default["default"].each(___default["default"].keys(obj), function (key) {
14317
+ // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'K'.
14318
+ result[key] = lambda(obj[key], key);
14319
+ });
14320
+ return result;
14321
+ };
14322
+
14323
+ /**
14324
+ * Maps an array to an object
14325
+ *
14326
+ * > mapObjectFromArray(['a', 'b'], function(elem) {
14327
+ * return elem + elem;
14328
+ * });
14329
+ * {a: 'aa', b: 'bb'}
14330
+ */
14331
+ const mapObjectFromArray$1 = function (arr, lambda) {
14332
+ const result = {};
14333
+ ___default["default"].each(arr, function (elem) {
14334
+ result[elem] = lambda(elem);
14335
+ });
14336
+ return result;
14337
+ };
14338
+ var objective_ = {
14339
+ pluck: pluck,
14340
+ mapObject: mapObject$2,
14341
+ mapObjectFromArray: mapObjectFromArray$1
14342
+ };
14343
+
14407
14344
  /**
14408
14345
  * MovableLine
14409
14346
  */
@@ -17966,33 +17903,33 @@ class Lint extends React__namespace.Component {
17966
17903
  let warningText;
17967
17904
  let warningTextStyle;
17968
17905
  if (this.props.severity === Severity.Error) {
17969
- severityStyle = styles$A.indicatorError;
17906
+ severityStyle = styles$B.indicatorError;
17970
17907
  warningText = "Error";
17971
- warningTextStyle = styles$A.publishBlockingError;
17908
+ warningTextStyle = styles$B.publishBlockingError;
17972
17909
  } else if (this.props.severity === Severity.Warning) {
17973
- severityStyle = styles$A.indicatorWarning;
17910
+ severityStyle = styles$B.indicatorWarning;
17974
17911
  warningText = "Warning";
17975
- warningTextStyle = styles$A.warning;
17912
+ warningTextStyle = styles$B.warning;
17976
17913
  } else {
17977
- severityStyle = styles$A.indicatorGuideline;
17914
+ severityStyle = styles$B.indicatorGuideline;
17978
17915
  warningText = "Recommendation";
17979
- warningTextStyle = styles$A.warning;
17916
+ warningTextStyle = styles$B.warning;
17980
17917
  }
17981
17918
  return /*#__PURE__*/React__namespace.createElement("a", {
17982
17919
  href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
17983
17920
  target: "lint-help-window",
17984
17921
  className: aphrodite.css(style)
17985
17922
  }, /*#__PURE__*/React__namespace.createElement("span", {
17986
- className: aphrodite.css(styles$A.indicator, severityStyle)
17923
+ className: aphrodite.css(styles$B.indicator, severityStyle)
17987
17924
  }, this.props.severity === 1 && /*#__PURE__*/React__namespace.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React__namespace.createElement("div", {
17988
- className: aphrodite.css(styles$A.tooltip, tooltipAbove && styles$A.tooltipAbove)
17925
+ className: aphrodite.css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
17989
17926
  }, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React__namespace.createElement("p", {
17990
17927
  key: i,
17991
- className: aphrodite.css(styles$A.tooltipParagraph)
17928
+ className: aphrodite.css(styles$B.tooltipParagraph)
17992
17929
  }, /*#__PURE__*/React__namespace.createElement("span", {
17993
17930
  className: aphrodite.css(warningTextStyle)
17994
17931
  }, warningText, ":", " "), m)), /*#__PURE__*/React__namespace.createElement("div", {
17995
- className: aphrodite.css(styles$A.tail, tooltipAbove && styles$A.tailAbove)
17932
+ className: aphrodite.css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
17996
17933
  })));
17997
17934
  };
17998
17935
 
@@ -18020,20 +17957,20 @@ class Lint extends React__namespace.Component {
18020
17957
  }
18021
17958
  if (blockHighlight) {
18022
17959
  return /*#__PURE__*/React__namespace.createElement("span", {
18023
- className: aphrodite.css(styles$A.lintContainer, styles$A.lintContainerBlock)
18024
- }, this.renderLink(styles$A.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
17960
+ className: aphrodite.css(styles$B.lintContainer, styles$B.lintContainerBlock)
17961
+ }, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
18025
17962
  }
18026
17963
  if (inline) {
18027
17964
  return /*#__PURE__*/React__namespace.createElement("span", {
18028
- className: aphrodite.css(styles$A.lintContainer)
18029
- }, this.renderLink(styles$A.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
17965
+ className: aphrodite.css(styles$B.lintContainer)
17966
+ }, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
18030
17967
  }
18031
17968
  return /*#__PURE__*/React__namespace.createElement("div", {
18032
- className: aphrodite.css(styles$A.lintContainer)
18033
- }, this.renderLink(styles$A.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
17969
+ className: aphrodite.css(styles$B.lintContainer)
17970
+ }, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
18034
17971
  }
18035
17972
  }
18036
- const styles$A = aphrodite.StyleSheet.create({
17973
+ const styles$B = aphrodite.StyleSheet.create({
18037
17974
  // This is the class of the outermost element.
18038
17975
  // We use relative positioning so that the lint indicator can be
18039
17976
  // positioned absolutely relative to the position of the linty container.
@@ -20135,7 +20072,7 @@ class Renderer extends React__namespace.Component {
20135
20072
  };
20136
20073
  const mobileInnerStyle = {
20137
20074
  ...innerStyle,
20138
- ...styles$z.mobileZoomableParentFix
20075
+ ...styles$A.mobileZoomableParentFix
20139
20076
  };
20140
20077
  return /*#__PURE__*/React__namespace.createElement("div", {
20141
20078
  key: state.key,
@@ -20272,7 +20209,7 @@ class Renderer extends React__namespace.Component {
20272
20209
  };
20273
20210
  const mobileInnerStyle = {
20274
20211
  ...innerStyle,
20275
- ...styles$z.mobileZoomableParentFix
20212
+ ...styles$A.mobileZoomableParentFix
20276
20213
  };
20277
20214
  const wrappedOutput = /*#__PURE__*/React__namespace.createElement("div", {
20278
20215
  style: {
@@ -20780,7 +20717,7 @@ class Renderer extends React__namespace.Component {
20780
20717
  return this.lastRenderedMarkdown;
20781
20718
  }
20782
20719
  }
20783
- const styles$z = {
20720
+ const styles$A = {
20784
20721
  mobileZoomableParentFix: {
20785
20722
  // NOTE(abdul): There is an issue where transform animations will
20786
20723
  // cause the Zoomable component to disappear when running on the
@@ -21715,10 +21652,10 @@ class InputNumber extends React__namespace.Component {
21715
21652
  // Note: This is _very_ similar to what `numeric-input.jsx` does. If
21716
21653
  // you modify this, double-check if you also need to modify that
21717
21654
  // component.
21718
- const inputStyles = [styles$y.default, this.props.size === "small" ? styles$y.small : null, this.props.rightAlign ? styles$y.rightAlign : styles$y.leftAlign];
21655
+ const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
21719
21656
  // Unanswered
21720
21657
  if (rubric && !this.props.currentValue) {
21721
- inputStyles.push(styles$y.answerStateUnanswered);
21658
+ inputStyles.push(styles$z.answerStateUnanswered);
21722
21659
  }
21723
21660
  return /*#__PURE__*/React__namespace.createElement(InputWithExamples
21724
21661
  // eslint-disable-next-line react/no-string-refs
@@ -21866,7 +21803,7 @@ class InputNumber extends React__namespace.Component {
21866
21803
  return answerString;
21867
21804
  }
21868
21805
  }
21869
- const styles$y = aphrodite.StyleSheet.create({
21806
+ const styles$z = aphrodite.StyleSheet.create({
21870
21807
  default: {
21871
21808
  width: 80,
21872
21809
  height: "auto"
@@ -22864,7 +22801,7 @@ const FocusRing = function (props) {
22864
22801
  };
22865
22802
  return /*#__PURE__*/React__namespace.createElement("span", {
22866
22803
  "data-test-id": "focus-ring",
22867
- className: aphrodite.css(styles$x.ring),
22804
+ className: aphrodite.css(styles$y.ring),
22868
22805
  style: style
22869
22806
  }, children);
22870
22807
  };
@@ -22873,7 +22810,7 @@ FocusRing.defaultProps = {
22873
22810
  color: kaGreen$1,
22874
22811
  multipleSelect: false
22875
22812
  };
22876
- const styles$x = aphrodite.StyleSheet.create({
22813
+ const styles$y = aphrodite.StyleSheet.create({
22877
22814
  ring: {
22878
22815
  margin: "auto",
22879
22816
  display: "inline-block",
@@ -22910,7 +22847,7 @@ function getChoiceLetter(pos) {
22910
22847
  }
22911
22848
 
22912
22849
  const CHOICE_ICON_SIZE = 24;
22913
- const styles$w = aphrodite.StyleSheet.create({
22850
+ const styles$x = aphrodite.StyleSheet.create({
22914
22851
  iconWrapper: {
22915
22852
  display: "inline-block",
22916
22853
  position: "relative"
@@ -22933,7 +22870,7 @@ const CrossOutLine = function (props) {
22933
22870
  width: CROSS_OUT_LINE_SIZE,
22934
22871
  height: CROSS_OUT_LINE_SIZE,
22935
22872
  viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
22936
- className: aphrodite.css(styles$v.crossOutLine),
22873
+ className: aphrodite.css(styles$w.crossOutLine),
22937
22874
  "data-test-id": "choice-icon__cross-out-line"
22938
22875
  }, /*#__PURE__*/React__namespace.createElement("line", {
22939
22876
  // The line stretches from the bottom-left to top-right.
@@ -22948,7 +22885,7 @@ const CrossOutLine = function (props) {
22948
22885
  strokeLinecap: "round"
22949
22886
  }));
22950
22887
  };
22951
- const styles$v = aphrodite.StyleSheet.create({
22888
+ const styles$w = aphrodite.StyleSheet.create({
22952
22889
  crossOutLine: {
22953
22890
  // Center the icon within the container.
22954
22891
  position: "absolute",
@@ -23029,7 +22966,7 @@ const ChoiceIcon = function (props) {
23029
22966
  } = props;
23030
22967
  const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
23031
22968
  return /*#__PURE__*/React__namespace.createElement("div", {
23032
- className: aphrodite.css(styles$w.iconWrapper)
22969
+ className: aphrodite.css(styles$x.iconWrapper)
23033
22970
  }, /*#__PURE__*/React__namespace.createElement(FocusRing, {
23034
22971
  color: Color__default["default"].blue,
23035
22972
  visible: focused || hovered,
@@ -23038,13 +22975,13 @@ const ChoiceIcon = function (props) {
23038
22975
  // @ts-expect-error - TS2322 - Type '{ backgroundColor: string | null | undefined; borderColor: string; color: string; borderRadius: number; }' is not assignable to type 'Properties<string | number, string & {}>'.
23039
22976
  style: dynamicStyles,
23040
22977
  "data-test-id": "choice-icon__library-choice-icon",
23041
- className: aphrodite.css(styles$u.circle, showCorrectness && correct && styles$u.circleCorrect, showCorrectness && !correct && styles$u.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$u.circleIncorrectAnswered)
22978
+ className: aphrodite.css(styles$v.circle, showCorrectness && correct && styles$v.circleCorrect, showCorrectness && !correct && styles$v.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$v.circleIncorrectAnswered)
23042
22979
  // used in BaseRadio editMode to check
23043
22980
  // if we actually clicked on the radio icon
23044
22981
  ,
23045
22982
  "data-is-radio-icon": true
23046
22983
  }, /*#__PURE__*/React__namespace.createElement("div", {
23047
- className: aphrodite.css(styles$u.innerWrapper)
22984
+ className: aphrodite.css(styles$v.innerWrapper)
23048
22985
  }, /*#__PURE__*/React__namespace.createElement(ChoiceInner, {
23049
22986
  pos: pos,
23050
22987
  showCorrectness: showCorrectness,
@@ -23053,7 +22990,7 @@ const ChoiceIcon = function (props) {
23053
22990
  color: dynamicStyles.borderColor
23054
22991
  }));
23055
22992
  };
23056
- const styles$u = aphrodite.StyleSheet.create({
22993
+ const styles$v = aphrodite.StyleSheet.create({
23057
22994
  innerWrapper: {
23058
22995
  width: CHOICE_ICON_SIZE,
23059
22996
  height: CHOICE_ICON_SIZE,
@@ -23145,19 +23082,19 @@ const OptionStatus = function (props) {
23145
23082
  }
23146
23083
  let textStyle;
23147
23084
  if (correct) {
23148
- textStyle = styles$t.correct;
23085
+ textStyle = styles$u.correct;
23149
23086
  } else {
23150
23087
  if (checked || previouslyAnswered) {
23151
- textStyle = styles$t.incorrectAnswered;
23088
+ textStyle = styles$u.incorrectAnswered;
23152
23089
  } else {
23153
- textStyle = styles$t.incorrect;
23090
+ textStyle = styles$u.incorrect;
23154
23091
  }
23155
23092
  }
23156
23093
  return /*#__PURE__*/React__namespace.createElement("div", {
23157
- className: aphrodite.css(styles$t.text, textStyle)
23094
+ className: aphrodite.css(styles$u.text, textStyle)
23158
23095
  }, renderText(checked, correct, crossedOut));
23159
23096
  };
23160
- const styles$t = aphrodite.StyleSheet.create({
23097
+ const styles$u = aphrodite.StyleSheet.create({
23161
23098
  text: {
23162
23099
  alignItems: "center",
23163
23100
  display: "flex",
@@ -23231,8 +23168,8 @@ const Choice = function (props) {
23231
23168
  crossedOut: updatedCrossedOut
23232
23169
  });
23233
23170
  }
23234
- const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$s.description));
23235
- const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$s.rationale));
23171
+ const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$t.description));
23172
+ const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$t.rationale));
23236
23173
 
23237
23174
  // We want to show the choices as dimmed out when the choices are disabled.
23238
23175
  // However, we don't want to do this when we're in review mode in the
@@ -23343,14 +23280,16 @@ const Choice = function (props) {
23343
23280
  close
23344
23281
  } = _ref2;
23345
23282
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContent, {
23346
- title: "Cross out",
23347
- content: "Cross out option",
23283
+ title: i18n__namespace._("Cross out"),
23284
+ content: i18n__namespace._("Cross out option"),
23348
23285
  closeButtonVisible: true,
23349
23286
  actions: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksLayout.Strut, {
23350
23287
  size: Spacing__default["default"].medium_16
23351
23288
  }), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
23352
23289
  kind: "primary",
23353
- "aria-label": `Cross out Choice ${getChoiceLetter(pos)}`,
23290
+ "aria-label": i18n__namespace._("Cross out Choice %(letter)s", {
23291
+ letter: getChoiceLetter(pos)
23292
+ }),
23354
23293
  disabled: apiOptions.readOnly || reviewMode,
23355
23294
  onClick: () => {
23356
23295
  if (!crossedOut) {
@@ -23369,7 +23308,7 @@ const Choice = function (props) {
23369
23308
  }
23370
23309
  close();
23371
23310
  }
23372
- }, crossedOut ? "Bring back" : "Cross out"))
23311
+ }, crossedOut ? i18n__namespace._("Bring back") : i18n__namespace._("Cross out")))
23373
23312
  });
23374
23313
  }
23375
23314
  }, _ref3 => {
@@ -23378,7 +23317,9 @@ const Choice = function (props) {
23378
23317
  } = _ref3;
23379
23318
  return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
23380
23319
  onClick: open,
23381
- "aria-label": `Open menu for Choice ${getChoiceLetter(pos)}`,
23320
+ "aria-label": i18n__namespace._(`Open menu for Choice %(letter)s`, {
23321
+ letter: getChoiceLetter(pos)
23322
+ }),
23382
23323
  style: {
23383
23324
  alignSelf: "center",
23384
23325
  padding: "5px",
@@ -23399,7 +23340,7 @@ const Choice = function (props) {
23399
23340
  "data-test-id": `perseus-radio-rationale-content-${pos}`
23400
23341
  }, rationale));
23401
23342
  };
23402
- const styles$s = aphrodite.StyleSheet.create({
23343
+ const styles$t = aphrodite.StyleSheet.create({
23403
23344
  description: {
23404
23345
  display: "inline-block",
23405
23346
  width: "100%"
@@ -23591,10 +23532,10 @@ const BaseRadio = function (props) {
23591
23532
  const isMobile = apiOptions.isMobile;
23592
23533
  const firstChoiceHighlighted = choices[0].highlighted;
23593
23534
  const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
23594
- const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$r.radio, styles$r.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$r.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$r.radioContainerLastHighlighted));
23595
- const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$r.instructions, isMobile && styles$r.instructionsMobile));
23535
+ const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$s.radio, styles$s.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$s.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$s.radioContainerLastHighlighted));
23536
+ const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$s.instructions, isMobile && styles$s.instructionsMobile));
23596
23537
  const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
23597
- const responsiveClassName = aphrodite.css(styles$r.responsiveFieldset);
23538
+ const responsiveClassName = aphrodite.css(styles$s.responsiveFieldset);
23598
23539
  const fieldset = /*#__PURE__*/React__namespace.createElement("fieldset", {
23599
23540
  className: `perseus-widget-radio-fieldset ${responsiveClassName}`
23600
23541
  }, /*#__PURE__*/React__namespace.createElement("legend", {
@@ -23645,7 +23586,7 @@ const BaseRadio = function (props) {
23645
23586
  const aphroditeClassName = checked => {
23646
23587
  // Whether or not to show correctness borders
23647
23588
  // for this choice and the next choice.
23648
- return aphrodite.css(sharedStyles.aboveScratchpad, styles$r.item, styles$r.responsiveItem, checked && styles$r.selectedItem, checked && choice.highlighted && styles$r.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$r.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$r.nextHighlighted);
23589
+ return aphrodite.css(sharedStyles.aboveScratchpad, styles$s.item, styles$s.responsiveItem, checked && styles$s.selectedItem, checked && choice.highlighted && styles$s.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$s.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$s.nextHighlighted);
23649
23590
  };
23650
23591
 
23651
23592
  // HACK(abdulrahman): Preloads the selection-state
@@ -23719,14 +23660,14 @@ const BaseRadio = function (props) {
23719
23660
  // Allow for horizontal scrolling if content is too wide, which may be
23720
23661
  // an issue especially on phones.
23721
23662
  return /*#__PURE__*/React__namespace.createElement("div", {
23722
- className: aphrodite.css(styles$r.responsiveContainer)
23663
+ className: aphrodite.css(styles$s.responsiveContainer)
23723
23664
  }, fieldset);
23724
23665
  };
23725
23666
  BaseRadio.defaultProps = {
23726
23667
  editMode: false,
23727
23668
  multipleSelect: false
23728
23669
  };
23729
- const styles$r = aphrodite.StyleSheet.create({
23670
+ const styles$s = aphrodite.StyleSheet.create({
23730
23671
  instructions: {
23731
23672
  display: "block",
23732
23673
  color: gray17,
@@ -24385,9 +24326,9 @@ class Categorizer extends React__namespace.Component {
24385
24326
  indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
24386
24327
  }
24387
24328
  const table = /*#__PURE__*/React__namespace.createElement("table", {
24388
- className: "categorizer-table " + aphrodite.css(styles$q.mobileTable)
24329
+ className: "categorizer-table " + aphrodite.css(styles$r.mobileTable)
24389
24330
  }, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, /*#__PURE__*/React__namespace.createElement("td", {
24390
- className: aphrodite.css(styles$q.emptyHeaderCell)
24331
+ className: aphrodite.css(styles$r.emptyHeaderCell)
24391
24332
  }), this.props.categories.map((category, i) => {
24392
24333
  // Array index is the correct key here, as that's
24393
24334
  // how category grading actually works -- no way
@@ -24395,7 +24336,7 @@ class Categorizer extends React__namespace.Component {
24395
24336
  // middle. (If we later add that, this should be
24396
24337
  // fixed.)
24397
24338
  return /*#__PURE__*/React__namespace.createElement("th", {
24398
- className: aphrodite.css(styles$q.header),
24339
+ className: aphrodite.css(styles$r.header),
24399
24340
  key: i
24400
24341
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
24401
24342
  content: category,
@@ -24415,7 +24356,7 @@ class Categorizer extends React__namespace.Component {
24415
24356
  })), self.props.categories.map((catName, catNum) => {
24416
24357
  const selected = self.props.values[itemNum] === catNum;
24417
24358
  return /*#__PURE__*/React__namespace.createElement("td", {
24418
- className: "category " + aphrodite.css(styles$q.cell),
24359
+ className: "category " + aphrodite.css(styles$r.cell),
24419
24360
  key: catNum
24420
24361
  }, /*#__PURE__*/React__namespace.createElement("div", {
24421
24362
  className: ClassNames.INTERACTIVE,
@@ -24434,7 +24375,7 @@ class Categorizer extends React__namespace.Component {
24434
24375
  onChange: this.onChange.bind(this, itemNum, catNum),
24435
24376
  onClick: e => e.stopPropagation()
24436
24377
  }), !isMobile && /*#__PURE__*/React__namespace.createElement("span", {
24437
- className: aphrodite.css(styles$q.radioSpan, selected && styles$q.checkedRadioSpan, this.props.static && selected && styles$q.staticCheckedRadioSpan)
24378
+ className: aphrodite.css(styles$r.radioSpan, selected && styles$r.checkedRadioSpan, this.props.static && selected && styles$r.staticCheckedRadioSpan)
24438
24379
  }, selected ? /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleThin))));
24439
24380
  }));
24440
24381
  /* eslint-enable max-len */
@@ -24446,7 +24387,7 @@ class Categorizer extends React__namespace.Component {
24446
24387
  "categorizer-container": true,
24447
24388
  "static-mode": this.props.static
24448
24389
  });
24449
- const inlineStyles = this.props.apiOptions.isMobile ? [styles$q.fullBleedContainer] : [];
24390
+ const inlineStyles = this.props.apiOptions.isMobile ? [styles$r.fullBleedContainer] : [];
24450
24391
  return /*#__PURE__*/React__namespace.createElement("div", {
24451
24392
  className: extraClassNames + " " + aphrodite.css(...inlineStyles)
24452
24393
  }, table);
@@ -24495,7 +24436,7 @@ const pageMargin = 16;
24495
24436
 
24496
24437
  // Stylesheets aren't directly testable
24497
24438
  /* c8 ignore next */
24498
- const styles$q = aphrodite.StyleSheet.create({
24439
+ const styles$r = aphrodite.StyleSheet.create({
24499
24440
  mobileTable: {
24500
24441
  [mediaQueries.smOrSmaller]: {
24501
24442
  minWidth: "auto"
@@ -24605,7 +24546,7 @@ const toAbsoluteUrl = url => parseUrl(url).href;
24605
24546
  const {
24606
24547
  updateQueryString: updateQueryString$1
24607
24548
  } = Util;
24608
- function getUrlFromProgramID(programID) {
24549
+ function getUrlFromProgramID$1(programID) {
24609
24550
  const {
24610
24551
  InitialRequestUrl
24611
24552
  } = getDependencies();
@@ -24714,7 +24655,7 @@ class CSProgram extends React__namespace.Component {
24714
24655
  return /*#__PURE__*/React__namespace.createElement("div", null);
24715
24656
  }
24716
24657
  let styleContainer = false;
24717
- let url = getUrlFromProgramID(this.props.programID);
24658
+ let url = getUrlFromProgramID$1(this.props.programID);
24718
24659
  let className;
24719
24660
  const style = {
24720
24661
  height: this.props.height,
@@ -24758,7 +24699,7 @@ class CSProgram extends React__namespace.Component {
24758
24699
  // creator "went wild".
24759
24700
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
24760
24701
  return /*#__PURE__*/React__namespace.createElement("div", {
24761
- className: aphrodite.css(styles$p.widthOverride, styleContainer && styles$p.container)
24702
+ className: aphrodite.css(styles$q.widthOverride, styleContainer && styles$q.container)
24762
24703
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
24763
24704
  sandbox: sandboxOptions,
24764
24705
  src: url,
@@ -24768,7 +24709,7 @@ class CSProgram extends React__namespace.Component {
24768
24709
  }));
24769
24710
  }
24770
24711
  }
24771
- const styles$p = aphrodite.StyleSheet.create({
24712
+ const styles$q = aphrodite.StyleSheet.create({
24772
24713
  // Override the inherited width from the perseus paragraph class
24773
24714
  // 820 is minimum width for 420px editor and 400px canvas
24774
24715
  widthOverride: {
@@ -24816,7 +24757,7 @@ class Definition extends React__namespace.Component {
24816
24757
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
24817
24758
  content: /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
24818
24759
  color: "white",
24819
- style: styles$o.tooltipBody,
24760
+ style: styles$p.tooltipBody,
24820
24761
  closeButtonVisible: true
24821
24762
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
24822
24763
  apiOptions: this.props.apiOptions,
@@ -24847,7 +24788,7 @@ class Definition extends React__namespace.Component {
24847
24788
  });
24848
24789
  }
24849
24790
  }
24850
- const styles$o = {
24791
+ const styles$p = {
24851
24792
  tooltipBody: {
24852
24793
  color: Color__default["default"].offBlack,
24853
24794
  fontSize: 20,
@@ -25051,15 +24992,15 @@ class Explanation extends React__namespace.Component {
25051
24992
  const onClick = this._onClick;
25052
24993
  if (isMobile) {
25053
24994
  linkContainer = /*#__PURE__*/React__namespace.createElement("div", {
25054
- className: aphrodite.css(styles$n.linkContainer)
24995
+ className: aphrodite.css(styles$o.linkContainer)
25055
24996
  }, /*#__PURE__*/React__namespace.createElement("a", {
25056
- className: aphrodite.css(styles$n.mobileExplanationLink),
24997
+ className: aphrodite.css(styles$o.mobileExplanationLink),
25057
24998
  href: href,
25058
24999
  onClick: onClick,
25059
25000
  role: "button",
25060
25001
  "aria-expanded": this.state.expanded
25061
25002
  }, linkAnchor), this.state.expanded && /*#__PURE__*/React__namespace.createElement("svg", {
25062
- className: aphrodite.css(styles$n.disclosureArrow)
25003
+ className: aphrodite.css(styles$o.disclosureArrow)
25063
25004
  }, /*#__PURE__*/React__namespace.createElement("polygon", {
25064
25005
  style: {
25065
25006
  fill: backgroundColor
@@ -25072,13 +25013,13 @@ class Explanation extends React__namespace.Component {
25072
25013
  // an anchor tag (if rendered in a modal) or a Wonder Blocks
25073
25014
  // link component in lesson page, see: `article-page.jsx`.
25074
25015
  linkContainer = /*#__PURE__*/React__namespace.createElement("div", {
25075
- className: aphrodite.css(styles$n.linkContainer, styles$n.articleLink)
25016
+ className: aphrodite.css(styles$o.linkContainer, styles$o.articleLink)
25076
25017
  }, /*#__PURE__*/React__namespace.createElement(Link, {
25077
- className: aphrodite.css(styles$n.explanationLink)
25018
+ className: aphrodite.css(styles$o.explanationLink)
25078
25019
  // HACK(michaelpolyak): WB Link doesn't passthrough
25079
25020
  // class name.
25080
25021
  ,
25081
- style: styles$n.explanationLink,
25022
+ style: styles$o.explanationLink,
25082
25023
  href: href,
25083
25024
  onClick: onClick,
25084
25025
  role: "button",
@@ -25088,9 +25029,9 @@ class Explanation extends React__namespace.Component {
25088
25029
  // NOTE: For exercises, the baseElements `Link` is an
25089
25030
  // anchor tag, see: `perseus-api.jsx`.
25090
25031
  linkContainer = /*#__PURE__*/React__namespace.createElement("div", {
25091
- className: aphrodite.css(styles$n.linkContainer, styles$n.exerciseLink)
25032
+ className: aphrodite.css(styles$o.linkContainer, styles$o.exerciseLink)
25092
25033
  }, /*#__PURE__*/React__namespace.createElement(Link, {
25093
- className: aphrodite.css(styles$n.explanationLink),
25034
+ className: aphrodite.css(styles$o.explanationLink),
25094
25035
  href: href,
25095
25036
  onClick: onClick,
25096
25037
  role: "button",
@@ -25098,11 +25039,11 @@ class Explanation extends React__namespace.Component {
25098
25039
  }, `[${linkAnchor}]`));
25099
25040
  }
25100
25041
  }
25101
- const expandedStyle = isMobile ? styles$n.contentExpandedMobile : styles$n.contentExpanded;
25042
+ const expandedStyle = isMobile ? styles$o.contentExpandedMobile : styles$o.contentExpanded;
25102
25043
  return /*#__PURE__*/React__namespace.createElement("div", {
25103
- className: aphrodite.css(styles$n.container)
25044
+ className: aphrodite.css(styles$o.container)
25104
25045
  }, linkContainer, this.state.expanded && /*#__PURE__*/React__namespace.createElement("div", {
25105
- className: aphrodite.css(styles$n.content, isMobile && styles$n.contentMobile, this.state.expanded && expandedStyle)
25046
+ className: aphrodite.css(styles$o.content, isMobile && styles$o.contentMobile, this.state.expanded && expandedStyle)
25106
25047
  // eslint-disable-next-line react/no-string-refs
25107
25048
  ,
25108
25049
  ref: "content"
@@ -25125,7 +25066,7 @@ const verticalContentPadding = 10;
25125
25066
  const arrowWidth = 30;
25126
25067
  const arrowHeight = 14;
25127
25068
  const backgroundColor = gray95;
25128
- const styles$n = aphrodite.StyleSheet.create({
25069
+ const styles$o = aphrodite.StyleSheet.create({
25129
25070
  container: {
25130
25071
  display: "inline",
25131
25072
  position: "relative"
@@ -25231,15 +25172,15 @@ class GradedGroupAnswerBar extends React__namespace.Component {
25231
25172
  onNextQuestion
25232
25173
  } = this.props;
25233
25174
  const answerBarStyle = {
25234
- ...styles$m.answerBar,
25175
+ ...styles$n.answerBar,
25235
25176
  backgroundColor: answerBarState === "CORRECT" ? Color__default["default"].offWhite : "white",
25236
25177
  // Center the "Correct!" message only when there's no next question
25237
25178
  justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
25238
25179
  };
25239
25180
  const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React__namespace.createElement("span", {
25240
- style: styles$m.text
25181
+ style: styles$n.text
25241
25182
  }, /*#__PURE__*/React__namespace.createElement("span", {
25242
- style: styles$m.tryAgainIcon
25183
+ style: styles$n.tryAgainIcon
25243
25184
  }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React__namespace.createElement("span", {
25244
25185
  style: {
25245
25186
  marginLeft: 8
@@ -25258,7 +25199,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
25258
25199
  return /*#__PURE__*/React__namespace.createElement("div", {
25259
25200
  style: answerBarStyle
25260
25201
  }, /*#__PURE__*/React__namespace.createElement("span", {
25261
- style: styles$m.text
25202
+ style: styles$n.text
25262
25203
  }, /*#__PURE__*/React__namespace.createElement("span", {
25263
25204
  style: {
25264
25205
  fontSize: 28,
@@ -25280,7 +25221,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
25280
25221
  }
25281
25222
  }
25282
25223
  const fontSize = 17;
25283
- const styles$m = {
25224
+ const styles$n = {
25284
25225
  answerBar: {
25285
25226
  display: "flex",
25286
25227
  alignItems: "center",
@@ -25480,7 +25421,7 @@ class GradedGroup extends React__namespace.Component {
25480
25421
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
25481
25422
  gradeStatus = i18n__namespace._("Incorrect");
25482
25423
  }
25483
- const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$l.gradedGroupInSet) : aphrodite.css(styles$l.gradedGroup);
25424
+ const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$m.gradedGroupInSet) : aphrodite.css(styles$m.gradedGroup);
25484
25425
  const classes = classNames__default["default"]({
25485
25426
  [mobileClass]: apiOptions.isMobile,
25486
25427
  "perseus-graded-group": true,
@@ -25499,7 +25440,7 @@ class GradedGroup extends React__namespace.Component {
25499
25440
  return /*#__PURE__*/React__namespace.createElement("div", {
25500
25441
  className: classes
25501
25442
  }, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
25502
- className: aphrodite.css(styles$l.title)
25443
+ className: aphrodite.css(styles$m.title)
25503
25444
  }, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends({}, this.props, {
25504
25445
  // eslint-disable-next-line react/no-string-refs
25505
25446
  ref: "renderer",
@@ -25532,7 +25473,7 @@ class GradedGroup extends React__namespace.Component {
25532
25473
  }, i18n__namespace._("Next question")), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
25533
25474
  // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
25534
25475
  tabIndex: "0",
25535
- className: aphrodite.css(styles$l.explanationTitle),
25476
+ className: aphrodite.css(styles$m.explanationTitle),
25536
25477
  onClick: () => this.setState({
25537
25478
  showHint: false
25538
25479
  }),
@@ -25564,7 +25505,7 @@ class GradedGroup extends React__namespace.Component {
25564
25505
  showHint: true
25565
25506
  });
25566
25507
  },
25567
- className: aphrodite.css(styles$l.showHintLink)
25508
+ className: aphrodite.css(styles$m.showHintLink)
25568
25509
  }, i18n__namespace._("Explain"))), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React__namespace.createElement(GradedGroupAnswerBar, {
25569
25510
  apiOptions: apiOptions,
25570
25511
  answerBarState: answerBarState,
@@ -25576,7 +25517,7 @@ class GradedGroup extends React__namespace.Component {
25576
25517
  const traverseChildWidgets$3 = function (props, traverseRenderer) {
25577
25518
  return ___default["default"].extend({}, props, traverseRenderer(props));
25578
25519
  };
25579
- const styles$l = aphrodite.StyleSheet.create({
25520
+ const styles$m = aphrodite.StyleSheet.create({
25580
25521
  gradedGroupInSet: {
25581
25522
  // Reset a few desktop-only styles that come from graded-group.less
25582
25523
  marginLeft: 0,
@@ -25646,20 +25587,20 @@ class Indicators extends React__namespace.Component {
25646
25587
  return /*#__PURE__*/React__namespace.createElement("ul", {
25647
25588
  // reduntantly add class name for use in .less files--
25648
25589
  // the styles object key gets hashed
25649
- className: classNames__default["default"](aphrodite.css(styles$k.indicatorContainer), "indicatorContainer")
25590
+ className: classNames__default["default"](aphrodite.css(styles$l.indicatorContainer), "indicatorContainer")
25650
25591
  }, this.props.gradedGroups.map((_ref, i) => {
25651
25592
  let {
25652
25593
  title
25653
25594
  } = _ref;
25654
25595
  return /*#__PURE__*/React__namespace.createElement("li", {
25655
- className: aphrodite.css(styles$k.indicator),
25596
+ className: aphrodite.css(styles$l.indicator),
25656
25597
  key: title
25657
25598
  }, /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
25658
25599
  role: "button",
25659
25600
  "aria-label": i18n__namespace._("Skip to %(title)s", {
25660
25601
  title
25661
25602
  }),
25662
- style: styles$k.indicatorButton,
25603
+ style: styles$l.indicatorButton,
25663
25604
  onClick: () => this.props.onChangeCurrentGroup(i),
25664
25605
  onKeyDown: e => this.handleKeyDown(e, i)
25665
25606
  }, _ref2 => {
@@ -25669,9 +25610,9 @@ class Indicators extends React__namespace.Component {
25669
25610
  pressed
25670
25611
  } = _ref2;
25671
25612
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
25672
- style: [styles$k.indicatorDot, (hovered || focused || pressed) && styles$k.indicatorDotFocused]
25613
+ style: [styles$l.indicatorDot, (hovered || focused || pressed) && styles$l.indicatorDotFocused]
25673
25614
  }, i === this.props.currentGroup && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
25674
- style: styles$k.indicatorDotActive
25615
+ style: styles$l.indicatorDotActive
25675
25616
  }, /*#__PURE__*/React__namespace.createElement("span", {
25676
25617
  className: aphrodite.css(a11y.srOnly)
25677
25618
  }, i18n__namespace._("Current"))));
@@ -25747,7 +25688,7 @@ class GradedGroupSet extends React__namespace.Component {
25747
25688
  } = getDependencies();
25748
25689
  if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
25749
25690
  return /*#__PURE__*/React__namespace.createElement("div", {
25750
- className: aphrodite.css(styles$k.container)
25691
+ className: aphrodite.css(styles$l.container)
25751
25692
  }, this.props.gradedGroups.map((gradedGroup, i) => {
25752
25693
  return (
25753
25694
  /*#__PURE__*/
@@ -25770,13 +25711,13 @@ class GradedGroupSet extends React__namespace.Component {
25770
25711
  const numGroups = this.props.gradedGroups.length;
25771
25712
  const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
25772
25713
  return /*#__PURE__*/React__namespace.createElement("div", {
25773
- className: aphrodite.css(styles$k.container)
25714
+ className: aphrodite.css(styles$l.container)
25774
25715
  }, /*#__PURE__*/React__namespace.createElement("div", {
25775
- className: aphrodite.css(styles$k.top)
25716
+ className: aphrodite.css(styles$l.top)
25776
25717
  }, /*#__PURE__*/React__namespace.createElement("div", {
25777
- className: aphrodite.css(styles$k.title)
25718
+ className: aphrodite.css(styles$l.title)
25778
25719
  }, currentGroup.title), /*#__PURE__*/React__namespace.createElement("div", {
25779
- className: aphrodite.css(styles$k.spacer)
25720
+ className: aphrodite.css(styles$l.spacer)
25780
25721
  }), /*#__PURE__*/React__namespace.createElement(Indicators, {
25781
25722
  currentGroup: this.state.currentGroup,
25782
25723
  gradedGroups: this.props.gradedGroups,
@@ -25814,7 +25755,7 @@ var GradedGroupSet$1 = {
25814
25755
  tracking: "all",
25815
25756
  isLintable: true
25816
25757
  };
25817
- const styles$k = aphrodite.StyleSheet.create({
25758
+ const styles$l = aphrodite.StyleSheet.create({
25818
25759
  top: {
25819
25760
  display: "flex",
25820
25761
  flexDirection: "row"
@@ -25919,7 +25860,7 @@ class ButtonGroup extends React__namespace.Component {
25919
25860
  id: "" + i,
25920
25861
  ref: "button" + i,
25921
25862
  key: "" + i,
25922
- className: aphrodite.css(styles$j.buttonStyle, button.value === value && styles$j.selectedStyle),
25863
+ className: aphrodite.css(styles$k.buttonStyle, button.value === value && styles$k.selectedStyle),
25923
25864
  onClick: () => this.toggleSelect(button.value)
25924
25865
  }, button.content || "" + button.value);
25925
25866
  });
@@ -25932,7 +25873,7 @@ class ButtonGroup extends React__namespace.Component {
25932
25873
  }, buttons);
25933
25874
  }
25934
25875
  }
25935
- const styles$j = aphrodite.StyleSheet.create({
25876
+ const styles$k = aphrodite.StyleSheet.create({
25936
25877
  buttonStyle: {
25937
25878
  backgroundColor: "white",
25938
25879
  border: "1px solid #ccc",
@@ -31202,7 +31143,7 @@ const HideAnswersToggle = props => {
31202
31143
  const switchId = idFactory.get("hide-answers-toggle");
31203
31144
  const labelId = idFactory.get("hide-answers-label");
31204
31145
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31205
- style: styles$i.switchWrapper
31146
+ style: styles$j.switchWrapper
31206
31147
  }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31207
31148
  id: switchId,
31208
31149
  checked: props.areAnswersHidden,
@@ -31214,7 +31155,7 @@ const HideAnswersToggle = props => {
31214
31155
  tag: "label"
31215
31156
  }, strings.hideAnswersToggleLabel));
31216
31157
  };
31217
- const styles$i = aphrodite.StyleSheet.create({
31158
+ const styles$j = aphrodite.StyleSheet.create({
31218
31159
  switchWrapper: {
31219
31160
  display: "flex",
31220
31161
  flexDirection: "row",
@@ -31269,14 +31210,14 @@ const AnswerPill = props => {
31269
31210
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31270
31211
  onClick: correct ? undefined : onClick,
31271
31212
  ref: ref,
31272
- style: [style, popperStyle, styles$h.pill, correct && styles$h.correct, incorrect && styles$h.incorrect, (focused || hovered) && BringToFront]
31213
+ style: [style, popperStyle, styles$i.pill, correct && styles$i.correct, incorrect && styles$i.incorrect, (focused || hovered) && BringToFront]
31273
31214
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31274
31215
  content: answerString,
31275
31216
  inline: true
31276
31217
  }));
31277
31218
  });
31278
31219
  };
31279
- const styles$h = aphrodite.StyleSheet.create({
31220
+ const styles$i = aphrodite.StyleSheet.create({
31280
31221
  correct: {
31281
31222
  // WB green darkened by 18%
31282
31223
  backgroundColor: "#00880b"
@@ -31330,25 +31271,25 @@ class Marker extends React__namespace.Component {
31330
31271
  icon: iconNull
31331
31272
  };
31332
31273
  if (showCorrectness) {
31333
- iconStyles = [styles$g.markerGraded, showCorrectness === "correct" ? styles$g.markerCorrect : styles$g.markerIncorrect, isOpen && styles$g.markerSelected];
31274
+ iconStyles = [styles$h.markerGraded, showCorrectness === "correct" ? styles$h.markerCorrect : styles$h.markerIncorrect, isOpen && styles$h.markerSelected];
31334
31275
  args = {
31335
31276
  ...args,
31336
31277
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
31337
31278
  };
31338
31279
  } else if (selectedAnswers && selectedAnswers.length > 0) {
31339
- iconStyles = [styles$g.markerFilled, isOpen && styles$g.markerSelected];
31280
+ iconStyles = [styles$h.markerFilled, isOpen && styles$h.markerSelected];
31340
31281
  } else if (isOpen) {
31341
- iconStyles = [styles$g.markerSelected];
31282
+ iconStyles = [styles$h.markerSelected];
31342
31283
  args = {
31343
31284
  ...args,
31344
31285
  icon: iconChevronDown,
31345
31286
  size: 8
31346
31287
  };
31347
31288
  } else if (showPulsate) {
31348
- iconStyles = [styles$g.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$g.markerUnfilledPulsateOnce : showPulsate && styles$g.markerUnfilledPulsateInfinite];
31289
+ iconStyles = [styles$h.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$h.markerUnfilledPulsateOnce : showPulsate && styles$h.markerUnfilledPulsateInfinite];
31349
31290
  }
31350
31291
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31351
- style: [styles$g.markerIcon, iconStyles],
31292
+ style: [styles$h.markerIcon, iconStyles],
31352
31293
  ref: node => this._icon = node
31353
31294
  }, /*#__PURE__*/React__namespace.createElement(Icon, args));
31354
31295
  }
@@ -31369,7 +31310,7 @@ class Marker extends React__namespace.Component {
31369
31310
  const markerDisabled = showCorrectness === "correct";
31370
31311
  const active = hovered || focused;
31371
31312
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31372
- style: [styles$g.marker, active && !markerDisabled && styles$g.markerActive]
31313
+ style: [styles$h.marker, active && !markerDisabled && styles$h.markerActive]
31373
31314
  // already translated in: /widgets/graded-group.tsx
31374
31315
  ,
31375
31316
  "aria-label": markerDisabled ? i18n__namespace._("Correct!") : label
@@ -31384,7 +31325,7 @@ class Marker extends React__namespace.Component {
31384
31325
  }));
31385
31326
  }
31386
31327
  }
31387
- const styles$g = aphrodite.StyleSheet.create({
31328
+ const styles$h = aphrodite.StyleSheet.create({
31388
31329
  marker: {
31389
31330
  position: "absolute",
31390
31331
  backgroundColor: Color__default["default"].white,
@@ -31961,13 +31902,13 @@ class LabelImage extends React__namespace.Component {
31961
31902
  const promptString = isMobile ? multipleAnswers ? i18n__namespace._("Tap each dot on the image to select all answers that apply.") : i18n__namespace._("Tap each dot on the image to select an answer.") : multipleAnswers ? i18n__namespace._("Click each dot on the image to select all answers that apply.") : i18n__namespace._("Click each dot on the image to select an answer.");
31962
31903
  const choicesString = i18n__namespace._("Choices:");
31963
31904
  return /*#__PURE__*/React__namespace.createElement("div", {
31964
- className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$f.instructions))
31905
+ className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$g.instructions))
31965
31906
  }, /*#__PURE__*/React__namespace.createElement("div", {
31966
- className: aphrodite.css(styles$f.instructionsCaption)
31907
+ className: aphrodite.css(styles$g.instructionsCaption)
31967
31908
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React__namespace.createElement("div", {
31968
- className: aphrodite.css(styles$f.instructionsChoices)
31909
+ className: aphrodite.css(styles$g.instructionsChoices)
31969
31910
  }, choices.map((choice, index) => /*#__PURE__*/React__namespace.createElement("div", {
31970
- className: aphrodite.css(styles$f.instructionsChoice),
31911
+ className: aphrodite.css(styles$g.instructionsChoice),
31971
31912
  key: index
31972
31913
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31973
31914
  content: choice
@@ -31984,20 +31925,20 @@ class LabelImage extends React__namespace.Component {
31984
31925
  activeMarkerIndex
31985
31926
  } = this.state;
31986
31927
  return /*#__PURE__*/React__namespace.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React__namespace.createElement("div", {
31987
- className: aphrodite.css(styles$f.markersCanvas),
31928
+ className: aphrodite.css(styles$g.markersCanvas),
31988
31929
  style: {
31989
31930
  maxWidth: imageWidth,
31990
31931
  maxHeight: imageHeight
31991
31932
  }
31992
31933
  }, /*#__PURE__*/React__namespace.createElement("div", {
31993
- className: aphrodite.css(styles$f.imageContainer,
31934
+ className: aphrodite.css(styles$g.imageContainer,
31994
31935
  // Ensure image interaction is disabled while answer
31995
31936
  // choices popup is visible. This addresses specific
31996
31937
  // case where user may click on question image to
31997
31938
  // dismiss the popup. If the image is larger in size
31998
31939
  // than its rendered in the widget, this would
31999
31940
  // result in a zoom of the image.
32000
- activeMarkerIndex !== -1 && styles$f.imageInteractionDisabled)
31941
+ activeMarkerIndex !== -1 && styles$g.imageInteractionDisabled)
32001
31942
  }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref3 => {
32002
31943
  let {
32003
31944
  setAssetStatus
@@ -32023,7 +31964,7 @@ class LabelImage extends React__namespace.Component {
32023
31964
  }));
32024
31965
  }
32025
31966
  }
32026
- const styles$f = aphrodite.StyleSheet.create({
31967
+ const styles$g = aphrodite.StyleSheet.create({
32027
31968
  instructions: {
32028
31969
  paddingBottom: 16
32029
31970
  },
@@ -32384,7 +32325,7 @@ class Placeholder extends React__namespace.Component {
32384
32325
  const {
32385
32326
  layout
32386
32327
  } = this.props;
32387
- const className = aphrodite.css(styles$e.card, styles$e.placeholder, layout === Layout.HORIZONTAL && styles$e.horizontalCard);
32328
+ const className = aphrodite.css(styles$f.card, styles$f.placeholder, layout === Layout.HORIZONTAL && styles$f.horizontalCard);
32388
32329
  const style = {
32389
32330
  width: this.props.width,
32390
32331
  height: this.props.height
@@ -32482,7 +32423,7 @@ class Draggable extends React__namespace.Component {
32482
32423
  // We need to keep backwards compatbility with rules specified directly
32483
32424
  // in CSS. Hence the hacky tacking on of manual classNames.
32484
32425
  // See sortable.less for details.
32485
- let className = aphrodite.css(styles$e.card, styles$e.draggable, layout === Layout.HORIZONTAL && styles$e.horizontalCard, layout === Layout.VERTICAL && styles$e.verticalCard, type === ItemState.DRAGGING && styles$e.dragging, type === ItemState.DISABLED && styles$e.disabled, !includePadding && styles$e.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32426
+ let className = aphrodite.css(styles$f.card, styles$f.draggable, layout === Layout.HORIZONTAL && styles$f.horizontalCard, layout === Layout.VERTICAL && styles$f.verticalCard, type === ItemState.DRAGGING && styles$f.dragging, type === ItemState.DISABLED && styles$f.disabled, !includePadding && styles$f.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32486
32427
  if (!includePadding) {
32487
32428
  className += " perseus-sortable-draggable-unpadded";
32488
32429
  }
@@ -32782,7 +32723,7 @@ class Sortable extends React__namespace.Component {
32782
32723
  } = this.props;
32783
32724
  // We need to keep backwards compatbility with rules specified directly
32784
32725
  // in CSS. See sortable.less for details.
32785
- const className = aphrodite.css(styles$e.sortable) + " perseus-sortable";
32726
+ const className = aphrodite.css(styles$f.sortable) + " perseus-sortable";
32786
32727
  const syncWidth = this.props.constraints?.width || layout === Layout.VERTICAL;
32787
32728
  const syncHeight = this.props.constraints?.height || layout === Layout.HORIZONTAL;
32788
32729
  ___default["default"].each(this.state.items, function (item, i, items) {
@@ -33013,7 +32954,7 @@ class Sortable extends React__namespace.Component {
33013
32954
  return ___default["default"].pluck(this.state.items, "option");
33014
32955
  }
33015
32956
  }
33016
- const styles$e = aphrodite.StyleSheet.create({
32957
+ const styles$f = aphrodite.StyleSheet.create({
33017
32958
  sortable: {
33018
32959
  boxSizing: "border-box",
33019
32960
  float: "left",
@@ -33141,23 +33082,23 @@ class Matcher extends React__namespace.Component {
33141
33082
  };
33142
33083
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
33143
33084
  return /*#__PURE__*/React__namespace.createElement("table", {
33144
- className: aphrodite.css(styles$d.widget) + " " + HACKY_CSS_CLASSNAME
33085
+ className: aphrodite.css(styles$e.widget) + " " + HACKY_CSS_CLASSNAME
33145
33086
  }, /*#__PURE__*/React__namespace.createElement("tbody", null, showLabels && /*#__PURE__*/React__namespace.createElement("tr", {
33146
- className: aphrodite.css(styles$d.row)
33087
+ className: aphrodite.css(styles$e.row)
33147
33088
  }, /*#__PURE__*/React__namespace.createElement("th", {
33148
- className: aphrodite.css(styles$d.column, styles$d.columnLabel)
33089
+ className: aphrodite.css(styles$e.column, styles$e.columnLabel)
33149
33090
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
33150
33091
  content: this.props.labels[0] || "...",
33151
33092
  linterContext: this.props.linterContext
33152
33093
  })), /*#__PURE__*/React__namespace.createElement("th", {
33153
- className: aphrodite.css(styles$d.column, styles$d.columnRight, styles$d.columnLabel)
33094
+ className: aphrodite.css(styles$e.column, styles$e.columnRight, styles$e.columnLabel)
33154
33095
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
33155
33096
  content: this.props.labels[1] || "...",
33156
33097
  linterContext: this.props.linterContext
33157
33098
  }))), /*#__PURE__*/React__namespace.createElement("tr", {
33158
- className: aphrodite.css(styles$d.row)
33099
+ className: aphrodite.css(styles$e.row)
33159
33100
  }, /*#__PURE__*/React__namespace.createElement("td", {
33160
- className: aphrodite.css(styles$d.column)
33101
+ className: aphrodite.css(styles$e.column)
33161
33102
  }, /*#__PURE__*/React__namespace.createElement(Sortable, {
33162
33103
  options: left,
33163
33104
  layout: Layout.VERTICAL,
@@ -33172,7 +33113,7 @@ class Matcher extends React__namespace.Component {
33172
33113
  ,
33173
33114
  ref: "left"
33174
33115
  })), /*#__PURE__*/React__namespace.createElement("td", {
33175
- className: aphrodite.css(styles$d.column, styles$d.columnRight)
33116
+ className: aphrodite.css(styles$e.column, styles$e.columnRight)
33176
33117
  }, /*#__PURE__*/React__namespace.createElement(Sortable
33177
33118
  // @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33178
33119
  , {
@@ -33258,7 +33199,7 @@ ___default["default"].extend(Matcher, {
33258
33199
  });
33259
33200
  const padding = 5;
33260
33201
  const border = "1px solid #444";
33261
- const styles$d = aphrodite.StyleSheet.create({
33202
+ const styles$e = aphrodite.StyleSheet.create({
33262
33203
  widget: {
33263
33204
  paddingTop: padding,
33264
33205
  maxWidth: "100%",
@@ -34131,9 +34072,9 @@ function drawText(ctx, item) {
34131
34072
  if (item.value === null) {
34132
34073
  return;
34133
34074
  }
34134
- ctx.fillStyle = styles$c.fgColor;
34135
- ctx.font = styles$c.font;
34136
- ctx.fillText(item.value, item.pos[0] - styles$c.fontSizePx / 2 + 1, item.pos[1] + styles$c.fontSizePx / 2);
34075
+ ctx.fillStyle = styles$d.fgColor;
34076
+ ctx.font = styles$d.font;
34077
+ ctx.fillText(item.value, item.pos[0] - styles$d.fontSizePx / 2 + 1, item.pos[1] + styles$d.fontSizePx / 2);
34137
34078
  }
34138
34079
 
34139
34080
  /**
@@ -34154,16 +34095,16 @@ function drawText(ctx, item) {
34154
34095
  function drawDoubleLine(ctx, item) {
34155
34096
  // Outer line that forms both of the bond lines.
34156
34097
  let path = new Path2D();
34157
- ctx.lineWidth = 5 * styles$c.lineWidth;
34158
- ctx.strokeStyle = styles$c.fgColor;
34098
+ ctx.lineWidth = 5 * styles$d.lineWidth;
34099
+ ctx.strokeStyle = styles$d.fgColor;
34159
34100
  path.moveTo(item.startPos[0], item.startPos[1]);
34160
34101
  path.lineTo(item.endPos[0], item.endPos[1]);
34161
34102
  ctx.stroke(path);
34162
34103
 
34163
34104
  // Inner white line that separates the two bond lines.
34164
34105
  path = new Path2D();
34165
- ctx.lineWidth = 3 * styles$c.lineWidth;
34166
- ctx.strokeStyle = styles$c.bgColor;
34106
+ ctx.lineWidth = 3 * styles$d.lineWidth;
34107
+ ctx.strokeStyle = styles$d.bgColor;
34167
34108
  path.moveTo(item.startPos[0], item.startPos[1]);
34168
34109
  path.lineTo(item.endPos[0], item.endPos[1]);
34169
34110
  ctx.stroke(path);
@@ -34190,16 +34131,16 @@ function drawTripleLine(ctx, item) {
34190
34131
 
34191
34132
  // Outer line that will form the two outer bond lines.
34192
34133
  let path = new Path2D();
34193
- ctx.lineWidth = 7 * styles$c.lineWidth;
34194
- ctx.strokeStyle = styles$c.fgColor;
34134
+ ctx.lineWidth = 7 * styles$d.lineWidth;
34135
+ ctx.strokeStyle = styles$d.fgColor;
34195
34136
  path.moveTo(item.startPos[0], item.startPos[1]);
34196
34137
  path.lineTo(item.endPos[0], item.endPos[1]);
34197
34138
  ctx.stroke(path);
34198
34139
 
34199
34140
  // Middle white line that separates the bonds
34200
34141
  path = new Path2D();
34201
- ctx.lineWidth = 5 * styles$c.lineWidth;
34202
- ctx.strokeStyle = styles$c.bgColor;
34142
+ ctx.lineWidth = 5 * styles$d.lineWidth;
34143
+ ctx.strokeStyle = styles$d.bgColor;
34203
34144
  path.moveTo(item.startPos[0], item.startPos[1]);
34204
34145
  path.lineTo(item.endPos[0], item.endPos[1]);
34205
34146
  ctx.stroke(path);
@@ -34221,8 +34162,8 @@ function drawTripleLine(ctx, item) {
34221
34162
  */
34222
34163
  function drawLine(ctx, item) {
34223
34164
  const path = new Path2D();
34224
- ctx.lineWidth = styles$c.lineWidth;
34225
- ctx.strokeStyle = styles$c.fgColor;
34165
+ ctx.lineWidth = styles$d.lineWidth;
34166
+ ctx.strokeStyle = styles$d.fgColor;
34226
34167
  path.moveTo(item.startPos[0], item.startPos[1]);
34227
34168
  path.lineTo(item.endPos[0], item.endPos[1]);
34228
34169
  ctx.stroke(path);
@@ -34274,7 +34215,7 @@ function compareElements(item0, item1) {
34274
34215
  function draw(ctx, items) {
34275
34216
  items.sort(compareElements).forEach(drawItem(ctx));
34276
34217
  }
34277
- const styles$c = {
34218
+ const styles$d = {
34278
34219
  bgColor: "rgb(255, 255, 255)",
34279
34220
  fgColor: "rgb(0, 0, 0)",
34280
34221
  fontSizePx: 12,
@@ -36838,7 +36779,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
36838
36779
  const rects = this.state.cachedHighlightRects;
36839
36780
  return /*#__PURE__*/React__namespace.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React__namespace.createElement("div", {
36840
36781
  key: index,
36841
- className: aphrodite.css(styles$b.highlightRect),
36782
+ className: aphrodite.css(styles$c.highlightRect),
36842
36783
  style: {
36843
36784
  // NOTE(mdr): We apply `position: absolute` here
36844
36785
  // rather than in Aphrodite styles, because
@@ -36857,7 +36798,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
36857
36798
  })));
36858
36799
  }
36859
36800
  }
36860
- const styles$b = aphrodite.StyleSheet.create({
36801
+ const styles$c = aphrodite.StyleSheet.create({
36861
36802
  highlightRect: {
36862
36803
  background: "#fffabe" // highlighter yellow :)
36863
36804
  }
@@ -36938,7 +36879,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
36938
36879
  // TooltipContent wouldn't let me overwrite
36939
36880
  // user-select and onClick
36940
36881
  const content = /*#__PURE__*/React__namespace.createElement("div", {
36941
- className: aphrodite.css(styles$a.tooltipLabel),
36882
+ className: aphrodite.css(styles$b.tooltipLabel),
36942
36883
  onClick: this.props.onClick
36943
36884
  }, this.props.label);
36944
36885
  const style = {
@@ -36958,7 +36899,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
36958
36899
  }, /*#__PURE__*/React__namespace.createElement("div", null)));
36959
36900
  }
36960
36901
  }
36961
- const styles$a = aphrodite.StyleSheet.create({
36902
+ const styles$b = aphrodite.StyleSheet.create({
36962
36903
  tooltipLabel: {
36963
36904
  // Unlike most tooltip contents, we don't want this label to be
36964
36905
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -37516,7 +37457,7 @@ class HighlightableContent extends React__namespace.PureComponent {
37516
37457
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
37517
37458
  const buildHighlight = r => this._buildHighlight(r);
37518
37459
  return /*#__PURE__*/React__namespace.createElement("div", {
37519
- className: aphrodite.css(styles$9.container),
37460
+ className: aphrodite.css(styles$a.container),
37520
37461
  ref: container => this._container = container
37521
37462
  }, /*#__PURE__*/React__namespace.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React__namespace.createElement(HighlightingUI, {
37522
37463
  buildHighlight: buildHighlight,
@@ -37537,14 +37478,14 @@ class HighlightableContent extends React__namespace.PureComponent {
37537
37478
  onAddHighlight: this._handleAddHighlight,
37538
37479
  onRemoveHighlight: this._handleRemoveHighlight
37539
37480
  })), /*#__PURE__*/React__namespace.createElement("div", {
37540
- className: aphrodite.css(styles$9.content),
37481
+ className: aphrodite.css(styles$a.content),
37541
37482
  ref: content => this._content = content
37542
37483
  }, /*#__PURE__*/React__namespace.createElement(WordIndexer, {
37543
37484
  onWordsUpdate: this._handleWordsUpdate
37544
37485
  }, this.props.children)));
37545
37486
  }
37546
37487
  }
37547
- const styles$9 = aphrodite.StyleSheet.create({
37488
+ const styles$a = aphrodite.StyleSheet.create({
37548
37489
  // We render content with z-index 1, and highlights with z-index 0, so that
37549
37490
  // content will receive the browser's native pointer events. (Highlights
37550
37491
  // have their own magic code to manage hover detection, despite being
@@ -37940,7 +37881,7 @@ class LineHeightMeasurer extends React__namespace.Component {
37940
37881
  }
37941
37882
  render() {
37942
37883
  return /*#__PURE__*/React__namespace.createElement("div", {
37943
- className: aphrodite.css(styles$8.measurer),
37884
+ className: aphrodite.css(styles$9.measurer),
37944
37885
  "aria-hidden": "true"
37945
37886
  }, /*#__PURE__*/React__namespace.createElement("div", {
37946
37887
  ref: ref => this._line = ref,
@@ -37948,7 +37889,7 @@ class LineHeightMeasurer extends React__namespace.Component {
37948
37889
  }, "Line Height Measurement"));
37949
37890
  }
37950
37891
  }
37951
- const styles$8 = aphrodite.StyleSheet.create({
37892
+ const styles$9 = aphrodite.StyleSheet.create({
37952
37893
  measurer: {
37953
37894
  position: "absolute",
37954
37895
  top: 0,
@@ -39235,6 +39176,52 @@ var Plotter$1 = {
39235
39176
  staticTransform: staticTransform
39236
39177
  };
39237
39178
 
39179
+ /**
39180
+ * This widget is for embedding Khan Academy Python programs.
39181
+ */
39182
+ function getUrlFromProgramID(programID) {
39183
+ const path = `/python-program/${programID}/embedded`;
39184
+ return toAbsoluteUrl(path);
39185
+ }
39186
+ /* This renders the program in an iframe. */
39187
+ class PythonProgram extends React__namespace.Component {
39188
+ static defaultProps = {
39189
+ height: 400
39190
+ };
39191
+ render() {
39192
+ const url = getUrlFromProgramID(this.props.programID);
39193
+ const iframeStyle = {
39194
+ height: this.props.height,
39195
+ width: "100%"
39196
+ };
39197
+ const sandboxOptions = ["allow-popups", "allow-same-origin", "allow-scripts", "allow-top-navigation"].join(" ");
39198
+
39199
+ // We sandbox the iframe so that we allowlist only the functionality
39200
+ // that we need. This makes it a bit safer in case some content
39201
+ // creator "went wild".
39202
+ // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
39203
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
39204
+ style: styles$8.container
39205
+ }, /*#__PURE__*/React__namespace.createElement("iframe", {
39206
+ sandbox: sandboxOptions,
39207
+ src: url,
39208
+ style: iframeStyle,
39209
+ allowFullScreen: true
39210
+ }));
39211
+ }
39212
+ }
39213
+ const styles$8 = aphrodite.StyleSheet.create({
39214
+ container: {
39215
+ margin: "auto",
39216
+ width: "100%"
39217
+ }
39218
+ });
39219
+ var PythonProgram$1 = {
39220
+ name: "python-program",
39221
+ displayName: "Python Program",
39222
+ widget: PythonProgram
39223
+ };
39224
+
39238
39225
  class Separator extends React__namespace.Component {
39239
39226
  arrowLength = 100;
39240
39227
  static propTypes = {
@@ -41669,7 +41656,7 @@ var Video$1 = {
41669
41656
  };
41670
41657
 
41671
41658
  /* eslint-disable import/no-named-as-default */
41672
- var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Unit, Video$1, DeprecatedStandin$1];
41659
+ var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, PythonProgram$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Unit, Video$1, DeprecatedStandin$1];
41673
41660
 
41674
41661
  /**
41675
41662
  * This should be called by all clients, specifying whether extra widgets are
@@ -41709,7 +41696,7 @@ const init = function (options) {
41709
41696
 
41710
41697
  // This file is processed by a Rollup plugin (replace) to inject the production
41711
41698
  const libName = "@khanacademy/perseus";
41712
- const libVersion = "19.1.8";
41699
+ const libVersion = "19.2.0";
41713
41700
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
41714
41701
 
41715
41702
  const apiVersion = {
@@ -43154,6 +43141,8 @@ const ItemExtras = [
43154
43141
 
43155
43142
  // prettier-ignore
43156
43143
 
43144
+ // prettier-ignore
43145
+
43157
43146
  //prettier-ignore
43158
43147
 
43159
43148
  // A background image applied to various widgets.