@khanacademy/perseus 19.6.2 → 19.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,11 +30,12 @@ var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
30
30
  var Banner = require('@khanacademy/wonder-blocks-banner');
31
31
  var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
32
32
  var debounce = require('lodash.debounce');
33
+ var mafs = require('mafs');
34
+ var createReactClass = require('create-react-class');
33
35
  var Switch = require('@khanacademy/wonder-blocks-switch');
34
36
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
35
37
  var Pill = require('@khanacademy/wonder-blocks-pill');
36
38
  var reactPopper = require('react-popper');
37
- var createReactClass = require('create-react-class');
38
39
  var Link = require('@khanacademy/wonder-blocks-link');
39
40
  var perseusCore = require('@khanacademy/perseus-core');
40
41
 
@@ -77,9 +78,9 @@ var SimpleMarkdown__default = /*#__PURE__*/_interopDefaultLegacy(SimpleMarkdown)
77
78
  var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
78
79
  var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
79
80
  var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
81
+ var createReactClass__default = /*#__PURE__*/_interopDefaultLegacy(createReactClass);
80
82
  var Switch__default = /*#__PURE__*/_interopDefaultLegacy(Switch);
81
83
  var Pill__default = /*#__PURE__*/_interopDefaultLegacy(Pill);
82
- var createReactClass__default = /*#__PURE__*/_interopDefaultLegacy(createReactClass);
83
84
  var Link__default = /*#__PURE__*/_interopDefaultLegacy(Link);
84
85
 
85
86
  function _extends() {
@@ -19315,6 +19316,15 @@ const isIdPathPrefix = function (prefixArray, wholeArray) {
19315
19316
  // some return a custom-built object, some delegate to
19316
19317
  // `WidgetJsonifyDeprecated` which returns an object containing widget props
19317
19318
  // (filtered by deprecated keys)).
19319
+ /**
19320
+ * The Widget type represents the common API that the Renderer uses to interact
19321
+ * with all widgets. All widgets must implement the methods in this API, unless
19322
+ * they are marked as optional (?: ...).
19323
+ *
19324
+ * These methods are called on the widget ref and allow the renderer to
19325
+ * communicate with the individual widgets to coordinate actions such as
19326
+ * scoring, state serialization/deserialization, and focus management.
19327
+ */
19318
19328
  class Renderer extends React__namespace.Component {
19319
19329
  // @ts-expect-error - TS2564 - Property '_foundTextNodes' has no initializer and is not definitely assigned in the constructor.
19320
19330
 
@@ -28316,7 +28326,875 @@ class Graph extends React__namespace.Component {
28316
28326
  }
28317
28327
  }
28318
28328
 
28319
- /* eslint-disable @babel/no-invalid-this, react/no-unsafe, react/sort-comp */
28329
+ const useInteractivePoint = (coords, snaps, range) => mafs.useMovablePoint(coords, {
28330
+ constrain: coord => constrain(coord, snaps, range),
28331
+ color: Color__default["default"].blue
28332
+ });
28333
+
28334
+ /**
28335
+ * We do not want to call `onGraphChange` until the user
28336
+ * has interacted with the graph. See the test,
28337
+ * "should reject no interaction"
28338
+ */
28339
+ const useEffectAfterFirstRender = (fn, deps) => {
28340
+ const firstRender = React.useRef(true);
28341
+ React.useEffect(() => {
28342
+ if (firstRender.current) {
28343
+ firstRender.current = false;
28344
+ return;
28345
+ }
28346
+ fn();
28347
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28348
+ }, [fn, ...deps]);
28349
+ };
28350
+ const snap = (val, step) => {
28351
+ const inverse = 1 / step;
28352
+ return Math.round(val * inverse) / inverse;
28353
+ };
28354
+ const clamp = (n, min, max) => Math.max(min, Math.min(max, n));
28355
+ const constrain = (coord, snapStep, range) => {
28356
+ const [x, y] = coord;
28357
+ const [xSnap, ySnap] = snapStep;
28358
+ const [[xMin, xMax], [yMin, yMax]] = range;
28359
+ return [clamp(snap(x, xSnap), xMin, xMax), clamp(snap(y, ySnap), yMin, yMax)];
28360
+ };
28361
+
28362
+ // same as pointsFromNormalized in interactive-graph.tsx
28363
+ const normalizePoints = (range, step, coordsList, noSnap) => coordsList.map(coords =>
28364
+ // maps over [x, y]
28365
+ coords.map((coord, i) => {
28366
+ const axisRange = range[i];
28367
+ if (noSnap) {
28368
+ return axisRange[0] + (axisRange[1] - axisRange[0]) * coord;
28369
+ }
28370
+ const axisStep = step[i];
28371
+ const nSteps = Math.floor((axisRange[1] - axisRange[0]) / axisStep);
28372
+ const tick = Math.round(coord * nSteps);
28373
+ return axisRange[0] + axisStep * tick;
28374
+ }));
28375
+
28376
+ // same as normalizeCoords in interactive-graph.tsx
28377
+ const normalizeCoords = (coordsList, ranges) => coordsList.map(coords => coords.map((coord, i) => {
28378
+ const extent = ranges[i][1] - ranges[i][0];
28379
+ return (coord + ranges[i][1]) / extent;
28380
+ }));
28381
+
28382
+ const getSegmentCoords = props => {
28383
+ const coords = props.graph.coords;
28384
+ if (coords) {
28385
+ return coords;
28386
+ }
28387
+ const ys = n => {
28388
+ switch (n) {
28389
+ case 2:
28390
+ return [5, -5];
28391
+ case 3:
28392
+ return [5, 0, -5];
28393
+ case 4:
28394
+ return [6, 2, -2, -6];
28395
+ case 5:
28396
+ return [6, 3, 0, -3, -6];
28397
+ case 6:
28398
+ return [5, 3, 1, -1, -3, -5];
28399
+ default:
28400
+ return [5];
28401
+ }
28402
+ };
28403
+ return ys(props.graph.numSegments).map(y => {
28404
+ let segment = [[-5, y], [5, y]];
28405
+ segment = normalizeCoords(segment, props.range);
28406
+ segment = normalizePoints(props.range, props.step, segment);
28407
+ return segment;
28408
+ });
28409
+ };
28410
+ const updateSegmentsArray = (segments, index, segment) => segments.map((seg, i) => index === i ? segment : seg);
28411
+ const SegmentGraph = props => {
28412
+ const segments = getSegmentCoords(props);
28413
+ const handleChange = (i, segment) => props.onGraphChange(current => ({
28414
+ ...current,
28415
+ coords: current.coords ? updateSegmentsArray(current.coords, i, segment) : updateSegmentsArray(segments, i, segment)
28416
+ }));
28417
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, segments.map((segment, i) => /*#__PURE__*/React__namespace.createElement(Segment, {
28418
+ key: i,
28419
+ i: i,
28420
+ segment: segment,
28421
+ snaps: props.snapStep,
28422
+ range: props.range,
28423
+ onChange: handleChange,
28424
+ "data-testid": "segment" + i
28425
+ })));
28426
+ };
28427
+ const Segment = props => {
28428
+ const [start, end] = props.segment;
28429
+ const {
28430
+ point: pt1,
28431
+ element: el1
28432
+ } = useInteractivePoint(start, props.snaps, props.range);
28433
+ const {
28434
+ point: pt2,
28435
+ element: el2
28436
+ } = useInteractivePoint(end, props.snaps, props.range);
28437
+ useEffectAfterFirstRender(() => props.onChange(props.i, [pt1, pt2]), [pt1, pt2]);
28438
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Line.Segment, {
28439
+ point1: pt1,
28440
+ point2: pt2
28441
+ }), el1, el2);
28442
+ };
28443
+
28444
+ const renderLineLabel = (n, _ref) => {
28445
+ let [min, max] = _ref;
28446
+ return n !== -1 && n !== min && n !== max;
28447
+ };
28448
+ const axisOptions = (props, index) => ({
28449
+ axis: props.markings === "graph",
28450
+ lines: props.step[index],
28451
+ subdivisions: props.step[index] / props.gridStep[index],
28452
+ labels: n => renderLineLabel(n, props.range[index]) ? n : ""
28453
+ });
28454
+ const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
28455
+ xAxis: axisOptions(props, 0),
28456
+ yAxis: axisOptions(props, 1)
28457
+ });
28458
+
28459
+ // Displays a stylized open eye: lint warnings are visible
28460
+ const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
28461
+ width: "24",
28462
+ height: "24",
28463
+ viewBox: "0 0 24 24",
28464
+ className: aphrodite.css(styles$j.icon)
28465
+ }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
28466
+ id: "a",
28467
+ 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"
28468
+ })), /*#__PURE__*/React__namespace.createElement("g", {
28469
+ fill: "none",
28470
+ fillRule: "evenodd"
28471
+ }, /*#__PURE__*/React__namespace.createElement("path", {
28472
+ fill: "none",
28473
+ d: "M0 0h24v24H0z"
28474
+ }), /*#__PURE__*/React__namespace.createElement("mask", {
28475
+ id: "b",
28476
+ fill: "#fff"
28477
+ }, /*#__PURE__*/React__namespace.createElement("use", {
28478
+ href: "#a"
28479
+ })), /*#__PURE__*/React__namespace.createElement("use", {
28480
+ fill: "#fff",
28481
+ fillRule: "nonzero",
28482
+ href: "#a"
28483
+ }), /*#__PURE__*/React__namespace.createElement("g", {
28484
+ fill: "#fff",
28485
+ mask: "url(#b)"
28486
+ }, /*#__PURE__*/React__namespace.createElement("path", {
28487
+ d: "M0 0h24v24H0z"
28488
+ }))));
28489
+
28490
+ // Displays a stylized eye with a line through it: I don't want to see lint
28491
+ const HiddenIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
28492
+ width: "24",
28493
+ height: "24",
28494
+ viewBox: "0 0 24 24",
28495
+ className: aphrodite.css(styles$j.icon)
28496
+ }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
28497
+ id: "a",
28498
+ 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"
28499
+ })), /*#__PURE__*/React__namespace.createElement("g", {
28500
+ fill: "none",
28501
+ fillRule: "evenodd"
28502
+ }, /*#__PURE__*/React__namespace.createElement("path", {
28503
+ fill: "none",
28504
+ d: "M0 0h24v24H0z"
28505
+ }), /*#__PURE__*/React__namespace.createElement("mask", {
28506
+ id: "b",
28507
+ fill: "#fff"
28508
+ }, /*#__PURE__*/React__namespace.createElement("use", {
28509
+ href: "#a"
28510
+ })), /*#__PURE__*/React__namespace.createElement("use", {
28511
+ fill: "#fff",
28512
+ fillRule: "nonzero",
28513
+ href: "#a"
28514
+ }), /*#__PURE__*/React__namespace.createElement("g", {
28515
+ fill: "#fff",
28516
+ mask: "url(#b)"
28517
+ }, /*#__PURE__*/React__namespace.createElement("path", {
28518
+ d: "M0 0h24v24H0z"
28519
+ }))));
28520
+ const HUD = _ref => {
28521
+ let {
28522
+ message,
28523
+ enabled,
28524
+ onClick,
28525
+ fixedPosition = true
28526
+ } = _ref;
28527
+ let state;
28528
+ let icon;
28529
+ if (enabled) {
28530
+ state = styles$j.enabled;
28531
+ icon = /*#__PURE__*/React__namespace.createElement(VisibleIcon, null);
28532
+ } else {
28533
+ state = styles$j.disabled;
28534
+ icon = /*#__PURE__*/React__namespace.createElement(HiddenIcon, null);
28535
+ }
28536
+ return /*#__PURE__*/React__namespace.createElement("button", {
28537
+ className: aphrodite.css(styles$j.hud, fixedPosition && styles$j.hudFixedPosition, state),
28538
+ onClick: e => {
28539
+ onClick();
28540
+ }
28541
+ }, icon, message);
28542
+ };
28543
+ const styles$j = aphrodite.StyleSheet.create({
28544
+ hud: {
28545
+ boxSizing: "border-box",
28546
+ height: 36,
28547
+ padding: "9px 16px",
28548
+ borderRadius: 18,
28549
+ fontFamily: boldFontFamily,
28550
+ fontSize: "15px",
28551
+ lineHeight: "18px",
28552
+ color: white$1,
28553
+ userSelect: "none",
28554
+ borderWidth: 0 // <button> gives us a border by default
28555
+ },
28556
+
28557
+ // We want to render the element in-place in our fixtures, so allow us to
28558
+ // render in the bottom corner in production and in-place in testing.
28559
+ hudFixedPosition: {
28560
+ bottom: 20,
28561
+ position: "fixed",
28562
+ right: 20,
28563
+ zIndex: 1
28564
+ },
28565
+ icon: {
28566
+ width: 24,
28567
+ height: 24,
28568
+ marginRight: 8,
28569
+ marginTop: -3,
28570
+ verticalAlign: "middle"
28571
+ },
28572
+ enabled: {
28573
+ backgroundColor: warningColor,
28574
+ ":hover": {
28575
+ backgroundColor: warningColorHover
28576
+ },
28577
+ ":active": {
28578
+ backgroundColor: warningColorActive
28579
+ }
28580
+ },
28581
+ disabled: {
28582
+ backgroundColor: gray76,
28583
+ ":hover": {
28584
+ backgroundColor: "#a1a5a9" // in between those two grays
28585
+ },
28586
+
28587
+ ":active": {
28588
+ backgroundColor: gray68
28589
+ }
28590
+ }
28591
+ });
28592
+
28593
+ const colors$1 = {
28594
+ grayLight: "#aaa",
28595
+ basicBorderColor: "#ccc",
28596
+ white: "#fff"
28597
+ };
28598
+ const triangleBeforeAfter = {
28599
+ borderBottom: "9px solid transparent",
28600
+ borderTop: "9px solid transparent",
28601
+ content: '" "',
28602
+ height: "0",
28603
+ position: "absolute",
28604
+ top: "0",
28605
+ width: "0"
28606
+ };
28607
+ const styles$i = aphrodite.StyleSheet.create({
28608
+ infoTip: {
28609
+ display: "inline-block",
28610
+ marginLeft: "5px",
28611
+ position: "relative"
28612
+ },
28613
+ infoTipContainer: {
28614
+ position: "absolute",
28615
+ top: "-12px",
28616
+ left: "22px",
28617
+ zIndex: 1000
28618
+ },
28619
+ infoTipTriangle: {
28620
+ height: "10px",
28621
+ left: "0",
28622
+ position: "absolute",
28623
+ top: "8px",
28624
+ width: "0",
28625
+ zIndex: 1,
28626
+ ":before": {
28627
+ ...triangleBeforeAfter,
28628
+ borderRight: "9px solid #bbb",
28629
+ right: "0"
28630
+ },
28631
+ ":after": {
28632
+ ...triangleBeforeAfter,
28633
+ borderRight: `9px solid ${colors$1.white}`,
28634
+ right: "-1px"
28635
+ }
28636
+ },
28637
+ verticalShadow: {
28638
+ border: `1px solid ${colors$1.basicBorderColor}`,
28639
+ boxShadow: `0 1px 3px ${colors$1.basicBorderColor}`,
28640
+ borderBottom: `1px solid ${colors$1.grayLight}`
28641
+ },
28642
+ infoTipContentContainer: {
28643
+ background: colors$1.white,
28644
+ padding: "5px 10px",
28645
+ width: "240px"
28646
+ }
28647
+ });
28648
+ 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=";
28649
+ class InfoTip$1 extends React__namespace.Component {
28650
+ state = {
28651
+ hover: false
28652
+ };
28653
+ handleMouseEnter = () => {
28654
+ this.setState({
28655
+ hover: true
28656
+ });
28657
+ };
28658
+ handleMouseLeave = () => {
28659
+ this.setState({
28660
+ hover: false
28661
+ });
28662
+ };
28663
+ render() {
28664
+ return /*#__PURE__*/React__namespace.createElement("div", {
28665
+ className: aphrodite.css(styles$i.infoTip)
28666
+ }, /*#__PURE__*/React__namespace.createElement("img", {
28667
+ alt: "",
28668
+ width: 10,
28669
+ height: 10,
28670
+ src: questionMark,
28671
+ onMouseEnter: this.handleMouseEnter,
28672
+ onMouseLeave: this.handleMouseLeave
28673
+ }), /*#__PURE__*/React__namespace.createElement("div", {
28674
+ className: aphrodite.css(styles$i.infoTipContainer),
28675
+ style: {
28676
+ display: this.state.hover ? "block" : "none"
28677
+ }
28678
+ }, /*#__PURE__*/React__namespace.createElement("div", {
28679
+ className: aphrodite.css(styles$i.infoTipTriangle)
28680
+ }), /*#__PURE__*/React__namespace.createElement("div", {
28681
+ className: aphrodite.css(styles$i.verticalShadow, styles$i.infoTipContentContainer)
28682
+ }, this.props.children)));
28683
+ }
28684
+ }
28685
+
28686
+ /**
28687
+ * A wrapper around info-tip/info-tip.jsx that can be rendered on the
28688
+ * server without causing a checksum mismatch on the client.
28689
+ * (RCSS generates classnames with a randomSuffix, which ensures that any
28690
+ * two sets of generated classnames will not match.)
28691
+ */
28692
+ class InfoTip extends React__namespace.Component {
28693
+ state = {
28694
+ didMount: false
28695
+ };
28696
+ componentDidMount() {
28697
+ /* eslint-disable react/no-did-mount-set-state */
28698
+ this.setState({
28699
+ didMount: true
28700
+ });
28701
+ /* eslint-enable react/no-did-mount-set-state */
28702
+ }
28703
+
28704
+ render() {
28705
+ if (this.state.didMount) {
28706
+ return /*#__PURE__*/React__namespace.createElement(InfoTip$1, this.props);
28707
+ }
28708
+ return /*#__PURE__*/React__namespace.createElement("div", null);
28709
+ }
28710
+ }
28711
+
28712
+ /**
28713
+ * MultiButtonGroup is an aesthetically pleasing group of buttons,
28714
+ * which allows multiple buttons to be selected at the same time.
28715
+ *
28716
+ * NOTE: This component is almost identical to ./button-group.jsx except that
28717
+ * this component allows multiple selection!
28718
+ */
28719
+ class MultiButtonGroup extends React__namespace.Component {
28720
+ static defaultProps = {
28721
+ values: [],
28722
+ allowEmpty: true
28723
+ };
28724
+ focus() {
28725
+ // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
28726
+ ReactDOM__namespace.findDOMNode(this)?.focus();
28727
+ return true;
28728
+ }
28729
+ toggleSelect = newValue => {
28730
+ const values = (this.props.values || []).slice(0);
28731
+ const allowEmpty = this.props.allowEmpty;
28732
+ if (values.indexOf(newValue) >= 0 && (values.length > 1 || allowEmpty)) {
28733
+ // If the value is already selected, unselect it
28734
+ values.splice(values.indexOf(newValue), 1);
28735
+ } else {
28736
+ // Otherwise merge with other values and return
28737
+ if (values.indexOf(newValue) < 0) {
28738
+ values.push(newValue);
28739
+ }
28740
+ }
28741
+ this.props.onChange(values);
28742
+ };
28743
+ render() {
28744
+ const values = this.props.values || [];
28745
+ const buttons = this.props.buttons.map((button, i) => {
28746
+ const selected = values.indexOf(button.value) >= 0;
28747
+ return /*#__PURE__*/React__namespace.createElement("button", {
28748
+ title: button.title,
28749
+ type: "button",
28750
+ id: "" + i,
28751
+ key: "" + i,
28752
+ ref: "button" + i,
28753
+ className: aphrodite.css(styles$h.buttonStyle, selected && styles$h.selectedStyle),
28754
+ onClick: () => this.toggleSelect(button.value)
28755
+ }, button.content || "" + button.value);
28756
+ });
28757
+ const outerStyle = {
28758
+ display: "inline-block"
28759
+ };
28760
+ return /*#__PURE__*/React__namespace.createElement("div", {
28761
+ style: outerStyle
28762
+ }, buttons);
28763
+ }
28764
+ }
28765
+ const styles$h = aphrodite.StyleSheet.create({
28766
+ buttonStyle: {
28767
+ backgroundColor: "white",
28768
+ border: "1px solid #ccc",
28769
+ borderLeft: "0",
28770
+ cursor: "pointer",
28771
+ margin: "0",
28772
+ padding: "5px 10px",
28773
+ position: "relative",
28774
+ // for hover
28775
+
28776
+ ":first-child": {
28777
+ borderLeft: "1px solid #ccc",
28778
+ borderTopLeftRadius: "3px",
28779
+ borderBottomLeftRadius: "3px"
28780
+ },
28781
+ ":last-child": {
28782
+ borderRight: "1px solid #ccc",
28783
+ borderTopRightRadius: "3px",
28784
+ borderBottomRightRadius: "3px"
28785
+ },
28786
+ ":hover": {
28787
+ backgroundColor: "#ccc"
28788
+ },
28789
+ ":focus": {
28790
+ zIndex: 2
28791
+ }
28792
+ },
28793
+ selectedStyle: {
28794
+ backgroundColor: "#ddd"
28795
+ }
28796
+ });
28797
+
28798
+ const {
28799
+ firstNumericalParse,
28800
+ captureScratchpadTouchStart
28801
+ } = Util;
28802
+ const toNumericString = KhanMath.toNumericString;
28803
+ const getNumericFormat = KhanMath.getNumericFormat;
28804
+
28805
+ /* An input box that accepts only numeric strings
28806
+ *
28807
+ * Calls onChange(value, format) for valid numbers.
28808
+ * Reverts to the current value onBlur or on [ENTER],
28809
+ * but maintains the format (i.e. 3/2, 1 1/2, 150%)
28810
+ * Accepts empty input and sends it to onChange as null
28811
+ * if no numeric placeholder is set.
28812
+ * If given a checkValidity function, will turn
28813
+ * the background/outline red when invalid
28814
+ * If useArrowKeys is set to true, up/down arrows will
28815
+ * increment/decrement integers
28816
+ * Optionally takes a size ("mini", "small", "normal")
28817
+ */
28818
+ class NumberInput extends React__namespace.Component {
28819
+ static propTypes = {
28820
+ value: PropTypes__default["default"].number,
28821
+ format: PropTypes__default["default"].string,
28822
+ placeholder: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number]),
28823
+ onChange: PropTypes__default["default"].func.isRequired,
28824
+ onFormatChange: PropTypes__default["default"].func,
28825
+ checkValidity: PropTypes__default["default"].func,
28826
+ size: PropTypes__default["default"].string,
28827
+ label: PropTypes__default["default"].oneOf(["put your labels outside your inputs!"])
28828
+ };
28829
+ static defaultProps = {
28830
+ value: null,
28831
+ placeholder: null,
28832
+ format: null,
28833
+ onFormatChange: () => null,
28834
+ checkValidity: () => true,
28835
+ useArrowKeys: false
28836
+ };
28837
+ state = {
28838
+ format: this.props.format
28839
+ };
28840
+ render() {
28841
+ let classes = classNames__default["default"]({
28842
+ "number-input": true,
28843
+ "invalid-input": !this._checkValidity(this.props.value),
28844
+ mini: this.props.size === "mini",
28845
+ small: this.props.size === "small",
28846
+ normal: this.props.size === "normal"
28847
+ });
28848
+ if (this.props.className != null) {
28849
+ classes = classes + " " + this.props.className;
28850
+ }
28851
+ const {
28852
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28853
+ onFormatChange,
28854
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28855
+ checkValidity,
28856
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28857
+ useArrowKeys,
28858
+ ...restProps
28859
+ } = this.props;
28860
+ return /*#__PURE__*/React__namespace.createElement("input", _extends({}, restProps, {
28861
+ className: classes,
28862
+ type: "text"
28863
+ // eslint-disable-next-line react/no-string-refs
28864
+ ,
28865
+ ref: "input",
28866
+ onChange: this._handleChange,
28867
+ onFocus: this._handleFocus,
28868
+ onBlur: this._handleBlur,
28869
+ onKeyPress: this._handleBlur,
28870
+ onKeyDown: this._onKeyDown
28871
+ // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
28872
+ ,
28873
+ onTouchStart: captureScratchpadTouchStart,
28874
+ defaultValue: toNumericString(this.props.value, this.state.format),
28875
+ value: undefined
28876
+ }));
28877
+ }
28878
+ componentDidUpdate(prevProps) {
28879
+ if (!kmath.number.equal(this.getValue(), this.props.value)) {
28880
+ this._setValue(this.props.value, this.state.format);
28881
+ }
28882
+ }
28883
+
28884
+ /* Return the current "value" of this input
28885
+ * If empty, it returns the placeholder (if it is a number) or null
28886
+ */
28887
+ getValue = () => {
28888
+ return this.parseInputValue(
28889
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
28890
+ ReactDOM__default["default"].findDOMNode(this.refs.input).value // eslint-disable-line react/no-string-refs
28891
+ );
28892
+ };
28893
+
28894
+ /* Return the current string value of this input */
28895
+ getStringValue = () => {
28896
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
28897
+ return ReactDOM__default["default"].findDOMNode(this.refs.input).value.toString(); // eslint-disable-line react/no-string-refs
28898
+ };
28899
+
28900
+ parseInputValue = value => {
28901
+ if (value === "") {
28902
+ const placeholder = this.props.placeholder;
28903
+ return ___default["default"].isFinite(placeholder) ? +placeholder : null;
28904
+ }
28905
+ const result = firstNumericalParse(value);
28906
+ return ___default["default"].isFinite(result) ? result : this.props.value;
28907
+ };
28908
+
28909
+ /* Set text input focus to this input */
28910
+ focus = () => {
28911
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
28912
+ ReactDOM__default["default"].findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
28913
+ this._handleFocus();
28914
+ };
28915
+ blur = () => {
28916
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
28917
+ ReactDOM__default["default"].findDOMNode(this.refs.input).blur(); // eslint-disable-line react/no-string-refs
28918
+ this._handleBlur();
28919
+ };
28920
+ setSelectionRange = (selectionStart, selectionEnd) => {
28921
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
28922
+ ReactDOM__default["default"].findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
28923
+ };
28924
+ getSelectionStart = () => {
28925
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
28926
+ return ReactDOM__default["default"].findDOMNode(this).selectionStart;
28927
+ };
28928
+ getSelectionEnd = () => {
28929
+ // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
28930
+ return ReactDOM__default["default"].findDOMNode(this).selectionEnd;
28931
+ };
28932
+ _checkValidity = value => {
28933
+ if (value == null) {
28934
+ return true;
28935
+ }
28936
+ const val = firstNumericalParse(value);
28937
+ const checkValidity = this.props.checkValidity;
28938
+ return ___default["default"].isFinite(val) && checkValidity(val);
28939
+ };
28940
+ _handleChange = e => {
28941
+ const text = e.target.value;
28942
+ const value = this.parseInputValue(text);
28943
+ const format = getNumericFormat(text);
28944
+ this.props.onChange(value);
28945
+ if (format) {
28946
+ this.props.onFormatChange(value, format);
28947
+ this.setState({
28948
+ format: format
28949
+ });
28950
+ }
28951
+ };
28952
+ _handleFocus = () => {
28953
+ if (this.props.onFocus) {
28954
+ this.props.onFocus();
28955
+ }
28956
+ };
28957
+ _handleBlur = e => {
28958
+ // Only continue on blur or "enter"
28959
+ // @ts-expect-error - TS2339 - Property 'keyCode' does not exist on type 'KeyboardEvent<Element> | FocusEvent<Element, Element>'.
28960
+ if (e && e.type === "keypress" && e.keyCode !== 13) {
28961
+ return;
28962
+ }
28963
+ this._setValue(this.props.value, this.state.format);
28964
+ if (this.props.onBlur) {
28965
+ this.props.onBlur();
28966
+ }
28967
+ };
28968
+ _onKeyDown = e => {
28969
+ if (this.props.onKeyDown) {
28970
+ this.props.onKeyDown(e);
28971
+ }
28972
+ if (!this.props.useArrowKeys || !___default["default"].contains(["ArrowUp", "ArrowDown"], e.key)) {
28973
+ return;
28974
+ }
28975
+ let val = this.getValue();
28976
+ if (val !== Math.floor(val)) {
28977
+ return; // bail if not an integer
28978
+ }
28979
+
28980
+ if (e.key === "ArrowUp") {
28981
+ val = val + 1;
28982
+ } else if (e.key === "ArrowDown") {
28983
+ val = val - 1;
28984
+ }
28985
+ if (this._checkValidity(val)) {
28986
+ this.props.onChange(val);
28987
+ }
28988
+ };
28989
+ _setValue = (val, format) => {
28990
+ // eslint-disable-next-line react/no-string-refs
28991
+ // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
28992
+ $__default["default"](ReactDOM__default["default"].findDOMNode(this.refs.input)).val(toNumericString(val, format));
28993
+ };
28994
+ }
28995
+
28996
+ /* eslint-disable @babel/no-invalid-this */
28997
+
28998
+ /* A checkbox that syncs its value to props using the
28999
+ * renderer's onChange method, and gets the prop name
29000
+ * dynamically from its props list
29001
+ */
29002
+ const PropCheckBox = createReactClass__default["default"]({
29003
+ displayName: "PropCheckBox",
29004
+ propTypes: {
29005
+ labelAlignment: PropTypes__default["default"].oneOf(["left", "right"])
29006
+ },
29007
+ DEFAULT_PROPS: {
29008
+ label: null,
29009
+ onChange: null,
29010
+ labelAlignment: "left"
29011
+ },
29012
+ getDefaultProps: function () {
29013
+ return this.DEFAULT_PROPS;
29014
+ },
29015
+ propName: function () {
29016
+ const propName = ___default["default"].find(___default["default"].keys(this.props), function (localPropName) {
29017
+ // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
29018
+ return !___default["default"].has(this.DEFAULT_PROPS, localPropName);
29019
+ }, this);
29020
+ if (!propName) {
29021
+ throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
29022
+ }
29023
+ return propName;
29024
+ },
29025
+ _labelAlignLeft: function () {
29026
+ return this.props.labelAlignment === "left";
29027
+ },
29028
+ render: function () {
29029
+ const propName = this.propName();
29030
+ return /*#__PURE__*/React__namespace.createElement("label", null, this._labelAlignLeft() && this.props.label, /*#__PURE__*/React__namespace.createElement("input", {
29031
+ type: "checkbox",
29032
+ checked: this.props[propName],
29033
+ onChange: this.toggle
29034
+ }), !this._labelAlignLeft() && this.props.label);
29035
+ },
29036
+ toggle: function () {
29037
+ const propName = this.propName();
29038
+ const changes = {};
29039
+ changes[propName] = !this.props[propName];
29040
+ this.props.onChange(changes);
29041
+ }
29042
+ });
29043
+
29044
+ const truth = () => true;
29045
+
29046
+ /* A minor abstraction on top of NumberInput for ranges
29047
+ *
29048
+ */
29049
+ class RangeInput extends React__namespace.Component {
29050
+ static propTypes = {
29051
+ value: PropTypes__default["default"].array.isRequired,
29052
+ onChange: PropTypes__default["default"].func.isRequired,
29053
+ placeholder: PropTypes__default["default"].array,
29054
+ checkValidity: PropTypes__default["default"].func
29055
+ };
29056
+ static defaultProps = {
29057
+ placeholder: [null, null]
29058
+ };
29059
+ render() {
29060
+ const value = this.props.value;
29061
+ const checkValidity = this.props.checkValidity || truth;
29062
+ return /*#__PURE__*/React__namespace.createElement("div", {
29063
+ className: "range-input"
29064
+ }, /*#__PURE__*/React__namespace.createElement(NumberInput, _extends({}, this.props, {
29065
+ value: value[0],
29066
+ checkValidity: val => checkValidity([val, value[1]])
29067
+ // eslint-disable-next-line react/jsx-no-bind
29068
+ ,
29069
+ onChange: this.onChange.bind(this, 0),
29070
+ placeholder: this.props.placeholder[0]
29071
+ })), /*#__PURE__*/React__namespace.createElement(NumberInput, _extends({}, this.props, {
29072
+ value: value[1],
29073
+ checkValidity: val => checkValidity([value[0], val])
29074
+ // eslint-disable-next-line react/jsx-no-bind
29075
+ ,
29076
+ onChange: this.onChange.bind(this, 1),
29077
+ placeholder: this.props.placeholder[1]
29078
+ })));
29079
+ }
29080
+ onChange = (i, newVal) => {
29081
+ const value = this.props.value;
29082
+ if (i === 0) {
29083
+ this.props.onChange([newVal, value[1]]);
29084
+ } else {
29085
+ this.props.onChange([value[0], newVal]);
29086
+ }
29087
+ };
29088
+ }
29089
+
29090
+ var components = /*#__PURE__*/Object.freeze({
29091
+ __proto__: null,
29092
+ ButtonGroup: ButtonGroup,
29093
+ Graph: Graph,
29094
+ Graphie: Graphie,
29095
+ HUD: HUD,
29096
+ Icon: Icon,
29097
+ InfoTip: InfoTip,
29098
+ InlineIcon: InlineIcon,
29099
+ MathInput: MathInput,
29100
+ MultiButtonGroup: MultiButtonGroup,
29101
+ NumberInput: NumberInput,
29102
+ PropCheckBox: PropCheckBox,
29103
+ RangeInput: RangeInput,
29104
+ SvgImage: SvgImage,
29105
+ TextInput: TextInput,
29106
+ TextListEditor: TextListEditor
29107
+ });
29108
+
29109
+ /**
29110
+ * If a graphie URL is provided in `backgroundImage`, will return the rendered graphie background.
29111
+ * Otherwise, returns `null`.
29112
+ */
29113
+ const getLegacyGrid = (box, backgroundImage) => {
29114
+ const {
29115
+ url,
29116
+ width,
29117
+ height
29118
+ } = backgroundImage ?? {};
29119
+ if (url && typeof url === "string") {
29120
+ const scale = box[0] / interactiveSizes$1.defaultBoxSize;
29121
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29122
+ style: {
29123
+ position: "absolute",
29124
+ bottom: 0,
29125
+ left: 0
29126
+ }
29127
+ }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref => {
29128
+ let {
29129
+ setAssetStatus
29130
+ } = _ref;
29131
+ return /*#__PURE__*/React__namespace.createElement(SvgImage, {
29132
+ src: url,
29133
+ width: width,
29134
+ height: height,
29135
+ scale: scale,
29136
+ responsive: false,
29137
+ setAssetStatus: setAssetStatus,
29138
+ alt: ""
29139
+ });
29140
+ }));
29141
+ }
29142
+ return null;
29143
+ };
29144
+
29145
+ const renderGraph = props => {
29146
+ const {
29147
+ graph,
29148
+ ...rest
29149
+ } = props;
29150
+ switch (graph.type) {
29151
+ case "segment":
29152
+ return /*#__PURE__*/React__namespace.createElement(SegmentGraph, _extends({}, rest, {
29153
+ graph: graph,
29154
+ onGraphChange: props.onGraphChange
29155
+ }));
29156
+ }
29157
+ };
29158
+ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
29159
+ // Storing the gradable state in a ref so that it can be updated without
29160
+ // causing a re-render.
29161
+ const graphRef = React__namespace.useRef(props.graph);
29162
+ const handleGraphUpdate = callback => {
29163
+ graphRef.current = callback(graphRef.current);
29164
+ };
29165
+ React__namespace.useImperativeHandle(ref, () => ({
29166
+ getUserInput: () => graphRef.current
29167
+ }));
29168
+ const [width, height] = getInteractiveBoxFromSizeClass(props.containerSizeClass);
29169
+ const legacyGrid = getLegacyGrid([width, height], props.backgroundImage);
29170
+ return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29171
+ style: {
29172
+ width: props.backgroundImage?.width ?? width,
29173
+ height: props.backgroundImage?.height ?? height,
29174
+ position: "relative"
29175
+ }
29176
+ }, legacyGrid, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
29177
+ style: {
29178
+ position: "absolute",
29179
+ bottom: 0,
29180
+ left: 0
29181
+ }
29182
+ }, /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
29183
+ viewBox: {
29184
+ x: props.range[0],
29185
+ y: props.range[1],
29186
+ padding: 0
29187
+ },
29188
+ pan: false,
29189
+ zoom: false,
29190
+ width: width,
29191
+ height: height
29192
+ }, !!legacyGrid && /*#__PURE__*/React__namespace.createElement(Grid, props), renderGraph({
29193
+ ...props,
29194
+ onGraphChange: handleGraphUpdate
29195
+ }))));
29196
+ });
29197
+
28320
29198
  const {
28321
29199
  DeprecationMixin
28322
29200
  } = Util;
@@ -28393,6 +29271,7 @@ class InteractiveGraph extends React__namespace.Component {
28393
29271
  type: "linear"
28394
29272
  }
28395
29273
  };
29274
+ mafsRef = /*#__PURE__*/React__namespace.createRef();
28396
29275
  state = {
28397
29276
  shouldShowInstructions: _getShouldShowInstructions(this.props)
28398
29277
  };
@@ -28402,9 +29281,11 @@ class InteractiveGraph extends React__namespace.Component {
28402
29281
  DeprecationMixin.UNSAFE_componentWillMount.call(this);
28403
29282
  }
28404
29283
  componentDidMount() {
28405
- // eslint-disable-next-line react/no-string-refs
28406
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
28407
- this.setGraphie(this.refs.graph.graphie());
29284
+ if (this.refs.graph) {
29285
+ // eslint-disable-next-line react/no-string-refs
29286
+ // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
29287
+ this.setGraphie(this.refs.graph.graphie());
29288
+ }
28408
29289
  }
28409
29290
  UNSAFE_componentWillReceiveProps(nextProps) {
28410
29291
  if (this.isClickToAddPoints() !== this.isClickToAddPoints(nextProps)) {
@@ -29501,16 +30382,22 @@ class InteractiveGraph extends React__namespace.Component {
29501
30382
  graph: graph
29502
30383
  });
29503
30384
  };
29504
- getUserInput = () => {
29505
- return InteractiveGraph.getUserInputFromProps(this.props);
29506
- };
29507
- simpleValidate = rubric => {
29508
- return InteractiveGraph.validate(this.getUserInput(), rubric, this);
29509
- };
30385
+ getUserInput = () => this.mafsRef.current?.getUserInput?.() ?? InteractiveGraph.getUserInputFromProps(this.props);
30386
+ simpleValidate = rubric => InteractiveGraph.validate(this.getUserInput(), rubric, this);
29510
30387
  focus = $__default["default"].noop;
30388
+
30389
+ // const segment: boolean = useFeatureIsOn("mafs-segment-graph");
30390
+ // <Renderer apiOptions={{flags: {mafs: {segment}}}}
29511
30391
  render() {
30392
+ // Mafs shim
30393
+ if (this.props.apiOptions?.flags?.["mafs"]?.[this.props.graph.type]) {
30394
+ return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, this.props, {
30395
+ ref: this.mafsRef
30396
+ }));
30397
+ }
29512
30398
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
29513
30399
  let instructions;
30400
+ // isClickToAddPoints() only applies to points and polygons
29514
30401
  if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
29515
30402
  if (this.props.graph.type === "point") {
29516
30403
  instructions = i18n__namespace._("Click to add points");
@@ -30795,7 +31682,7 @@ var globalConstants = /*#__PURE__*/Object.freeze({
30795
31682
  pureLgMax: pureLgMax
30796
31683
  });
30797
31684
 
30798
- const colors$1 = {
31685
+ const colors = {
30799
31686
  white: "#FFFFFF",
30800
31687
  gray98: "#FAFAFA",
30801
31688
  gray97: "#F6F7F7",
@@ -30855,7 +31742,7 @@ const colors$1 = {
30855
31742
  };
30856
31743
  const borderRadius = 4;
30857
31744
  const breadcrumbStyles = {
30858
- color: colors$1.breadcrumbs,
31745
+ color: colors.breadcrumbs,
30859
31746
  fontFamily: "inherit",
30860
31747
  fontSize: 15,
30861
31748
  fontWeight: "bold",
@@ -30925,14 +31812,14 @@ const typography = {
30925
31812
  },
30926
31813
  // For callouts
30927
31814
  smallHeading: {
30928
- color: colors$1.gray25,
31815
+ color: colors.gray25,
30929
31816
  fontFamily: "inherit",
30930
31817
  fontSize: 17,
30931
31818
  fontWeight: "bold",
30932
31819
  lineHeight: "23px"
30933
31820
  },
30934
31821
  smallHeadingMobile: {
30935
- color: colors$1.gray25,
31822
+ color: colors.gray25,
30936
31823
  fontFamily: "inherit",
30937
31824
  fontSize: 15,
30938
31825
  fontWeight: "bold",
@@ -30940,7 +31827,7 @@ const typography = {
30940
31827
  },
30941
31828
  // Accent headings
30942
31829
  accentHeading: {
30943
- color: colors$1.gray68,
31830
+ color: colors.gray68,
30944
31831
  fontFamily: "inherit",
30945
31832
  fontSize: 15,
30946
31833
  fontWeight: "bold",
@@ -31048,7 +31935,7 @@ const typography = {
31048
31935
  // HACK(kevinb): temporary wonder blocks styles for header only
31049
31936
  // TODO(kevinb): use components from wonder-blocks-typography instead
31050
31937
  wonderBlocksTitle: {
31051
- color: colors$1.white,
31938
+ color: colors.white,
31052
31939
  fontWeight: 900,
31053
31940
  // "Black" weight
31054
31941
  fontSize: 28,
@@ -31070,7 +31957,7 @@ const typography = {
31070
31957
 
31071
31958
  var globalStyles = /*#__PURE__*/Object.freeze({
31072
31959
  __proto__: null,
31073
- colors: colors$1,
31960
+ colors: colors,
31074
31961
  borderRadius: borderRadius,
31075
31962
  fonts: fonts,
31076
31963
  typography: typography
@@ -31135,7 +32022,7 @@ const HideAnswersToggle = props => {
31135
32022
  const switchId = idFactory.get("hide-answers-toggle");
31136
32023
  const labelId = idFactory.get("hide-answers-label");
31137
32024
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31138
- style: styles$j.switchWrapper
32025
+ style: styles$g.switchWrapper
31139
32026
  }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31140
32027
  id: switchId,
31141
32028
  checked: props.areAnswersHidden,
@@ -31147,7 +32034,7 @@ const HideAnswersToggle = props => {
31147
32034
  tag: "label"
31148
32035
  }, strings.hideAnswersToggleLabel));
31149
32036
  };
31150
- const styles$j = aphrodite.StyleSheet.create({
32037
+ const styles$g = aphrodite.StyleSheet.create({
31151
32038
  switchWrapper: {
31152
32039
  display: "flex",
31153
32040
  flexDirection: "row",
@@ -31202,14 +32089,14 @@ const AnswerPill = props => {
31202
32089
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31203
32090
  onClick: correct ? undefined : onClick,
31204
32091
  ref: ref,
31205
- style: [style, popperStyle, styles$i.pill, correct && styles$i.correct, incorrect && styles$i.incorrect, (focused || hovered) && BringToFront]
32092
+ style: [style, popperStyle, styles$f.pill, correct && styles$f.correct, incorrect && styles$f.incorrect, (focused || hovered) && BringToFront]
31206
32093
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31207
32094
  content: answerString,
31208
32095
  inline: true
31209
32096
  }));
31210
32097
  });
31211
32098
  };
31212
- const styles$i = aphrodite.StyleSheet.create({
32099
+ const styles$f = aphrodite.StyleSheet.create({
31213
32100
  correct: {
31214
32101
  // WB green darkened by 18%
31215
32102
  backgroundColor: "#00880b"
@@ -31263,25 +32150,25 @@ class Marker extends React__namespace.Component {
31263
32150
  icon: iconNull
31264
32151
  };
31265
32152
  if (showCorrectness) {
31266
- iconStyles = [styles$h.markerGraded, showCorrectness === "correct" ? styles$h.markerCorrect : styles$h.markerIncorrect, isOpen && styles$h.markerSelected];
32153
+ iconStyles = [styles$e.markerGraded, showCorrectness === "correct" ? styles$e.markerCorrect : styles$e.markerIncorrect, isOpen && styles$e.markerSelected];
31267
32154
  args = {
31268
32155
  ...args,
31269
32156
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
31270
32157
  };
31271
32158
  } else if (selectedAnswers && selectedAnswers.length > 0) {
31272
- iconStyles = [styles$h.markerFilled, isOpen && styles$h.markerSelected];
32159
+ iconStyles = [styles$e.markerFilled, isOpen && styles$e.markerSelected];
31273
32160
  } else if (isOpen) {
31274
- iconStyles = [styles$h.markerSelected];
32161
+ iconStyles = [styles$e.markerSelected];
31275
32162
  args = {
31276
32163
  ...args,
31277
32164
  icon: iconChevronDown,
31278
32165
  size: 8
31279
32166
  };
31280
32167
  } else if (showPulsate) {
31281
- iconStyles = [styles$h.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$h.markerUnfilledPulsateOnce : showPulsate && styles$h.markerUnfilledPulsateInfinite];
32168
+ iconStyles = [styles$e.markerPulsateBase, shouldReduceMotion() ? showPulsate && styles$e.markerUnfilledPulsateOnce : showPulsate && styles$e.markerUnfilledPulsateInfinite];
31282
32169
  }
31283
32170
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31284
- style: [styles$h.markerIcon, iconStyles],
32171
+ style: [styles$e.markerIcon, iconStyles],
31285
32172
  ref: node => this._icon = node
31286
32173
  }, /*#__PURE__*/React__namespace.createElement(Icon, args));
31287
32174
  }
@@ -31302,7 +32189,7 @@ class Marker extends React__namespace.Component {
31302
32189
  const markerDisabled = showCorrectness === "correct";
31303
32190
  const active = hovered || focused;
31304
32191
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31305
- style: [styles$h.marker, active && !markerDisabled && styles$h.markerActive]
32192
+ style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive]
31306
32193
  // already translated in: /widgets/graded-group.tsx
31307
32194
  ,
31308
32195
  "aria-label": markerDisabled ? i18n__namespace._("Correct!") : label
@@ -31317,7 +32204,7 @@ class Marker extends React__namespace.Component {
31317
32204
  }));
31318
32205
  }
31319
32206
  }
31320
- const styles$h = aphrodite.StyleSheet.create({
32207
+ const styles$e = aphrodite.StyleSheet.create({
31321
32208
  marker: {
31322
32209
  position: "absolute",
31323
32210
  backgroundColor: Color__default["default"].white,
@@ -31894,13 +32781,13 @@ class LabelImage extends React__namespace.Component {
31894
32781
  const promptString = isMobile ? multipleAnswers ? i18n__namespace._("Tap each dot on the image to select all answers that apply.") : i18n__namespace._("Tap each dot on the image to select an answer.") : multipleAnswers ? i18n__namespace._("Click each dot on the image to select all answers that apply.") : i18n__namespace._("Click each dot on the image to select an answer.");
31895
32782
  const choicesString = i18n__namespace._("Choices:");
31896
32783
  return /*#__PURE__*/React__namespace.createElement("div", {
31897
- className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$g.instructions))
32784
+ className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$d.instructions))
31898
32785
  }, /*#__PURE__*/React__namespace.createElement("div", {
31899
- className: aphrodite.css(styles$g.instructionsCaption)
32786
+ className: aphrodite.css(styles$d.instructionsCaption)
31900
32787
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React__namespace.createElement("div", {
31901
- className: aphrodite.css(styles$g.instructionsChoices)
32788
+ className: aphrodite.css(styles$d.instructionsChoices)
31902
32789
  }, choices.map((choice, index) => /*#__PURE__*/React__namespace.createElement("div", {
31903
- className: aphrodite.css(styles$g.instructionsChoice),
32790
+ className: aphrodite.css(styles$d.instructionsChoice),
31904
32791
  key: index
31905
32792
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31906
32793
  content: choice
@@ -31917,20 +32804,20 @@ class LabelImage extends React__namespace.Component {
31917
32804
  activeMarkerIndex
31918
32805
  } = this.state;
31919
32806
  return /*#__PURE__*/React__namespace.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React__namespace.createElement("div", {
31920
- className: aphrodite.css(styles$g.markersCanvas),
32807
+ className: aphrodite.css(styles$d.markersCanvas),
31921
32808
  style: {
31922
32809
  maxWidth: imageWidth,
31923
32810
  maxHeight: imageHeight
31924
32811
  }
31925
32812
  }, /*#__PURE__*/React__namespace.createElement("div", {
31926
- className: aphrodite.css(styles$g.imageContainer,
32813
+ className: aphrodite.css(styles$d.imageContainer,
31927
32814
  // Ensure image interaction is disabled while answer
31928
32815
  // choices popup is visible. This addresses specific
31929
32816
  // case where user may click on question image to
31930
32817
  // dismiss the popup. If the image is larger in size
31931
32818
  // than its rendered in the widget, this would
31932
32819
  // result in a zoom of the image.
31933
- activeMarkerIndex !== -1 && styles$g.imageInteractionDisabled)
32820
+ activeMarkerIndex !== -1 && styles$d.imageInteractionDisabled)
31934
32821
  }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref3 => {
31935
32822
  let {
31936
32823
  setAssetStatus
@@ -31956,7 +32843,7 @@ class LabelImage extends React__namespace.Component {
31956
32843
  }));
31957
32844
  }
31958
32845
  }
31959
- const styles$g = aphrodite.StyleSheet.create({
32846
+ const styles$d = aphrodite.StyleSheet.create({
31960
32847
  instructions: {
31961
32848
  paddingBottom: 16
31962
32849
  },
@@ -32317,7 +33204,7 @@ class Placeholder extends React__namespace.Component {
32317
33204
  const {
32318
33205
  layout
32319
33206
  } = this.props;
32320
- const className = aphrodite.css(styles$f.card, styles$f.placeholder, layout === Layout.HORIZONTAL && styles$f.horizontalCard);
33207
+ const className = aphrodite.css(styles$c.card, styles$c.placeholder, layout === Layout.HORIZONTAL && styles$c.horizontalCard);
32321
33208
  const style = {
32322
33209
  width: this.props.width,
32323
33210
  height: this.props.height
@@ -32415,7 +33302,7 @@ class Draggable extends React__namespace.Component {
32415
33302
  // We need to keep backwards compatbility with rules specified directly
32416
33303
  // in CSS. Hence the hacky tacking on of manual classNames.
32417
33304
  // See sortable.less for details.
32418
- let className = aphrodite.css(styles$f.card, styles$f.draggable, layout === Layout.HORIZONTAL && styles$f.horizontalCard, layout === Layout.VERTICAL && styles$f.verticalCard, type === ItemState.DRAGGING && styles$f.dragging, type === ItemState.DISABLED && styles$f.disabled, !includePadding && styles$f.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
33305
+ let className = aphrodite.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";
32419
33306
  if (!includePadding) {
32420
33307
  className += " perseus-sortable-draggable-unpadded";
32421
33308
  }
@@ -32715,7 +33602,7 @@ class Sortable extends React__namespace.Component {
32715
33602
  } = this.props;
32716
33603
  // We need to keep backwards compatbility with rules specified directly
32717
33604
  // in CSS. See sortable.less for details.
32718
- const className = aphrodite.css(styles$f.sortable) + " perseus-sortable";
33605
+ const className = aphrodite.css(styles$c.sortable) + " perseus-sortable";
32719
33606
  const syncWidth = this.props.constraints?.width || layout === Layout.VERTICAL;
32720
33607
  const syncHeight = this.props.constraints?.height || layout === Layout.HORIZONTAL;
32721
33608
  ___default["default"].each(this.state.items, function (item, i, items) {
@@ -32946,7 +33833,7 @@ class Sortable extends React__namespace.Component {
32946
33833
  return ___default["default"].pluck(this.state.items, "option");
32947
33834
  }
32948
33835
  }
32949
- const styles$f = aphrodite.StyleSheet.create({
33836
+ const styles$c = aphrodite.StyleSheet.create({
32950
33837
  sortable: {
32951
33838
  boxSizing: "border-box",
32952
33839
  float: "left",
@@ -33074,23 +33961,23 @@ class Matcher extends React__namespace.Component {
33074
33961
  };
33075
33962
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
33076
33963
  return /*#__PURE__*/React__namespace.createElement("table", {
33077
- className: aphrodite.css(styles$e.widget) + " " + HACKY_CSS_CLASSNAME
33964
+ className: aphrodite.css(styles$b.widget) + " " + HACKY_CSS_CLASSNAME
33078
33965
  }, /*#__PURE__*/React__namespace.createElement("tbody", null, showLabels && /*#__PURE__*/React__namespace.createElement("tr", {
33079
- className: aphrodite.css(styles$e.row)
33966
+ className: aphrodite.css(styles$b.row)
33080
33967
  }, /*#__PURE__*/React__namespace.createElement("th", {
33081
- className: aphrodite.css(styles$e.column, styles$e.columnLabel)
33968
+ className: aphrodite.css(styles$b.column, styles$b.columnLabel)
33082
33969
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
33083
33970
  content: this.props.labels[0] || "...",
33084
33971
  linterContext: this.props.linterContext
33085
33972
  })), /*#__PURE__*/React__namespace.createElement("th", {
33086
- className: aphrodite.css(styles$e.column, styles$e.columnRight, styles$e.columnLabel)
33973
+ className: aphrodite.css(styles$b.column, styles$b.columnRight, styles$b.columnLabel)
33087
33974
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
33088
33975
  content: this.props.labels[1] || "...",
33089
33976
  linterContext: this.props.linterContext
33090
33977
  }))), /*#__PURE__*/React__namespace.createElement("tr", {
33091
- className: aphrodite.css(styles$e.row)
33978
+ className: aphrodite.css(styles$b.row)
33092
33979
  }, /*#__PURE__*/React__namespace.createElement("td", {
33093
- className: aphrodite.css(styles$e.column)
33980
+ className: aphrodite.css(styles$b.column)
33094
33981
  }, /*#__PURE__*/React__namespace.createElement(Sortable, {
33095
33982
  options: left,
33096
33983
  layout: Layout.VERTICAL,
@@ -33105,7 +33992,7 @@ class Matcher extends React__namespace.Component {
33105
33992
  ,
33106
33993
  ref: "left"
33107
33994
  })), /*#__PURE__*/React__namespace.createElement("td", {
33108
- className: aphrodite.css(styles$e.column, styles$e.columnRight)
33995
+ className: aphrodite.css(styles$b.column, styles$b.columnRight)
33109
33996
  }, /*#__PURE__*/React__namespace.createElement(Sortable
33110
33997
  // @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33111
33998
  , {
@@ -33191,7 +34078,7 @@ ___default["default"].extend(Matcher, {
33191
34078
  });
33192
34079
  const padding = 5;
33193
34080
  const border = "1px solid #444";
33194
- const styles$e = aphrodite.StyleSheet.create({
34081
+ const styles$b = aphrodite.StyleSheet.create({
33195
34082
  widget: {
33196
34083
  paddingTop: padding,
33197
34084
  maxWidth: "100%",
@@ -33224,204 +34111,6 @@ var Matcher$1 = {
33224
34111
  isLintable: true
33225
34112
  };
33226
34113
 
33227
- const {
33228
- firstNumericalParse,
33229
- captureScratchpadTouchStart
33230
- } = Util;
33231
- const toNumericString = KhanMath.toNumericString;
33232
- const getNumericFormat = KhanMath.getNumericFormat;
33233
-
33234
- /* An input box that accepts only numeric strings
33235
- *
33236
- * Calls onChange(value, format) for valid numbers.
33237
- * Reverts to the current value onBlur or on [ENTER],
33238
- * but maintains the format (i.e. 3/2, 1 1/2, 150%)
33239
- * Accepts empty input and sends it to onChange as null
33240
- * if no numeric placeholder is set.
33241
- * If given a checkValidity function, will turn
33242
- * the background/outline red when invalid
33243
- * If useArrowKeys is set to true, up/down arrows will
33244
- * increment/decrement integers
33245
- * Optionally takes a size ("mini", "small", "normal")
33246
- */
33247
- class NumberInput extends React__namespace.Component {
33248
- static propTypes = {
33249
- value: PropTypes__default["default"].number,
33250
- format: PropTypes__default["default"].string,
33251
- placeholder: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number]),
33252
- onChange: PropTypes__default["default"].func.isRequired,
33253
- onFormatChange: PropTypes__default["default"].func,
33254
- checkValidity: PropTypes__default["default"].func,
33255
- size: PropTypes__default["default"].string,
33256
- label: PropTypes__default["default"].oneOf(["put your labels outside your inputs!"])
33257
- };
33258
- static defaultProps = {
33259
- value: null,
33260
- placeholder: null,
33261
- format: null,
33262
- onFormatChange: () => null,
33263
- checkValidity: () => true,
33264
- useArrowKeys: false
33265
- };
33266
- state = {
33267
- format: this.props.format
33268
- };
33269
- render() {
33270
- let classes = classNames__default["default"]({
33271
- "number-input": true,
33272
- "invalid-input": !this._checkValidity(this.props.value),
33273
- mini: this.props.size === "mini",
33274
- small: this.props.size === "small",
33275
- normal: this.props.size === "normal"
33276
- });
33277
- if (this.props.className != null) {
33278
- classes = classes + " " + this.props.className;
33279
- }
33280
- const {
33281
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33282
- onFormatChange,
33283
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33284
- checkValidity,
33285
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33286
- useArrowKeys,
33287
- ...restProps
33288
- } = this.props;
33289
- return /*#__PURE__*/React__namespace.createElement("input", _extends({}, restProps, {
33290
- className: classes,
33291
- type: "text"
33292
- // eslint-disable-next-line react/no-string-refs
33293
- ,
33294
- ref: "input",
33295
- onChange: this._handleChange,
33296
- onFocus: this._handleFocus,
33297
- onBlur: this._handleBlur,
33298
- onKeyPress: this._handleBlur,
33299
- onKeyDown: this._onKeyDown
33300
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
33301
- ,
33302
- onTouchStart: captureScratchpadTouchStart,
33303
- defaultValue: toNumericString(this.props.value, this.state.format),
33304
- value: undefined
33305
- }));
33306
- }
33307
- componentDidUpdate(prevProps) {
33308
- if (!kmath.number.equal(this.getValue(), this.props.value)) {
33309
- this._setValue(this.props.value, this.state.format);
33310
- }
33311
- }
33312
-
33313
- /* Return the current "value" of this input
33314
- * If empty, it returns the placeholder (if it is a number) or null
33315
- */
33316
- getValue = () => {
33317
- return this.parseInputValue(
33318
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
33319
- ReactDOM__default["default"].findDOMNode(this.refs.input).value // eslint-disable-line react/no-string-refs
33320
- );
33321
- };
33322
-
33323
- /* Return the current string value of this input */
33324
- getStringValue = () => {
33325
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
33326
- return ReactDOM__default["default"].findDOMNode(this.refs.input).value.toString(); // eslint-disable-line react/no-string-refs
33327
- };
33328
-
33329
- parseInputValue = value => {
33330
- if (value === "") {
33331
- const placeholder = this.props.placeholder;
33332
- return ___default["default"].isFinite(placeholder) ? +placeholder : null;
33333
- }
33334
- const result = firstNumericalParse(value);
33335
- return ___default["default"].isFinite(result) ? result : this.props.value;
33336
- };
33337
-
33338
- /* Set text input focus to this input */
33339
- focus = () => {
33340
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
33341
- ReactDOM__default["default"].findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
33342
- this._handleFocus();
33343
- };
33344
- blur = () => {
33345
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
33346
- ReactDOM__default["default"].findDOMNode(this.refs.input).blur(); // eslint-disable-line react/no-string-refs
33347
- this._handleBlur();
33348
- };
33349
- setSelectionRange = (selectionStart, selectionEnd) => {
33350
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
33351
- ReactDOM__default["default"].findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
33352
- };
33353
- getSelectionStart = () => {
33354
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
33355
- return ReactDOM__default["default"].findDOMNode(this).selectionStart;
33356
- };
33357
- getSelectionEnd = () => {
33358
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
33359
- return ReactDOM__default["default"].findDOMNode(this).selectionEnd;
33360
- };
33361
- _checkValidity = value => {
33362
- if (value == null) {
33363
- return true;
33364
- }
33365
- const val = firstNumericalParse(value);
33366
- const checkValidity = this.props.checkValidity;
33367
- return ___default["default"].isFinite(val) && checkValidity(val);
33368
- };
33369
- _handleChange = e => {
33370
- const text = e.target.value;
33371
- const value = this.parseInputValue(text);
33372
- const format = getNumericFormat(text);
33373
- this.props.onChange(value);
33374
- if (format) {
33375
- this.props.onFormatChange(value, format);
33376
- this.setState({
33377
- format: format
33378
- });
33379
- }
33380
- };
33381
- _handleFocus = () => {
33382
- if (this.props.onFocus) {
33383
- this.props.onFocus();
33384
- }
33385
- };
33386
- _handleBlur = e => {
33387
- // Only continue on blur or "enter"
33388
- // @ts-expect-error - TS2339 - Property 'keyCode' does not exist on type 'KeyboardEvent<Element> | FocusEvent<Element, Element>'.
33389
- if (e && e.type === "keypress" && e.keyCode !== 13) {
33390
- return;
33391
- }
33392
- this._setValue(this.props.value, this.state.format);
33393
- if (this.props.onBlur) {
33394
- this.props.onBlur();
33395
- }
33396
- };
33397
- _onKeyDown = e => {
33398
- if (this.props.onKeyDown) {
33399
- this.props.onKeyDown(e);
33400
- }
33401
- if (!this.props.useArrowKeys || !___default["default"].contains(["ArrowUp", "ArrowDown"], e.key)) {
33402
- return;
33403
- }
33404
- let val = this.getValue();
33405
- if (val !== Math.floor(val)) {
33406
- return; // bail if not an integer
33407
- }
33408
-
33409
- if (e.key === "ArrowUp") {
33410
- val = val + 1;
33411
- } else if (e.key === "ArrowDown") {
33412
- val = val - 1;
33413
- }
33414
- if (this._checkValidity(val)) {
33415
- this.props.onChange(val);
33416
- }
33417
- };
33418
- _setValue = (val, format) => {
33419
- // eslint-disable-next-line react/no-string-refs
33420
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
33421
- $__default["default"](ReactDOM__default["default"].findDOMNode(this.refs.input)).val(toNumericString(val, format));
33422
- };
33423
- }
33424
-
33425
34114
  // Type imports
33426
34115
 
33427
34116
  const {
@@ -34064,9 +34753,9 @@ function drawText(ctx, item) {
34064
34753
  if (item.value === null) {
34065
34754
  return;
34066
34755
  }
34067
- ctx.fillStyle = styles$d.fgColor;
34068
- ctx.font = styles$d.font;
34069
- ctx.fillText(item.value, item.pos[0] - styles$d.fontSizePx / 2 + 1, item.pos[1] + styles$d.fontSizePx / 2);
34756
+ ctx.fillStyle = styles$a.fgColor;
34757
+ ctx.font = styles$a.font;
34758
+ ctx.fillText(item.value, item.pos[0] - styles$a.fontSizePx / 2 + 1, item.pos[1] + styles$a.fontSizePx / 2);
34070
34759
  }
34071
34760
 
34072
34761
  /**
@@ -34087,16 +34776,16 @@ function drawText(ctx, item) {
34087
34776
  function drawDoubleLine(ctx, item) {
34088
34777
  // Outer line that forms both of the bond lines.
34089
34778
  let path = new Path2D();
34090
- ctx.lineWidth = 5 * styles$d.lineWidth;
34091
- ctx.strokeStyle = styles$d.fgColor;
34779
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34780
+ ctx.strokeStyle = styles$a.fgColor;
34092
34781
  path.moveTo(item.startPos[0], item.startPos[1]);
34093
34782
  path.lineTo(item.endPos[0], item.endPos[1]);
34094
34783
  ctx.stroke(path);
34095
34784
 
34096
34785
  // Inner white line that separates the two bond lines.
34097
34786
  path = new Path2D();
34098
- ctx.lineWidth = 3 * styles$d.lineWidth;
34099
- ctx.strokeStyle = styles$d.bgColor;
34787
+ ctx.lineWidth = 3 * styles$a.lineWidth;
34788
+ ctx.strokeStyle = styles$a.bgColor;
34100
34789
  path.moveTo(item.startPos[0], item.startPos[1]);
34101
34790
  path.lineTo(item.endPos[0], item.endPos[1]);
34102
34791
  ctx.stroke(path);
@@ -34123,16 +34812,16 @@ function drawTripleLine(ctx, item) {
34123
34812
 
34124
34813
  // Outer line that will form the two outer bond lines.
34125
34814
  let path = new Path2D();
34126
- ctx.lineWidth = 7 * styles$d.lineWidth;
34127
- ctx.strokeStyle = styles$d.fgColor;
34815
+ ctx.lineWidth = 7 * styles$a.lineWidth;
34816
+ ctx.strokeStyle = styles$a.fgColor;
34128
34817
  path.moveTo(item.startPos[0], item.startPos[1]);
34129
34818
  path.lineTo(item.endPos[0], item.endPos[1]);
34130
34819
  ctx.stroke(path);
34131
34820
 
34132
34821
  // Middle white line that separates the bonds
34133
34822
  path = new Path2D();
34134
- ctx.lineWidth = 5 * styles$d.lineWidth;
34135
- ctx.strokeStyle = styles$d.bgColor;
34823
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34824
+ ctx.strokeStyle = styles$a.bgColor;
34136
34825
  path.moveTo(item.startPos[0], item.startPos[1]);
34137
34826
  path.lineTo(item.endPos[0], item.endPos[1]);
34138
34827
  ctx.stroke(path);
@@ -34154,8 +34843,8 @@ function drawTripleLine(ctx, item) {
34154
34843
  */
34155
34844
  function drawLine(ctx, item) {
34156
34845
  const path = new Path2D();
34157
- ctx.lineWidth = styles$d.lineWidth;
34158
- ctx.strokeStyle = styles$d.fgColor;
34846
+ ctx.lineWidth = styles$a.lineWidth;
34847
+ ctx.strokeStyle = styles$a.fgColor;
34159
34848
  path.moveTo(item.startPos[0], item.startPos[1]);
34160
34849
  path.lineTo(item.endPos[0], item.endPos[1]);
34161
34850
  ctx.stroke(path);
@@ -34207,7 +34896,7 @@ function compareElements(item0, item1) {
34207
34896
  function draw(ctx, items) {
34208
34897
  items.sort(compareElements).forEach(drawItem(ctx));
34209
34898
  }
34210
- const styles$d = {
34899
+ const styles$a = {
34211
34900
  bgColor: "rgb(255, 255, 255)",
34212
34901
  fgColor: "rgb(0, 0, 0)",
34213
34902
  fontSizePx: 12,
@@ -36771,7 +37460,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
36771
37460
  const rects = this.state.cachedHighlightRects;
36772
37461
  return /*#__PURE__*/React__namespace.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React__namespace.createElement("div", {
36773
37462
  key: index,
36774
- className: aphrodite.css(styles$c.highlightRect),
37463
+ className: aphrodite.css(styles$9.highlightRect),
36775
37464
  style: {
36776
37465
  // NOTE(mdr): We apply `position: absolute` here
36777
37466
  // rather than in Aphrodite styles, because
@@ -36790,7 +37479,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
36790
37479
  })));
36791
37480
  }
36792
37481
  }
36793
- const styles$c = aphrodite.StyleSheet.create({
37482
+ const styles$9 = aphrodite.StyleSheet.create({
36794
37483
  highlightRect: {
36795
37484
  background: "#fffabe" // highlighter yellow :)
36796
37485
  }
@@ -36871,7 +37560,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
36871
37560
  // TooltipContent wouldn't let me overwrite
36872
37561
  // user-select and onClick
36873
37562
  const content = /*#__PURE__*/React__namespace.createElement("div", {
36874
- className: aphrodite.css(styles$b.tooltipLabel),
37563
+ className: aphrodite.css(styles$8.tooltipLabel),
36875
37564
  onClick: this.props.onClick
36876
37565
  }, this.props.label);
36877
37566
  const style = {
@@ -36891,7 +37580,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
36891
37580
  }, /*#__PURE__*/React__namespace.createElement("div", null)));
36892
37581
  }
36893
37582
  }
36894
- const styles$b = aphrodite.StyleSheet.create({
37583
+ const styles$8 = aphrodite.StyleSheet.create({
36895
37584
  tooltipLabel: {
36896
37585
  // Unlike most tooltip contents, we don't want this label to be
36897
37586
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -37449,7 +38138,7 @@ class HighlightableContent extends React__namespace.PureComponent {
37449
38138
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
37450
38139
  const buildHighlight = r => this._buildHighlight(r);
37451
38140
  return /*#__PURE__*/React__namespace.createElement("div", {
37452
- className: aphrodite.css(styles$a.container),
38141
+ className: aphrodite.css(styles$7.container),
37453
38142
  ref: container => this._container = container
37454
38143
  }, /*#__PURE__*/React__namespace.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React__namespace.createElement(HighlightingUI, {
37455
38144
  buildHighlight: buildHighlight,
@@ -37470,14 +38159,14 @@ class HighlightableContent extends React__namespace.PureComponent {
37470
38159
  onAddHighlight: this._handleAddHighlight,
37471
38160
  onRemoveHighlight: this._handleRemoveHighlight
37472
38161
  })), /*#__PURE__*/React__namespace.createElement("div", {
37473
- className: aphrodite.css(styles$a.content),
38162
+ className: aphrodite.css(styles$7.content),
37474
38163
  ref: content => this._content = content
37475
38164
  }, /*#__PURE__*/React__namespace.createElement(WordIndexer, {
37476
38165
  onWordsUpdate: this._handleWordsUpdate
37477
38166
  }, this.props.children)));
37478
38167
  }
37479
38168
  }
37480
- const styles$a = aphrodite.StyleSheet.create({
38169
+ const styles$7 = aphrodite.StyleSheet.create({
37481
38170
  // We render content with z-index 1, and highlights with z-index 0, so that
37482
38171
  // content will receive the browser's native pointer events. (Highlights
37483
38172
  // have their own magic code to manage hover detection, despite being
@@ -37873,7 +38562,7 @@ class LineHeightMeasurer extends React__namespace.Component {
37873
38562
  }
37874
38563
  render() {
37875
38564
  return /*#__PURE__*/React__namespace.createElement("div", {
37876
- className: aphrodite.css(styles$9.measurer),
38565
+ className: aphrodite.css(styles$6.measurer),
37877
38566
  "aria-hidden": "true"
37878
38567
  }, /*#__PURE__*/React__namespace.createElement("div", {
37879
38568
  ref: ref => this._line = ref,
@@ -37881,7 +38570,7 @@ class LineHeightMeasurer extends React__namespace.Component {
37881
38570
  }, "Line Height Measurement"));
37882
38571
  }
37883
38572
  }
37884
- const styles$9 = aphrodite.StyleSheet.create({
38573
+ const styles$6 = aphrodite.StyleSheet.create({
37885
38574
  measurer: {
37886
38575
  position: "absolute",
37887
38576
  top: 0,
@@ -39193,7 +39882,7 @@ class PythonProgram extends React__namespace.Component {
39193
39882
  // creator "went wild".
39194
39883
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
39195
39884
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
39196
- style: styles$8.container
39885
+ style: styles$5.container
39197
39886
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
39198
39887
  sandbox: sandboxOptions,
39199
39888
  src: url,
@@ -39202,7 +39891,7 @@ class PythonProgram extends React__namespace.Component {
39202
39891
  }));
39203
39892
  }
39204
39893
  }
39205
- const styles$8 = aphrodite.StyleSheet.create({
39894
+ const styles$5 = aphrodite.StyleSheet.create({
39206
39895
  container: {
39207
39896
  margin: "auto",
39208
39897
  width: "100%"
@@ -39439,125 +40128,6 @@ var Sequence$1 = {
39439
40128
  isLintable: true
39440
40129
  };
39441
40130
 
39442
- const colors = {
39443
- grayLight: "#aaa",
39444
- basicBorderColor: "#ccc",
39445
- white: "#fff"
39446
- };
39447
- const triangleBeforeAfter = {
39448
- borderBottom: "9px solid transparent",
39449
- borderTop: "9px solid transparent",
39450
- content: '" "',
39451
- height: "0",
39452
- position: "absolute",
39453
- top: "0",
39454
- width: "0"
39455
- };
39456
- const styles$7 = aphrodite.StyleSheet.create({
39457
- infoTip: {
39458
- display: "inline-block",
39459
- marginLeft: "5px",
39460
- position: "relative"
39461
- },
39462
- infoTipContainer: {
39463
- position: "absolute",
39464
- top: "-12px",
39465
- left: "22px",
39466
- zIndex: 1000
39467
- },
39468
- infoTipTriangle: {
39469
- height: "10px",
39470
- left: "0",
39471
- position: "absolute",
39472
- top: "8px",
39473
- width: "0",
39474
- zIndex: 1,
39475
- ":before": {
39476
- ...triangleBeforeAfter,
39477
- borderRight: "9px solid #bbb",
39478
- right: "0"
39479
- },
39480
- ":after": {
39481
- ...triangleBeforeAfter,
39482
- borderRight: `9px solid ${colors.white}`,
39483
- right: "-1px"
39484
- }
39485
- },
39486
- verticalShadow: {
39487
- border: `1px solid ${colors.basicBorderColor}`,
39488
- boxShadow: `0 1px 3px ${colors.basicBorderColor}`,
39489
- borderBottom: `1px solid ${colors.grayLight}`
39490
- },
39491
- infoTipContentContainer: {
39492
- background: colors.white,
39493
- padding: "5px 10px",
39494
- width: "240px"
39495
- }
39496
- });
39497
- 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=";
39498
- class InfoTip$1 extends React__namespace.Component {
39499
- state = {
39500
- hover: false
39501
- };
39502
- handleMouseEnter = () => {
39503
- this.setState({
39504
- hover: true
39505
- });
39506
- };
39507
- handleMouseLeave = () => {
39508
- this.setState({
39509
- hover: false
39510
- });
39511
- };
39512
- render() {
39513
- return /*#__PURE__*/React__namespace.createElement("div", {
39514
- className: aphrodite.css(styles$7.infoTip)
39515
- }, /*#__PURE__*/React__namespace.createElement("img", {
39516
- alt: "",
39517
- width: 10,
39518
- height: 10,
39519
- src: questionMark,
39520
- onMouseEnter: this.handleMouseEnter,
39521
- onMouseLeave: this.handleMouseLeave
39522
- }), /*#__PURE__*/React__namespace.createElement("div", {
39523
- className: aphrodite.css(styles$7.infoTipContainer),
39524
- style: {
39525
- display: this.state.hover ? "block" : "none"
39526
- }
39527
- }, /*#__PURE__*/React__namespace.createElement("div", {
39528
- className: aphrodite.css(styles$7.infoTipTriangle)
39529
- }), /*#__PURE__*/React__namespace.createElement("div", {
39530
- className: aphrodite.css(styles$7.verticalShadow, styles$7.infoTipContentContainer)
39531
- }, this.props.children)));
39532
- }
39533
- }
39534
-
39535
- /**
39536
- * A wrapper around info-tip/info-tip.jsx that can be rendered on the
39537
- * server without causing a checksum mismatch on the client.
39538
- * (RCSS generates classnames with a randomSuffix, which ensures that any
39539
- * two sets of generated classnames will not match.)
39540
- */
39541
- class InfoTip extends React__namespace.Component {
39542
- state = {
39543
- didMount: false
39544
- };
39545
- componentDidMount() {
39546
- /* eslint-disable react/no-did-mount-set-state */
39547
- this.setState({
39548
- didMount: true
39549
- });
39550
- /* eslint-enable react/no-did-mount-set-state */
39551
- }
39552
-
39553
- render() {
39554
- if (this.state.didMount) {
39555
- return /*#__PURE__*/React__namespace.createElement(InfoTip$1, this.props);
39556
- }
39557
- return /*#__PURE__*/React__namespace.createElement("div", null);
39558
- }
39559
- }
39560
-
39561
40131
  /* eslint-disable @typescript-eslint/no-unused-vars, react/no-unsafe, react/sort-comp */
39562
40132
  const {
39563
40133
  assert: assert$1
@@ -41515,7 +42085,7 @@ const VideoTranscriptLink = props => {
41515
42085
  {
41516
42086
  const video = result.data?.video;
41517
42087
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
41518
- style: styles$6.transcriptLink
42088
+ style: styles$4.transcriptLink
41519
42089
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.Text, null, video?.title), /*#__PURE__*/React__namespace.createElement(wonderBlocksLayout.Strut, {
41520
42090
  size: 10
41521
42091
  }), /*#__PURE__*/React__namespace.createElement(Link__default["default"], {
@@ -41532,7 +42102,7 @@ const VideoTranscriptLink = props => {
41532
42102
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, i18n__namespace._("Something went wrong."));
41533
42103
  }
41534
42104
  };
41535
- const styles$6 = aphrodite.StyleSheet.create({
42105
+ const styles$4 = aphrodite.StyleSheet.create({
41536
42106
  transcriptLink: {
41537
42107
  flexDirection: "row",
41538
42108
  width: "100%",
@@ -41688,7 +42258,7 @@ const init = function (options) {
41688
42258
 
41689
42259
  // This file is processed by a Rollup plugin (replace) to inject the production
41690
42260
  const libName = "@khanacademy/perseus";
41691
- const libVersion = "19.6.2";
42261
+ const libVersion = "19.7.0";
41692
42262
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
41693
42263
 
41694
42264
  const apiVersion = {
@@ -41901,7 +42471,7 @@ class HintRenderer extends React__namespace.Component {
41901
42471
  const {
41902
42472
  isMobile
41903
42473
  } = apiOptions;
41904
- const classNames = classNames__default["default"]("hint", !isMobile && "perseus-hint-renderer", isMobile && aphrodite.css(styles$5.newHint), isMobile && lastRendered && aphrodite.css(styles$5.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
42474
+ const classNames = classNames__default["default"]("hint", !isMobile && "perseus-hint-renderer", isMobile && aphrodite.css(styles$3.newHint), isMobile && lastRendered && aphrodite.css(styles$3.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
41905
42475
 
41906
42476
  // TODO(charlie): Allowing `customKeypad` would require that we
41907
42477
  // extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
@@ -41942,7 +42512,7 @@ class HintRenderer extends React__namespace.Component {
41942
42512
  );
41943
42513
  }
41944
42514
  }
41945
- const styles$5 = aphrodite.StyleSheet.create({
42515
+ const styles$3 = aphrodite.StyleSheet.create({
41946
42516
  newHint: {
41947
42517
  marginBottom: 1.5 * baseUnitPx,
41948
42518
  borderLeftColor: gray97,
@@ -42119,15 +42689,15 @@ class HintsRenderer extends React__namespace.Component {
42119
42689
  } = apiOptions;
42120
42690
  const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
42121
42691
  const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
42122
- const classNames = classNames__default["default"](this.props.className, apiOptions.isMobile && hintsVisible > 0 && aphrodite.css(styles$4.mobileHintStylesHintsRenderer));
42692
+ const classNames = classNames__default["default"](this.props.className, apiOptions.isMobile && hintsVisible > 0 && aphrodite.css(styles$2.mobileHintStylesHintsRenderer));
42123
42693
  return /*#__PURE__*/React__namespace.createElement("div", {
42124
42694
  className: classNames
42125
42695
  }, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React__namespace.createElement("div", {
42126
- className: aphrodite.css(styles$4.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
42696
+ className: aphrodite.css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
42127
42697
  }, i18n__namespace._("Hints")), hints, showGetAnotherHint && /*#__PURE__*/React__namespace.createElement("button", {
42128
42698
  // @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>'.
42129
42699
  rel: "button",
42130
- className: aphrodite.css(styles$4.linkButton, styles$4.getAnotherHintButton, apiOptions.isMobile && styles$4.mobileHintStylesGetAnotherHintButton),
42700
+ className: aphrodite.css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
42131
42701
  onClick: evt => {
42132
42702
  evt.preventDefault();
42133
42703
  evt.stopPropagation();
@@ -42136,14 +42706,14 @@ class HintsRenderer extends React__namespace.Component {
42136
42706
  }
42137
42707
  }
42138
42708
  }, /*#__PURE__*/React__namespace.createElement("span", {
42139
- className: aphrodite.css(styles$4.plusText, apiOptions.isMobile && styles$4.mobileHintStylesPlusText)
42709
+ className: aphrodite.css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
42140
42710
  }, "+"), /*#__PURE__*/React__namespace.createElement("span", {
42141
- className: aphrodite.css(styles$4.getAnotherHintText)
42711
+ className: aphrodite.css(styles$2.getAnotherHintText)
42142
42712
  }, i18n__namespace._("Get another hint"), " ", hintRatioCopy)));
42143
42713
  }
42144
42714
  }
42145
42715
  const hintIndentation = baseUnitPx + hintBorderWidth;
42146
- const styles$4 = aphrodite.StyleSheet.create({
42716
+ const styles$2 = aphrodite.StyleSheet.create({
42147
42717
  // eslint-disable-next-line react-native/no-unused-styles
42148
42718
  rendererMargins: {
42149
42719
  marginTop: baseUnitPx
@@ -42555,11 +43125,11 @@ class ServerItemRenderer extends React__namespace.Component {
42555
43125
  // mobile hint styles, which are flush to the left.
42556
43126
  // NOTE(charlie): We may still want to apply this
42557
43127
  // padding for desktop exercises.
42558
- apiOptions.isMobile ? undefined : aphrodite.css(styles$3.hintsContainer)
43128
+ apiOptions.isMobile ? undefined : aphrodite.css(styles$1.hintsContainer)
42559
43129
  }, hintsRenderer)));
42560
43130
  }
42561
43131
  }
42562
- const styles$3 = aphrodite.StyleSheet.create({
43132
+ const styles$1 = aphrodite.StyleSheet.create({
42563
43133
  hintsContainer: {
42564
43134
  marginLeft: 50
42565
43135
  }
@@ -42696,339 +43266,6 @@ class ElementContainer extends React__namespace.Component {
42696
43266
  }
42697
43267
  }
42698
43268
 
42699
- // Displays a stylized open eye: lint warnings are visible
42700
- const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
42701
- width: "24",
42702
- height: "24",
42703
- viewBox: "0 0 24 24",
42704
- className: aphrodite.css(styles$2.icon)
42705
- }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
42706
- id: "a",
42707
- 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"
42708
- })), /*#__PURE__*/React__namespace.createElement("g", {
42709
- fill: "none",
42710
- fillRule: "evenodd"
42711
- }, /*#__PURE__*/React__namespace.createElement("path", {
42712
- fill: "none",
42713
- d: "M0 0h24v24H0z"
42714
- }), /*#__PURE__*/React__namespace.createElement("mask", {
42715
- id: "b",
42716
- fill: "#fff"
42717
- }, /*#__PURE__*/React__namespace.createElement("use", {
42718
- href: "#a"
42719
- })), /*#__PURE__*/React__namespace.createElement("use", {
42720
- fill: "#fff",
42721
- fillRule: "nonzero",
42722
- href: "#a"
42723
- }), /*#__PURE__*/React__namespace.createElement("g", {
42724
- fill: "#fff",
42725
- mask: "url(#b)"
42726
- }, /*#__PURE__*/React__namespace.createElement("path", {
42727
- d: "M0 0h24v24H0z"
42728
- }))));
42729
-
42730
- // Displays a stylized eye with a line through it: I don't want to see lint
42731
- const HiddenIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
42732
- width: "24",
42733
- height: "24",
42734
- viewBox: "0 0 24 24",
42735
- className: aphrodite.css(styles$2.icon)
42736
- }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
42737
- id: "a",
42738
- 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"
42739
- })), /*#__PURE__*/React__namespace.createElement("g", {
42740
- fill: "none",
42741
- fillRule: "evenodd"
42742
- }, /*#__PURE__*/React__namespace.createElement("path", {
42743
- fill: "none",
42744
- d: "M0 0h24v24H0z"
42745
- }), /*#__PURE__*/React__namespace.createElement("mask", {
42746
- id: "b",
42747
- fill: "#fff"
42748
- }, /*#__PURE__*/React__namespace.createElement("use", {
42749
- href: "#a"
42750
- })), /*#__PURE__*/React__namespace.createElement("use", {
42751
- fill: "#fff",
42752
- fillRule: "nonzero",
42753
- href: "#a"
42754
- }), /*#__PURE__*/React__namespace.createElement("g", {
42755
- fill: "#fff",
42756
- mask: "url(#b)"
42757
- }, /*#__PURE__*/React__namespace.createElement("path", {
42758
- d: "M0 0h24v24H0z"
42759
- }))));
42760
- const HUD = _ref => {
42761
- let {
42762
- message,
42763
- enabled,
42764
- onClick,
42765
- fixedPosition = true
42766
- } = _ref;
42767
- let state;
42768
- let icon;
42769
- if (enabled) {
42770
- state = styles$2.enabled;
42771
- icon = /*#__PURE__*/React__namespace.createElement(VisibleIcon, null);
42772
- } else {
42773
- state = styles$2.disabled;
42774
- icon = /*#__PURE__*/React__namespace.createElement(HiddenIcon, null);
42775
- }
42776
- return /*#__PURE__*/React__namespace.createElement("button", {
42777
- className: aphrodite.css(styles$2.hud, fixedPosition && styles$2.hudFixedPosition, state),
42778
- onClick: e => {
42779
- onClick();
42780
- }
42781
- }, icon, message);
42782
- };
42783
- const styles$2 = aphrodite.StyleSheet.create({
42784
- hud: {
42785
- boxSizing: "border-box",
42786
- height: 36,
42787
- padding: "9px 16px",
42788
- borderRadius: 18,
42789
- fontFamily: boldFontFamily,
42790
- fontSize: "15px",
42791
- lineHeight: "18px",
42792
- color: white$1,
42793
- userSelect: "none",
42794
- borderWidth: 0 // <button> gives us a border by default
42795
- },
42796
-
42797
- // We want to render the element in-place in our fixtures, so allow us to
42798
- // render in the bottom corner in production and in-place in testing.
42799
- hudFixedPosition: {
42800
- bottom: 20,
42801
- position: "fixed",
42802
- right: 20,
42803
- zIndex: 1
42804
- },
42805
- icon: {
42806
- width: 24,
42807
- height: 24,
42808
- marginRight: 8,
42809
- marginTop: -3,
42810
- verticalAlign: "middle"
42811
- },
42812
- enabled: {
42813
- backgroundColor: warningColor,
42814
- ":hover": {
42815
- backgroundColor: warningColorHover
42816
- },
42817
- ":active": {
42818
- backgroundColor: warningColorActive
42819
- }
42820
- },
42821
- disabled: {
42822
- backgroundColor: gray76,
42823
- ":hover": {
42824
- backgroundColor: "#a1a5a9" // in between those two grays
42825
- },
42826
-
42827
- ":active": {
42828
- backgroundColor: gray68
42829
- }
42830
- }
42831
- });
42832
-
42833
- /**
42834
- * MultiButtonGroup is an aesthetically pleasing group of buttons,
42835
- * which allows multiple buttons to be selected at the same time.
42836
- *
42837
- * NOTE: This component is almost identical to ./button-group.jsx except that
42838
- * this component allows multiple selection!
42839
- */
42840
- class MultiButtonGroup extends React__namespace.Component {
42841
- static defaultProps = {
42842
- values: [],
42843
- allowEmpty: true
42844
- };
42845
- focus() {
42846
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
42847
- ReactDOM__namespace.findDOMNode(this)?.focus();
42848
- return true;
42849
- }
42850
- toggleSelect = newValue => {
42851
- const values = (this.props.values || []).slice(0);
42852
- const allowEmpty = this.props.allowEmpty;
42853
- if (values.indexOf(newValue) >= 0 && (values.length > 1 || allowEmpty)) {
42854
- // If the value is already selected, unselect it
42855
- values.splice(values.indexOf(newValue), 1);
42856
- } else {
42857
- // Otherwise merge with other values and return
42858
- if (values.indexOf(newValue) < 0) {
42859
- values.push(newValue);
42860
- }
42861
- }
42862
- this.props.onChange(values);
42863
- };
42864
- render() {
42865
- const values = this.props.values || [];
42866
- const buttons = this.props.buttons.map((button, i) => {
42867
- const selected = values.indexOf(button.value) >= 0;
42868
- return /*#__PURE__*/React__namespace.createElement("button", {
42869
- title: button.title,
42870
- type: "button",
42871
- id: "" + i,
42872
- key: "" + i,
42873
- ref: "button" + i,
42874
- className: aphrodite.css(styles$1.buttonStyle, selected && styles$1.selectedStyle),
42875
- onClick: () => this.toggleSelect(button.value)
42876
- }, button.content || "" + button.value);
42877
- });
42878
- const outerStyle = {
42879
- display: "inline-block"
42880
- };
42881
- return /*#__PURE__*/React__namespace.createElement("div", {
42882
- style: outerStyle
42883
- }, buttons);
42884
- }
42885
- }
42886
- const styles$1 = aphrodite.StyleSheet.create({
42887
- buttonStyle: {
42888
- backgroundColor: "white",
42889
- border: "1px solid #ccc",
42890
- borderLeft: "0",
42891
- cursor: "pointer",
42892
- margin: "0",
42893
- padding: "5px 10px",
42894
- position: "relative",
42895
- // for hover
42896
-
42897
- ":first-child": {
42898
- borderLeft: "1px solid #ccc",
42899
- borderTopLeftRadius: "3px",
42900
- borderBottomLeftRadius: "3px"
42901
- },
42902
- ":last-child": {
42903
- borderRight: "1px solid #ccc",
42904
- borderTopRightRadius: "3px",
42905
- borderBottomRightRadius: "3px"
42906
- },
42907
- ":hover": {
42908
- backgroundColor: "#ccc"
42909
- },
42910
- ":focus": {
42911
- zIndex: 2
42912
- }
42913
- },
42914
- selectedStyle: {
42915
- backgroundColor: "#ddd"
42916
- }
42917
- });
42918
-
42919
- /* eslint-disable @babel/no-invalid-this */
42920
-
42921
- /* A checkbox that syncs its value to props using the
42922
- * renderer's onChange method, and gets the prop name
42923
- * dynamically from its props list
42924
- */
42925
- const PropCheckBox = createReactClass__default["default"]({
42926
- displayName: "PropCheckBox",
42927
- propTypes: {
42928
- labelAlignment: PropTypes__default["default"].oneOf(["left", "right"])
42929
- },
42930
- DEFAULT_PROPS: {
42931
- label: null,
42932
- onChange: null,
42933
- labelAlignment: "left"
42934
- },
42935
- getDefaultProps: function () {
42936
- return this.DEFAULT_PROPS;
42937
- },
42938
- propName: function () {
42939
- const propName = ___default["default"].find(___default["default"].keys(this.props), function (localPropName) {
42940
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
42941
- return !___default["default"].has(this.DEFAULT_PROPS, localPropName);
42942
- }, this);
42943
- if (!propName) {
42944
- throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
42945
- }
42946
- return propName;
42947
- },
42948
- _labelAlignLeft: function () {
42949
- return this.props.labelAlignment === "left";
42950
- },
42951
- render: function () {
42952
- const propName = this.propName();
42953
- return /*#__PURE__*/React__namespace.createElement("label", null, this._labelAlignLeft() && this.props.label, /*#__PURE__*/React__namespace.createElement("input", {
42954
- type: "checkbox",
42955
- checked: this.props[propName],
42956
- onChange: this.toggle
42957
- }), !this._labelAlignLeft() && this.props.label);
42958
- },
42959
- toggle: function () {
42960
- const propName = this.propName();
42961
- const changes = {};
42962
- changes[propName] = !this.props[propName];
42963
- this.props.onChange(changes);
42964
- }
42965
- });
42966
-
42967
- const truth = () => true;
42968
-
42969
- /* A minor abstraction on top of NumberInput for ranges
42970
- *
42971
- */
42972
- class RangeInput extends React__namespace.Component {
42973
- static propTypes = {
42974
- value: PropTypes__default["default"].array.isRequired,
42975
- onChange: PropTypes__default["default"].func.isRequired,
42976
- placeholder: PropTypes__default["default"].array,
42977
- checkValidity: PropTypes__default["default"].func
42978
- };
42979
- static defaultProps = {
42980
- placeholder: [null, null]
42981
- };
42982
- render() {
42983
- const value = this.props.value;
42984
- const checkValidity = this.props.checkValidity || truth;
42985
- return /*#__PURE__*/React__namespace.createElement("div", {
42986
- className: "range-input"
42987
- }, /*#__PURE__*/React__namespace.createElement(NumberInput, _extends({}, this.props, {
42988
- value: value[0],
42989
- checkValidity: val => checkValidity([val, value[1]])
42990
- // eslint-disable-next-line react/jsx-no-bind
42991
- ,
42992
- onChange: this.onChange.bind(this, 0),
42993
- placeholder: this.props.placeholder[0]
42994
- })), /*#__PURE__*/React__namespace.createElement(NumberInput, _extends({}, this.props, {
42995
- value: value[1],
42996
- checkValidity: val => checkValidity([value[0], val])
42997
- // eslint-disable-next-line react/jsx-no-bind
42998
- ,
42999
- onChange: this.onChange.bind(this, 1),
43000
- placeholder: this.props.placeholder[1]
43001
- })));
43002
- }
43003
- onChange = (i, newVal) => {
43004
- const value = this.props.value;
43005
- if (i === 0) {
43006
- this.props.onChange([newVal, value[1]]);
43007
- } else {
43008
- this.props.onChange([value[0], newVal]);
43009
- }
43010
- };
43011
- }
43012
-
43013
- var components = /*#__PURE__*/Object.freeze({
43014
- __proto__: null,
43015
- ButtonGroup: ButtonGroup,
43016
- Graph: Graph,
43017
- Graphie: Graphie,
43018
- HUD: HUD,
43019
- Icon: Icon,
43020
- InfoTip: InfoTip,
43021
- InlineIcon: InlineIcon,
43022
- MathInput: MathInput,
43023
- MultiButtonGroup: MultiButtonGroup,
43024
- NumberInput: NumberInput,
43025
- PropCheckBox: PropCheckBox,
43026
- RangeInput: RangeInput,
43027
- SvgImage: SvgImage,
43028
- TextInput: TextInput,
43029
- TextListEditor: TextListEditor
43030
- });
43031
-
43032
43269
  const devices = {
43033
43270
  PHONE: "phone",
43034
43271
  TABLET: "tablet",