@khanacademy/perseus 19.6.3 → 19.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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() {
@@ -28325,7 +28326,875 @@ class Graph extends React__namespace.Component {
28325
28326
  }
28326
28327
  }
28327
28328
 
28328
- /* 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
+
28329
29198
  const {
28330
29199
  DeprecationMixin
28331
29200
  } = Util;
@@ -28402,6 +29271,7 @@ class InteractiveGraph extends React__namespace.Component {
28402
29271
  type: "linear"
28403
29272
  }
28404
29273
  };
29274
+ mafsRef = /*#__PURE__*/React__namespace.createRef();
28405
29275
  state = {
28406
29276
  shouldShowInstructions: _getShouldShowInstructions(this.props)
28407
29277
  };
@@ -28411,9 +29281,11 @@ class InteractiveGraph extends React__namespace.Component {
28411
29281
  DeprecationMixin.UNSAFE_componentWillMount.call(this);
28412
29282
  }
28413
29283
  componentDidMount() {
28414
- // eslint-disable-next-line react/no-string-refs
28415
- // @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
28416
- 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
+ }
28417
29289
  }
28418
29290
  UNSAFE_componentWillReceiveProps(nextProps) {
28419
29291
  if (this.isClickToAddPoints() !== this.isClickToAddPoints(nextProps)) {
@@ -29510,16 +30382,22 @@ class InteractiveGraph extends React__namespace.Component {
29510
30382
  graph: graph
29511
30383
  });
29512
30384
  };
29513
- getUserInput = () => {
29514
- return InteractiveGraph.getUserInputFromProps(this.props);
29515
- };
29516
- simpleValidate = rubric => {
29517
- return InteractiveGraph.validate(this.getUserInput(), rubric, this);
29518
- };
30385
+ getUserInput = () => this.mafsRef.current?.getUserInput?.() ?? InteractiveGraph.getUserInputFromProps(this.props);
30386
+ simpleValidate = rubric => InteractiveGraph.validate(this.getUserInput(), rubric, this);
29519
30387
  focus = $__default["default"].noop;
30388
+
30389
+ // const segment: boolean = useFeatureIsOn("mafs-segment-graph");
30390
+ // <Renderer apiOptions={{flags: {mafs: {segment}}}}
29520
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
+ }
29521
30398
  const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
29522
30399
  let instructions;
30400
+ // isClickToAddPoints() only applies to points and polygons
29523
30401
  if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
29524
30402
  if (this.props.graph.type === "point") {
29525
30403
  instructions = i18n__namespace._("Click to add points");
@@ -30804,7 +31682,7 @@ var globalConstants = /*#__PURE__*/Object.freeze({
30804
31682
  pureLgMax: pureLgMax
30805
31683
  });
30806
31684
 
30807
- const colors$1 = {
31685
+ const colors = {
30808
31686
  white: "#FFFFFF",
30809
31687
  gray98: "#FAFAFA",
30810
31688
  gray97: "#F6F7F7",
@@ -30864,7 +31742,7 @@ const colors$1 = {
30864
31742
  };
30865
31743
  const borderRadius = 4;
30866
31744
  const breadcrumbStyles = {
30867
- color: colors$1.breadcrumbs,
31745
+ color: colors.breadcrumbs,
30868
31746
  fontFamily: "inherit",
30869
31747
  fontSize: 15,
30870
31748
  fontWeight: "bold",
@@ -30934,14 +31812,14 @@ const typography = {
30934
31812
  },
30935
31813
  // For callouts
30936
31814
  smallHeading: {
30937
- color: colors$1.gray25,
31815
+ color: colors.gray25,
30938
31816
  fontFamily: "inherit",
30939
31817
  fontSize: 17,
30940
31818
  fontWeight: "bold",
30941
31819
  lineHeight: "23px"
30942
31820
  },
30943
31821
  smallHeadingMobile: {
30944
- color: colors$1.gray25,
31822
+ color: colors.gray25,
30945
31823
  fontFamily: "inherit",
30946
31824
  fontSize: 15,
30947
31825
  fontWeight: "bold",
@@ -30949,7 +31827,7 @@ const typography = {
30949
31827
  },
30950
31828
  // Accent headings
30951
31829
  accentHeading: {
30952
- color: colors$1.gray68,
31830
+ color: colors.gray68,
30953
31831
  fontFamily: "inherit",
30954
31832
  fontSize: 15,
30955
31833
  fontWeight: "bold",
@@ -31057,7 +31935,7 @@ const typography = {
31057
31935
  // HACK(kevinb): temporary wonder blocks styles for header only
31058
31936
  // TODO(kevinb): use components from wonder-blocks-typography instead
31059
31937
  wonderBlocksTitle: {
31060
- color: colors$1.white,
31938
+ color: colors.white,
31061
31939
  fontWeight: 900,
31062
31940
  // "Black" weight
31063
31941
  fontSize: 28,
@@ -31079,7 +31957,7 @@ const typography = {
31079
31957
 
31080
31958
  var globalStyles = /*#__PURE__*/Object.freeze({
31081
31959
  __proto__: null,
31082
- colors: colors$1,
31960
+ colors: colors,
31083
31961
  borderRadius: borderRadius,
31084
31962
  fonts: fonts,
31085
31963
  typography: typography
@@ -31144,7 +32022,7 @@ const HideAnswersToggle = props => {
31144
32022
  const switchId = idFactory.get("hide-answers-toggle");
31145
32023
  const labelId = idFactory.get("hide-answers-label");
31146
32024
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31147
- style: styles$j.switchWrapper
32025
+ style: styles$g.switchWrapper
31148
32026
  }, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
31149
32027
  id: switchId,
31150
32028
  checked: props.areAnswersHidden,
@@ -31156,7 +32034,7 @@ const HideAnswersToggle = props => {
31156
32034
  tag: "label"
31157
32035
  }, strings.hideAnswersToggleLabel));
31158
32036
  };
31159
- const styles$j = aphrodite.StyleSheet.create({
32037
+ const styles$g = aphrodite.StyleSheet.create({
31160
32038
  switchWrapper: {
31161
32039
  display: "flex",
31162
32040
  flexDirection: "row",
@@ -31211,14 +32089,14 @@ const AnswerPill = props => {
31211
32089
  id: idFactory.get("perseus-label-image-widget-answer-pill"),
31212
32090
  onClick: correct ? undefined : onClick,
31213
32091
  ref: ref,
31214
- 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]
31215
32093
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31216
32094
  content: answerString,
31217
32095
  inline: true
31218
32096
  }));
31219
32097
  });
31220
32098
  };
31221
- const styles$i = aphrodite.StyleSheet.create({
32099
+ const styles$f = aphrodite.StyleSheet.create({
31222
32100
  correct: {
31223
32101
  // WB green darkened by 18%
31224
32102
  backgroundColor: "#00880b"
@@ -31272,25 +32150,25 @@ class Marker extends React__namespace.Component {
31272
32150
  icon: iconNull
31273
32151
  };
31274
32152
  if (showCorrectness) {
31275
- 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];
31276
32154
  args = {
31277
32155
  ...args,
31278
32156
  icon: showCorrectness === "correct" ? iconCheck : iconMinus
31279
32157
  };
31280
32158
  } else if (selectedAnswers && selectedAnswers.length > 0) {
31281
- iconStyles = [styles$h.markerFilled, isOpen && styles$h.markerSelected];
32159
+ iconStyles = [styles$e.markerFilled, isOpen && styles$e.markerSelected];
31282
32160
  } else if (isOpen) {
31283
- iconStyles = [styles$h.markerSelected];
32161
+ iconStyles = [styles$e.markerSelected];
31284
32162
  args = {
31285
32163
  ...args,
31286
32164
  icon: iconChevronDown,
31287
32165
  size: 8
31288
32166
  };
31289
32167
  } else if (showPulsate) {
31290
- 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];
31291
32169
  }
31292
32170
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31293
- style: [styles$h.markerIcon, iconStyles],
32171
+ style: [styles$e.markerIcon, iconStyles],
31294
32172
  ref: node => this._icon = node
31295
32173
  }, /*#__PURE__*/React__namespace.createElement(Icon, args));
31296
32174
  }
@@ -31311,7 +32189,7 @@ class Marker extends React__namespace.Component {
31311
32189
  const markerDisabled = showCorrectness === "correct";
31312
32190
  const active = hovered || focused;
31313
32191
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31314
- style: [styles$h.marker, active && !markerDisabled && styles$h.markerActive]
32192
+ style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive]
31315
32193
  // already translated in: /widgets/graded-group.tsx
31316
32194
  ,
31317
32195
  "aria-label": markerDisabled ? i18n__namespace._("Correct!") : label
@@ -31326,7 +32204,7 @@ class Marker extends React__namespace.Component {
31326
32204
  }));
31327
32205
  }
31328
32206
  }
31329
- const styles$h = aphrodite.StyleSheet.create({
32207
+ const styles$e = aphrodite.StyleSheet.create({
31330
32208
  marker: {
31331
32209
  position: "absolute",
31332
32210
  backgroundColor: Color__default["default"].white,
@@ -31903,13 +32781,13 @@ class LabelImage extends React__namespace.Component {
31903
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.");
31904
32782
  const choicesString = i18n__namespace._("Choices:");
31905
32783
  return /*#__PURE__*/React__namespace.createElement("div", {
31906
- 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))
31907
32785
  }, /*#__PURE__*/React__namespace.createElement("div", {
31908
- className: aphrodite.css(styles$g.instructionsCaption)
32786
+ className: aphrodite.css(styles$d.instructionsCaption)
31909
32787
  }, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React__namespace.createElement("div", {
31910
- className: aphrodite.css(styles$g.instructionsChoices)
32788
+ className: aphrodite.css(styles$d.instructionsChoices)
31911
32789
  }, choices.map((choice, index) => /*#__PURE__*/React__namespace.createElement("div", {
31912
- className: aphrodite.css(styles$g.instructionsChoice),
32790
+ className: aphrodite.css(styles$d.instructionsChoice),
31913
32791
  key: index
31914
32792
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
31915
32793
  content: choice
@@ -31926,20 +32804,20 @@ class LabelImage extends React__namespace.Component {
31926
32804
  activeMarkerIndex
31927
32805
  } = this.state;
31928
32806
  return /*#__PURE__*/React__namespace.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React__namespace.createElement("div", {
31929
- className: aphrodite.css(styles$g.markersCanvas),
32807
+ className: aphrodite.css(styles$d.markersCanvas),
31930
32808
  style: {
31931
32809
  maxWidth: imageWidth,
31932
32810
  maxHeight: imageHeight
31933
32811
  }
31934
32812
  }, /*#__PURE__*/React__namespace.createElement("div", {
31935
- className: aphrodite.css(styles$g.imageContainer,
32813
+ className: aphrodite.css(styles$d.imageContainer,
31936
32814
  // Ensure image interaction is disabled while answer
31937
32815
  // choices popup is visible. This addresses specific
31938
32816
  // case where user may click on question image to
31939
32817
  // dismiss the popup. If the image is larger in size
31940
32818
  // than its rendered in the widget, this would
31941
32819
  // result in a zoom of the image.
31942
- activeMarkerIndex !== -1 && styles$g.imageInteractionDisabled)
32820
+ activeMarkerIndex !== -1 && styles$d.imageInteractionDisabled)
31943
32821
  }, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref3 => {
31944
32822
  let {
31945
32823
  setAssetStatus
@@ -31965,7 +32843,7 @@ class LabelImage extends React__namespace.Component {
31965
32843
  }));
31966
32844
  }
31967
32845
  }
31968
- const styles$g = aphrodite.StyleSheet.create({
32846
+ const styles$d = aphrodite.StyleSheet.create({
31969
32847
  instructions: {
31970
32848
  paddingBottom: 16
31971
32849
  },
@@ -32326,7 +33204,7 @@ class Placeholder extends React__namespace.Component {
32326
33204
  const {
32327
33205
  layout
32328
33206
  } = this.props;
32329
- 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);
32330
33208
  const style = {
32331
33209
  width: this.props.width,
32332
33210
  height: this.props.height
@@ -32424,7 +33302,7 @@ class Draggable extends React__namespace.Component {
32424
33302
  // We need to keep backwards compatbility with rules specified directly
32425
33303
  // in CSS. Hence the hacky tacking on of manual classNames.
32426
33304
  // See sortable.less for details.
32427
- 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";
32428
33306
  if (!includePadding) {
32429
33307
  className += " perseus-sortable-draggable-unpadded";
32430
33308
  }
@@ -32724,7 +33602,7 @@ class Sortable extends React__namespace.Component {
32724
33602
  } = this.props;
32725
33603
  // We need to keep backwards compatbility with rules specified directly
32726
33604
  // in CSS. See sortable.less for details.
32727
- const className = aphrodite.css(styles$f.sortable) + " perseus-sortable";
33605
+ const className = aphrodite.css(styles$c.sortable) + " perseus-sortable";
32728
33606
  const syncWidth = this.props.constraints?.width || layout === Layout.VERTICAL;
32729
33607
  const syncHeight = this.props.constraints?.height || layout === Layout.HORIZONTAL;
32730
33608
  ___default["default"].each(this.state.items, function (item, i, items) {
@@ -32955,7 +33833,7 @@ class Sortable extends React__namespace.Component {
32955
33833
  return ___default["default"].pluck(this.state.items, "option");
32956
33834
  }
32957
33835
  }
32958
- const styles$f = aphrodite.StyleSheet.create({
33836
+ const styles$c = aphrodite.StyleSheet.create({
32959
33837
  sortable: {
32960
33838
  boxSizing: "border-box",
32961
33839
  float: "left",
@@ -33083,23 +33961,23 @@ class Matcher extends React__namespace.Component {
33083
33961
  };
33084
33962
  const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
33085
33963
  return /*#__PURE__*/React__namespace.createElement("table", {
33086
- className: aphrodite.css(styles$e.widget) + " " + HACKY_CSS_CLASSNAME
33964
+ className: aphrodite.css(styles$b.widget) + " " + HACKY_CSS_CLASSNAME
33087
33965
  }, /*#__PURE__*/React__namespace.createElement("tbody", null, showLabels && /*#__PURE__*/React__namespace.createElement("tr", {
33088
- className: aphrodite.css(styles$e.row)
33966
+ className: aphrodite.css(styles$b.row)
33089
33967
  }, /*#__PURE__*/React__namespace.createElement("th", {
33090
- className: aphrodite.css(styles$e.column, styles$e.columnLabel)
33968
+ className: aphrodite.css(styles$b.column, styles$b.columnLabel)
33091
33969
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
33092
33970
  content: this.props.labels[0] || "...",
33093
33971
  linterContext: this.props.linterContext
33094
33972
  })), /*#__PURE__*/React__namespace.createElement("th", {
33095
- 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)
33096
33974
  }, /*#__PURE__*/React__namespace.createElement(Renderer, {
33097
33975
  content: this.props.labels[1] || "...",
33098
33976
  linterContext: this.props.linterContext
33099
33977
  }))), /*#__PURE__*/React__namespace.createElement("tr", {
33100
- className: aphrodite.css(styles$e.row)
33978
+ className: aphrodite.css(styles$b.row)
33101
33979
  }, /*#__PURE__*/React__namespace.createElement("td", {
33102
- className: aphrodite.css(styles$e.column)
33980
+ className: aphrodite.css(styles$b.column)
33103
33981
  }, /*#__PURE__*/React__namespace.createElement(Sortable, {
33104
33982
  options: left,
33105
33983
  layout: Layout.VERTICAL,
@@ -33114,7 +33992,7 @@ class Matcher extends React__namespace.Component {
33114
33992
  ,
33115
33993
  ref: "left"
33116
33994
  })), /*#__PURE__*/React__namespace.createElement("td", {
33117
- className: aphrodite.css(styles$e.column, styles$e.columnRight)
33995
+ className: aphrodite.css(styles$b.column, styles$b.columnRight)
33118
33996
  }, /*#__PURE__*/React__namespace.createElement(Sortable
33119
33997
  // @ts-expect-error - TS2322 - Type 'readonly unknown[]' is not assignable to type 'readonly string[]'.
33120
33998
  , {
@@ -33200,7 +34078,7 @@ ___default["default"].extend(Matcher, {
33200
34078
  });
33201
34079
  const padding = 5;
33202
34080
  const border = "1px solid #444";
33203
- const styles$e = aphrodite.StyleSheet.create({
34081
+ const styles$b = aphrodite.StyleSheet.create({
33204
34082
  widget: {
33205
34083
  paddingTop: padding,
33206
34084
  maxWidth: "100%",
@@ -33233,204 +34111,6 @@ var Matcher$1 = {
33233
34111
  isLintable: true
33234
34112
  };
33235
34113
 
33236
- const {
33237
- firstNumericalParse,
33238
- captureScratchpadTouchStart
33239
- } = Util;
33240
- const toNumericString = KhanMath.toNumericString;
33241
- const getNumericFormat = KhanMath.getNumericFormat;
33242
-
33243
- /* An input box that accepts only numeric strings
33244
- *
33245
- * Calls onChange(value, format) for valid numbers.
33246
- * Reverts to the current value onBlur or on [ENTER],
33247
- * but maintains the format (i.e. 3/2, 1 1/2, 150%)
33248
- * Accepts empty input and sends it to onChange as null
33249
- * if no numeric placeholder is set.
33250
- * If given a checkValidity function, will turn
33251
- * the background/outline red when invalid
33252
- * If useArrowKeys is set to true, up/down arrows will
33253
- * increment/decrement integers
33254
- * Optionally takes a size ("mini", "small", "normal")
33255
- */
33256
- class NumberInput extends React__namespace.Component {
33257
- static propTypes = {
33258
- value: PropTypes__default["default"].number,
33259
- format: PropTypes__default["default"].string,
33260
- placeholder: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number]),
33261
- onChange: PropTypes__default["default"].func.isRequired,
33262
- onFormatChange: PropTypes__default["default"].func,
33263
- checkValidity: PropTypes__default["default"].func,
33264
- size: PropTypes__default["default"].string,
33265
- label: PropTypes__default["default"].oneOf(["put your labels outside your inputs!"])
33266
- };
33267
- static defaultProps = {
33268
- value: null,
33269
- placeholder: null,
33270
- format: null,
33271
- onFormatChange: () => null,
33272
- checkValidity: () => true,
33273
- useArrowKeys: false
33274
- };
33275
- state = {
33276
- format: this.props.format
33277
- };
33278
- render() {
33279
- let classes = classNames__default["default"]({
33280
- "number-input": true,
33281
- "invalid-input": !this._checkValidity(this.props.value),
33282
- mini: this.props.size === "mini",
33283
- small: this.props.size === "small",
33284
- normal: this.props.size === "normal"
33285
- });
33286
- if (this.props.className != null) {
33287
- classes = classes + " " + this.props.className;
33288
- }
33289
- const {
33290
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33291
- onFormatChange,
33292
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33293
- checkValidity,
33294
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33295
- useArrowKeys,
33296
- ...restProps
33297
- } = this.props;
33298
- return /*#__PURE__*/React__namespace.createElement("input", _extends({}, restProps, {
33299
- className: classes,
33300
- type: "text"
33301
- // eslint-disable-next-line react/no-string-refs
33302
- ,
33303
- ref: "input",
33304
- onChange: this._handleChange,
33305
- onFocus: this._handleFocus,
33306
- onBlur: this._handleBlur,
33307
- onKeyPress: this._handleBlur,
33308
- onKeyDown: this._onKeyDown
33309
- // @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
33310
- ,
33311
- onTouchStart: captureScratchpadTouchStart,
33312
- defaultValue: toNumericString(this.props.value, this.state.format),
33313
- value: undefined
33314
- }));
33315
- }
33316
- componentDidUpdate(prevProps) {
33317
- if (!kmath.number.equal(this.getValue(), this.props.value)) {
33318
- this._setValue(this.props.value, this.state.format);
33319
- }
33320
- }
33321
-
33322
- /* Return the current "value" of this input
33323
- * If empty, it returns the placeholder (if it is a number) or null
33324
- */
33325
- getValue = () => {
33326
- return this.parseInputValue(
33327
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
33328
- ReactDOM__default["default"].findDOMNode(this.refs.input).value // eslint-disable-line react/no-string-refs
33329
- );
33330
- };
33331
-
33332
- /* Return the current string value of this input */
33333
- getStringValue = () => {
33334
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
33335
- return ReactDOM__default["default"].findDOMNode(this.refs.input).value.toString(); // eslint-disable-line react/no-string-refs
33336
- };
33337
-
33338
- parseInputValue = value => {
33339
- if (value === "") {
33340
- const placeholder = this.props.placeholder;
33341
- return ___default["default"].isFinite(placeholder) ? +placeholder : null;
33342
- }
33343
- const result = firstNumericalParse(value);
33344
- return ___default["default"].isFinite(result) ? result : this.props.value;
33345
- };
33346
-
33347
- /* Set text input focus to this input */
33348
- focus = () => {
33349
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'focus' does not exist on type 'Element | Text'.
33350
- ReactDOM__default["default"].findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
33351
- this._handleFocus();
33352
- };
33353
- blur = () => {
33354
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'blur' does not exist on type 'Element | Text'.
33355
- ReactDOM__default["default"].findDOMNode(this.refs.input).blur(); // eslint-disable-line react/no-string-refs
33356
- this._handleBlur();
33357
- };
33358
- setSelectionRange = (selectionStart, selectionEnd) => {
33359
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'setSelectionRange' does not exist on type 'Element | Text'.
33360
- ReactDOM__default["default"].findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
33361
- };
33362
- getSelectionStart = () => {
33363
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
33364
- return ReactDOM__default["default"].findDOMNode(this).selectionStart;
33365
- };
33366
- getSelectionEnd = () => {
33367
- // @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'.
33368
- return ReactDOM__default["default"].findDOMNode(this).selectionEnd;
33369
- };
33370
- _checkValidity = value => {
33371
- if (value == null) {
33372
- return true;
33373
- }
33374
- const val = firstNumericalParse(value);
33375
- const checkValidity = this.props.checkValidity;
33376
- return ___default["default"].isFinite(val) && checkValidity(val);
33377
- };
33378
- _handleChange = e => {
33379
- const text = e.target.value;
33380
- const value = this.parseInputValue(text);
33381
- const format = getNumericFormat(text);
33382
- this.props.onChange(value);
33383
- if (format) {
33384
- this.props.onFormatChange(value, format);
33385
- this.setState({
33386
- format: format
33387
- });
33388
- }
33389
- };
33390
- _handleFocus = () => {
33391
- if (this.props.onFocus) {
33392
- this.props.onFocus();
33393
- }
33394
- };
33395
- _handleBlur = e => {
33396
- // Only continue on blur or "enter"
33397
- // @ts-expect-error - TS2339 - Property 'keyCode' does not exist on type 'KeyboardEvent<Element> | FocusEvent<Element, Element>'.
33398
- if (e && e.type === "keypress" && e.keyCode !== 13) {
33399
- return;
33400
- }
33401
- this._setValue(this.props.value, this.state.format);
33402
- if (this.props.onBlur) {
33403
- this.props.onBlur();
33404
- }
33405
- };
33406
- _onKeyDown = e => {
33407
- if (this.props.onKeyDown) {
33408
- this.props.onKeyDown(e);
33409
- }
33410
- if (!this.props.useArrowKeys || !___default["default"].contains(["ArrowUp", "ArrowDown"], e.key)) {
33411
- return;
33412
- }
33413
- let val = this.getValue();
33414
- if (val !== Math.floor(val)) {
33415
- return; // bail if not an integer
33416
- }
33417
-
33418
- if (e.key === "ArrowUp") {
33419
- val = val + 1;
33420
- } else if (e.key === "ArrowDown") {
33421
- val = val - 1;
33422
- }
33423
- if (this._checkValidity(val)) {
33424
- this.props.onChange(val);
33425
- }
33426
- };
33427
- _setValue = (val, format) => {
33428
- // eslint-disable-next-line react/no-string-refs
33429
- // @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
33430
- $__default["default"](ReactDOM__default["default"].findDOMNode(this.refs.input)).val(toNumericString(val, format));
33431
- };
33432
- }
33433
-
33434
34114
  // Type imports
33435
34115
 
33436
34116
  const {
@@ -34073,9 +34753,9 @@ function drawText(ctx, item) {
34073
34753
  if (item.value === null) {
34074
34754
  return;
34075
34755
  }
34076
- ctx.fillStyle = styles$d.fgColor;
34077
- ctx.font = styles$d.font;
34078
- 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);
34079
34759
  }
34080
34760
 
34081
34761
  /**
@@ -34096,16 +34776,16 @@ function drawText(ctx, item) {
34096
34776
  function drawDoubleLine(ctx, item) {
34097
34777
  // Outer line that forms both of the bond lines.
34098
34778
  let path = new Path2D();
34099
- ctx.lineWidth = 5 * styles$d.lineWidth;
34100
- ctx.strokeStyle = styles$d.fgColor;
34779
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34780
+ ctx.strokeStyle = styles$a.fgColor;
34101
34781
  path.moveTo(item.startPos[0], item.startPos[1]);
34102
34782
  path.lineTo(item.endPos[0], item.endPos[1]);
34103
34783
  ctx.stroke(path);
34104
34784
 
34105
34785
  // Inner white line that separates the two bond lines.
34106
34786
  path = new Path2D();
34107
- ctx.lineWidth = 3 * styles$d.lineWidth;
34108
- ctx.strokeStyle = styles$d.bgColor;
34787
+ ctx.lineWidth = 3 * styles$a.lineWidth;
34788
+ ctx.strokeStyle = styles$a.bgColor;
34109
34789
  path.moveTo(item.startPos[0], item.startPos[1]);
34110
34790
  path.lineTo(item.endPos[0], item.endPos[1]);
34111
34791
  ctx.stroke(path);
@@ -34132,16 +34812,16 @@ function drawTripleLine(ctx, item) {
34132
34812
 
34133
34813
  // Outer line that will form the two outer bond lines.
34134
34814
  let path = new Path2D();
34135
- ctx.lineWidth = 7 * styles$d.lineWidth;
34136
- ctx.strokeStyle = styles$d.fgColor;
34815
+ ctx.lineWidth = 7 * styles$a.lineWidth;
34816
+ ctx.strokeStyle = styles$a.fgColor;
34137
34817
  path.moveTo(item.startPos[0], item.startPos[1]);
34138
34818
  path.lineTo(item.endPos[0], item.endPos[1]);
34139
34819
  ctx.stroke(path);
34140
34820
 
34141
34821
  // Middle white line that separates the bonds
34142
34822
  path = new Path2D();
34143
- ctx.lineWidth = 5 * styles$d.lineWidth;
34144
- ctx.strokeStyle = styles$d.bgColor;
34823
+ ctx.lineWidth = 5 * styles$a.lineWidth;
34824
+ ctx.strokeStyle = styles$a.bgColor;
34145
34825
  path.moveTo(item.startPos[0], item.startPos[1]);
34146
34826
  path.lineTo(item.endPos[0], item.endPos[1]);
34147
34827
  ctx.stroke(path);
@@ -34163,8 +34843,8 @@ function drawTripleLine(ctx, item) {
34163
34843
  */
34164
34844
  function drawLine(ctx, item) {
34165
34845
  const path = new Path2D();
34166
- ctx.lineWidth = styles$d.lineWidth;
34167
- ctx.strokeStyle = styles$d.fgColor;
34846
+ ctx.lineWidth = styles$a.lineWidth;
34847
+ ctx.strokeStyle = styles$a.fgColor;
34168
34848
  path.moveTo(item.startPos[0], item.startPos[1]);
34169
34849
  path.lineTo(item.endPos[0], item.endPos[1]);
34170
34850
  ctx.stroke(path);
@@ -34216,7 +34896,7 @@ function compareElements(item0, item1) {
34216
34896
  function draw(ctx, items) {
34217
34897
  items.sort(compareElements).forEach(drawItem(ctx));
34218
34898
  }
34219
- const styles$d = {
34899
+ const styles$a = {
34220
34900
  bgColor: "rgb(255, 255, 255)",
34221
34901
  fgColor: "rgb(0, 0, 0)",
34222
34902
  fontSizePx: 12,
@@ -36780,7 +37460,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
36780
37460
  const rects = this.state.cachedHighlightRects;
36781
37461
  return /*#__PURE__*/React__namespace.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React__namespace.createElement("div", {
36782
37462
  key: index,
36783
- className: aphrodite.css(styles$c.highlightRect),
37463
+ className: aphrodite.css(styles$9.highlightRect),
36784
37464
  style: {
36785
37465
  // NOTE(mdr): We apply `position: absolute` here
36786
37466
  // rather than in Aphrodite styles, because
@@ -36799,7 +37479,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
36799
37479
  })));
36800
37480
  }
36801
37481
  }
36802
- const styles$c = aphrodite.StyleSheet.create({
37482
+ const styles$9 = aphrodite.StyleSheet.create({
36803
37483
  highlightRect: {
36804
37484
  background: "#fffabe" // highlighter yellow :)
36805
37485
  }
@@ -36880,7 +37560,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
36880
37560
  // TooltipContent wouldn't let me overwrite
36881
37561
  // user-select and onClick
36882
37562
  const content = /*#__PURE__*/React__namespace.createElement("div", {
36883
- className: aphrodite.css(styles$b.tooltipLabel),
37563
+ className: aphrodite.css(styles$8.tooltipLabel),
36884
37564
  onClick: this.props.onClick
36885
37565
  }, this.props.label);
36886
37566
  const style = {
@@ -36900,7 +37580,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
36900
37580
  }, /*#__PURE__*/React__namespace.createElement("div", null)));
36901
37581
  }
36902
37582
  }
36903
- const styles$b = aphrodite.StyleSheet.create({
37583
+ const styles$8 = aphrodite.StyleSheet.create({
36904
37584
  tooltipLabel: {
36905
37585
  // Unlike most tooltip contents, we don't want this label to be
36906
37586
  // selectable. Selecting it is not only unhelpful, but dangerous: if
@@ -37458,7 +38138,7 @@ class HighlightableContent extends React__namespace.PureComponent {
37458
38138
  // starting point: https://phabricator.khanacademy.org/D35623?id=170698
37459
38139
  const buildHighlight = r => this._buildHighlight(r);
37460
38140
  return /*#__PURE__*/React__namespace.createElement("div", {
37461
- className: aphrodite.css(styles$a.container),
38141
+ className: aphrodite.css(styles$7.container),
37462
38142
  ref: container => this._container = container
37463
38143
  }, /*#__PURE__*/React__namespace.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React__namespace.createElement(HighlightingUI, {
37464
38144
  buildHighlight: buildHighlight,
@@ -37479,14 +38159,14 @@ class HighlightableContent extends React__namespace.PureComponent {
37479
38159
  onAddHighlight: this._handleAddHighlight,
37480
38160
  onRemoveHighlight: this._handleRemoveHighlight
37481
38161
  })), /*#__PURE__*/React__namespace.createElement("div", {
37482
- className: aphrodite.css(styles$a.content),
38162
+ className: aphrodite.css(styles$7.content),
37483
38163
  ref: content => this._content = content
37484
38164
  }, /*#__PURE__*/React__namespace.createElement(WordIndexer, {
37485
38165
  onWordsUpdate: this._handleWordsUpdate
37486
38166
  }, this.props.children)));
37487
38167
  }
37488
38168
  }
37489
- const styles$a = aphrodite.StyleSheet.create({
38169
+ const styles$7 = aphrodite.StyleSheet.create({
37490
38170
  // We render content with z-index 1, and highlights with z-index 0, so that
37491
38171
  // content will receive the browser's native pointer events. (Highlights
37492
38172
  // have their own magic code to manage hover detection, despite being
@@ -37882,7 +38562,7 @@ class LineHeightMeasurer extends React__namespace.Component {
37882
38562
  }
37883
38563
  render() {
37884
38564
  return /*#__PURE__*/React__namespace.createElement("div", {
37885
- className: aphrodite.css(styles$9.measurer),
38565
+ className: aphrodite.css(styles$6.measurer),
37886
38566
  "aria-hidden": "true"
37887
38567
  }, /*#__PURE__*/React__namespace.createElement("div", {
37888
38568
  ref: ref => this._line = ref,
@@ -37890,7 +38570,7 @@ class LineHeightMeasurer extends React__namespace.Component {
37890
38570
  }, "Line Height Measurement"));
37891
38571
  }
37892
38572
  }
37893
- const styles$9 = aphrodite.StyleSheet.create({
38573
+ const styles$6 = aphrodite.StyleSheet.create({
37894
38574
  measurer: {
37895
38575
  position: "absolute",
37896
38576
  top: 0,
@@ -39202,7 +39882,7 @@ class PythonProgram extends React__namespace.Component {
39202
39882
  // creator "went wild".
39203
39883
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
39204
39884
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
39205
- style: styles$8.container
39885
+ style: styles$5.container
39206
39886
  }, /*#__PURE__*/React__namespace.createElement("iframe", {
39207
39887
  sandbox: sandboxOptions,
39208
39888
  src: url,
@@ -39211,7 +39891,7 @@ class PythonProgram extends React__namespace.Component {
39211
39891
  }));
39212
39892
  }
39213
39893
  }
39214
- const styles$8 = aphrodite.StyleSheet.create({
39894
+ const styles$5 = aphrodite.StyleSheet.create({
39215
39895
  container: {
39216
39896
  margin: "auto",
39217
39897
  width: "100%"
@@ -39448,125 +40128,6 @@ var Sequence$1 = {
39448
40128
  isLintable: true
39449
40129
  };
39450
40130
 
39451
- const colors = {
39452
- grayLight: "#aaa",
39453
- basicBorderColor: "#ccc",
39454
- white: "#fff"
39455
- };
39456
- const triangleBeforeAfter = {
39457
- borderBottom: "9px solid transparent",
39458
- borderTop: "9px solid transparent",
39459
- content: '" "',
39460
- height: "0",
39461
- position: "absolute",
39462
- top: "0",
39463
- width: "0"
39464
- };
39465
- const styles$7 = aphrodite.StyleSheet.create({
39466
- infoTip: {
39467
- display: "inline-block",
39468
- marginLeft: "5px",
39469
- position: "relative"
39470
- },
39471
- infoTipContainer: {
39472
- position: "absolute",
39473
- top: "-12px",
39474
- left: "22px",
39475
- zIndex: 1000
39476
- },
39477
- infoTipTriangle: {
39478
- height: "10px",
39479
- left: "0",
39480
- position: "absolute",
39481
- top: "8px",
39482
- width: "0",
39483
- zIndex: 1,
39484
- ":before": {
39485
- ...triangleBeforeAfter,
39486
- borderRight: "9px solid #bbb",
39487
- right: "0"
39488
- },
39489
- ":after": {
39490
- ...triangleBeforeAfter,
39491
- borderRight: `9px solid ${colors.white}`,
39492
- right: "-1px"
39493
- }
39494
- },
39495
- verticalShadow: {
39496
- border: `1px solid ${colors.basicBorderColor}`,
39497
- boxShadow: `0 1px 3px ${colors.basicBorderColor}`,
39498
- borderBottom: `1px solid ${colors.grayLight}`
39499
- },
39500
- infoTipContentContainer: {
39501
- background: colors.white,
39502
- padding: "5px 10px",
39503
- width: "240px"
39504
- }
39505
- });
39506
- 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=";
39507
- class InfoTip$1 extends React__namespace.Component {
39508
- state = {
39509
- hover: false
39510
- };
39511
- handleMouseEnter = () => {
39512
- this.setState({
39513
- hover: true
39514
- });
39515
- };
39516
- handleMouseLeave = () => {
39517
- this.setState({
39518
- hover: false
39519
- });
39520
- };
39521
- render() {
39522
- return /*#__PURE__*/React__namespace.createElement("div", {
39523
- className: aphrodite.css(styles$7.infoTip)
39524
- }, /*#__PURE__*/React__namespace.createElement("img", {
39525
- alt: "",
39526
- width: 10,
39527
- height: 10,
39528
- src: questionMark,
39529
- onMouseEnter: this.handleMouseEnter,
39530
- onMouseLeave: this.handleMouseLeave
39531
- }), /*#__PURE__*/React__namespace.createElement("div", {
39532
- className: aphrodite.css(styles$7.infoTipContainer),
39533
- style: {
39534
- display: this.state.hover ? "block" : "none"
39535
- }
39536
- }, /*#__PURE__*/React__namespace.createElement("div", {
39537
- className: aphrodite.css(styles$7.infoTipTriangle)
39538
- }), /*#__PURE__*/React__namespace.createElement("div", {
39539
- className: aphrodite.css(styles$7.verticalShadow, styles$7.infoTipContentContainer)
39540
- }, this.props.children)));
39541
- }
39542
- }
39543
-
39544
- /**
39545
- * A wrapper around info-tip/info-tip.jsx that can be rendered on the
39546
- * server without causing a checksum mismatch on the client.
39547
- * (RCSS generates classnames with a randomSuffix, which ensures that any
39548
- * two sets of generated classnames will not match.)
39549
- */
39550
- class InfoTip extends React__namespace.Component {
39551
- state = {
39552
- didMount: false
39553
- };
39554
- componentDidMount() {
39555
- /* eslint-disable react/no-did-mount-set-state */
39556
- this.setState({
39557
- didMount: true
39558
- });
39559
- /* eslint-enable react/no-did-mount-set-state */
39560
- }
39561
-
39562
- render() {
39563
- if (this.state.didMount) {
39564
- return /*#__PURE__*/React__namespace.createElement(InfoTip$1, this.props);
39565
- }
39566
- return /*#__PURE__*/React__namespace.createElement("div", null);
39567
- }
39568
- }
39569
-
39570
40131
  /* eslint-disable @typescript-eslint/no-unused-vars, react/no-unsafe, react/sort-comp */
39571
40132
  const {
39572
40133
  assert: assert$1
@@ -41524,7 +42085,7 @@ const VideoTranscriptLink = props => {
41524
42085
  {
41525
42086
  const video = result.data?.video;
41526
42087
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
41527
- style: styles$6.transcriptLink
42088
+ style: styles$4.transcriptLink
41528
42089
  }, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.Text, null, video?.title), /*#__PURE__*/React__namespace.createElement(wonderBlocksLayout.Strut, {
41529
42090
  size: 10
41530
42091
  }), /*#__PURE__*/React__namespace.createElement(Link__default["default"], {
@@ -41541,7 +42102,7 @@ const VideoTranscriptLink = props => {
41541
42102
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, i18n__namespace._("Something went wrong."));
41542
42103
  }
41543
42104
  };
41544
- const styles$6 = aphrodite.StyleSheet.create({
42105
+ const styles$4 = aphrodite.StyleSheet.create({
41545
42106
  transcriptLink: {
41546
42107
  flexDirection: "row",
41547
42108
  width: "100%",
@@ -41697,7 +42258,7 @@ const init = function (options) {
41697
42258
 
41698
42259
  // This file is processed by a Rollup plugin (replace) to inject the production
41699
42260
  const libName = "@khanacademy/perseus";
41700
- const libVersion = "19.6.3";
42261
+ const libVersion = "19.7.0";
41701
42262
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
41702
42263
 
41703
42264
  const apiVersion = {
@@ -41910,7 +42471,7 @@ class HintRenderer extends React__namespace.Component {
41910
42471
  const {
41911
42472
  isMobile
41912
42473
  } = apiOptions;
41913
- 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);
41914
42475
 
41915
42476
  // TODO(charlie): Allowing `customKeypad` would require that we
41916
42477
  // extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
@@ -41951,7 +42512,7 @@ class HintRenderer extends React__namespace.Component {
41951
42512
  );
41952
42513
  }
41953
42514
  }
41954
- const styles$5 = aphrodite.StyleSheet.create({
42515
+ const styles$3 = aphrodite.StyleSheet.create({
41955
42516
  newHint: {
41956
42517
  marginBottom: 1.5 * baseUnitPx,
41957
42518
  borderLeftColor: gray97,
@@ -42128,15 +42689,15 @@ class HintsRenderer extends React__namespace.Component {
42128
42689
  } = apiOptions;
42129
42690
  const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
42130
42691
  const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
42131
- 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));
42132
42693
  return /*#__PURE__*/React__namespace.createElement("div", {
42133
42694
  className: classNames
42134
42695
  }, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React__namespace.createElement("div", {
42135
- className: aphrodite.css(styles$4.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
42696
+ className: aphrodite.css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
42136
42697
  }, i18n__namespace._("Hints")), hints, showGetAnotherHint && /*#__PURE__*/React__namespace.createElement("button", {
42137
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>'.
42138
42699
  rel: "button",
42139
- 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),
42140
42701
  onClick: evt => {
42141
42702
  evt.preventDefault();
42142
42703
  evt.stopPropagation();
@@ -42145,14 +42706,14 @@ class HintsRenderer extends React__namespace.Component {
42145
42706
  }
42146
42707
  }
42147
42708
  }, /*#__PURE__*/React__namespace.createElement("span", {
42148
- className: aphrodite.css(styles$4.plusText, apiOptions.isMobile && styles$4.mobileHintStylesPlusText)
42709
+ className: aphrodite.css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
42149
42710
  }, "+"), /*#__PURE__*/React__namespace.createElement("span", {
42150
- className: aphrodite.css(styles$4.getAnotherHintText)
42711
+ className: aphrodite.css(styles$2.getAnotherHintText)
42151
42712
  }, i18n__namespace._("Get another hint"), " ", hintRatioCopy)));
42152
42713
  }
42153
42714
  }
42154
42715
  const hintIndentation = baseUnitPx + hintBorderWidth;
42155
- const styles$4 = aphrodite.StyleSheet.create({
42716
+ const styles$2 = aphrodite.StyleSheet.create({
42156
42717
  // eslint-disable-next-line react-native/no-unused-styles
42157
42718
  rendererMargins: {
42158
42719
  marginTop: baseUnitPx
@@ -42564,11 +43125,11 @@ class ServerItemRenderer extends React__namespace.Component {
42564
43125
  // mobile hint styles, which are flush to the left.
42565
43126
  // NOTE(charlie): We may still want to apply this
42566
43127
  // padding for desktop exercises.
42567
- apiOptions.isMobile ? undefined : aphrodite.css(styles$3.hintsContainer)
43128
+ apiOptions.isMobile ? undefined : aphrodite.css(styles$1.hintsContainer)
42568
43129
  }, hintsRenderer)));
42569
43130
  }
42570
43131
  }
42571
- const styles$3 = aphrodite.StyleSheet.create({
43132
+ const styles$1 = aphrodite.StyleSheet.create({
42572
43133
  hintsContainer: {
42573
43134
  marginLeft: 50
42574
43135
  }
@@ -42705,339 +43266,6 @@ class ElementContainer extends React__namespace.Component {
42705
43266
  }
42706
43267
  }
42707
43268
 
42708
- // Displays a stylized open eye: lint warnings are visible
42709
- const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
42710
- width: "24",
42711
- height: "24",
42712
- viewBox: "0 0 24 24",
42713
- className: aphrodite.css(styles$2.icon)
42714
- }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
42715
- id: "a",
42716
- 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"
42717
- })), /*#__PURE__*/React__namespace.createElement("g", {
42718
- fill: "none",
42719
- fillRule: "evenodd"
42720
- }, /*#__PURE__*/React__namespace.createElement("path", {
42721
- fill: "none",
42722
- d: "M0 0h24v24H0z"
42723
- }), /*#__PURE__*/React__namespace.createElement("mask", {
42724
- id: "b",
42725
- fill: "#fff"
42726
- }, /*#__PURE__*/React__namespace.createElement("use", {
42727
- href: "#a"
42728
- })), /*#__PURE__*/React__namespace.createElement("use", {
42729
- fill: "#fff",
42730
- fillRule: "nonzero",
42731
- href: "#a"
42732
- }), /*#__PURE__*/React__namespace.createElement("g", {
42733
- fill: "#fff",
42734
- mask: "url(#b)"
42735
- }, /*#__PURE__*/React__namespace.createElement("path", {
42736
- d: "M0 0h24v24H0z"
42737
- }))));
42738
-
42739
- // Displays a stylized eye with a line through it: I don't want to see lint
42740
- const HiddenIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
42741
- width: "24",
42742
- height: "24",
42743
- viewBox: "0 0 24 24",
42744
- className: aphrodite.css(styles$2.icon)
42745
- }, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
42746
- id: "a",
42747
- 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"
42748
- })), /*#__PURE__*/React__namespace.createElement("g", {
42749
- fill: "none",
42750
- fillRule: "evenodd"
42751
- }, /*#__PURE__*/React__namespace.createElement("path", {
42752
- fill: "none",
42753
- d: "M0 0h24v24H0z"
42754
- }), /*#__PURE__*/React__namespace.createElement("mask", {
42755
- id: "b",
42756
- fill: "#fff"
42757
- }, /*#__PURE__*/React__namespace.createElement("use", {
42758
- href: "#a"
42759
- })), /*#__PURE__*/React__namespace.createElement("use", {
42760
- fill: "#fff",
42761
- fillRule: "nonzero",
42762
- href: "#a"
42763
- }), /*#__PURE__*/React__namespace.createElement("g", {
42764
- fill: "#fff",
42765
- mask: "url(#b)"
42766
- }, /*#__PURE__*/React__namespace.createElement("path", {
42767
- d: "M0 0h24v24H0z"
42768
- }))));
42769
- const HUD = _ref => {
42770
- let {
42771
- message,
42772
- enabled,
42773
- onClick,
42774
- fixedPosition = true
42775
- } = _ref;
42776
- let state;
42777
- let icon;
42778
- if (enabled) {
42779
- state = styles$2.enabled;
42780
- icon = /*#__PURE__*/React__namespace.createElement(VisibleIcon, null);
42781
- } else {
42782
- state = styles$2.disabled;
42783
- icon = /*#__PURE__*/React__namespace.createElement(HiddenIcon, null);
42784
- }
42785
- return /*#__PURE__*/React__namespace.createElement("button", {
42786
- className: aphrodite.css(styles$2.hud, fixedPosition && styles$2.hudFixedPosition, state),
42787
- onClick: e => {
42788
- onClick();
42789
- }
42790
- }, icon, message);
42791
- };
42792
- const styles$2 = aphrodite.StyleSheet.create({
42793
- hud: {
42794
- boxSizing: "border-box",
42795
- height: 36,
42796
- padding: "9px 16px",
42797
- borderRadius: 18,
42798
- fontFamily: boldFontFamily,
42799
- fontSize: "15px",
42800
- lineHeight: "18px",
42801
- color: white$1,
42802
- userSelect: "none",
42803
- borderWidth: 0 // <button> gives us a border by default
42804
- },
42805
-
42806
- // We want to render the element in-place in our fixtures, so allow us to
42807
- // render in the bottom corner in production and in-place in testing.
42808
- hudFixedPosition: {
42809
- bottom: 20,
42810
- position: "fixed",
42811
- right: 20,
42812
- zIndex: 1
42813
- },
42814
- icon: {
42815
- width: 24,
42816
- height: 24,
42817
- marginRight: 8,
42818
- marginTop: -3,
42819
- verticalAlign: "middle"
42820
- },
42821
- enabled: {
42822
- backgroundColor: warningColor,
42823
- ":hover": {
42824
- backgroundColor: warningColorHover
42825
- },
42826
- ":active": {
42827
- backgroundColor: warningColorActive
42828
- }
42829
- },
42830
- disabled: {
42831
- backgroundColor: gray76,
42832
- ":hover": {
42833
- backgroundColor: "#a1a5a9" // in between those two grays
42834
- },
42835
-
42836
- ":active": {
42837
- backgroundColor: gray68
42838
- }
42839
- }
42840
- });
42841
-
42842
- /**
42843
- * MultiButtonGroup is an aesthetically pleasing group of buttons,
42844
- * which allows multiple buttons to be selected at the same time.
42845
- *
42846
- * NOTE: This component is almost identical to ./button-group.jsx except that
42847
- * this component allows multiple selection!
42848
- */
42849
- class MultiButtonGroup extends React__namespace.Component {
42850
- static defaultProps = {
42851
- values: [],
42852
- allowEmpty: true
42853
- };
42854
- focus() {
42855
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
42856
- ReactDOM__namespace.findDOMNode(this)?.focus();
42857
- return true;
42858
- }
42859
- toggleSelect = newValue => {
42860
- const values = (this.props.values || []).slice(0);
42861
- const allowEmpty = this.props.allowEmpty;
42862
- if (values.indexOf(newValue) >= 0 && (values.length > 1 || allowEmpty)) {
42863
- // If the value is already selected, unselect it
42864
- values.splice(values.indexOf(newValue), 1);
42865
- } else {
42866
- // Otherwise merge with other values and return
42867
- if (values.indexOf(newValue) < 0) {
42868
- values.push(newValue);
42869
- }
42870
- }
42871
- this.props.onChange(values);
42872
- };
42873
- render() {
42874
- const values = this.props.values || [];
42875
- const buttons = this.props.buttons.map((button, i) => {
42876
- const selected = values.indexOf(button.value) >= 0;
42877
- return /*#__PURE__*/React__namespace.createElement("button", {
42878
- title: button.title,
42879
- type: "button",
42880
- id: "" + i,
42881
- key: "" + i,
42882
- ref: "button" + i,
42883
- className: aphrodite.css(styles$1.buttonStyle, selected && styles$1.selectedStyle),
42884
- onClick: () => this.toggleSelect(button.value)
42885
- }, button.content || "" + button.value);
42886
- });
42887
- const outerStyle = {
42888
- display: "inline-block"
42889
- };
42890
- return /*#__PURE__*/React__namespace.createElement("div", {
42891
- style: outerStyle
42892
- }, buttons);
42893
- }
42894
- }
42895
- const styles$1 = aphrodite.StyleSheet.create({
42896
- buttonStyle: {
42897
- backgroundColor: "white",
42898
- border: "1px solid #ccc",
42899
- borderLeft: "0",
42900
- cursor: "pointer",
42901
- margin: "0",
42902
- padding: "5px 10px",
42903
- position: "relative",
42904
- // for hover
42905
-
42906
- ":first-child": {
42907
- borderLeft: "1px solid #ccc",
42908
- borderTopLeftRadius: "3px",
42909
- borderBottomLeftRadius: "3px"
42910
- },
42911
- ":last-child": {
42912
- borderRight: "1px solid #ccc",
42913
- borderTopRightRadius: "3px",
42914
- borderBottomRightRadius: "3px"
42915
- },
42916
- ":hover": {
42917
- backgroundColor: "#ccc"
42918
- },
42919
- ":focus": {
42920
- zIndex: 2
42921
- }
42922
- },
42923
- selectedStyle: {
42924
- backgroundColor: "#ddd"
42925
- }
42926
- });
42927
-
42928
- /* eslint-disable @babel/no-invalid-this */
42929
-
42930
- /* A checkbox that syncs its value to props using the
42931
- * renderer's onChange method, and gets the prop name
42932
- * dynamically from its props list
42933
- */
42934
- const PropCheckBox = createReactClass__default["default"]({
42935
- displayName: "PropCheckBox",
42936
- propTypes: {
42937
- labelAlignment: PropTypes__default["default"].oneOf(["left", "right"])
42938
- },
42939
- DEFAULT_PROPS: {
42940
- label: null,
42941
- onChange: null,
42942
- labelAlignment: "left"
42943
- },
42944
- getDefaultProps: function () {
42945
- return this.DEFAULT_PROPS;
42946
- },
42947
- propName: function () {
42948
- const propName = ___default["default"].find(___default["default"].keys(this.props), function (localPropName) {
42949
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
42950
- return !___default["default"].has(this.DEFAULT_PROPS, localPropName);
42951
- }, this);
42952
- if (!propName) {
42953
- throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
42954
- }
42955
- return propName;
42956
- },
42957
- _labelAlignLeft: function () {
42958
- return this.props.labelAlignment === "left";
42959
- },
42960
- render: function () {
42961
- const propName = this.propName();
42962
- return /*#__PURE__*/React__namespace.createElement("label", null, this._labelAlignLeft() && this.props.label, /*#__PURE__*/React__namespace.createElement("input", {
42963
- type: "checkbox",
42964
- checked: this.props[propName],
42965
- onChange: this.toggle
42966
- }), !this._labelAlignLeft() && this.props.label);
42967
- },
42968
- toggle: function () {
42969
- const propName = this.propName();
42970
- const changes = {};
42971
- changes[propName] = !this.props[propName];
42972
- this.props.onChange(changes);
42973
- }
42974
- });
42975
-
42976
- const truth = () => true;
42977
-
42978
- /* A minor abstraction on top of NumberInput for ranges
42979
- *
42980
- */
42981
- class RangeInput extends React__namespace.Component {
42982
- static propTypes = {
42983
- value: PropTypes__default["default"].array.isRequired,
42984
- onChange: PropTypes__default["default"].func.isRequired,
42985
- placeholder: PropTypes__default["default"].array,
42986
- checkValidity: PropTypes__default["default"].func
42987
- };
42988
- static defaultProps = {
42989
- placeholder: [null, null]
42990
- };
42991
- render() {
42992
- const value = this.props.value;
42993
- const checkValidity = this.props.checkValidity || truth;
42994
- return /*#__PURE__*/React__namespace.createElement("div", {
42995
- className: "range-input"
42996
- }, /*#__PURE__*/React__namespace.createElement(NumberInput, _extends({}, this.props, {
42997
- value: value[0],
42998
- checkValidity: val => checkValidity([val, value[1]])
42999
- // eslint-disable-next-line react/jsx-no-bind
43000
- ,
43001
- onChange: this.onChange.bind(this, 0),
43002
- placeholder: this.props.placeholder[0]
43003
- })), /*#__PURE__*/React__namespace.createElement(NumberInput, _extends({}, this.props, {
43004
- value: value[1],
43005
- checkValidity: val => checkValidity([value[0], val])
43006
- // eslint-disable-next-line react/jsx-no-bind
43007
- ,
43008
- onChange: this.onChange.bind(this, 1),
43009
- placeholder: this.props.placeholder[1]
43010
- })));
43011
- }
43012
- onChange = (i, newVal) => {
43013
- const value = this.props.value;
43014
- if (i === 0) {
43015
- this.props.onChange([newVal, value[1]]);
43016
- } else {
43017
- this.props.onChange([value[0], newVal]);
43018
- }
43019
- };
43020
- }
43021
-
43022
- var components = /*#__PURE__*/Object.freeze({
43023
- __proto__: null,
43024
- ButtonGroup: ButtonGroup,
43025
- Graph: Graph,
43026
- Graphie: Graphie,
43027
- HUD: HUD,
43028
- Icon: Icon,
43029
- InfoTip: InfoTip,
43030
- InlineIcon: InlineIcon,
43031
- MathInput: MathInput,
43032
- MultiButtonGroup: MultiButtonGroup,
43033
- NumberInput: NumberInput,
43034
- PropCheckBox: PropCheckBox,
43035
- RangeInput: RangeInput,
43036
- SvgImage: SvgImage,
43037
- TextInput: TextInput,
43038
- TextListEditor: TextListEditor
43039
- });
43040
-
43041
43269
  const devices = {
43042
43270
  PHONE: "phone",
43043
43271
  TABLET: "tablet",