@khanacademy/perseus 19.6.3 → 19.7.1

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] = props.box;
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,25 @@ 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;
29387
30259
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
30260
+ const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
30261
+ const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
30262
+
30263
+ // Mafs shim
30264
+ 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]) {
30265
+ return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, this.props, {
30266
+ ref: this.mafsRef,
30267
+ gridStep: gridStep,
30268
+ snapStep: snapStep,
30269
+ box: box
30270
+ }));
30271
+ }
29388
30272
  let instructions;
30273
+ // isClickToAddPoints() only applies to points and polygons
29389
30274
  if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
29390
30275
  if (this.props.graph.type === "point") {
29391
30276
  instructions = i18n._("Click to add points");
@@ -29399,8 +30284,6 @@ class InteractiveGraph extends React.Component {
29399
30284
  if (this.isClickToAddPoints()) {
29400
30285
  onMouseDown = this.handleAddPointsMouseDown;
29401
30286
  }
29402
- const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
29403
- const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
29404
30287
  const isMobile = this.props.apiOptions.isMobile;
29405
30288
  return /*#__PURE__*/React.createElement("div", {
29406
30289
  className: "perseus-widget " + "perseus-widget-interactive-graph",
@@ -30688,7 +31571,7 @@ var globalConstants = /*#__PURE__*/Object.freeze({
30688
31571
  pureLgMax: pureLgMax
30689
31572
  });
30690
31573
 
30691
- const colors$1 = {
31574
+ const colors = {
30692
31575
  white: "#FFFFFF",
30693
31576
  gray98: "#FAFAFA",
30694
31577
  gray97: "#F6F7F7",
@@ -30748,7 +31631,7 @@ const colors$1 = {
30748
31631
  };
30749
31632
  const borderRadius = 4;
30750
31633
  const breadcrumbStyles = {
30751
- color: colors$1.breadcrumbs,
31634
+ color: colors.breadcrumbs,
30752
31635
  fontFamily: "inherit",
30753
31636
  fontSize: 15,
30754
31637
  fontWeight: "bold",
@@ -30818,14 +31701,14 @@ const typography = {
30818
31701
  },
30819
31702
  // For callouts
30820
31703
  smallHeading: {
30821
- color: colors$1.gray25,
31704
+ color: colors.gray25,
30822
31705
  fontFamily: "inherit",
30823
31706
  fontSize: 17,
30824
31707
  fontWeight: "bold",
30825
31708
  lineHeight: "23px"
30826
31709
  },
30827
31710
  smallHeadingMobile: {
30828
- color: colors$1.gray25,
31711
+ color: colors.gray25,
30829
31712
  fontFamily: "inherit",
30830
31713
  fontSize: 15,
30831
31714
  fontWeight: "bold",
@@ -30833,7 +31716,7 @@ const typography = {
30833
31716
  },
30834
31717
  // Accent headings
30835
31718
  accentHeading: {
30836
- color: colors$1.gray68,
31719
+ color: colors.gray68,
30837
31720
  fontFamily: "inherit",
30838
31721
  fontSize: 15,
30839
31722
  fontWeight: "bold",
@@ -30939,7 +31822,7 @@ const typography = {
30939
31822
  // HACK(kevinb): temporary wonder blocks styles for header only
30940
31823
  // TODO(kevinb): use components from wonder-blocks-typography instead
30941
31824
  wonderBlocksTitle: {
30942
- color: colors$1.white,
31825
+ color: colors.white,
30943
31826
  fontWeight: 900,
30944
31827
  // "Black" weight
30945
31828
  fontSize: 28,
@@ -30961,7 +31844,7 @@ const typography = {
30961
31844
 
30962
31845
  var globalStyles = /*#__PURE__*/Object.freeze({
30963
31846
  __proto__: null,
30964
- colors: colors$1,
31847
+ colors: colors,
30965
31848
  borderRadius: borderRadius,
30966
31849
  fonts: fonts,
30967
31850
  typography: typography
@@ -31023,7 +31906,7 @@ const HideAnswersToggle = props => {
31023
31906
  const switchId = idFactory.get("hide-answers-toggle");
31024
31907
  const labelId = idFactory.get("hide-answers-label");
31025
31908
  return /*#__PURE__*/React.createElement(View, {
31026
- style: styles$j.switchWrapper
31909
+ style: styles$g.switchWrapper
31027
31910
  }, /*#__PURE__*/React.createElement(Switch, {
31028
31911
  id: switchId,
31029
31912
  checked: props.areAnswersHidden,
@@ -31035,7 +31918,7 @@ const HideAnswersToggle = props => {
31035
31918
  tag: "label"
31036
31919
  }, strings.hideAnswersToggleLabel));
31037
31920
  };
31038
- const styles$j = StyleSheet.create({
31921
+ const styles$g = StyleSheet.create({
31039
31922
  switchWrapper: {
31040
31923
  display: "flex",
31041
31924
  flexDirection: "row",
@@ -31088,13 +31971,13 @@ const AnswerPill = props => {
31088
31971
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31089
31972
  onClick: correct ? undefined : onClick,
31090
31973
  ref: ref,
31091
- style: [style, popperStyle, styles$i.pill, correct && styles$i.correct, incorrect && styles$i.incorrect, (focused || hovered) && BringToFront]
31974
+ style: [style, popperStyle, styles$f.pill, correct && styles$f.correct, incorrect && styles$f.incorrect, (focused || hovered) && BringToFront]
31092
31975
  }, /*#__PURE__*/React.createElement(Renderer, {
31093
31976
  content: answerString,
31094
31977
  inline: true
31095
31978
  })));
31096
31979
  };
31097
- const styles$i = StyleSheet.create({
31980
+ const styles$f = StyleSheet.create({
31098
31981
  correct: {
31099
31982
  // WB green darkened by 18%
31100
31983
  backgroundColor: "#00880b"
@@ -31147,23 +32030,23 @@ class Marker extends React.Component {
31147
32030
  icon: iconNull
31148
32031
  };
31149
32032
  if (showCorrectness) {
31150
- iconStyles = [styles$h.markerGraded, showCorrectness === "correct" ? styles$h.markerCorrect : styles$h.markerIncorrect, isOpen && styles$h.markerSelected];
32033
+ iconStyles = [styles$e.markerGraded, showCorrectness === "correct" ? styles$e.markerCorrect : styles$e.markerIncorrect, isOpen && styles$e.markerSelected];
31151
32034
  args = _extends({}, args, {
31152
32035
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
31153
32036
  });
31154
32037
  } else if (selectedAnswers && selectedAnswers.length > 0) {
31155
- iconStyles = [styles$h.markerFilled, isOpen && styles$h.markerSelected];
32038
+ iconStyles = [styles$e.markerFilled, isOpen && styles$e.markerSelected];
31156
32039
  } else if (isOpen) {
31157
- iconStyles = [styles$h.markerSelected];
32040
+ iconStyles = [styles$e.markerSelected];
31158
32041
  args = _extends({}, args, {
31159
32042
  icon: iconChevronDown,
31160
32043
  size: 8
31161
32044
  });
31162
32045
  } else if (showPulsate) {
31163
- iconStyles = [styles$h.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$h.markerUnfilledPulsateOnce : showPulsate && styles$h.markerUnfilledPulsateInfinite];
32046
+ iconStyles = [styles$e.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$e.markerUnfilledPulsateOnce : showPulsate && styles$e.markerUnfilledPulsateInfinite];
31164
32047
  }
31165
32048
  return /*#__PURE__*/React.createElement(View, {
31166
- style: [styles$h.markerIcon, iconStyles],
32049
+ style: [styles$e.markerIcon, iconStyles],
31167
32050
  ref: node => this._icon = node
31168
32051
  }, /*#__PURE__*/React.createElement(Icon, args));
31169
32052
  }
@@ -31185,7 +32068,7 @@ class Marker extends React.Component {
31185
32068
  const markerDisabled = showCorrectness === "correct";
31186
32069
  const active = hovered || focused;
31187
32070
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
31188
- style: [styles$h.marker, active && !markerDisabled && styles$h.markerActive]
32071
+ style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive]
31189
32072
  // already translated in: /widgets/graded-group.tsx
31190
32073
  ,
31191
32074
  "aria-label": markerDisabled ? i18n._("Correct!") : label
@@ -31203,7 +32086,7 @@ class Marker extends React.Component {
31203
32086
  Marker.defaultProps = {
31204
32087
  selected: []
31205
32088
  };
31206
- const styles$h = StyleSheet.create({
32089
+ const styles$e = StyleSheet.create({
31207
32090
  marker: {
31208
32091
  position: "absolute",
31209
32092
  backgroundColor: Color.white,
@@ -31773,13 +32656,13 @@ class LabelImage extends React.Component {
31773
32656
  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
32657
  const choicesString = i18n._("Choices:");
31775
32658
  return /*#__PURE__*/React.createElement("div", {
31776
- className: classNames("perseus-label-image-widget-instructions", css(styles$g.instructions))
32659
+ className: classNames("perseus-label-image-widget-instructions", css(styles$d.instructions))
31777
32660
  }, /*#__PURE__*/React.createElement("div", {
31778
- className: css(styles$g.instructionsCaption)
32661
+ className: css(styles$d.instructionsCaption)
31779
32662
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React.createElement("div", {
31780
- className: css(styles$g.instructionsChoices)
32663
+ className: css(styles$d.instructionsChoices)
31781
32664
  }, choices.map((choice, index) => /*#__PURE__*/React.createElement("div", {
31782
- className: css(styles$g.instructionsChoice),
32665
+ className: css(styles$d.instructionsChoice),
31783
32666
  key: index
31784
32667
  }, /*#__PURE__*/React.createElement(Renderer, {
31785
32668
  content: choice
@@ -31796,20 +32679,20 @@ class LabelImage extends React.Component {
31796
32679
  activeMarkerIndex
31797
32680
  } = this.state;
31798
32681
  return /*#__PURE__*/React.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React.createElement("div", {
31799
- className: css(styles$g.markersCanvas),
32682
+ className: css(styles$d.markersCanvas),
31800
32683
  style: {
31801
32684
  maxWidth: imageWidth,
31802
32685
  maxHeight: imageHeight
31803
32686
  }
31804
32687
  }, /*#__PURE__*/React.createElement("div", {
31805
- className: css(styles$g.imageContainer,
32688
+ className: css(styles$d.imageContainer,
31806
32689
  // Ensure image interaction is disabled while answer
31807
32690
  // choices popup is visible. This addresses specific
31808
32691
  // case where user may click on question image to
31809
32692
  // dismiss the popup. If the image is larger in size
31810
32693
  // than its rendered in the widget, this would
31811
32694
  // result in a zoom of the image.
31812
- activeMarkerIndex !== -1 && styles$g.imageInteractionDisabled)
32695
+ activeMarkerIndex !== -1 && styles$d.imageInteractionDisabled)
31813
32696
  }, /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
31814
32697
  setAssetStatus
31815
32698
  }) => /*#__PURE__*/React.createElement(SvgImage, {
@@ -31833,7 +32716,7 @@ class LabelImage extends React.Component {
31833
32716
  }));
31834
32717
  }
31835
32718
  }
31836
- const styles$g = StyleSheet.create({
32719
+ const styles$d = StyleSheet.create({
31837
32720
  instructions: {
31838
32721
  paddingBottom: 16
31839
32722
  },
@@ -32190,7 +33073,7 @@ class Placeholder extends React.Component {
32190
33073
  const {
32191
33074
  layout
32192
33075
  } = this.props;
32193
- const className = css(styles$f.card, styles$f.placeholder, layout === Layout.HORIZONTAL && styles$f.horizontalCard);
33076
+ const className = css(styles$c.card, styles$c.placeholder, layout === Layout.HORIZONTAL && styles$c.horizontalCard);
32194
33077
  const style = {
32195
33078
  width: this.props.width,
32196
33079
  height: this.props.height
@@ -32373,7 +33256,7 @@ class Draggable extends React.Component {
32373
33256
  // We need to keep backwards compatbility with rules specified directly
32374
33257
  // in CSS. Hence the hacky tacking on of manual classNames.
32375
33258
  // 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";
33259
+ 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
33260
  if (!includePadding) {
32378
33261
  className += " perseus-sortable-draggable-unpadded";
32379
33262
  }
@@ -32580,7 +33463,7 @@ class Sortable extends React.Component {
32580
33463
  } = this.props;
32581
33464
  // We need to keep backwards compatbility with rules specified directly
32582
33465
  // in CSS. See sortable.less for details.
32583
- const className = css(styles$f.sortable) + " perseus-sortable";
33466
+ const className = css(styles$c.sortable) + " perseus-sortable";
32584
33467
  const syncWidth = ((_this$props$constrain = this.props.constraints) == null ? void 0 : _this$props$constrain.width) || layout === Layout.VERTICAL;
32585
33468
  const syncHeight = ((_this$props$constrain2 = this.props.constraints) == null ? void 0 : _this$props$constrain2.height) || layout === Layout.HORIZONTAL;
32586
33469
  _.each(this.state.items, function (item, i, items) {
@@ -32822,7 +33705,7 @@ Sortable.defaultProps = {
32822
33705
  linterContext: PerseusLinter.linterContextDefault,
32823
33706
  waitForTexRendererToLoad: true
32824
33707
  };
32825
- const styles$f = StyleSheet.create({
33708
+ const styles$c = StyleSheet.create({
32826
33709
  sortable: {
32827
33710
  boxSizing: "border-box",
32828
33711
  float: "left",
@@ -32984,23 +33867,23 @@ class Matcher extends React.Component {
32984
33867
  };
32985
33868
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
32986
33869
  return /*#__PURE__*/React.createElement("table", {
32987
- className: css(styles$e.widget) + " " + HACKY_CSS_CLASSNAME
33870
+ className: css(styles$b.widget) + " " + HACKY_CSS_CLASSNAME
32988
33871
  }, /*#__PURE__*/React.createElement("tbody", null, showLabels && /*#__PURE__*/React.createElement("tr", {
32989
- className: css(styles$e.row)
33872
+ className: css(styles$b.row)
32990
33873
  }, /*#__PURE__*/React.createElement("th", {
32991
- className: css(styles$e.column, styles$e.columnLabel)
33874
+ className: css(styles$b.column, styles$b.columnLabel)
32992
33875
  }, /*#__PURE__*/React.createElement(Renderer, {
32993
33876
  content: this.props.labels[0] || "...",
32994
33877
  linterContext: this.props.linterContext
32995
33878
  })), /*#__PURE__*/React.createElement("th", {
32996
- className: css(styles$e.column, styles$e.columnRight, styles$e.columnLabel)
33879
+ className: css(styles$b.column, styles$b.columnRight, styles$b.columnLabel)
32997
33880
  }, /*#__PURE__*/React.createElement(Renderer, {
32998
33881
  content: this.props.labels[1] || "...",
32999
33882
  linterContext: this.props.linterContext
33000
33883
  }))), /*#__PURE__*/React.createElement("tr", {
33001
- className: css(styles$e.row)
33884
+ className: css(styles$b.row)
33002
33885
  }, /*#__PURE__*/React.createElement("td", {
33003
- className: css(styles$e.column)
33886
+ className: css(styles$b.column)
33004
33887
  }, /*#__PURE__*/React.createElement(Sortable, {
33005
33888
  options: left,
33006
33889
  layout: Layout.VERTICAL,
@@ -33015,7 +33898,7 @@ class Matcher extends React.Component {
33015
33898
  ,
33016
33899
  ref: "left"
33017
33900
  })), /*#__PURE__*/React.createElement("td", {
33018
- className: css(styles$e.column, styles$e.columnRight)
33901
+ className: css(styles$b.column, styles$b.columnRight)
33019
33902
  }, /*#__PURE__*/React.createElement(Sortable
33020
33903
  // @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33021
33904
  , {
@@ -33068,7 +33951,7 @@ _.extend(Matcher, {
33068
33951
  });
33069
33952
  const padding = 5;
33070
33953
  const border = "1px solid #444";
33071
- const styles$e = StyleSheet.create({
33954
+ const styles$b = StyleSheet.create({
33072
33955
  widget: {
33073
33956
  paddingTop: padding,
33074
33957
  maxWidth: "100%",
@@ -33101,197 +33984,6 @@ var Matcher$1 = {
33101
33984
  isLintable: true
33102
33985
  };
33103
33986
 
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
33987
  // Type imports
33296
33988
 
33297
33989
  const {
@@ -33935,9 +34627,9 @@ function drawText(ctx, item) {
33935
34627
  if (item.value === null) {
33936
34628
  return;
33937
34629
  }
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);
34630
+ ctx.fillStyle = styles$a.fgColor;
34631
+ ctx.font = styles$a.font;
34632
+ ctx.fillText(item.value, item.pos[0] - styles$a.fontSizePx / 2 + 1, item.pos[1] + styles$a.fontSizePx / 2);
33941
34633
  }
33942
34634
 
33943
34635
  /**
@@ -33958,16 +34650,16 @@ function drawText(ctx, item) {
33958
34650
  function drawDoubleLine(ctx, item) {
33959
34651
  // Outer line that forms both of the bond lines.
33960
34652
  let path = new Path2D();
33961
- ctx.lineWidth = 5 * styles$d.lineWidth;
33962
- ctx.strokeStyle = styles$d.fgColor;
34653
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34654
+ ctx.strokeStyle = styles$a.fgColor;
33963
34655
  path.moveTo(item.startPos[0], item.startPos[1]);
33964
34656
  path.lineTo(item.endPos[0], item.endPos[1]);
33965
34657
  ctx.stroke(path);
33966
34658
 
33967
34659
  // Inner white line that separates the two bond lines.
33968
34660
  path = new Path2D();
33969
- ctx.lineWidth = 3 * styles$d.lineWidth;
33970
- ctx.strokeStyle = styles$d.bgColor;
34661
+ ctx.lineWidth = 3 * styles$a.lineWidth;
34662
+ ctx.strokeStyle = styles$a.bgColor;
33971
34663
  path.moveTo(item.startPos[0], item.startPos[1]);
33972
34664
  path.lineTo(item.endPos[0], item.endPos[1]);
33973
34665
  ctx.stroke(path);
@@ -33994,16 +34686,16 @@ function drawTripleLine(ctx, item) {
33994
34686
 
33995
34687
  // Outer line that will form the two outer bond lines.
33996
34688
  let path = new Path2D();
33997
- ctx.lineWidth = 7 * styles$d.lineWidth;
33998
- ctx.strokeStyle = styles$d.fgColor;
34689
+ ctx.lineWidth = 7 * styles$a.lineWidth;
34690
+ ctx.strokeStyle = styles$a.fgColor;
33999
34691
  path.moveTo(item.startPos[0], item.startPos[1]);
34000
34692
  path.lineTo(item.endPos[0], item.endPos[1]);
34001
34693
  ctx.stroke(path);
34002
34694
 
34003
34695
  // Middle white line that separates the bonds
34004
34696
  path = new Path2D();
34005
- ctx.lineWidth = 5 * styles$d.lineWidth;
34006
- ctx.strokeStyle = styles$d.bgColor;
34697
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34698
+ ctx.strokeStyle = styles$a.bgColor;
34007
34699
  path.moveTo(item.startPos[0], item.startPos[1]);
34008
34700
  path.lineTo(item.endPos[0], item.endPos[1]);
34009
34701
  ctx.stroke(path);
@@ -34025,8 +34717,8 @@ function drawTripleLine(ctx, item) {
34025
34717
  */
34026
34718
  function drawLine(ctx, item) {
34027
34719
  const path = new Path2D();
34028
- ctx.lineWidth = styles$d.lineWidth;
34029
- ctx.strokeStyle = styles$d.fgColor;
34720
+ ctx.lineWidth = styles$a.lineWidth;
34721
+ ctx.strokeStyle = styles$a.fgColor;
34030
34722
  path.moveTo(item.startPos[0], item.startPos[1]);
34031
34723
  path.lineTo(item.endPos[0], item.endPos[1]);
34032
34724
  ctx.stroke(path);
@@ -34078,7 +34770,7 @@ function compareElements(item0, item1) {
34078
34770
  function draw(ctx, items) {
34079
34771
  items.sort(compareElements).forEach(drawItem(ctx));
34080
34772
  }
34081
- const styles$d = {
34773
+ const styles$a = {
34082
34774
  bgColor: "rgb(255, 255, 255)",
34083
34775
  fgColor: "rgb(0, 0, 0)",
34084
34776
  fontSizePx: 12,
@@ -36640,7 +37332,7 @@ class HighlightRenderer extends React.PureComponent {
36640
37332
  const rects = this.state.cachedHighlightRects;
36641
37333
  return /*#__PURE__*/React.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React.createElement("div", {
36642
37334
  key: index,
36643
- className: css(styles$c.highlightRect),
37335
+ className: css(styles$9.highlightRect),
36644
37336
  style: {
36645
37337
  // NOTE(mdr): We apply `position: absolute` here
36646
37338
  // rather than in Aphrodite styles, because
@@ -36659,7 +37351,7 @@ class HighlightRenderer extends React.PureComponent {
36659
37351
  })));
36660
37352
  }
36661
37353
  }
36662
- const styles$c = StyleSheet.create({
37354
+ const styles$9 = StyleSheet.create({
36663
37355
  highlightRect: {
36664
37356
  background: "#fffabe" // highlighter yellow :)
36665
37357
  }
@@ -36740,7 +37432,7 @@ class HighlightTooltip extends React.PureComponent {
36740
37432
  // TooltipContent wouldn't let me overwrite
36741
37433
  // user-select and onClick
36742
37434
  const content = /*#__PURE__*/React.createElement("div", {
36743
- className: css(styles$b.tooltipLabel),
37435
+ className: css(styles$8.tooltipLabel),
36744
37436
  onClick: this.props.onClick
36745
37437
  }, this.props.label);
36746
37438
  const style = {
@@ -36760,7 +37452,7 @@ class HighlightTooltip extends React.PureComponent {
36760
37452
  }, /*#__PURE__*/React.createElement("div", null)));
36761
37453
  }
36762
37454
  }
36763
- const styles$b = StyleSheet.create({
37455
+ const styles$8 = StyleSheet.create({
36764
37456
  tooltipLabel: {
36765
37457
  // Unlike most tooltip contents, we don't want this label to be
36766
37458
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -37312,7 +38004,7 @@ class HighlightableContent extends React.PureComponent {
37312
38004
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
37313
38005
  const buildHighlight = r => this._buildHighlight(r);
37314
38006
  return /*#__PURE__*/React.createElement("div", {
37315
- className: css(styles$a.container),
38007
+ className: css(styles$7.container),
37316
38008
  ref: container => this._container = container
37317
38009
  }, /*#__PURE__*/React.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React.createElement(HighlightingUI, {
37318
38010
  buildHighlight: buildHighlight,
@@ -37333,14 +38025,14 @@ class HighlightableContent extends React.PureComponent {
37333
38025
  onAddHighlight: this._handleAddHighlight,
37334
38026
  onRemoveHighlight: this._handleRemoveHighlight
37335
38027
  })), /*#__PURE__*/React.createElement("div", {
37336
- className: css(styles$a.content),
38028
+ className: css(styles$7.content),
37337
38029
  ref: content => this._content = content
37338
38030
  }, /*#__PURE__*/React.createElement(WordIndexer, {
37339
38031
  onWordsUpdate: this._handleWordsUpdate
37340
38032
  }, this.props.children)));
37341
38033
  }
37342
38034
  }
37343
- const styles$a = StyleSheet.create({
38035
+ const styles$7 = StyleSheet.create({
37344
38036
  // We render content with z-index 1, and highlights with z-index 0, so that
37345
38037
  // content will receive the browser's native pointer events. (Highlights
37346
38038
  // have their own magic code to manage hover detection, despite being
@@ -37740,7 +38432,7 @@ class LineHeightMeasurer extends React.Component {
37740
38432
  }
37741
38433
  render() {
37742
38434
  return /*#__PURE__*/React.createElement("div", {
37743
- className: css(styles$9.measurer),
38435
+ className: css(styles$6.measurer),
37744
38436
  "aria-hidden": "true"
37745
38437
  }, /*#__PURE__*/React.createElement("div", {
37746
38438
  ref: ref => this._line = ref,
@@ -37748,7 +38440,7 @@ class LineHeightMeasurer extends React.Component {
37748
38440
  }, "Line Height Measurement"));
37749
38441
  }
37750
38442
  }
37751
- const styles$9 = StyleSheet.create({
38443
+ const styles$6 = StyleSheet.create({
37752
38444
  measurer: {
37753
38445
  position: "absolute",
37754
38446
  top: 0,
@@ -39060,7 +39752,7 @@ class PythonProgram extends React.Component {
39060
39752
  // creator "went wild".
39061
39753
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
39062
39754
  return /*#__PURE__*/React.createElement(View, {
39063
- style: styles$8.container
39755
+ style: styles$5.container
39064
39756
  }, /*#__PURE__*/React.createElement("iframe", {
39065
39757
  sandbox: sandboxOptions,
39066
39758
  src: url,
@@ -39072,7 +39764,7 @@ class PythonProgram extends React.Component {
39072
39764
  PythonProgram.defaultProps = {
39073
39765
  height: 400
39074
39766
  };
39075
- const styles$8 = StyleSheet.create({
39767
+ const styles$5 = StyleSheet.create({
39076
39768
  container: {
39077
39769
  margin: "auto",
39078
39770
  width: "100%"
@@ -39312,129 +40004,6 @@ var Sequence$1 = {
39312
40004
  isLintable: true
39313
40005
  };
39314
40006
 
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
40007
  const {
39439
40008
  assert: assert$1
39440
40009
  } = InteractiveUtil;
@@ -41389,7 +41958,7 @@ const VideoTranscriptLink = props => {
41389
41958
  var _result$data;
41390
41959
  const video = (_result$data = result.data) == null ? void 0 : _result$data.video;
41391
41960
  return /*#__PURE__*/React.createElement(View, {
41392
- style: styles$6.transcriptLink
41961
+ style: styles$4.transcriptLink
41393
41962
  }, /*#__PURE__*/React.createElement(Text$1, null, video == null ? void 0 : video.title), /*#__PURE__*/React.createElement(Strut, {
41394
41963
  size: 10
41395
41964
  }), /*#__PURE__*/React.createElement(Link, {
@@ -41406,7 +41975,7 @@ const VideoTranscriptLink = props => {
41406
41975
  return /*#__PURE__*/React.createElement(View, null, i18n._("Something went wrong."));
41407
41976
  }
41408
41977
  };
41409
- const styles$6 = StyleSheet.create({
41978
+ const styles$4 = StyleSheet.create({
41410
41979
  transcriptLink: {
41411
41980
  flexDirection: "row",
41412
41981
  width: "100%",
@@ -41559,7 +42128,7 @@ const init = function init(options) {
41559
42128
 
41560
42129
  // This file is processed by a Rollup plugin (replace) to inject the production
41561
42130
  const libName = "@khanacademy/perseus";
41562
- const libVersion = "19.6.3";
42131
+ const libVersion = "19.7.1";
41563
42132
  addLibraryVersionToPerseusDebug(libName, libVersion);
41564
42133
 
41565
42134
  const apiVersion = {
@@ -41769,7 +42338,7 @@ class HintRenderer extends React.Component {
41769
42338
  const {
41770
42339
  isMobile
41771
42340
  } = 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);
42341
+ 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
42342
 
41774
42343
  // TODO(charlie): Allowing `customKeypad` would require that we
41775
42344
  // extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
@@ -41812,7 +42381,7 @@ class HintRenderer extends React.Component {
41812
42381
  HintRenderer.defaultProps = {
41813
42382
  linterContext: PerseusLinter.linterContextDefault
41814
42383
  };
41815
- const styles$5 = StyleSheet.create({
42384
+ const styles$3 = StyleSheet.create({
41816
42385
  newHint: {
41817
42386
  marginBottom: 1.5 * baseUnitPx,
41818
42387
  borderLeftColor: gray97,
@@ -41985,15 +42554,15 @@ class HintsRenderer extends React.Component {
41985
42554
  } = apiOptions;
41986
42555
  const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
41987
42556
  const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
41988
- const classNames$1 = classNames(this.props.className, apiOptions.isMobile && hintsVisible > 0 && css(styles$4.mobileHintStylesHintsRenderer));
42557
+ const classNames$1 = classNames(this.props.className, apiOptions.isMobile && hintsVisible > 0 && css(styles$2.mobileHintStylesHintsRenderer));
41989
42558
  return /*#__PURE__*/React.createElement("div", {
41990
42559
  className: classNames$1
41991
42560
  }, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React.createElement("div", {
41992
- className: css(styles$4.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
42561
+ className: css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
41993
42562
  }, i18n._("Hints")), hints, showGetAnotherHint && /*#__PURE__*/React.createElement("button", {
41994
42563
  // @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
42564
  rel: "button",
41996
- className: css(styles$4.linkButton, styles$4.getAnotherHintButton, apiOptions.isMobile && styles$4.mobileHintStylesGetAnotherHintButton),
42565
+ className: css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
41997
42566
  onClick: evt => {
41998
42567
  evt.preventDefault();
41999
42568
  evt.stopPropagation();
@@ -42002,9 +42571,9 @@ class HintsRenderer extends React.Component {
42002
42571
  }
42003
42572
  }
42004
42573
  }, /*#__PURE__*/React.createElement("span", {
42005
- className: css(styles$4.plusText, apiOptions.isMobile && styles$4.mobileHintStylesPlusText)
42574
+ className: css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
42006
42575
  }, "+"), /*#__PURE__*/React.createElement("span", {
42007
- className: css(styles$4.getAnotherHintText)
42576
+ className: css(styles$2.getAnotherHintText)
42008
42577
  }, i18n._("Get another hint"), " ", hintRatioCopy)));
42009
42578
  }
42010
42579
  }
@@ -42012,7 +42581,7 @@ HintsRenderer.defaultProps = {
42012
42581
  linterContext: PerseusLinter.linterContextDefault
42013
42582
  };
42014
42583
  const hintIndentation = baseUnitPx + hintBorderWidth;
42015
- const styles$4 = StyleSheet.create({
42584
+ const styles$2 = StyleSheet.create({
42016
42585
  // eslint-disable-next-line react-native/no-unused-styles
42017
42586
  rendererMargins: {
42018
42587
  marginTop: baseUnitPx
@@ -42419,7 +42988,7 @@ class ServerItemRenderer extends React.Component {
42419
42988
  // mobile hint styles, which are flush to the left.
42420
42989
  // NOTE(charlie): We may still want to apply this
42421
42990
  // padding for desktop exercises.
42422
- apiOptions.isMobile ? undefined : css(styles$3.hintsContainer)
42991
+ apiOptions.isMobile ? undefined : css(styles$1.hintsContainer)
42423
42992
  }, hintsRenderer)));
42424
42993
  }
42425
42994
  }
@@ -42429,7 +42998,7 @@ ServerItemRenderer.defaultProps = {
42429
42998
  linterContext: PerseusLinter.linterContextDefault,
42430
42999
  onRendered: isRendered => {}
42431
43000
  };
42432
- const styles$3 = StyleSheet.create({
43001
+ const styles$1 = StyleSheet.create({
42433
43002
  hintsContainer: {
42434
43003
  marginLeft: 50
42435
43004
  }
@@ -42563,345 +43132,6 @@ ElementContainer.defaultProps = {
42563
43132
  title: "More"
42564
43133
  };
42565
43134
 
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
43135
  const devices = {
42906
43136
  PHONE: "phone",
42907
43137
  TABLET: "tablet",