@khanacademy/perseus 19.6.3 → 19.7.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/es/index.js CHANGED
@@ -29,11 +29,12 @@ import { Strut } from '@khanacademy/wonder-blocks-layout';
29
29
  import Banner from '@khanacademy/wonder-blocks-banner';
30
30
  import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-blocks-dropdown';
31
31
  import debounce$1 from 'lodash.debounce';
32
+ import { useMovablePoint, Line as Line$4, Coordinates, Mafs } from 'mafs';
33
+ import createReactClass from 'create-react-class';
32
34
  import Switch from '@khanacademy/wonder-blocks-switch';
33
35
  import { LabelMedium } from '@khanacademy/wonder-blocks-typography';
34
36
  import Pill from '@khanacademy/wonder-blocks-pill';
35
37
  import { Popper } from 'react-popper';
36
- import createReactClass from 'create-react-class';
37
38
  import Link from '@khanacademy/wonder-blocks-link';
38
39
  import { addLibraryVersionToPerseusDebug } from '@khanacademy/perseus-core';
39
40
 
@@ -1901,7 +1902,7 @@ const KhanAnswerTypes = {
1901
1902
  }
1902
1903
  };
1903
1904
 
1904
- const _excluded$4 = ["scoring"];
1905
+ const _excluded$5 = ["scoring"];
1905
1906
  const ERROR_TITLE = i18n._("Oops!");
1906
1907
  const ERROR_MESSAGE = i18n._("Sorry, I don't understand that!");
1907
1908
 
@@ -1989,7 +1990,7 @@ class Expression extends React.Component {
1989
1990
  let {
1990
1991
  scoring
1991
1992
  } = _ref,
1992
- rubric = _objectWithoutPropertiesLoose(_ref, _excluded$4);
1993
+ rubric = _objectWithoutPropertiesLoose(_ref, _excluded$5);
1993
1994
  const score = Expression.validate(this.getUserInput(), rubric, onInputError || function () {});
1994
1995
 
1995
1996
  // "scoring" is a flag that indicates when we are checking answers.
@@ -21392,7 +21393,7 @@ InputWithExamples.defaultProps = {
21392
21393
  className: ""
21393
21394
  };
21394
21395
 
21395
- const _excluded$3 = ["keypadElement", "onFocus", "value"];
21396
+ const _excluded$4 = ["keypadElement", "onFocus", "value"];
21396
21397
  class SimpleKeypadInput extends React.Component {
21397
21398
  constructor(...args) {
21398
21399
  super(...args);
@@ -21431,7 +21432,7 @@ class SimpleKeypadInput extends React.Component {
21431
21432
  onFocus,
21432
21433
  value
21433
21434
  } = _this$props,
21434
- rest = _objectWithoutPropertiesLoose(_this$props, _excluded$3);
21435
+ rest = _objectWithoutPropertiesLoose(_this$props, _excluded$4);
21435
21436
  return (
21436
21437
  /*#__PURE__*/
21437
21438
  // @ts-expect-error - TS2769 - No overload matches this call.
@@ -23262,14 +23263,14 @@ var Choice$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.
23262
23263
  forwardedRef: ref
23263
23264
  })));
23264
23265
 
23265
- const _excluded$2 = ["showContent", "content", "forwardedRef"];
23266
+ const _excluded$3 = ["showContent", "content", "forwardedRef"];
23266
23267
  const ChoiceNoneAbove = function ChoiceNoneAbove(props) {
23267
23268
  const {
23268
23269
  showContent,
23269
23270
  content,
23270
23271
  forwardedRef
23271
23272
  } = props,
23272
- rest = _objectWithoutPropertiesLoose(props, _excluded$2);
23273
+ rest = _objectWithoutPropertiesLoose(props, _excluded$3);
23273
23274
  const choiceProps = _extends({}, rest, {
23274
23275
  content: showContent ? content :
23275
23276
  /*#__PURE__*/
@@ -28173,6 +28174,872 @@ Graph.defaultProps = {
28173
28174
  isMobile: false
28174
28175
  };
28175
28176
 
28177
+ const useInteractivePoint = (coords, snaps, range) => useMovablePoint(coords, {
28178
+ constrain: coord => constrain(coord, snaps, range),
28179
+ color: Color.blue
28180
+ });
28181
+
28182
+ /**
28183
+ * We do not want to call `onGraphChange` until the user
28184
+ * has interacted with the graph. See the test,
28185
+ * "should reject no interaction"
28186
+ */
28187
+ const useEffectAfterFirstRender = (fn, deps) => {
28188
+ const firstRender = useRef(true);
28189
+ useEffect(() => {
28190
+ if (firstRender.current) {
28191
+ firstRender.current = false;
28192
+ return;
28193
+ }
28194
+ fn();
28195
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28196
+ }, [fn, ...deps]);
28197
+ };
28198
+ const snap = (val, step) => {
28199
+ const inverse = 1 / step;
28200
+ return Math.round(val * inverse) / inverse;
28201
+ };
28202
+ const clamp = (n, min, max) => Math.max(min, Math.min(max, n));
28203
+ const constrain = (coord, snapStep, range) => {
28204
+ const [x, y] = coord;
28205
+ const [xSnap, ySnap] = snapStep;
28206
+ const [[xMin, xMax], [yMin, yMax]] = range;
28207
+ return [clamp(snap(x, xSnap), xMin, xMax), clamp(snap(y, ySnap), yMin, yMax)];
28208
+ };
28209
+
28210
+ // same as pointsFromNormalized in interactive-graph.tsx
28211
+ const normalizePoints = (range, step, coordsList, noSnap) => coordsList.map(coords =>
28212
+ // maps over [x, y]
28213
+ coords.map((coord, i) => {
28214
+ const axisRange = range[i];
28215
+ if (noSnap) {
28216
+ return axisRange[0] + (axisRange[1] - axisRange[0]) * coord;
28217
+ }
28218
+ const axisStep = step[i];
28219
+ const nSteps = Math.floor((axisRange[1] - axisRange[0]) / axisStep);
28220
+ const tick = Math.round(coord * nSteps);
28221
+ return axisRange[0] + axisStep * tick;
28222
+ }));
28223
+
28224
+ // same as normalizeCoords in interactive-graph.tsx
28225
+ const normalizeCoords = (coordsList, ranges) => coordsList.map(coords => coords.map((coord, i) => {
28226
+ const extent = ranges[i][1] - ranges[i][0];
28227
+ return (coord + ranges[i][1]) / extent;
28228
+ }));
28229
+
28230
+ const getSegmentCoords = props => {
28231
+ const coords = props.graph.coords;
28232
+ if (coords) {
28233
+ return coords;
28234
+ }
28235
+ const ys = n => {
28236
+ switch (n) {
28237
+ case 2:
28238
+ return [5, -5];
28239
+ case 3:
28240
+ return [5, 0, -5];
28241
+ case 4:
28242
+ return [6, 2, -2, -6];
28243
+ case 5:
28244
+ return [6, 3, 0, -3, -6];
28245
+ case 6:
28246
+ return [5, 3, 1, -1, -3, -5];
28247
+ default:
28248
+ return [5];
28249
+ }
28250
+ };
28251
+ return ys(props.graph.numSegments).map(y => {
28252
+ let segment = [[-5, y], [5, y]];
28253
+ segment = normalizeCoords(segment, props.range);
28254
+ segment = normalizePoints(props.range, props.step, segment);
28255
+ return segment;
28256
+ });
28257
+ };
28258
+ const updateSegmentsArray = (segments, index, segment) => segments.map((seg, i) => index === i ? segment : seg);
28259
+ const SegmentGraph = props => {
28260
+ const segments = getSegmentCoords(props);
28261
+ const handleChange = (i, segment) => props.onGraphChange(current => _extends({}, current, {
28262
+ coords: current.coords ? updateSegmentsArray(current.coords, i, segment) : updateSegmentsArray(segments, i, segment)
28263
+ }));
28264
+ return /*#__PURE__*/React.createElement(React.Fragment, null, segments.map((segment, i) => /*#__PURE__*/React.createElement(Segment, {
28265
+ key: i,
28266
+ i: i,
28267
+ segment: segment,
28268
+ snaps: props.snapStep,
28269
+ range: props.range,
28270
+ onChange: handleChange,
28271
+ "data-testid": "segment" + i
28272
+ })));
28273
+ };
28274
+ const Segment = props => {
28275
+ const [start, end] = props.segment;
28276
+ const {
28277
+ point: pt1,
28278
+ element: el1
28279
+ } = useInteractivePoint(start, props.snaps, props.range);
28280
+ const {
28281
+ point: pt2,
28282
+ element: el2
28283
+ } = useInteractivePoint(end, props.snaps, props.range);
28284
+ useEffectAfterFirstRender(() => props.onChange(props.i, [pt1, pt2]), [pt1, pt2]);
28285
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Line$4.Segment, {
28286
+ point1: pt1,
28287
+ point2: pt2
28288
+ }), el1, el2);
28289
+ };
28290
+
28291
+ const renderLineLabel = (n, [min, max]) => n !== -1 && n !== min && n !== max;
28292
+ const axisOptions = (props, index) => ({
28293
+ axis: props.markings === "graph",
28294
+ lines: props.step[index],
28295
+ subdivisions: props.step[index] / props.gridStep[index],
28296
+ labels: n => renderLineLabel(n, props.range[index]) ? n : ""
28297
+ });
28298
+ const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
28299
+ xAxis: axisOptions(props, 0),
28300
+ yAxis: axisOptions(props, 1)
28301
+ });
28302
+
28303
+ // Displays a stylized open eye: lint warnings are visible
28304
+ const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
28305
+ width: "24",
28306
+ height: "24",
28307
+ viewBox: "0 0 24 24",
28308
+ className: css(styles$j.icon)
28309
+ }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
28310
+ id: "a",
28311
+ d: "M7.401 10.035c-1.424.748-2.599 1.905-3.544 " + "3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 " + "12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 " + "1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-" + "3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 " + "0 0 0 0 6z"
28312
+ })), /*#__PURE__*/React.createElement("g", {
28313
+ fill: "none",
28314
+ fillRule: "evenodd"
28315
+ }, /*#__PURE__*/React.createElement("path", {
28316
+ fill: "none",
28317
+ d: "M0 0h24v24H0z"
28318
+ }), /*#__PURE__*/React.createElement("mask", {
28319
+ id: "b",
28320
+ fill: "#fff"
28321
+ }, /*#__PURE__*/React.createElement("use", {
28322
+ href: "#a"
28323
+ })), /*#__PURE__*/React.createElement("use", {
28324
+ fill: "#fff",
28325
+ fillRule: "nonzero",
28326
+ href: "#a"
28327
+ }), /*#__PURE__*/React.createElement("g", {
28328
+ fill: "#fff",
28329
+ mask: "url(#b)"
28330
+ }, /*#__PURE__*/React.createElement("path", {
28331
+ d: "M0 0h24v24H0z"
28332
+ }))));
28333
+
28334
+ // Displays a stylized eye with a line through it: I don't want to see lint
28335
+ const HiddenIcon = () => /*#__PURE__*/React.createElement("svg", {
28336
+ width: "24",
28337
+ height: "24",
28338
+ viewBox: "0 0 24 24",
28339
+ className: css(styles$j.icon)
28340
+ }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
28341
+ id: "a",
28342
+ d: "M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 " + "7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 " + "1.028c-.945-1.574-2.12-2.73-3.544-3.48.258." + "604.401 1.268.401 1.966 0 1.02-.305 " + "1.967-.828 2.757l2.535 2.536a1 1 0 0 " + "1-1.414 1.414l-12-12a1 1 0 0 1 " + "1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 " + "0-4.001-4.001l4 4.001zM6.072 8.486l2.976 " + "2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 " + "0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 " + "3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 " + "2.363-3.085 3.929-4z"
28343
+ })), /*#__PURE__*/React.createElement("g", {
28344
+ fill: "none",
28345
+ fillRule: "evenodd"
28346
+ }, /*#__PURE__*/React.createElement("path", {
28347
+ fill: "none",
28348
+ d: "M0 0h24v24H0z"
28349
+ }), /*#__PURE__*/React.createElement("mask", {
28350
+ id: "b",
28351
+ fill: "#fff"
28352
+ }, /*#__PURE__*/React.createElement("use", {
28353
+ href: "#a"
28354
+ })), /*#__PURE__*/React.createElement("use", {
28355
+ fill: "#fff",
28356
+ fillRule: "nonzero",
28357
+ href: "#a"
28358
+ }), /*#__PURE__*/React.createElement("g", {
28359
+ fill: "#fff",
28360
+ mask: "url(#b)"
28361
+ }, /*#__PURE__*/React.createElement("path", {
28362
+ d: "M0 0h24v24H0z"
28363
+ }))));
28364
+ const HUD = ({
28365
+ message,
28366
+ enabled,
28367
+ onClick,
28368
+ fixedPosition: _fixedPosition = true
28369
+ }) => {
28370
+ let state;
28371
+ let icon;
28372
+ if (enabled) {
28373
+ state = styles$j.enabled;
28374
+ icon = /*#__PURE__*/React.createElement(VisibleIcon, null);
28375
+ } else {
28376
+ state = styles$j.disabled;
28377
+ icon = /*#__PURE__*/React.createElement(HiddenIcon, null);
28378
+ }
28379
+ return /*#__PURE__*/React.createElement("button", {
28380
+ className: css(styles$j.hud, _fixedPosition && styles$j.hudFixedPosition, state),
28381
+ onClick: e => {
28382
+ onClick();
28383
+ }
28384
+ }, icon, message);
28385
+ };
28386
+ const styles$j = StyleSheet.create({
28387
+ hud: {
28388
+ boxSizing: "border-box",
28389
+ height: 36,
28390
+ padding: "9px 16px",
28391
+ borderRadius: 18,
28392
+ fontFamily: boldFontFamily,
28393
+ fontSize: "15px",
28394
+ lineHeight: "18px",
28395
+ color: white$1,
28396
+ userSelect: "none",
28397
+ borderWidth: 0 // <button> gives us a border by default
28398
+ },
28399
+
28400
+ // We want to render the element in-place in our fixtures, so allow us to
28401
+ // render in the bottom corner in production and in-place in testing.
28402
+ hudFixedPosition: {
28403
+ bottom: 20,
28404
+ position: "fixed",
28405
+ right: 20,
28406
+ zIndex: 1
28407
+ },
28408
+ icon: {
28409
+ width: 24,
28410
+ height: 24,
28411
+ marginRight: 8,
28412
+ marginTop: -3,
28413
+ verticalAlign: "middle"
28414
+ },
28415
+ enabled: {
28416
+ backgroundColor: warningColor,
28417
+ ":hover": {
28418
+ backgroundColor: warningColorHover
28419
+ },
28420
+ ":active": {
28421
+ backgroundColor: warningColorActive
28422
+ }
28423
+ },
28424
+ disabled: {
28425
+ backgroundColor: gray76,
28426
+ ":hover": {
28427
+ backgroundColor: "#a1a5a9" // in between those two grays
28428
+ },
28429
+
28430
+ ":active": {
28431
+ backgroundColor: gray68
28432
+ }
28433
+ }
28434
+ });
28435
+
28436
+ const colors$1 = {
28437
+ grayLight: "#aaa",
28438
+ basicBorderColor: "#ccc",
28439
+ white: "#fff"
28440
+ };
28441
+ const triangleBeforeAfter = {
28442
+ borderBottom: "9px solid transparent",
28443
+ borderTop: "9px solid transparent",
28444
+ content: '" "',
28445
+ height: "0",
28446
+ position: "absolute",
28447
+ top: "0",
28448
+ width: "0"
28449
+ };
28450
+ const styles$i = StyleSheet.create({
28451
+ infoTip: {
28452
+ display: "inline-block",
28453
+ marginLeft: "5px",
28454
+ position: "relative"
28455
+ },
28456
+ infoTipContainer: {
28457
+ position: "absolute",
28458
+ top: "-12px",
28459
+ left: "22px",
28460
+ zIndex: 1000
28461
+ },
28462
+ infoTipTriangle: {
28463
+ height: "10px",
28464
+ left: "0",
28465
+ position: "absolute",
28466
+ top: "8px",
28467
+ width: "0",
28468
+ zIndex: 1,
28469
+ ":before": _extends({}, triangleBeforeAfter, {
28470
+ borderRight: "9px solid #bbb",
28471
+ right: "0"
28472
+ }),
28473
+ ":after": _extends({}, triangleBeforeAfter, {
28474
+ borderRight: `9px solid ${colors$1.white}`,
28475
+ right: "-1px"
28476
+ })
28477
+ },
28478
+ verticalShadow: {
28479
+ border: `1px solid ${colors$1.basicBorderColor}`,
28480
+ boxShadow: `0 1px 3px ${colors$1.basicBorderColor}`,
28481
+ borderBottom: `1px solid ${colors$1.grayLight}`
28482
+ },
28483
+ infoTipContentContainer: {
28484
+ background: colors$1.white,
28485
+ padding: "5px 10px",
28486
+ width: "240px"
28487
+ }
28488
+ });
28489
+ const questionMark = "data:image/png;base64," + "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBB" + "ZG9iZSBJbWFnZVJlYWR5ccllPAAAA3NpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/" + "eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+" + "IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2Jl" + "IFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAg" + "ICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5" + "LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9" + "IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHht" + "bG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3Vy" + "Y2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHht" + "cE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2N2M3NTAxYS04YmVlLTQ0M2Mt" + "YmRiNS04OGM2N2IxN2NhYzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUJCRTk4" + "Qjc4NjAwMTFFMzg3QUJDNEI4Mzk2QTRGQkQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5p" + "aWQ6OUJCRTk4QjY4NjAwMTFFMzg3QUJDNEI4Mzk2QTRGQkQiIHhtcDpDcmVhdG9yVG9v" + "bD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRG" + "cm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NGE5ZDI0OTMtODk1NC00OGFkLTlh" + "MTgtZDAwM2MwYWNjNDJlIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY3Yzc1MDFh" + "LThiZWUtNDQzYy1iZGI1LTg4YzY3YjE3Y2FjMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4g" + "PC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pqm89uYAAADM" + "SURBVHjaXJA9DoJAEIUH1M4TUHIFsCMGen9OwCGw1YRGW2ntKel0exsojHIBC0ouQAyU" + "viFDstmXfNmZeS+zm7XSNCXRFiRgJf0bXIHixpbhGdxBBJYC1w/xaA424MhNEATkui71" + "fU9KqfEU78UbD9PdbJRlOdae55GmhIP+1NV1TcMwkOM41DSNHvRtMhTHMRVFQW3b6mOL" + "gx99kue5GRp/gIOZuZGvNpTNwjD8oliANU+qqqKu6/TQBdymN57AHjzBT+B6Jx79BRgA" + "vc49kQA4yxgAAAAASUVORK5CYII=";
28490
+ class InfoTip$1 extends React.Component {
28491
+ constructor(...args) {
28492
+ super(...args);
28493
+ this.state = {
28494
+ hover: false
28495
+ };
28496
+ this.handleMouseEnter = () => {
28497
+ this.setState({
28498
+ hover: true
28499
+ });
28500
+ };
28501
+ this.handleMouseLeave = () => {
28502
+ this.setState({
28503
+ hover: false
28504
+ });
28505
+ };
28506
+ }
28507
+ render() {
28508
+ return /*#__PURE__*/React.createElement("div", {
28509
+ className: css(styles$i.infoTip)
28510
+ }, /*#__PURE__*/React.createElement("img", {
28511
+ alt: "",
28512
+ width: 10,
28513
+ height: 10,
28514
+ src: questionMark,
28515
+ onMouseEnter: this.handleMouseEnter,
28516
+ onMouseLeave: this.handleMouseLeave
28517
+ }), /*#__PURE__*/React.createElement("div", {
28518
+ className: css(styles$i.infoTipContainer),
28519
+ style: {
28520
+ display: this.state.hover ? "block" : "none"
28521
+ }
28522
+ }, /*#__PURE__*/React.createElement("div", {
28523
+ className: css(styles$i.infoTipTriangle)
28524
+ }), /*#__PURE__*/React.createElement("div", {
28525
+ className: css(styles$i.verticalShadow, styles$i.infoTipContentContainer)
28526
+ }, this.props.children)));
28527
+ }
28528
+ }
28529
+
28530
+ /**
28531
+ * A wrapper around info-tip/info-tip.jsx that can be rendered on the
28532
+ * server without causing a checksum mismatch on the client.
28533
+ * (RCSS generates classnames with a randomSuffix, which ensures that any
28534
+ * two sets of generated classnames will not match.)
28535
+ */
28536
+ class InfoTip extends React.Component {
28537
+ constructor(...args) {
28538
+ super(...args);
28539
+ this.state = {
28540
+ didMount: false
28541
+ };
28542
+ }
28543
+ componentDidMount() {
28544
+ /* eslint-disable react/no-did-mount-set-state */
28545
+ this.setState({
28546
+ didMount: true
28547
+ });
28548
+ /* eslint-enable react/no-did-mount-set-state */
28549
+ }
28550
+
28551
+ render() {
28552
+ if (this.state.didMount) {
28553
+ return /*#__PURE__*/React.createElement(InfoTip$1, this.props);
28554
+ }
28555
+ return /*#__PURE__*/React.createElement("div", null);
28556
+ }
28557
+ }
28558
+
28559
+ /**
28560
+ * MultiButtonGroup is an aesthetically pleasing group of buttons,
28561
+ * which allows multiple buttons to be selected at the same time.
28562
+ *
28563
+ * NOTE: This component is almost identical to ./button-group.jsx except that
28564
+ * this component allows multiple selection!
28565
+ */
28566
+ class MultiButtonGroup extends React.Component {
28567
+ constructor(...args) {
28568
+ super(...args);
28569
+ this.toggleSelect = newValue => {
28570
+ const values = (this.props.values || []).slice(0);
28571
+ const allowEmpty = this.props.allowEmpty;
28572
+ if (values.indexOf(newValue) >= 0 && (values.length > 1 || allowEmpty)) {
28573
+ // If the value is already selected, unselect it
28574
+ values.splice(values.indexOf(newValue), 1);
28575
+ } else {
28576
+ // Otherwise merge with other values and return
28577
+ if (values.indexOf(newValue) < 0) {
28578
+ values.push(newValue);
28579
+ }
28580
+ }
28581
+ this.props.onChange(values);
28582
+ };
28583
+ }
28584
+ focus() {
28585
+ var _ReactDOM$findDOMNode;
28586
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
28587
+ (_ReactDOM$findDOMNode = ReactDOM.findDOMNode(this)) == null || _ReactDOM$findDOMNode.focus();
28588
+ return true;
28589
+ }
28590
+ render() {
28591
+ const values = this.props.values || [];
28592
+ const buttons = this.props.buttons.map((button, i) => {
28593
+ const selected = values.indexOf(button.value) >= 0;
28594
+ return /*#__PURE__*/React.createElement("button", {
28595
+ title: button.title,
28596
+ type: "button",
28597
+ id: "" + i,
28598
+ key: "" + i,
28599
+ ref: "button" + i,
28600
+ className: css(styles$h.buttonStyle, selected && styles$h.selectedStyle),
28601
+ onClick: () => this.toggleSelect(button.value)
28602
+ }, button.content || "" + button.value);
28603
+ });
28604
+ const outerStyle = {
28605
+ display: "inline-block"
28606
+ };
28607
+ return /*#__PURE__*/React.createElement("div", {
28608
+ style: outerStyle
28609
+ }, buttons);
28610
+ }
28611
+ }
28612
+ MultiButtonGroup.defaultProps = {
28613
+ values: [],
28614
+ allowEmpty: true
28615
+ };
28616
+ const styles$h = StyleSheet.create({
28617
+ buttonStyle: {
28618
+ backgroundColor: "white",
28619
+ border: "1px solid #ccc",
28620
+ borderLeft: "0",
28621
+ cursor: "pointer",
28622
+ margin: "0",
28623
+ padding: "5px 10px",
28624
+ position: "relative",
28625
+ // for hover
28626
+
28627
+ ":first-child": {
28628
+ borderLeft: "1px solid #ccc",
28629
+ borderTopLeftRadius: "3px",
28630
+ borderBottomLeftRadius: "3px"
28631
+ },
28632
+ ":last-child": {
28633
+ borderRight: "1px solid #ccc",
28634
+ borderTopRightRadius: "3px",
28635
+ borderBottomRightRadius: "3px"
28636
+ },
28637
+ ":hover": {
28638
+ backgroundColor: "#ccc"
28639
+ },
28640
+ ":focus": {
28641
+ zIndex: 2
28642
+ }
28643
+ },
28644
+ selectedStyle: {
28645
+ backgroundColor: "#ddd"
28646
+ }
28647
+ });
28648
+
28649
+ const _excluded$2 = ["onFormatChange", "checkValidity", "useArrowKeys"];
28650
+ const {
28651
+ firstNumericalParse,
28652
+ captureScratchpadTouchStart
28653
+ } = Util;
28654
+ const toNumericString = KhanMath.toNumericString;
28655
+ const getNumericFormat = KhanMath.getNumericFormat;
28656
+
28657
+ /* An input box that accepts only numeric strings
28658
+ *
28659
+ * Calls onChange(value, format) for valid numbers.
28660
+ * Reverts to the current value onBlur or on [ENTER],
28661
+ * but maintains the format (i.e. 3/2, 1 1/2, 150%)
28662
+ * Accepts empty input and sends it to onChange as null
28663
+ * if no numeric placeholder is set.
28664
+ * If given a checkValidity function, will turn
28665
+ * the background/outline red when invalid
28666
+ * If useArrowKeys is set to true, up/down arrows will
28667
+ * increment/decrement integers
28668
+ * Optionally takes a size ("mini", "small", "normal")
28669
+ */
28670
+ class NumberInput extends React.Component {
28671
+ constructor(...args) {
28672
+ super(...args);
28673
+ this.state = {
28674
+ format: this.props.format
28675
+ };
28676
+ /* Return the current "value" of this input
28677
+ * If empty, it returns the placeholder (if it is a number) or null
28678
+ */
28679
+ this.getValue = () => {
28680
+ return this.parseInputValue(
28681
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
28682
+ ReactDOM__default.findDOMNode(this.refs.input).value // eslint-disable-line react/no-string-refs
28683
+ );
28684
+ };
28685
+ /* Return the current string value of this input */
28686
+ this.getStringValue = () => {
28687
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
28688
+ return ReactDOM__default.findDOMNode(this.refs.input).value.toString(); // eslint-disable-line react/no-string-refs
28689
+ };
28690
+ this.parseInputValue = value => {
28691
+ if (value === "") {
28692
+ const placeholder = this.props.placeholder;
28693
+ return _.isFinite(placeholder) ? +placeholder : null;
28694
+ }
28695
+ const result = firstNumericalParse(value);
28696
+ return _.isFinite(result) ? result : this.props.value;
28697
+ };
28698
+ /* Set text input focus to this input */
28699
+ this.focus = () => {
28700
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
28701
+ ReactDOM__default.findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
28702
+ this._handleFocus();
28703
+ };
28704
+ this.blur = () => {
28705
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
28706
+ ReactDOM__default.findDOMNode(this.refs.input).blur(); // eslint-disable-line react/no-string-refs
28707
+ this._handleBlur();
28708
+ };
28709
+ this.setSelectionRange = (selectionStart, selectionEnd) => {
28710
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
28711
+ ReactDOM__default.findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
28712
+ };
28713
+ this.getSelectionStart = () => {
28714
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
28715
+ return ReactDOM__default.findDOMNode(this).selectionStart;
28716
+ };
28717
+ this.getSelectionEnd = () => {
28718
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
28719
+ return ReactDOM__default.findDOMNode(this).selectionEnd;
28720
+ };
28721
+ this._checkValidity = value => {
28722
+ if (value == null) {
28723
+ return true;
28724
+ }
28725
+ const val = firstNumericalParse(value);
28726
+ const checkValidity = this.props.checkValidity;
28727
+ return _.isFinite(val) && checkValidity(val);
28728
+ };
28729
+ this._handleChange = e => {
28730
+ const text = e.target.value;
28731
+ const value = this.parseInputValue(text);
28732
+ const format = getNumericFormat(text);
28733
+ this.props.onChange(value);
28734
+ if (format) {
28735
+ this.props.onFormatChange(value, format);
28736
+ this.setState({
28737
+ format: format
28738
+ });
28739
+ }
28740
+ };
28741
+ this._handleFocus = () => {
28742
+ if (this.props.onFocus) {
28743
+ this.props.onFocus();
28744
+ }
28745
+ };
28746
+ this._handleBlur = e => {
28747
+ // Only continue on blur or "enter"
28748
+ // @ts-expect-error - TS2339 - Property 'keyCode' does not exist on type 'KeyboardEvent<Element> | FocusEvent<Element, Element>'.
28749
+ if (e && e.type === "keypress" && e.keyCode !== 13) {
28750
+ return;
28751
+ }
28752
+ this._setValue(this.props.value, this.state.format);
28753
+ if (this.props.onBlur) {
28754
+ this.props.onBlur();
28755
+ }
28756
+ };
28757
+ this._onKeyDown = e => {
28758
+ if (this.props.onKeyDown) {
28759
+ this.props.onKeyDown(e);
28760
+ }
28761
+ if (!this.props.useArrowKeys || !_.contains(["ArrowUp", "ArrowDown"], e.key)) {
28762
+ return;
28763
+ }
28764
+ let val = this.getValue();
28765
+ if (val !== Math.floor(val)) {
28766
+ return; // bail if not an integer
28767
+ }
28768
+
28769
+ if (e.key === "ArrowUp") {
28770
+ val = val + 1;
28771
+ } else if (e.key === "ArrowDown") {
28772
+ val = val - 1;
28773
+ }
28774
+ if (this._checkValidity(val)) {
28775
+ this.props.onChange(val);
28776
+ }
28777
+ };
28778
+ this._setValue = (val, format) => {
28779
+ // eslint-disable-next-line react/no-string-refs
28780
+ // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
28781
+ $(ReactDOM__default.findDOMNode(this.refs.input)).val(toNumericString(val, format));
28782
+ };
28783
+ }
28784
+ render() {
28785
+ let classes = classNames({
28786
+ "number-input": true,
28787
+ "invalid-input": !this._checkValidity(this.props.value),
28788
+ mini: this.props.size === "mini",
28789
+ small: this.props.size === "small",
28790
+ normal: this.props.size === "normal"
28791
+ });
28792
+ if (this.props.className != null) {
28793
+ classes = classes + " " + this.props.className;
28794
+ }
28795
+ const _this$props = this.props,
28796
+ restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
28797
+ return /*#__PURE__*/React.createElement("input", _extends({}, restProps, {
28798
+ className: classes,
28799
+ type: "text"
28800
+ // eslint-disable-next-line react/no-string-refs
28801
+ ,
28802
+ ref: "input",
28803
+ onChange: this._handleChange,
28804
+ onFocus: this._handleFocus,
28805
+ onBlur: this._handleBlur,
28806
+ onKeyPress: this._handleBlur,
28807
+ onKeyDown: this._onKeyDown
28808
+ // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
28809
+ ,
28810
+ onTouchStart: captureScratchpadTouchStart,
28811
+ defaultValue: toNumericString(this.props.value, this.state.format),
28812
+ value: undefined
28813
+ }));
28814
+ }
28815
+ componentDidUpdate(prevProps) {
28816
+ if (!number.equal(this.getValue(), this.props.value)) {
28817
+ this._setValue(this.props.value, this.state.format);
28818
+ }
28819
+ }
28820
+ }
28821
+ NumberInput.propTypes = {
28822
+ value: PropTypes.number,
28823
+ format: PropTypes.string,
28824
+ placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
28825
+ onChange: PropTypes.func.isRequired,
28826
+ onFormatChange: PropTypes.func,
28827
+ checkValidity: PropTypes.func,
28828
+ size: PropTypes.string,
28829
+ label: PropTypes.oneOf(["put your labels outside your inputs!"])
28830
+ };
28831
+ NumberInput.defaultProps = {
28832
+ value: null,
28833
+ placeholder: null,
28834
+ format: null,
28835
+ onFormatChange: () => null,
28836
+ checkValidity: () => true,
28837
+ useArrowKeys: false
28838
+ };
28839
+
28840
+ /* eslint-disable @babel/no-invalid-this */
28841
+
28842
+ /* A checkbox that syncs its value to props using the
28843
+ * renderer's onChange method, and gets the prop name
28844
+ * dynamically from its props list
28845
+ */
28846
+ const PropCheckBox = createReactClass({
28847
+ displayName: "PropCheckBox",
28848
+ propTypes: {
28849
+ labelAlignment: PropTypes.oneOf(["left", "right"])
28850
+ },
28851
+ DEFAULT_PROPS: {
28852
+ label: null,
28853
+ onChange: null,
28854
+ labelAlignment: "left"
28855
+ },
28856
+ getDefaultProps: function () {
28857
+ return this.DEFAULT_PROPS;
28858
+ },
28859
+ propName: function () {
28860
+ const propName = _.find(_.keys(this.props), function (localPropName) {
28861
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
28862
+ return !_.has(this.DEFAULT_PROPS, localPropName);
28863
+ }, this);
28864
+ if (!propName) {
28865
+ throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
28866
+ }
28867
+ return propName;
28868
+ },
28869
+ _labelAlignLeft: function () {
28870
+ return this.props.labelAlignment === "left";
28871
+ },
28872
+ render: function () {
28873
+ const propName = this.propName();
28874
+ return /*#__PURE__*/React.createElement("label", null, this._labelAlignLeft() && this.props.label, /*#__PURE__*/React.createElement("input", {
28875
+ type: "checkbox",
28876
+ checked: this.props[propName],
28877
+ onChange: this.toggle
28878
+ }), !this._labelAlignLeft() && this.props.label);
28879
+ },
28880
+ toggle: function () {
28881
+ const propName = this.propName();
28882
+ const changes = {};
28883
+ changes[propName] = !this.props[propName];
28884
+ this.props.onChange(changes);
28885
+ }
28886
+ });
28887
+
28888
+ const truth = () => true;
28889
+
28890
+ /* A minor abstraction on top of NumberInput for ranges
28891
+ *
28892
+ */
28893
+ class RangeInput extends React.Component {
28894
+ constructor(...args) {
28895
+ super(...args);
28896
+ this.onChange = (i, newVal) => {
28897
+ const value = this.props.value;
28898
+ if (i === 0) {
28899
+ this.props.onChange([newVal, value[1]]);
28900
+ } else {
28901
+ this.props.onChange([value[0], newVal]);
28902
+ }
28903
+ };
28904
+ }
28905
+ render() {
28906
+ const value = this.props.value;
28907
+ const checkValidity = this.props.checkValidity || truth;
28908
+ return /*#__PURE__*/React.createElement("div", {
28909
+ className: "range-input"
28910
+ }, /*#__PURE__*/React.createElement(NumberInput, _extends({}, this.props, {
28911
+ value: value[0],
28912
+ checkValidity: val => checkValidity([val, value[1]])
28913
+ // eslint-disable-next-line react/jsx-no-bind
28914
+ ,
28915
+ onChange: this.onChange.bind(this, 0),
28916
+ placeholder: this.props.placeholder[0]
28917
+ })), /*#__PURE__*/React.createElement(NumberInput, _extends({}, this.props, {
28918
+ value: value[1],
28919
+ checkValidity: val => checkValidity([value[0], val])
28920
+ // eslint-disable-next-line react/jsx-no-bind
28921
+ ,
28922
+ onChange: this.onChange.bind(this, 1),
28923
+ placeholder: this.props.placeholder[1]
28924
+ })));
28925
+ }
28926
+ }
28927
+ RangeInput.propTypes = {
28928
+ value: PropTypes.array.isRequired,
28929
+ onChange: PropTypes.func.isRequired,
28930
+ placeholder: PropTypes.array,
28931
+ checkValidity: PropTypes.func
28932
+ };
28933
+ RangeInput.defaultProps = {
28934
+ placeholder: [null, null]
28935
+ };
28936
+
28937
+ var components = /*#__PURE__*/Object.freeze({
28938
+ __proto__: null,
28939
+ ButtonGroup: ButtonGroup,
28940
+ Graph: Graph,
28941
+ Graphie: Graphie,
28942
+ HUD: HUD,
28943
+ Icon: Icon,
28944
+ InfoTip: InfoTip,
28945
+ InlineIcon: InlineIcon,
28946
+ MathInput: MathInput,
28947
+ MultiButtonGroup: MultiButtonGroup,
28948
+ NumberInput: NumberInput,
28949
+ PropCheckBox: PropCheckBox,
28950
+ RangeInput: RangeInput,
28951
+ SvgImage: SvgImage,
28952
+ TextInput: TextInput,
28953
+ TextListEditor: TextListEditor
28954
+ });
28955
+
28956
+ /**
28957
+ * If a graphie URL is provided in `backgroundImage`, will return the rendered graphie background.
28958
+ * Otherwise, returns `null`.
28959
+ */
28960
+ const getLegacyGrid = (box, backgroundImage) => {
28961
+ const {
28962
+ url,
28963
+ width,
28964
+ height
28965
+ } = backgroundImage != null ? backgroundImage : {};
28966
+ if (url && typeof url === "string") {
28967
+ const scale = box[0] / interactiveSizes$1.defaultBoxSize;
28968
+ return /*#__PURE__*/React.createElement(View, {
28969
+ style: {
28970
+ position: "absolute",
28971
+ bottom: 0,
28972
+ left: 0
28973
+ }
28974
+ }, /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
28975
+ setAssetStatus
28976
+ }) => /*#__PURE__*/React.createElement(SvgImage, {
28977
+ src: url,
28978
+ width: width,
28979
+ height: height,
28980
+ scale: scale,
28981
+ responsive: false,
28982
+ setAssetStatus: setAssetStatus,
28983
+ alt: ""
28984
+ })));
28985
+ }
28986
+ return null;
28987
+ };
28988
+
28989
+ const _excluded$1 = ["graph"];
28990
+ const renderGraph = props => {
28991
+ const {
28992
+ graph
28993
+ } = props,
28994
+ rest = _objectWithoutPropertiesLoose(props, _excluded$1);
28995
+ switch (graph.type) {
28996
+ case "segment":
28997
+ return /*#__PURE__*/React.createElement(SegmentGraph, _extends({}, rest, {
28998
+ graph: graph,
28999
+ onGraphChange: props.onGraphChange
29000
+ }));
29001
+ }
29002
+ };
29003
+ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
29004
+ var _props$backgroundImag, _props$backgroundImag2, _props$backgroundImag3, _props$backgroundImag4;
29005
+ // Storing the gradable state in a ref so that it can be updated without
29006
+ // causing a re-render.
29007
+ const graphRef = React.useRef(props.graph);
29008
+ const handleGraphUpdate = callback => {
29009
+ graphRef.current = callback(graphRef.current);
29010
+ };
29011
+ React.useImperativeHandle(ref, () => ({
29012
+ getUserInput: () => graphRef.current
29013
+ }));
29014
+ const [width, height] = getInteractiveBoxFromSizeClass(props.containerSizeClass);
29015
+ const legacyGrid = getLegacyGrid([width, height], props.backgroundImage);
29016
+ return /*#__PURE__*/React.createElement(View, {
29017
+ style: {
29018
+ width: (_props$backgroundImag = (_props$backgroundImag2 = props.backgroundImage) == null ? void 0 : _props$backgroundImag2.width) != null ? _props$backgroundImag : width,
29019
+ height: (_props$backgroundImag3 = (_props$backgroundImag4 = props.backgroundImage) == null ? void 0 : _props$backgroundImag4.height) != null ? _props$backgroundImag3 : height,
29020
+ position: "relative"
29021
+ }
29022
+ }, legacyGrid, /*#__PURE__*/React.createElement(View, {
29023
+ style: {
29024
+ position: "absolute",
29025
+ bottom: 0,
29026
+ left: 0
29027
+ }
29028
+ }, /*#__PURE__*/React.createElement(Mafs, {
29029
+ viewBox: {
29030
+ x: props.range[0],
29031
+ y: props.range[1],
29032
+ padding: 0
29033
+ },
29034
+ pan: false,
29035
+ zoom: false,
29036
+ width: width,
29037
+ height: height
29038
+ }, !!legacyGrid && /*#__PURE__*/React.createElement(Grid, props), renderGraph(_extends({}, props, {
29039
+ onGraphChange: handleGraphUpdate
29040
+ })))));
29041
+ });
29042
+
28176
29043
  const {
28177
29044
  DeprecationMixin
28178
29045
  } = Util;
@@ -28250,6 +29117,7 @@ class InteractiveGraph extends React.Component {
28250
29117
  this.sinusoid = void 0;
28251
29118
  this.trashCan = void 0;
28252
29119
  this.vertHairline = void 0;
29120
+ this.mafsRef = /*#__PURE__*/React.createRef();
28253
29121
  this.state = {
28254
29122
  shouldShowInstructions: _getShouldShowInstructions(this.props)
28255
29123
  };
@@ -29329,11 +30197,10 @@ class InteractiveGraph extends React.Component {
29329
30197
  });
29330
30198
  };
29331
30199
  this.getUserInput = () => {
29332
- return InteractiveGraph.getUserInputFromProps(this.props);
29333
- };
29334
- this.simpleValidate = rubric => {
29335
- return InteractiveGraph.validate(this.getUserInput(), rubric, this);
30200
+ var _this$mafsRef$current, _this$mafsRef$current2;
30201
+ return (_this$mafsRef$current = (_this$mafsRef$current2 = this.mafsRef.current) == null || _this$mafsRef$current2.getUserInput == null ? void 0 : _this$mafsRef$current2.getUserInput()) != null ? _this$mafsRef$current : InteractiveGraph.getUserInputFromProps(this.props);
29336
30202
  };
30203
+ this.simpleValidate = rubric => InteractiveGraph.validate(this.getUserInput(), rubric, this);
29337
30204
  this.focus = $.noop;
29338
30205
  }
29339
30206
  // TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
@@ -29341,9 +30208,11 @@ class InteractiveGraph extends React.Component {
29341
30208
  DeprecationMixin.UNSAFE_componentWillMount.call(this);
29342
30209
  }
29343
30210
  componentDidMount() {
29344
- // eslint-disable-next-line react/no-string-refs
29345
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
29346
- this.setGraphie(this.refs.graph.graphie());
30211
+ if (this.refs.graph) {
30212
+ // eslint-disable-next-line react/no-string-refs
30213
+ // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
30214
+ this.setGraphie(this.refs.graph.graphie());
30215
+ }
29347
30216
  }
29348
30217
  UNSAFE_componentWillReceiveProps(nextProps) {
29349
30218
  var _this$props$backgroun, _nextProps$background;
@@ -29383,9 +30252,19 @@ class InteractiveGraph extends React.Component {
29383
30252
  areSegmentGraphsEqual(prevGraph, currentGraph) {
29384
30253
  return prevGraph.numSegments !== currentGraph.numSegments;
29385
30254
  }
30255
+ // const segment: boolean = useFeatureIsOn("mafs-segment-graph");
30256
+ // <Renderer apiOptions={{flags: {mafs: {segment}}}}
29386
30257
  render() {
30258
+ var _this$props$apiOption;
30259
+ // Mafs shim
30260
+ if ((_this$props$apiOption = this.props.apiOptions) != null && (_this$props$apiOption = _this$props$apiOption.flags) != null && (_this$props$apiOption = _this$props$apiOption["mafs"]) != null && _this$props$apiOption[this.props.graph.type]) {
30261
+ return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, this.props, {
30262
+ ref: this.mafsRef
30263
+ }));
30264
+ }
29387
30265
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
29388
30266
  let instructions;
30267
+ // isClickToAddPoints() only applies to points and polygons
29389
30268
  if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
29390
30269
  if (this.props.graph.type === "point") {
29391
30270
  instructions = i18n._("Click to add points");
@@ -30688,7 +31567,7 @@ var globalConstants = /*#__PURE__*/Object.freeze({
30688
31567
  pureLgMax: pureLgMax
30689
31568
  });
30690
31569
 
30691
- const colors$1 = {
31570
+ const colors = {
30692
31571
  white: "#FFFFFF",
30693
31572
  gray98: "#FAFAFA",
30694
31573
  gray97: "#F6F7F7",
@@ -30748,7 +31627,7 @@ const colors$1 = {
30748
31627
  };
30749
31628
  const borderRadius = 4;
30750
31629
  const breadcrumbStyles = {
30751
- color: colors$1.breadcrumbs,
31630
+ color: colors.breadcrumbs,
30752
31631
  fontFamily: "inherit",
30753
31632
  fontSize: 15,
30754
31633
  fontWeight: "bold",
@@ -30818,14 +31697,14 @@ const typography = {
30818
31697
  },
30819
31698
  // For callouts
30820
31699
  smallHeading: {
30821
- color: colors$1.gray25,
31700
+ color: colors.gray25,
30822
31701
  fontFamily: "inherit",
30823
31702
  fontSize: 17,
30824
31703
  fontWeight: "bold",
30825
31704
  lineHeight: "23px"
30826
31705
  },
30827
31706
  smallHeadingMobile: {
30828
- color: colors$1.gray25,
31707
+ color: colors.gray25,
30829
31708
  fontFamily: "inherit",
30830
31709
  fontSize: 15,
30831
31710
  fontWeight: "bold",
@@ -30833,7 +31712,7 @@ const typography = {
30833
31712
  },
30834
31713
  // Accent headings
30835
31714
  accentHeading: {
30836
- color: colors$1.gray68,
31715
+ color: colors.gray68,
30837
31716
  fontFamily: "inherit",
30838
31717
  fontSize: 15,
30839
31718
  fontWeight: "bold",
@@ -30939,7 +31818,7 @@ const typography = {
30939
31818
  // HACK(kevinb): temporary wonder blocks styles for header only
30940
31819
  // TODO(kevinb): use components from wonder-blocks-typography instead
30941
31820
  wonderBlocksTitle: {
30942
- color: colors$1.white,
31821
+ color: colors.white,
30943
31822
  fontWeight: 900,
30944
31823
  // "Black" weight
30945
31824
  fontSize: 28,
@@ -30961,7 +31840,7 @@ const typography = {
30961
31840
 
30962
31841
  var globalStyles = /*#__PURE__*/Object.freeze({
30963
31842
  __proto__: null,
30964
- colors: colors$1,
31843
+ colors: colors,
30965
31844
  borderRadius: borderRadius,
30966
31845
  fonts: fonts,
30967
31846
  typography: typography
@@ -31023,7 +31902,7 @@ const HideAnswersToggle = props => {
31023
31902
  const switchId = idFactory.get("hide-answers-toggle");
31024
31903
  const labelId = idFactory.get("hide-answers-label");
31025
31904
  return /*#__PURE__*/React.createElement(View, {
31026
- style: styles$j.switchWrapper
31905
+ style: styles$g.switchWrapper
31027
31906
  }, /*#__PURE__*/React.createElement(Switch, {
31028
31907
  id: switchId,
31029
31908
  checked: props.areAnswersHidden,
@@ -31035,7 +31914,7 @@ const HideAnswersToggle = props => {
31035
31914
  tag: "label"
31036
31915
  }, strings.hideAnswersToggleLabel));
31037
31916
  };
31038
- const styles$j = StyleSheet.create({
31917
+ const styles$g = StyleSheet.create({
31039
31918
  switchWrapper: {
31040
31919
  display: "flex",
31041
31920
  flexDirection: "row",
@@ -31088,13 +31967,13 @@ const AnswerPill = props => {
31088
31967
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31089
31968
  onClick: correct ? undefined : onClick,
31090
31969
  ref: ref,
31091
- style: [style, popperStyle, styles$i.pill, correct && styles$i.correct, incorrect && styles$i.incorrect, (focused || hovered) && BringToFront]
31970
+ style: [style, popperStyle, styles$f.pill, correct && styles$f.correct, incorrect && styles$f.incorrect, (focused || hovered) && BringToFront]
31092
31971
  }, /*#__PURE__*/React.createElement(Renderer, {
31093
31972
  content: answerString,
31094
31973
  inline: true
31095
31974
  })));
31096
31975
  };
31097
- const styles$i = StyleSheet.create({
31976
+ const styles$f = StyleSheet.create({
31098
31977
  correct: {
31099
31978
  // WB green darkened by 18%
31100
31979
  backgroundColor: "#00880b"
@@ -31147,23 +32026,23 @@ class Marker extends React.Component {
31147
32026
  icon: iconNull
31148
32027
  };
31149
32028
  if (showCorrectness) {
31150
- iconStyles = [styles$h.markerGraded, showCorrectness === "correct" ? styles$h.markerCorrect : styles$h.markerIncorrect, isOpen && styles$h.markerSelected];
32029
+ iconStyles = [styles$e.markerGraded, showCorrectness === "correct" ? styles$e.markerCorrect : styles$e.markerIncorrect, isOpen && styles$e.markerSelected];
31151
32030
  args = _extends({}, args, {
31152
32031
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
31153
32032
  });
31154
32033
  } else if (selectedAnswers && selectedAnswers.length > 0) {
31155
- iconStyles = [styles$h.markerFilled, isOpen && styles$h.markerSelected];
32034
+ iconStyles = [styles$e.markerFilled, isOpen && styles$e.markerSelected];
31156
32035
  } else if (isOpen) {
31157
- iconStyles = [styles$h.markerSelected];
32036
+ iconStyles = [styles$e.markerSelected];
31158
32037
  args = _extends({}, args, {
31159
32038
  icon: iconChevronDown,
31160
32039
  size: 8
31161
32040
  });
31162
32041
  } else if (showPulsate) {
31163
- iconStyles = [styles$h.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$h.markerUnfilledPulsateOnce : showPulsate && styles$h.markerUnfilledPulsateInfinite];
32042
+ iconStyles = [styles$e.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$e.markerUnfilledPulsateOnce : showPulsate && styles$e.markerUnfilledPulsateInfinite];
31164
32043
  }
31165
32044
  return /*#__PURE__*/React.createElement(View, {
31166
- style: [styles$h.markerIcon, iconStyles],
32045
+ style: [styles$e.markerIcon, iconStyles],
31167
32046
  ref: node => this._icon = node
31168
32047
  }, /*#__PURE__*/React.createElement(Icon, args));
31169
32048
  }
@@ -31185,7 +32064,7 @@ class Marker extends React.Component {
31185
32064
  const markerDisabled = showCorrectness === "correct";
31186
32065
  const active = hovered || focused;
31187
32066
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
31188
- style: [styles$h.marker, active && !markerDisabled && styles$h.markerActive]
32067
+ style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive]
31189
32068
  // already translated in: /widgets/graded-group.tsx
31190
32069
  ,
31191
32070
  "aria-label": markerDisabled ? i18n._("Correct!") : label
@@ -31203,7 +32082,7 @@ class Marker extends React.Component {
31203
32082
  Marker.defaultProps = {
31204
32083
  selected: []
31205
32084
  };
31206
- const styles$h = StyleSheet.create({
32085
+ const styles$e = StyleSheet.create({
31207
32086
  marker: {
31208
32087
  position: "absolute",
31209
32088
  backgroundColor: Color.white,
@@ -31773,13 +32652,13 @@ class LabelImage extends React.Component {
31773
32652
  const promptString = isMobile ? multipleAnswers ? i18n._("Tap each dot on the image to select all answers that apply.") : i18n._("Tap each dot on the image to select an answer.") : multipleAnswers ? i18n._("Click each dot on the image to select all answers that apply.") : i18n._("Click each dot on the image to select an answer.");
31774
32653
  const choicesString = i18n._("Choices:");
31775
32654
  return /*#__PURE__*/React.createElement("div", {
31776
- className: classNames("perseus-label-image-widget-instructions", css(styles$g.instructions))
32655
+ className: classNames("perseus-label-image-widget-instructions", css(styles$d.instructions))
31777
32656
  }, /*#__PURE__*/React.createElement("div", {
31778
- className: css(styles$g.instructionsCaption)
32657
+ className: css(styles$d.instructionsCaption)
31779
32658
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React.createElement("div", {
31780
- className: css(styles$g.instructionsChoices)
32659
+ className: css(styles$d.instructionsChoices)
31781
32660
  }, choices.map((choice, index) => /*#__PURE__*/React.createElement("div", {
31782
- className: css(styles$g.instructionsChoice),
32661
+ className: css(styles$d.instructionsChoice),
31783
32662
  key: index
31784
32663
  }, /*#__PURE__*/React.createElement(Renderer, {
31785
32664
  content: choice
@@ -31796,20 +32675,20 @@ class LabelImage extends React.Component {
31796
32675
  activeMarkerIndex
31797
32676
  } = this.state;
31798
32677
  return /*#__PURE__*/React.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React.createElement("div", {
31799
- className: css(styles$g.markersCanvas),
32678
+ className: css(styles$d.markersCanvas),
31800
32679
  style: {
31801
32680
  maxWidth: imageWidth,
31802
32681
  maxHeight: imageHeight
31803
32682
  }
31804
32683
  }, /*#__PURE__*/React.createElement("div", {
31805
- className: css(styles$g.imageContainer,
32684
+ className: css(styles$d.imageContainer,
31806
32685
  // Ensure image interaction is disabled while answer
31807
32686
  // choices popup is visible. This addresses specific
31808
32687
  // case where user may click on question image to
31809
32688
  // dismiss the popup. If the image is larger in size
31810
32689
  // than its rendered in the widget, this would
31811
32690
  // result in a zoom of the image.
31812
- activeMarkerIndex !== -1 && styles$g.imageInteractionDisabled)
32691
+ activeMarkerIndex !== -1 && styles$d.imageInteractionDisabled)
31813
32692
  }, /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
31814
32693
  setAssetStatus
31815
32694
  }) => /*#__PURE__*/React.createElement(SvgImage, {
@@ -31833,7 +32712,7 @@ class LabelImage extends React.Component {
31833
32712
  }));
31834
32713
  }
31835
32714
  }
31836
- const styles$g = StyleSheet.create({
32715
+ const styles$d = StyleSheet.create({
31837
32716
  instructions: {
31838
32717
  paddingBottom: 16
31839
32718
  },
@@ -32190,7 +33069,7 @@ class Placeholder extends React.Component {
32190
33069
  const {
32191
33070
  layout
32192
33071
  } = this.props;
32193
- const className = css(styles$f.card, styles$f.placeholder, layout === Layout.HORIZONTAL && styles$f.horizontalCard);
33072
+ const className = css(styles$c.card, styles$c.placeholder, layout === Layout.HORIZONTAL && styles$c.horizontalCard);
32194
33073
  const style = {
32195
33074
  width: this.props.width,
32196
33075
  height: this.props.height
@@ -32373,7 +33252,7 @@ class Draggable extends React.Component {
32373
33252
  // We need to keep backwards compatbility with rules specified directly
32374
33253
  // in CSS. Hence the hacky tacking on of manual classNames.
32375
33254
  // See sortable.less for details.
32376
- let className = 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";
33255
+ let className = css(styles$c.card, styles$c.draggable, layout === Layout.HORIZONTAL && styles$c.horizontalCard, layout === Layout.VERTICAL && styles$c.verticalCard, type === ItemState.DRAGGING && styles$c.dragging, type === ItemState.DISABLED && styles$c.disabled, !includePadding && styles$c.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
32377
33256
  if (!includePadding) {
32378
33257
  className += " perseus-sortable-draggable-unpadded";
32379
33258
  }
@@ -32580,7 +33459,7 @@ class Sortable extends React.Component {
32580
33459
  } = this.props;
32581
33460
  // We need to keep backwards compatbility with rules specified directly
32582
33461
  // in CSS. See sortable.less for details.
32583
- const className = css(styles$f.sortable) + " perseus-sortable";
33462
+ const className = css(styles$c.sortable) + " perseus-sortable";
32584
33463
  const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
32585
33464
  const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
32586
33465
  _.each(this.state.items, function (item, i, items) {
@@ -32822,7 +33701,7 @@ Sortable.defaultProps = {
32822
33701
  linterContext: PerseusLinter.linterContextDefault,
32823
33702
  waitForTexRendererToLoad: true
32824
33703
  };
32825
- const styles$f = StyleSheet.create({
33704
+ const styles$c = StyleSheet.create({
32826
33705
  sortable: {
32827
33706
  boxSizing: "border-box",
32828
33707
  float: "left",
@@ -32984,23 +33863,23 @@ class Matcher extends React.Component {
32984
33863
  };
32985
33864
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
32986
33865
  return /*#__PURE__*/React.createElement("table", {
32987
- className: css(styles$e.widget) + " " + HACKY_CSS_CLASSNAME
33866
+ className: css(styles$b.widget) + " " + HACKY_CSS_CLASSNAME
32988
33867
  }, /*#__PURE__*/React.createElement("tbody", null, showLabels && /*#__PURE__*/React.createElement("tr", {
32989
- className: css(styles$e.row)
33868
+ className: css(styles$b.row)
32990
33869
  }, /*#__PURE__*/React.createElement("th", {
32991
- className: css(styles$e.column, styles$e.columnLabel)
33870
+ className: css(styles$b.column, styles$b.columnLabel)
32992
33871
  }, /*#__PURE__*/React.createElement(Renderer, {
32993
33872
  content: this.props.labels[0] || "...",
32994
33873
  linterContext: this.props.linterContext
32995
33874
  })), /*#__PURE__*/React.createElement("th", {
32996
- className: css(styles$e.column, styles$e.columnRight, styles$e.columnLabel)
33875
+ className: css(styles$b.column, styles$b.columnRight, styles$b.columnLabel)
32997
33876
  }, /*#__PURE__*/React.createElement(Renderer, {
32998
33877
  content: this.props.labels[1] || "...",
32999
33878
  linterContext: this.props.linterContext
33000
33879
  }))), /*#__PURE__*/React.createElement("tr", {
33001
- className: css(styles$e.row)
33880
+ className: css(styles$b.row)
33002
33881
  }, /*#__PURE__*/React.createElement("td", {
33003
- className: css(styles$e.column)
33882
+ className: css(styles$b.column)
33004
33883
  }, /*#__PURE__*/React.createElement(Sortable, {
33005
33884
  options: left,
33006
33885
  layout: Layout.VERTICAL,
@@ -33015,7 +33894,7 @@ class Matcher extends React.Component {
33015
33894
  ,
33016
33895
  ref: "left"
33017
33896
  })), /*#__PURE__*/React.createElement("td", {
33018
- className: css(styles$e.column, styles$e.columnRight)
33897
+ className: css(styles$b.column, styles$b.columnRight)
33019
33898
  }, /*#__PURE__*/React.createElement(Sortable
33020
33899
  // @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33021
33900
  , {
@@ -33068,7 +33947,7 @@ _.extend(Matcher, {
33068
33947
  });
33069
33948
  const padding = 5;
33070
33949
  const border = "1px solid #444";
33071
- const styles$e = StyleSheet.create({
33950
+ const styles$b = StyleSheet.create({
33072
33951
  widget: {
33073
33952
  paddingTop: padding,
33074
33953
  maxWidth: "100%",
@@ -33101,197 +33980,6 @@ var Matcher$1 = {
33101
33980
  isLintable: true
33102
33981
  };
33103
33982
 
33104
- const _excluded$1 = ["onFormatChange", "checkValidity", "useArrowKeys"];
33105
- const {
33106
- firstNumericalParse,
33107
- captureScratchpadTouchStart
33108
- } = Util;
33109
- const toNumericString = KhanMath.toNumericString;
33110
- const getNumericFormat = KhanMath.getNumericFormat;
33111
-
33112
- /* An input box that accepts only numeric strings
33113
- *
33114
- * Calls onChange(value, format) for valid numbers.
33115
- * Reverts to the current value onBlur or on [ENTER],
33116
- * but maintains the format (i.e. 3/2, 1 1/2, 150%)
33117
- * Accepts empty input and sends it to onChange as null
33118
- * if no numeric placeholder is set.
33119
- * If given a checkValidity function, will turn
33120
- * the background/outline red when invalid
33121
- * If useArrowKeys is set to true, up/down arrows will
33122
- * increment/decrement integers
33123
- * Optionally takes a size ("mini", "small", "normal")
33124
- */
33125
- class NumberInput extends React.Component {
33126
- constructor(...args) {
33127
- super(...args);
33128
- this.state = {
33129
- format: this.props.format
33130
- };
33131
- /* Return the current "value" of this input
33132
- * If empty, it returns the placeholder (if it is a number) or null
33133
- */
33134
- this.getValue = () => {
33135
- return this.parseInputValue(
33136
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
33137
- ReactDOM__default.findDOMNode(this.refs.input).value // eslint-disable-line react/no-string-refs
33138
- );
33139
- };
33140
- /* Return the current string value of this input */
33141
- this.getStringValue = () => {
33142
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
33143
- return ReactDOM__default.findDOMNode(this.refs.input).value.toString(); // eslint-disable-line react/no-string-refs
33144
- };
33145
- this.parseInputValue = value => {
33146
- if (value === "") {
33147
- const placeholder = this.props.placeholder;
33148
- return _.isFinite(placeholder) ? +placeholder : null;
33149
- }
33150
- const result = firstNumericalParse(value);
33151
- return _.isFinite(result) ? result : this.props.value;
33152
- };
33153
- /* Set text input focus to this input */
33154
- this.focus = () => {
33155
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
33156
- ReactDOM__default.findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
33157
- this._handleFocus();
33158
- };
33159
- this.blur = () => {
33160
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
33161
- ReactDOM__default.findDOMNode(this.refs.input).blur(); // eslint-disable-line react/no-string-refs
33162
- this._handleBlur();
33163
- };
33164
- this.setSelectionRange = (selectionStart, selectionEnd) => {
33165
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
33166
- ReactDOM__default.findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
33167
- };
33168
- this.getSelectionStart = () => {
33169
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
33170
- return ReactDOM__default.findDOMNode(this).selectionStart;
33171
- };
33172
- this.getSelectionEnd = () => {
33173
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
33174
- return ReactDOM__default.findDOMNode(this).selectionEnd;
33175
- };
33176
- this._checkValidity = value => {
33177
- if (value == null) {
33178
- return true;
33179
- }
33180
- const val = firstNumericalParse(value);
33181
- const checkValidity = this.props.checkValidity;
33182
- return _.isFinite(val) && checkValidity(val);
33183
- };
33184
- this._handleChange = e => {
33185
- const text = e.target.value;
33186
- const value = this.parseInputValue(text);
33187
- const format = getNumericFormat(text);
33188
- this.props.onChange(value);
33189
- if (format) {
33190
- this.props.onFormatChange(value, format);
33191
- this.setState({
33192
- format: format
33193
- });
33194
- }
33195
- };
33196
- this._handleFocus = () => {
33197
- if (this.props.onFocus) {
33198
- this.props.onFocus();
33199
- }
33200
- };
33201
- this._handleBlur = e => {
33202
- // Only continue on blur or "enter"
33203
- // @ts-expect-error - TS2339 - Property 'keyCode' does not exist on type 'KeyboardEvent<Element> | FocusEvent<Element, Element>'.
33204
- if (e && e.type === "keypress" && e.keyCode !== 13) {
33205
- return;
33206
- }
33207
- this._setValue(this.props.value, this.state.format);
33208
- if (this.props.onBlur) {
33209
- this.props.onBlur();
33210
- }
33211
- };
33212
- this._onKeyDown = e => {
33213
- if (this.props.onKeyDown) {
33214
- this.props.onKeyDown(e);
33215
- }
33216
- if (!this.props.useArrowKeys || !_.contains(["ArrowUp", "ArrowDown"], e.key)) {
33217
- return;
33218
- }
33219
- let val = this.getValue();
33220
- if (val !== Math.floor(val)) {
33221
- return; // bail if not an integer
33222
- }
33223
-
33224
- if (e.key === "ArrowUp") {
33225
- val = val + 1;
33226
- } else if (e.key === "ArrowDown") {
33227
- val = val - 1;
33228
- }
33229
- if (this._checkValidity(val)) {
33230
- this.props.onChange(val);
33231
- }
33232
- };
33233
- this._setValue = (val, format) => {
33234
- // eslint-disable-next-line react/no-string-refs
33235
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
33236
- $(ReactDOM__default.findDOMNode(this.refs.input)).val(toNumericString(val, format));
33237
- };
33238
- }
33239
- render() {
33240
- let classes = classNames({
33241
- "number-input": true,
33242
- "invalid-input": !this._checkValidity(this.props.value),
33243
- mini: this.props.size === "mini",
33244
- small: this.props.size === "small",
33245
- normal: this.props.size === "normal"
33246
- });
33247
- if (this.props.className != null) {
33248
- classes = classes + " " + this.props.className;
33249
- }
33250
- const _this$props = this.props,
33251
- restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
33252
- return /*#__PURE__*/React.createElement("input", _extends({}, restProps, {
33253
- className: classes,
33254
- type: "text"
33255
- // eslint-disable-next-line react/no-string-refs
33256
- ,
33257
- ref: "input",
33258
- onChange: this._handleChange,
33259
- onFocus: this._handleFocus,
33260
- onBlur: this._handleBlur,
33261
- onKeyPress: this._handleBlur,
33262
- onKeyDown: this._onKeyDown
33263
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
33264
- ,
33265
- onTouchStart: captureScratchpadTouchStart,
33266
- defaultValue: toNumericString(this.props.value, this.state.format),
33267
- value: undefined
33268
- }));
33269
- }
33270
- componentDidUpdate(prevProps) {
33271
- if (!number.equal(this.getValue(), this.props.value)) {
33272
- this._setValue(this.props.value, this.state.format);
33273
- }
33274
- }
33275
- }
33276
- NumberInput.propTypes = {
33277
- value: PropTypes.number,
33278
- format: PropTypes.string,
33279
- placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
33280
- onChange: PropTypes.func.isRequired,
33281
- onFormatChange: PropTypes.func,
33282
- checkValidity: PropTypes.func,
33283
- size: PropTypes.string,
33284
- label: PropTypes.oneOf(["put your labels outside your inputs!"])
33285
- };
33286
- NumberInput.defaultProps = {
33287
- value: null,
33288
- placeholder: null,
33289
- format: null,
33290
- onFormatChange: () => null,
33291
- checkValidity: () => true,
33292
- useArrowKeys: false
33293
- };
33294
-
33295
33983
  // Type imports
33296
33984
 
33297
33985
  const {
@@ -33935,9 +34623,9 @@ function drawText(ctx, item) {
33935
34623
  if (item.value === null) {
33936
34624
  return;
33937
34625
  }
33938
- ctx.fillStyle = styles$d.fgColor;
33939
- ctx.font = styles$d.font;
33940
- ctx.fillText(item.value, item.pos[0] - styles$d.fontSizePx / 2 + 1, item.pos[1] + styles$d.fontSizePx / 2);
34626
+ ctx.fillStyle = styles$a.fgColor;
34627
+ ctx.font = styles$a.font;
34628
+ ctx.fillText(item.value, item.pos[0] - styles$a.fontSizePx / 2 + 1, item.pos[1] + styles$a.fontSizePx / 2);
33941
34629
  }
33942
34630
 
33943
34631
  /**
@@ -33958,16 +34646,16 @@ function drawText(ctx, item) {
33958
34646
  function drawDoubleLine(ctx, item) {
33959
34647
  // Outer line that forms both of the bond lines.
33960
34648
  let path = new Path2D();
33961
- ctx.lineWidth = 5 * styles$d.lineWidth;
33962
- ctx.strokeStyle = styles$d.fgColor;
34649
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34650
+ ctx.strokeStyle = styles$a.fgColor;
33963
34651
  path.moveTo(item.startPos[0], item.startPos[1]);
33964
34652
  path.lineTo(item.endPos[0], item.endPos[1]);
33965
34653
  ctx.stroke(path);
33966
34654
 
33967
34655
  // Inner white line that separates the two bond lines.
33968
34656
  path = new Path2D();
33969
- ctx.lineWidth = 3 * styles$d.lineWidth;
33970
- ctx.strokeStyle = styles$d.bgColor;
34657
+ ctx.lineWidth = 3 * styles$a.lineWidth;
34658
+ ctx.strokeStyle = styles$a.bgColor;
33971
34659
  path.moveTo(item.startPos[0], item.startPos[1]);
33972
34660
  path.lineTo(item.endPos[0], item.endPos[1]);
33973
34661
  ctx.stroke(path);
@@ -33994,16 +34682,16 @@ function drawTripleLine(ctx, item) {
33994
34682
 
33995
34683
  // Outer line that will form the two outer bond lines.
33996
34684
  let path = new Path2D();
33997
- ctx.lineWidth = 7 * styles$d.lineWidth;
33998
- ctx.strokeStyle = styles$d.fgColor;
34685
+ ctx.lineWidth = 7 * styles$a.lineWidth;
34686
+ ctx.strokeStyle = styles$a.fgColor;
33999
34687
  path.moveTo(item.startPos[0], item.startPos[1]);
34000
34688
  path.lineTo(item.endPos[0], item.endPos[1]);
34001
34689
  ctx.stroke(path);
34002
34690
 
34003
34691
  // Middle white line that separates the bonds
34004
34692
  path = new Path2D();
34005
- ctx.lineWidth = 5 * styles$d.lineWidth;
34006
- ctx.strokeStyle = styles$d.bgColor;
34693
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34694
+ ctx.strokeStyle = styles$a.bgColor;
34007
34695
  path.moveTo(item.startPos[0], item.startPos[1]);
34008
34696
  path.lineTo(item.endPos[0], item.endPos[1]);
34009
34697
  ctx.stroke(path);
@@ -34025,8 +34713,8 @@ function drawTripleLine(ctx, item) {
34025
34713
  */
34026
34714
  function drawLine(ctx, item) {
34027
34715
  const path = new Path2D();
34028
- ctx.lineWidth = styles$d.lineWidth;
34029
- ctx.strokeStyle = styles$d.fgColor;
34716
+ ctx.lineWidth = styles$a.lineWidth;
34717
+ ctx.strokeStyle = styles$a.fgColor;
34030
34718
  path.moveTo(item.startPos[0], item.startPos[1]);
34031
34719
  path.lineTo(item.endPos[0], item.endPos[1]);
34032
34720
  ctx.stroke(path);
@@ -34078,7 +34766,7 @@ function compareElements(item0, item1) {
34078
34766
  function draw(ctx, items) {
34079
34767
  items.sort(compareElements).forEach(drawItem(ctx));
34080
34768
  }
34081
- const styles$d = {
34769
+ const styles$a = {
34082
34770
  bgColor: "rgb(255, 255, 255)",
34083
34771
  fgColor: "rgb(0, 0, 0)",
34084
34772
  fontSizePx: 12,
@@ -36640,7 +37328,7 @@ class HighlightRenderer extends React.PureComponent {
36640
37328
  const rects = this.state.cachedHighlightRects;
36641
37329
  return /*#__PURE__*/React.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React.createElement("div", {
36642
37330
  key: index,
36643
- className: css(styles$c.highlightRect),
37331
+ className: css(styles$9.highlightRect),
36644
37332
  style: {
36645
37333
  // NOTE(mdr): We apply `position: absolute` here
36646
37334
  // rather than in Aphrodite styles, because
@@ -36659,7 +37347,7 @@ class HighlightRenderer extends React.PureComponent {
36659
37347
  })));
36660
37348
  }
36661
37349
  }
36662
- const styles$c = StyleSheet.create({
37350
+ const styles$9 = StyleSheet.create({
36663
37351
  highlightRect: {
36664
37352
  background: "#fffabe" // highlighter yellow :)
36665
37353
  }
@@ -36740,7 +37428,7 @@ class HighlightTooltip extends React.PureComponent {
36740
37428
  // TooltipContent wouldn't let me overwrite
36741
37429
  // user-select and onClick
36742
37430
  const content = /*#__PURE__*/React.createElement("div", {
36743
- className: css(styles$b.tooltipLabel),
37431
+ className: css(styles$8.tooltipLabel),
36744
37432
  onClick: this.props.onClick
36745
37433
  }, this.props.label);
36746
37434
  const style = {
@@ -36760,7 +37448,7 @@ class HighlightTooltip extends React.PureComponent {
36760
37448
  }, /*#__PURE__*/React.createElement("div", null)));
36761
37449
  }
36762
37450
  }
36763
- const styles$b = StyleSheet.create({
37451
+ const styles$8 = StyleSheet.create({
36764
37452
  tooltipLabel: {
36765
37453
  // Unlike most tooltip contents, we don't want this label to be
36766
37454
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -37312,7 +38000,7 @@ class HighlightableContent extends React.PureComponent {
37312
38000
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
37313
38001
  const buildHighlight = r => this._buildHighlight(r);
37314
38002
  return /*#__PURE__*/React.createElement("div", {
37315
- className: css(styles$a.container),
38003
+ className: css(styles$7.container),
37316
38004
  ref: container => this._container = container
37317
38005
  }, /*#__PURE__*/React.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React.createElement(HighlightingUI, {
37318
38006
  buildHighlight: buildHighlight,
@@ -37333,14 +38021,14 @@ class HighlightableContent extends React.PureComponent {
37333
38021
  onAddHighlight: this._handleAddHighlight,
37334
38022
  onRemoveHighlight: this._handleRemoveHighlight
37335
38023
  })), /*#__PURE__*/React.createElement("div", {
37336
- className: css(styles$a.content),
38024
+ className: css(styles$7.content),
37337
38025
  ref: content => this._content = content
37338
38026
  }, /*#__PURE__*/React.createElement(WordIndexer, {
37339
38027
  onWordsUpdate: this._handleWordsUpdate
37340
38028
  }, this.props.children)));
37341
38029
  }
37342
38030
  }
37343
- const styles$a = StyleSheet.create({
38031
+ const styles$7 = StyleSheet.create({
37344
38032
  // We render content with z-index 1, and highlights with z-index 0, so that
37345
38033
  // content will receive the browser's native pointer events. (Highlights
37346
38034
  // have their own magic code to manage hover detection, despite being
@@ -37740,7 +38428,7 @@ class LineHeightMeasurer extends React.Component {
37740
38428
  }
37741
38429
  render() {
37742
38430
  return /*#__PURE__*/React.createElement("div", {
37743
- className: css(styles$9.measurer),
38431
+ className: css(styles$6.measurer),
37744
38432
  "aria-hidden": "true"
37745
38433
  }, /*#__PURE__*/React.createElement("div", {
37746
38434
  ref: ref => this._line = ref,
@@ -37748,7 +38436,7 @@ class LineHeightMeasurer extends React.Component {
37748
38436
  }, "Line Height Measurement"));
37749
38437
  }
37750
38438
  }
37751
- const styles$9 = StyleSheet.create({
38439
+ const styles$6 = StyleSheet.create({
37752
38440
  measurer: {
37753
38441
  position: "absolute",
37754
38442
  top: 0,
@@ -39060,7 +39748,7 @@ class PythonProgram extends React.Component {
39060
39748
  // creator "went wild".
39061
39749
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
39062
39750
  return /*#__PURE__*/React.createElement(View, {
39063
- style: styles$8.container
39751
+ style: styles$5.container
39064
39752
  }, /*#__PURE__*/React.createElement("iframe", {
39065
39753
  sandbox: sandboxOptions,
39066
39754
  src: url,
@@ -39072,7 +39760,7 @@ class PythonProgram extends React.Component {
39072
39760
  PythonProgram.defaultProps = {
39073
39761
  height: 400
39074
39762
  };
39075
- const styles$8 = StyleSheet.create({
39763
+ const styles$5 = StyleSheet.create({
39076
39764
  container: {
39077
39765
  margin: "auto",
39078
39766
  width: "100%"
@@ -39312,129 +40000,6 @@ var Sequence$1 = {
39312
40000
  isLintable: true
39313
40001
  };
39314
40002
 
39315
- const colors = {
39316
- grayLight: "#aaa",
39317
- basicBorderColor: "#ccc",
39318
- white: "#fff"
39319
- };
39320
- const triangleBeforeAfter = {
39321
- borderBottom: "9px solid transparent",
39322
- borderTop: "9px solid transparent",
39323
- content: '" "',
39324
- height: "0",
39325
- position: "absolute",
39326
- top: "0",
39327
- width: "0"
39328
- };
39329
- const styles$7 = StyleSheet.create({
39330
- infoTip: {
39331
- display: "inline-block",
39332
- marginLeft: "5px",
39333
- position: "relative"
39334
- },
39335
- infoTipContainer: {
39336
- position: "absolute",
39337
- top: "-12px",
39338
- left: "22px",
39339
- zIndex: 1000
39340
- },
39341
- infoTipTriangle: {
39342
- height: "10px",
39343
- left: "0",
39344
- position: "absolute",
39345
- top: "8px",
39346
- width: "0",
39347
- zIndex: 1,
39348
- ":before": _extends({}, triangleBeforeAfter, {
39349
- borderRight: "9px solid #bbb",
39350
- right: "0"
39351
- }),
39352
- ":after": _extends({}, triangleBeforeAfter, {
39353
- borderRight: `9px solid ${colors.white}`,
39354
- right: "-1px"
39355
- })
39356
- },
39357
- verticalShadow: {
39358
- border: `1px solid ${colors.basicBorderColor}`,
39359
- boxShadow: `0 1px 3px ${colors.basicBorderColor}`,
39360
- borderBottom: `1px solid ${colors.grayLight}`
39361
- },
39362
- infoTipContentContainer: {
39363
- background: colors.white,
39364
- padding: "5px 10px",
39365
- width: "240px"
39366
- }
39367
- });
39368
- const questionMark = "data:image/png;base64," + "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBB" + "ZG9iZSBJbWFnZVJlYWR5ccllPAAAA3NpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/" + "eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+" + "IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2Jl" + "IFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAg" + "ICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5" + "LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9" + "IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHht" + "bG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3Vy" + "Y2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHht" + "cE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2N2M3NTAxYS04YmVlLTQ0M2Mt" + "YmRiNS04OGM2N2IxN2NhYzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUJCRTk4" + "Qjc4NjAwMTFFMzg3QUJDNEI4Mzk2QTRGQkQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5p" + "aWQ6OUJCRTk4QjY4NjAwMTFFMzg3QUJDNEI4Mzk2QTRGQkQiIHhtcDpDcmVhdG9yVG9v" + "bD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRG" + "cm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NGE5ZDI0OTMtODk1NC00OGFkLTlh" + "MTgtZDAwM2MwYWNjNDJlIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjY3Yzc1MDFh" + "LThiZWUtNDQzYy1iZGI1LTg4YzY3YjE3Y2FjMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4g" + "PC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pqm89uYAAADM" + "SURBVHjaXJA9DoJAEIUH1M4TUHIFsCMGen9OwCGw1YRGW2ntKel0exsojHIBC0ouQAyU" + "viFDstmXfNmZeS+zm7XSNCXRFiRgJf0bXIHixpbhGdxBBJYC1w/xaA424MhNEATkui71" + "fU9KqfEU78UbD9PdbJRlOdae55GmhIP+1NV1TcMwkOM41DSNHvRtMhTHMRVFQW3b6mOL" + "gx99kue5GRp/gIOZuZGvNpTNwjD8oliANU+qqqKu6/TQBdymN57AHjzBT+B6Jx79BRgA" + "vc49kQA4yxgAAAAASUVORK5CYII=";
39369
- class InfoTip$1 extends React.Component {
39370
- constructor(...args) {
39371
- super(...args);
39372
- this.state = {
39373
- hover: false
39374
- };
39375
- this.handleMouseEnter = () => {
39376
- this.setState({
39377
- hover: true
39378
- });
39379
- };
39380
- this.handleMouseLeave = () => {
39381
- this.setState({
39382
- hover: false
39383
- });
39384
- };
39385
- }
39386
- render() {
39387
- return /*#__PURE__*/React.createElement("div", {
39388
- className: css(styles$7.infoTip)
39389
- }, /*#__PURE__*/React.createElement("img", {
39390
- alt: "",
39391
- width: 10,
39392
- height: 10,
39393
- src: questionMark,
39394
- onMouseEnter: this.handleMouseEnter,
39395
- onMouseLeave: this.handleMouseLeave
39396
- }), /*#__PURE__*/React.createElement("div", {
39397
- className: css(styles$7.infoTipContainer),
39398
- style: {
39399
- display: this.state.hover ? "block" : "none"
39400
- }
39401
- }, /*#__PURE__*/React.createElement("div", {
39402
- className: css(styles$7.infoTipTriangle)
39403
- }), /*#__PURE__*/React.createElement("div", {
39404
- className: css(styles$7.verticalShadow, styles$7.infoTipContentContainer)
39405
- }, this.props.children)));
39406
- }
39407
- }
39408
-
39409
- /**
39410
- * A wrapper around info-tip/info-tip.jsx that can be rendered on the
39411
- * server without causing a checksum mismatch on the client.
39412
- * (RCSS generates classnames with a randomSuffix, which ensures that any
39413
- * two sets of generated classnames will not match.)
39414
- */
39415
- class InfoTip extends React.Component {
39416
- constructor(...args) {
39417
- super(...args);
39418
- this.state = {
39419
- didMount: false
39420
- };
39421
- }
39422
- componentDidMount() {
39423
- /* eslint-disable react/no-did-mount-set-state */
39424
- this.setState({
39425
- didMount: true
39426
- });
39427
- /* eslint-enable react/no-did-mount-set-state */
39428
- }
39429
-
39430
- render() {
39431
- if (this.state.didMount) {
39432
- return /*#__PURE__*/React.createElement(InfoTip$1, this.props);
39433
- }
39434
- return /*#__PURE__*/React.createElement("div", null);
39435
- }
39436
- }
39437
-
39438
40003
  const {
39439
40004
  assert: assert$1
39440
40005
  } = InteractiveUtil;
@@ -41389,7 +41954,7 @@ const VideoTranscriptLink = props => {
41389
41954
  var _result$data;
41390
41955
  const video = (_result$data = result.data) == null ? void 0 : _result$data.video;
41391
41956
  return /*#__PURE__*/React.createElement(View, {
41392
- style: styles$6.transcriptLink
41957
+ style: styles$4.transcriptLink
41393
41958
  }, /*#__PURE__*/React.createElement(Text$1, null, video == null ? void 0 : video.title), /*#__PURE__*/React.createElement(Strut, {
41394
41959
  size: 10
41395
41960
  }), /*#__PURE__*/React.createElement(Link, {
@@ -41406,7 +41971,7 @@ const VideoTranscriptLink = props => {
41406
41971
  return /*#__PURE__*/React.createElement(View, null, i18n._("Something went wrong."));
41407
41972
  }
41408
41973
  };
41409
- const styles$6 = StyleSheet.create({
41974
+ const styles$4 = StyleSheet.create({
41410
41975
  transcriptLink: {
41411
41976
  flexDirection: "row",
41412
41977
  width: "100%",
@@ -41559,7 +42124,7 @@ const init = function init(options) {
41559
42124
 
41560
42125
  // This file is processed by a Rollup plugin (replace) to inject the production
41561
42126
  const libName = "@khanacademy/perseus";
41562
- const libVersion = "19.6.3";
42127
+ const libVersion = "19.7.0";
41563
42128
  addLibraryVersionToPerseusDebug(libName, libVersion);
41564
42129
 
41565
42130
  const apiVersion = {
@@ -41769,7 +42334,7 @@ class HintRenderer extends React.Component {
41769
42334
  const {
41770
42335
  isMobile
41771
42336
  } = apiOptions;
41772
- const classNames$1 = classNames("hint", !isMobile && "perseus-hint-renderer", isMobile && css(styles$5.newHint), isMobile && lastRendered && css(styles$5.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
42337
+ const classNames$1 = classNames("hint", !isMobile && "perseus-hint-renderer", isMobile && css(styles$3.newHint), isMobile && lastRendered && css(styles$3.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
41773
42338
 
41774
42339
  // TODO(charlie): Allowing `customKeypad` would require that we
41775
42340
  // extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
@@ -41812,7 +42377,7 @@ class HintRenderer extends React.Component {
41812
42377
  HintRenderer.defaultProps = {
41813
42378
  linterContext: PerseusLinter.linterContextDefault
41814
42379
  };
41815
- const styles$5 = StyleSheet.create({
42380
+ const styles$3 = StyleSheet.create({
41816
42381
  newHint: {
41817
42382
  marginBottom: 1.5 * baseUnitPx,
41818
42383
  borderLeftColor: gray97,
@@ -41985,15 +42550,15 @@ class HintsRenderer extends React.Component {
41985
42550
  } = apiOptions;
41986
42551
  const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
41987
42552
  const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
41988
- const classNames$1 = classNames(this.props.className, apiOptions.isMobile && hintsVisible > 0 && css(styles$4.mobileHintStylesHintsRenderer));
42553
+ const classNames$1 = classNames(this.props.className, apiOptions.isMobile && hintsVisible > 0 && css(styles$2.mobileHintStylesHintsRenderer));
41989
42554
  return /*#__PURE__*/React.createElement("div", {
41990
42555
  className: classNames$1
41991
42556
  }, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React.createElement("div", {
41992
- className: css(styles$4.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
42557
+ className: css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
41993
42558
  }, i18n._("Hints")), hints, showGetAnotherHint && /*#__PURE__*/React.createElement("button", {
41994
42559
  // @ts-expect-error - TS2322 - Type '{ children: Element[]; rel: string; className: string; onClick: (evt: MouseEvent<HTMLButtonElement, MouseEvent>) => void; }' is not assignable to type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.
41995
42560
  rel: "button",
41996
- className: css(styles$4.linkButton, styles$4.getAnotherHintButton, apiOptions.isMobile && styles$4.mobileHintStylesGetAnotherHintButton),
42561
+ className: css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
41997
42562
  onClick: evt => {
41998
42563
  evt.preventDefault();
41999
42564
  evt.stopPropagation();
@@ -42002,9 +42567,9 @@ class HintsRenderer extends React.Component {
42002
42567
  }
42003
42568
  }
42004
42569
  }, /*#__PURE__*/React.createElement("span", {
42005
- className: css(styles$4.plusText, apiOptions.isMobile && styles$4.mobileHintStylesPlusText)
42570
+ className: css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
42006
42571
  }, "+"), /*#__PURE__*/React.createElement("span", {
42007
- className: css(styles$4.getAnotherHintText)
42572
+ className: css(styles$2.getAnotherHintText)
42008
42573
  }, i18n._("Get another hint"), " ", hintRatioCopy)));
42009
42574
  }
42010
42575
  }
@@ -42012,7 +42577,7 @@ HintsRenderer.defaultProps = {
42012
42577
  linterContext: PerseusLinter.linterContextDefault
42013
42578
  };
42014
42579
  const hintIndentation = baseUnitPx + hintBorderWidth;
42015
- const styles$4 = StyleSheet.create({
42580
+ const styles$2 = StyleSheet.create({
42016
42581
  // eslint-disable-next-line react-native/no-unused-styles
42017
42582
  rendererMargins: {
42018
42583
  marginTop: baseUnitPx
@@ -42419,7 +42984,7 @@ class ServerItemRenderer extends React.Component {
42419
42984
  // mobile hint styles, which are flush to the left.
42420
42985
  // NOTE(charlie): We may still want to apply this
42421
42986
  // padding for desktop exercises.
42422
- apiOptions.isMobile ? undefined : css(styles$3.hintsContainer)
42987
+ apiOptions.isMobile ? undefined : css(styles$1.hintsContainer)
42423
42988
  }, hintsRenderer)));
42424
42989
  }
42425
42990
  }
@@ -42429,7 +42994,7 @@ ServerItemRenderer.defaultProps = {
42429
42994
  linterContext: PerseusLinter.linterContextDefault,
42430
42995
  onRendered: isRendered => {}
42431
42996
  };
42432
- const styles$3 = StyleSheet.create({
42997
+ const styles$1 = StyleSheet.create({
42433
42998
  hintsContainer: {
42434
42999
  marginLeft: 50
42435
43000
  }
@@ -42563,345 +43128,6 @@ ElementContainer.defaultProps = {
42563
43128
  title: "More"
42564
43129
  };
42565
43130
 
42566
- // Displays a stylized open eye: lint warnings are visible
42567
- const VisibleIcon = () => /*#__PURE__*/React.createElement("svg", {
42568
- width: "24",
42569
- height: "24",
42570
- viewBox: "0 0 24 24",
42571
- className: css(styles$2.icon)
42572
- }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
42573
- id: "a",
42574
- d: "M7.401 10.035c-1.424.748-2.599 1.905-3.544 " + "3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 " + "12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 " + "1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-" + "3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 " + "0 0 0 0 6z"
42575
- })), /*#__PURE__*/React.createElement("g", {
42576
- fill: "none",
42577
- fillRule: "evenodd"
42578
- }, /*#__PURE__*/React.createElement("path", {
42579
- fill: "none",
42580
- d: "M0 0h24v24H0z"
42581
- }), /*#__PURE__*/React.createElement("mask", {
42582
- id: "b",
42583
- fill: "#fff"
42584
- }, /*#__PURE__*/React.createElement("use", {
42585
- href: "#a"
42586
- })), /*#__PURE__*/React.createElement("use", {
42587
- fill: "#fff",
42588
- fillRule: "nonzero",
42589
- href: "#a"
42590
- }), /*#__PURE__*/React.createElement("g", {
42591
- fill: "#fff",
42592
- mask: "url(#b)"
42593
- }, /*#__PURE__*/React.createElement("path", {
42594
- d: "M0 0h24v24H0z"
42595
- }))));
42596
-
42597
- // Displays a stylized eye with a line through it: I don't want to see lint
42598
- const HiddenIcon = () => /*#__PURE__*/React.createElement("svg", {
42599
- width: "24",
42600
- height: "24",
42601
- viewBox: "0 0 24 24",
42602
- className: css(styles$2.icon)
42603
- }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
42604
- id: "a",
42605
- d: "M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 " + "7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 " + "1.028c-.945-1.574-2.12-2.73-3.544-3.48.258." + "604.401 1.268.401 1.966 0 1.02-.305 " + "1.967-.828 2.757l2.535 2.536a1 1 0 0 " + "1-1.414 1.414l-12-12a1 1 0 0 1 " + "1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 " + "0-4.001-4.001l4 4.001zM6.072 8.486l2.976 " + "2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 " + "0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 " + "3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 " + "2.363-3.085 3.929-4z"
42606
- })), /*#__PURE__*/React.createElement("g", {
42607
- fill: "none",
42608
- fillRule: "evenodd"
42609
- }, /*#__PURE__*/React.createElement("path", {
42610
- fill: "none",
42611
- d: "M0 0h24v24H0z"
42612
- }), /*#__PURE__*/React.createElement("mask", {
42613
- id: "b",
42614
- fill: "#fff"
42615
- }, /*#__PURE__*/React.createElement("use", {
42616
- href: "#a"
42617
- })), /*#__PURE__*/React.createElement("use", {
42618
- fill: "#fff",
42619
- fillRule: "nonzero",
42620
- href: "#a"
42621
- }), /*#__PURE__*/React.createElement("g", {
42622
- fill: "#fff",
42623
- mask: "url(#b)"
42624
- }, /*#__PURE__*/React.createElement("path", {
42625
- d: "M0 0h24v24H0z"
42626
- }))));
42627
- const HUD = ({
42628
- message,
42629
- enabled,
42630
- onClick,
42631
- fixedPosition: _fixedPosition = true
42632
- }) => {
42633
- let state;
42634
- let icon;
42635
- if (enabled) {
42636
- state = styles$2.enabled;
42637
- icon = /*#__PURE__*/React.createElement(VisibleIcon, null);
42638
- } else {
42639
- state = styles$2.disabled;
42640
- icon = /*#__PURE__*/React.createElement(HiddenIcon, null);
42641
- }
42642
- return /*#__PURE__*/React.createElement("button", {
42643
- className: css(styles$2.hud, _fixedPosition && styles$2.hudFixedPosition, state),
42644
- onClick: e => {
42645
- onClick();
42646
- }
42647
- }, icon, message);
42648
- };
42649
- const styles$2 = StyleSheet.create({
42650
- hud: {
42651
- boxSizing: "border-box",
42652
- height: 36,
42653
- padding: "9px 16px",
42654
- borderRadius: 18,
42655
- fontFamily: boldFontFamily,
42656
- fontSize: "15px",
42657
- lineHeight: "18px",
42658
- color: white$1,
42659
- userSelect: "none",
42660
- borderWidth: 0 // <button> gives us a border by default
42661
- },
42662
-
42663
- // We want to render the element in-place in our fixtures, so allow us to
42664
- // render in the bottom corner in production and in-place in testing.
42665
- hudFixedPosition: {
42666
- bottom: 20,
42667
- position: "fixed",
42668
- right: 20,
42669
- zIndex: 1
42670
- },
42671
- icon: {
42672
- width: 24,
42673
- height: 24,
42674
- marginRight: 8,
42675
- marginTop: -3,
42676
- verticalAlign: "middle"
42677
- },
42678
- enabled: {
42679
- backgroundColor: warningColor,
42680
- ":hover": {
42681
- backgroundColor: warningColorHover
42682
- },
42683
- ":active": {
42684
- backgroundColor: warningColorActive
42685
- }
42686
- },
42687
- disabled: {
42688
- backgroundColor: gray76,
42689
- ":hover": {
42690
- backgroundColor: "#a1a5a9" // in between those two grays
42691
- },
42692
-
42693
- ":active": {
42694
- backgroundColor: gray68
42695
- }
42696
- }
42697
- });
42698
-
42699
- /**
42700
- * MultiButtonGroup is an aesthetically pleasing group of buttons,
42701
- * which allows multiple buttons to be selected at the same time.
42702
- *
42703
- * NOTE: This component is almost identical to ./button-group.jsx except that
42704
- * this component allows multiple selection!
42705
- */
42706
- class MultiButtonGroup extends React.Component {
42707
- constructor(...args) {
42708
- super(...args);
42709
- this.toggleSelect = newValue => {
42710
- const values = (this.props.values || []).slice(0);
42711
- const allowEmpty = this.props.allowEmpty;
42712
- if (values.indexOf(newValue) >= 0 && (values.length > 1 || allowEmpty)) {
42713
- // If the value is already selected, unselect it
42714
- values.splice(values.indexOf(newValue), 1);
42715
- } else {
42716
- // Otherwise merge with other values and return
42717
- if (values.indexOf(newValue) < 0) {
42718
- values.push(newValue);
42719
- }
42720
- }
42721
- this.props.onChange(values);
42722
- };
42723
- }
42724
- focus() {
42725
- var _ReactDOM$findDOMNode;
42726
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
42727
- (_ReactDOM$findDOMNode = ReactDOM.findDOMNode(this)) == null || _ReactDOM$findDOMNode.focus();
42728
- return true;
42729
- }
42730
- render() {
42731
- const values = this.props.values || [];
42732
- const buttons = this.props.buttons.map((button, i) => {
42733
- const selected = values.indexOf(button.value) >= 0;
42734
- return /*#__PURE__*/React.createElement("button", {
42735
- title: button.title,
42736
- type: "button",
42737
- id: "" + i,
42738
- key: "" + i,
42739
- ref: "button" + i,
42740
- className: css(styles$1.buttonStyle, selected && styles$1.selectedStyle),
42741
- onClick: () => this.toggleSelect(button.value)
42742
- }, button.content || "" + button.value);
42743
- });
42744
- const outerStyle = {
42745
- display: "inline-block"
42746
- };
42747
- return /*#__PURE__*/React.createElement("div", {
42748
- style: outerStyle
42749
- }, buttons);
42750
- }
42751
- }
42752
- MultiButtonGroup.defaultProps = {
42753
- values: [],
42754
- allowEmpty: true
42755
- };
42756
- const styles$1 = StyleSheet.create({
42757
- buttonStyle: {
42758
- backgroundColor: "white",
42759
- border: "1px solid #ccc",
42760
- borderLeft: "0",
42761
- cursor: "pointer",
42762
- margin: "0",
42763
- padding: "5px 10px",
42764
- position: "relative",
42765
- // for hover
42766
-
42767
- ":first-child": {
42768
- borderLeft: "1px solid #ccc",
42769
- borderTopLeftRadius: "3px",
42770
- borderBottomLeftRadius: "3px"
42771
- },
42772
- ":last-child": {
42773
- borderRight: "1px solid #ccc",
42774
- borderTopRightRadius: "3px",
42775
- borderBottomRightRadius: "3px"
42776
- },
42777
- ":hover": {
42778
- backgroundColor: "#ccc"
42779
- },
42780
- ":focus": {
42781
- zIndex: 2
42782
- }
42783
- },
42784
- selectedStyle: {
42785
- backgroundColor: "#ddd"
42786
- }
42787
- });
42788
-
42789
- /* eslint-disable @babel/no-invalid-this */
42790
-
42791
- /* A checkbox that syncs its value to props using the
42792
- * renderer's onChange method, and gets the prop name
42793
- * dynamically from its props list
42794
- */
42795
- const PropCheckBox = createReactClass({
42796
- displayName: "PropCheckBox",
42797
- propTypes: {
42798
- labelAlignment: PropTypes.oneOf(["left", "right"])
42799
- },
42800
- DEFAULT_PROPS: {
42801
- label: null,
42802
- onChange: null,
42803
- labelAlignment: "left"
42804
- },
42805
- getDefaultProps: function () {
42806
- return this.DEFAULT_PROPS;
42807
- },
42808
- propName: function () {
42809
- const propName = _.find(_.keys(this.props), function (localPropName) {
42810
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
42811
- return !_.has(this.DEFAULT_PROPS, localPropName);
42812
- }, this);
42813
- if (!propName) {
42814
- throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
42815
- }
42816
- return propName;
42817
- },
42818
- _labelAlignLeft: function () {
42819
- return this.props.labelAlignment === "left";
42820
- },
42821
- render: function () {
42822
- const propName = this.propName();
42823
- return /*#__PURE__*/React.createElement("label", null, this._labelAlignLeft() && this.props.label, /*#__PURE__*/React.createElement("input", {
42824
- type: "checkbox",
42825
- checked: this.props[propName],
42826
- onChange: this.toggle
42827
- }), !this._labelAlignLeft() && this.props.label);
42828
- },
42829
- toggle: function () {
42830
- const propName = this.propName();
42831
- const changes = {};
42832
- changes[propName] = !this.props[propName];
42833
- this.props.onChange(changes);
42834
- }
42835
- });
42836
-
42837
- const truth = () => true;
42838
-
42839
- /* A minor abstraction on top of NumberInput for ranges
42840
- *
42841
- */
42842
- class RangeInput extends React.Component {
42843
- constructor(...args) {
42844
- super(...args);
42845
- this.onChange = (i, newVal) => {
42846
- const value = this.props.value;
42847
- if (i === 0) {
42848
- this.props.onChange([newVal, value[1]]);
42849
- } else {
42850
- this.props.onChange([value[0], newVal]);
42851
- }
42852
- };
42853
- }
42854
- render() {
42855
- const value = this.props.value;
42856
- const checkValidity = this.props.checkValidity || truth;
42857
- return /*#__PURE__*/React.createElement("div", {
42858
- className: "range-input"
42859
- }, /*#__PURE__*/React.createElement(NumberInput, _extends({}, this.props, {
42860
- value: value[0],
42861
- checkValidity: val => checkValidity([val, value[1]])
42862
- // eslint-disable-next-line react/jsx-no-bind
42863
- ,
42864
- onChange: this.onChange.bind(this, 0),
42865
- placeholder: this.props.placeholder[0]
42866
- })), /*#__PURE__*/React.createElement(NumberInput, _extends({}, this.props, {
42867
- value: value[1],
42868
- checkValidity: val => checkValidity([value[0], val])
42869
- // eslint-disable-next-line react/jsx-no-bind
42870
- ,
42871
- onChange: this.onChange.bind(this, 1),
42872
- placeholder: this.props.placeholder[1]
42873
- })));
42874
- }
42875
- }
42876
- RangeInput.propTypes = {
42877
- value: PropTypes.array.isRequired,
42878
- onChange: PropTypes.func.isRequired,
42879
- placeholder: PropTypes.array,
42880
- checkValidity: PropTypes.func
42881
- };
42882
- RangeInput.defaultProps = {
42883
- placeholder: [null, null]
42884
- };
42885
-
42886
- var components = /*#__PURE__*/Object.freeze({
42887
- __proto__: null,
42888
- ButtonGroup: ButtonGroup,
42889
- Graph: Graph,
42890
- Graphie: Graphie,
42891
- HUD: HUD,
42892
- Icon: Icon,
42893
- InfoTip: InfoTip,
42894
- InlineIcon: InlineIcon,
42895
- MathInput: MathInput,
42896
- MultiButtonGroup: MultiButtonGroup,
42897
- NumberInput: NumberInput,
42898
- PropCheckBox: PropCheckBox,
42899
- RangeInput: RangeInput,
42900
- SvgImage: SvgImage,
42901
- TextInput: TextInput,
42902
- TextListEditor: TextListEditor
42903
- });
42904
-
42905
43131
  const devices = {
42906
43132
  PHONE: "phone",
42907
43133
  TABLET: "tablet",