@khanacademy/perseus 54.1.0 → 55.0.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/LICENSE +18 -0
- package/dist/components/number-input.d.ts +9 -10
- package/dist/components/range-input.d.ts +5 -6
- package/dist/components/simple-keypad-input.d.ts +5 -0
- package/dist/components/stub-tag-editor.d.ts +3 -4
- package/dist/components/text-list-editor.d.ts +3 -4
- package/dist/es/index.css +16 -6
- package/dist/es/index.js +901 -985
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +40 -10
- package/dist/es/strings.js.map +1 -1
- package/dist/index.css +16 -6
- package/dist/index.js +1035 -1086
- package/dist/index.js.map +1 -1
- package/dist/mixins/changeable.d.ts +1 -2
- package/dist/perseus-api.d.ts +1 -56
- package/dist/shared-utils/add-library-version-to-perseus-debug.d.ts +9 -0
- package/dist/strings.d.ts +34 -4
- package/dist/strings.js +142 -97
- package/dist/strings.js.map +1 -1
- package/dist/widget-ai-utils/numeric-input/prompt-utils.d.ts +1 -1
- package/dist/widgets/dropdown/dropdown.d.ts +5 -4
- package/dist/widgets/interactive-graph.d.ts +4 -2
- package/dist/widgets/interactive-graphs/graphs/circle.d.ts +7 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +6 -0
- package/dist/widgets/interactive-graphs/graphs/quadratic.d.ts +8 -0
- package/dist/widgets/interactive-graphs/graphs/sinusoid.d.ts +7 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +1 -1
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +6 -1
- package/dist/widgets/numeric-input/index.d.ts +1 -1
- package/dist/widgets/numeric-input/input-with-examples.d.ts +8 -0
- package/dist/widgets/numeric-input/numeric-input.class.d.ts +66 -0
- package/dist/widgets/numeric-input/numeric-input.d.ts +123 -77
- package/dist/widgets/numeric-input/utils.d.ts +25 -0
- package/package.json +120 -124
- package/dist/components/input-with-examples.d.ts +0 -51
- package/dist/components/tooltip.d.ts +0 -85
package/dist/index.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var _extends = require('@babel/runtime/helpers/extends');
|
|
5
6
|
var KAS = require('@khanacademy/kas');
|
|
6
7
|
var mathInput = require('@khanacademy/math-input');
|
|
7
8
|
var perseusCore = require('@khanacademy/perseus-core');
|
|
8
9
|
var PerseusLinter = require('@khanacademy/perseus-linter');
|
|
9
10
|
var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
10
|
-
var Tooltip
|
|
11
|
+
var Tooltip = require('@khanacademy/wonder-blocks-tooltip');
|
|
11
12
|
var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
|
|
12
13
|
var aphrodite = require('aphrodite');
|
|
13
14
|
var classNames$1 = require('classnames');
|
|
@@ -21,12 +22,13 @@ var $ = require('jquery');
|
|
|
21
22
|
var uuid = require('uuid');
|
|
22
23
|
var PropTypes = require('prop-types');
|
|
23
24
|
var perseusScore = require('@khanacademy/perseus-score');
|
|
25
|
+
var keypadContext = require('@khanacademy/keypad-context');
|
|
26
|
+
var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
|
|
24
27
|
var wonderStuffCore = require('@khanacademy/wonder-stuff-core');
|
|
25
28
|
var wonderBlocksProgressSpinner = require('@khanacademy/wonder-blocks-progress-spinner');
|
|
26
29
|
var kmath = require('@khanacademy/kmath');
|
|
27
30
|
var SimpleMarkdown = require('@khanacademy/simple-markdown');
|
|
28
31
|
var pureMarkdown = require('@khanacademy/pure-markdown');
|
|
29
|
-
var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
|
|
30
32
|
var Button = require('@khanacademy/wonder-blocks-button');
|
|
31
33
|
var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
|
|
32
34
|
var Banner = require('@khanacademy/wonder-blocks-banner');
|
|
@@ -47,26 +49,27 @@ var Link = require('@khanacademy/wonder-blocks-link');
|
|
|
47
49
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
48
50
|
|
|
49
51
|
function _interopNamespace(e) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
if (e && e.__esModule) return e;
|
|
53
|
+
var n = Object.create(null);
|
|
54
|
+
if (e) {
|
|
55
|
+
Object.keys(e).forEach(function (k) {
|
|
56
|
+
if (k !== 'default') {
|
|
57
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
58
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function () { return e[k]; }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
59
63
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
n["default"] = e;
|
|
64
|
-
return Object.freeze(n);
|
|
64
|
+
}
|
|
65
|
+
n["default"] = e;
|
|
66
|
+
return Object.freeze(n);
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
|
|
67
70
|
var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
|
|
68
71
|
var PerseusLinter__namespace = /*#__PURE__*/_interopNamespace(PerseusLinter);
|
|
69
|
-
var Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip
|
|
72
|
+
var Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip);
|
|
70
73
|
var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames$1);
|
|
71
74
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
72
75
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
@@ -88,21 +91,6 @@ var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
|
88
91
|
var cornersOutIcon__default = /*#__PURE__*/_interopDefaultLegacy(cornersOutIcon);
|
|
89
92
|
var Link__default = /*#__PURE__*/_interopDefaultLegacy(Link);
|
|
90
93
|
|
|
91
|
-
function _extends() {
|
|
92
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
93
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
94
|
-
var source = arguments[i];
|
|
95
|
-
for (var key in source) {
|
|
96
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
97
|
-
target[key] = source[key];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return target;
|
|
102
|
-
};
|
|
103
|
-
return _extends.apply(this, arguments);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
94
|
/**
|
|
107
95
|
* The translated strings that are used to render Perseus.
|
|
108
96
|
*/
|
|
@@ -398,20 +386,27 @@ const mockStrings = {
|
|
|
398
386
|
} = _ref29;
|
|
399
387
|
return `Circle. The center point is at ${centerX} comma ${centerY}.`;
|
|
400
388
|
},
|
|
401
|
-
|
|
389
|
+
srCircleRadiusPointRight: _ref30 => {
|
|
402
390
|
let {
|
|
403
391
|
radiusPointX,
|
|
404
392
|
radiusPointY
|
|
405
393
|
} = _ref30;
|
|
406
|
-
return `
|
|
394
|
+
return `Right radius endpoint at ${radiusPointX} comma ${radiusPointY}.`;
|
|
407
395
|
},
|
|
408
|
-
|
|
396
|
+
srCircleRadiusPointLeft: _ref31 => {
|
|
409
397
|
let {
|
|
410
|
-
|
|
398
|
+
radiusPointX,
|
|
399
|
+
radiusPointY
|
|
411
400
|
} = _ref31;
|
|
401
|
+
return `Left radius endpoint at ${radiusPointX} comma ${radiusPointY}.`;
|
|
402
|
+
},
|
|
403
|
+
srCircleRadius: _ref32 => {
|
|
404
|
+
let {
|
|
405
|
+
radius
|
|
406
|
+
} = _ref32;
|
|
412
407
|
return `Circle radius is ${radius}.`;
|
|
413
408
|
},
|
|
414
|
-
srCircleOuterPoints:
|
|
409
|
+
srCircleOuterPoints: _ref33 => {
|
|
415
410
|
let {
|
|
416
411
|
point1X,
|
|
417
412
|
point1Y,
|
|
@@ -421,83 +416,83 @@ const mockStrings = {
|
|
|
421
416
|
point3Y,
|
|
422
417
|
point4X,
|
|
423
418
|
point4Y
|
|
424
|
-
} =
|
|
419
|
+
} = _ref33;
|
|
425
420
|
return `Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`;
|
|
426
421
|
},
|
|
427
422
|
srLinearGraph: "A line on a coordinate plane.",
|
|
428
|
-
srLinearGraphPoints:
|
|
423
|
+
srLinearGraphPoints: _ref34 => {
|
|
429
424
|
let {
|
|
430
425
|
point1X,
|
|
431
426
|
point1Y,
|
|
432
427
|
point2X,
|
|
433
428
|
point2Y
|
|
434
|
-
} =
|
|
429
|
+
} = _ref34;
|
|
435
430
|
return `The line has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`;
|
|
436
431
|
},
|
|
437
432
|
srLinearGraphSlopeIncreasing: "Its slope increases from left to right.",
|
|
438
433
|
srLinearGraphSlopeDecreasing: "Its slope decreases from left to right.",
|
|
439
434
|
srLinearGraphSlopeHorizontal: "Its slope is zero.",
|
|
440
435
|
srLinearGraphSlopeVertical: "Its slope is undefined.",
|
|
441
|
-
srLinearGraphXOnlyIntercept:
|
|
436
|
+
srLinearGraphXOnlyIntercept: _ref35 => {
|
|
442
437
|
let {
|
|
443
438
|
xIntercept
|
|
444
|
-
} =
|
|
439
|
+
} = _ref35;
|
|
445
440
|
return `The line crosses the X-axis at ${xIntercept} comma 0.`;
|
|
446
441
|
},
|
|
447
|
-
srLinearGraphYOnlyIntercept:
|
|
442
|
+
srLinearGraphYOnlyIntercept: _ref36 => {
|
|
448
443
|
let {
|
|
449
444
|
yIntercept
|
|
450
|
-
} =
|
|
445
|
+
} = _ref36;
|
|
451
446
|
return `The line crosses the Y-axis at 0 comma ${yIntercept}.`;
|
|
452
447
|
},
|
|
453
|
-
srLinearGraphBothIntercepts:
|
|
448
|
+
srLinearGraphBothIntercepts: _ref37 => {
|
|
454
449
|
let {
|
|
455
450
|
xIntercept,
|
|
456
451
|
yIntercept
|
|
457
|
-
} =
|
|
452
|
+
} = _ref37;
|
|
458
453
|
return `The line crosses the X-axis at ${xIntercept} comma 0 and the Y-axis at 0 comma ${yIntercept}.`;
|
|
459
454
|
},
|
|
460
|
-
srLinearGraphOriginIntercept: "The line crosses the
|
|
461
|
-
srLinearGrabHandle:
|
|
455
|
+
srLinearGraphOriginIntercept: "The line crosses the X and Y axes at the graph's origin.",
|
|
456
|
+
srLinearGrabHandle: _ref38 => {
|
|
462
457
|
let {
|
|
463
458
|
point1X,
|
|
464
459
|
point1Y,
|
|
465
460
|
point2X,
|
|
466
461
|
point2Y
|
|
467
|
-
} =
|
|
468
|
-
return `Line
|
|
462
|
+
} = _ref38;
|
|
463
|
+
return `Line going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`;
|
|
469
464
|
},
|
|
470
|
-
srAngleStartingSide:
|
|
465
|
+
srAngleStartingSide: _ref39 => {
|
|
471
466
|
let {
|
|
472
467
|
x,
|
|
473
468
|
y
|
|
474
|
-
} =
|
|
469
|
+
} = _ref39;
|
|
475
470
|
return `Point 3, starting side at ${x} comma ${y}.`;
|
|
476
471
|
},
|
|
477
|
-
srAngleEndingSide:
|
|
472
|
+
srAngleEndingSide: _ref40 => {
|
|
478
473
|
let {
|
|
479
474
|
x,
|
|
480
475
|
y
|
|
481
|
-
} =
|
|
476
|
+
} = _ref40;
|
|
482
477
|
return `Point 2, ending side at ${x} comma ${y}.`;
|
|
483
478
|
},
|
|
484
|
-
srAngleVertex:
|
|
479
|
+
srAngleVertex: _ref41 => {
|
|
485
480
|
let {
|
|
486
481
|
x,
|
|
487
482
|
y
|
|
488
|
-
} =
|
|
483
|
+
} = _ref41;
|
|
489
484
|
return `Point 1, vertex at ${x} comma ${y}.`;
|
|
490
485
|
},
|
|
491
|
-
srAngleVertexWithAngleMeasure:
|
|
486
|
+
srAngleVertexWithAngleMeasure: _ref42 => {
|
|
492
487
|
let {
|
|
493
488
|
x,
|
|
494
489
|
y,
|
|
495
490
|
angleMeasure
|
|
496
|
-
} =
|
|
491
|
+
} = _ref42;
|
|
497
492
|
return `Point 1, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees.`;
|
|
498
493
|
},
|
|
499
494
|
srAngleGraphAriaLabel: "An angle on a coordinate plane.",
|
|
500
|
-
srAngleGraphAriaDescription:
|
|
495
|
+
srAngleGraphAriaDescription: _ref43 => {
|
|
501
496
|
let {
|
|
502
497
|
angleMeasure,
|
|
503
498
|
vertexX,
|
|
@@ -506,10 +501,10 @@ const mockStrings = {
|
|
|
506
501
|
startingSideY,
|
|
507
502
|
endingSideX,
|
|
508
503
|
endingSideY
|
|
509
|
-
} =
|
|
504
|
+
} = _ref43;
|
|
510
505
|
return `The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the starting side at ${startingSideX} comma ${startingSideY} and a point on the ending side at ${endingSideX} comma ${endingSideY}.`;
|
|
511
506
|
},
|
|
512
|
-
srAngleInteractiveElements:
|
|
507
|
+
srAngleInteractiveElements: _ref44 => {
|
|
513
508
|
let {
|
|
514
509
|
vertexX,
|
|
515
510
|
vertexY,
|
|
@@ -517,118 +512,136 @@ const mockStrings = {
|
|
|
517
512
|
startingSideY,
|
|
518
513
|
endingSideX,
|
|
519
514
|
endingSideY
|
|
520
|
-
} =
|
|
515
|
+
} = _ref44;
|
|
521
516
|
return `An angle formed by 3 points. The vertex is at ${vertexX} comma ${vertexY}. The starting side point is at ${startingSideX} comma ${startingSideY}. The ending side point is at ${endingSideX} comma ${endingSideY}.`;
|
|
522
517
|
},
|
|
523
518
|
srSingleSegmentGraphAriaLabel: "A line segment on a coordinate plane.",
|
|
524
|
-
srMultipleSegmentGraphAriaLabel:
|
|
519
|
+
srMultipleSegmentGraphAriaLabel: _ref45 => {
|
|
525
520
|
let {
|
|
526
521
|
countOfSegments
|
|
527
|
-
} =
|
|
522
|
+
} = _ref45;
|
|
528
523
|
return `${countOfSegments} segments on a coordinate plane.`;
|
|
529
524
|
},
|
|
530
|
-
srMultipleSegmentIndividualLabel:
|
|
525
|
+
srMultipleSegmentIndividualLabel: _ref46 => {
|
|
531
526
|
let {
|
|
532
527
|
point1X,
|
|
533
528
|
point1Y,
|
|
534
529
|
point2X,
|
|
535
530
|
point2Y,
|
|
536
531
|
indexOfSegment
|
|
537
|
-
} =
|
|
532
|
+
} = _ref46;
|
|
538
533
|
return `Segment ${indexOfSegment}: Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`;
|
|
539
534
|
},
|
|
540
|
-
srSingleSegmentLabel:
|
|
535
|
+
srSingleSegmentLabel: _ref47 => {
|
|
541
536
|
let {
|
|
542
537
|
point1X,
|
|
543
538
|
point1Y,
|
|
544
539
|
point2X,
|
|
545
540
|
point2Y
|
|
546
|
-
} =
|
|
541
|
+
} = _ref47;
|
|
547
542
|
return `Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`;
|
|
548
543
|
},
|
|
549
|
-
srSegmentLength:
|
|
544
|
+
srSegmentLength: _ref48 => {
|
|
550
545
|
let {
|
|
551
546
|
length
|
|
552
|
-
} =
|
|
547
|
+
} = _ref48;
|
|
553
548
|
return `Segment length ${length} units.`;
|
|
554
549
|
},
|
|
555
|
-
srSingleSegmentGraphEndpointAriaLabel:
|
|
550
|
+
srSingleSegmentGraphEndpointAriaLabel: _ref49 => {
|
|
556
551
|
let {
|
|
557
552
|
endpointNumber,
|
|
558
553
|
x,
|
|
559
554
|
y
|
|
560
|
-
} =
|
|
555
|
+
} = _ref49;
|
|
561
556
|
return `Endpoint ${endpointNumber} at ${x} comma ${y}.`;
|
|
562
557
|
},
|
|
563
|
-
srMultipleSegmentGraphEndpointAriaLabel:
|
|
558
|
+
srMultipleSegmentGraphEndpointAriaLabel: _ref50 => {
|
|
564
559
|
let {
|
|
565
560
|
endpointNumber,
|
|
566
561
|
x,
|
|
567
562
|
y,
|
|
568
563
|
indexOfSegment
|
|
569
|
-
} =
|
|
564
|
+
} = _ref50;
|
|
570
565
|
return `Endpoint ${endpointNumber} on segment ${indexOfSegment} at ${x} comma ${y}.`;
|
|
571
566
|
},
|
|
572
|
-
srSegmentGrabHandle:
|
|
567
|
+
srSegmentGrabHandle: _ref51 => {
|
|
573
568
|
let {
|
|
574
569
|
point1X,
|
|
575
570
|
point1Y,
|
|
576
571
|
point2X,
|
|
577
572
|
point2Y
|
|
578
|
-
} =
|
|
573
|
+
} = _ref51;
|
|
579
574
|
return `Segment from ${point1X} comma ${point1Y} to ${point2X} comma ${point2Y}.`;
|
|
580
575
|
},
|
|
581
576
|
srLinearSystemGraph: "Two lines on a coordinate plane.",
|
|
582
|
-
srLinearSystemPoints:
|
|
577
|
+
srLinearSystemPoints: _ref52 => {
|
|
583
578
|
let {
|
|
584
579
|
lineNumber,
|
|
585
580
|
point1X,
|
|
586
581
|
point1Y,
|
|
587
582
|
point2X,
|
|
588
583
|
point2Y
|
|
589
|
-
} =
|
|
584
|
+
} = _ref52;
|
|
590
585
|
return `Line ${lineNumber} has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`;
|
|
591
586
|
},
|
|
592
|
-
srLinearSystemPoint:
|
|
587
|
+
srLinearSystemPoint: _ref53 => {
|
|
593
588
|
let {
|
|
594
589
|
lineNumber,
|
|
595
590
|
pointSequence,
|
|
596
591
|
x,
|
|
597
592
|
y
|
|
598
|
-
} =
|
|
593
|
+
} = _ref53;
|
|
599
594
|
return `Point ${pointSequence} on line ${lineNumber} at ${x} comma ${y}.`;
|
|
600
595
|
},
|
|
596
|
+
srLinearSystemGrabHandle: _ref54 => {
|
|
597
|
+
let {
|
|
598
|
+
lineNumber,
|
|
599
|
+
point1X,
|
|
600
|
+
point1Y,
|
|
601
|
+
point2X,
|
|
602
|
+
point2Y
|
|
603
|
+
} = _ref54;
|
|
604
|
+
return `Line ${lineNumber} going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`;
|
|
605
|
+
},
|
|
606
|
+
srLinearSystemIntersection: _ref55 => {
|
|
607
|
+
let {
|
|
608
|
+
x,
|
|
609
|
+
y
|
|
610
|
+
} = _ref55;
|
|
611
|
+
return `Line 1 and line 2 intersect at point ${x} comma ${y}.`;
|
|
612
|
+
},
|
|
613
|
+
srLinearSystemParallel: "Line 1 and line 2 are parallel.",
|
|
601
614
|
srRayGraph: "A ray on a coordinate plane.",
|
|
602
|
-
srRayPoints:
|
|
615
|
+
srRayPoints: _ref56 => {
|
|
603
616
|
let {
|
|
604
617
|
point1X,
|
|
605
618
|
point1Y,
|
|
606
619
|
point2X,
|
|
607
620
|
point2Y
|
|
608
|
-
} =
|
|
621
|
+
} = _ref56;
|
|
609
622
|
return `The endpoint is at ${point1X} comma ${point1Y} and the ray goes through point ${point2X} comma ${point2Y}.`;
|
|
610
623
|
},
|
|
611
|
-
srRayGrabHandle:
|
|
624
|
+
srRayGrabHandle: _ref57 => {
|
|
612
625
|
let {
|
|
613
626
|
point1X,
|
|
614
627
|
point1Y,
|
|
615
628
|
point2X,
|
|
616
629
|
point2Y
|
|
617
|
-
} =
|
|
630
|
+
} = _ref57;
|
|
618
631
|
return `Ray with endpoint ${point1X} comma ${point1Y} going through point ${point2X} comma ${point2Y}.`;
|
|
619
632
|
},
|
|
620
|
-
srRayEndpoint:
|
|
633
|
+
srRayEndpoint: _ref58 => {
|
|
621
634
|
let {
|
|
622
635
|
x,
|
|
623
636
|
y
|
|
624
|
-
} =
|
|
637
|
+
} = _ref58;
|
|
625
638
|
return `Endpoint at ${x} comma ${y}.`;
|
|
626
639
|
},
|
|
627
|
-
srRayTerminalPoint:
|
|
640
|
+
srRayTerminalPoint: _ref59 => {
|
|
628
641
|
let {
|
|
629
642
|
x,
|
|
630
643
|
y
|
|
631
|
-
} =
|
|
644
|
+
} = _ref59;
|
|
632
645
|
return `Through point at ${x} comma ${y}.`;
|
|
633
646
|
},
|
|
634
647
|
srQuadraticGraph: "A parabola on a 4-quadrant coordinate plane.",
|
|
@@ -637,55 +650,55 @@ const mockStrings = {
|
|
|
637
650
|
srQuadraticGraphVertexOrigin: "Vertex is at the origin.",
|
|
638
651
|
srQuadraticGraphVertexXAxis: "Vertex is on the X-axis.",
|
|
639
652
|
srQuadraticGraphVertexYAxis: "Vertex is on the Y-axis.",
|
|
640
|
-
srQuadraticGraphVertexQuadrant:
|
|
653
|
+
srQuadraticGraphVertexQuadrant: _ref60 => {
|
|
641
654
|
let {
|
|
642
655
|
quadrant
|
|
643
|
-
} =
|
|
656
|
+
} = _ref60;
|
|
644
657
|
return `Vertex is in quadrant ${quadrant}.`;
|
|
645
658
|
},
|
|
646
|
-
srQuadraticTwoXIntercepts:
|
|
659
|
+
srQuadraticTwoXIntercepts: _ref61 => {
|
|
647
660
|
let {
|
|
648
661
|
intercept1,
|
|
649
662
|
intercept2
|
|
650
|
-
} =
|
|
663
|
+
} = _ref61;
|
|
651
664
|
return `The X-intercepts are at ${intercept1} comma 0 and ${intercept2} comma 0.`;
|
|
652
665
|
},
|
|
653
|
-
srQuadraticOneXIntercept:
|
|
666
|
+
srQuadraticOneXIntercept: _ref62 => {
|
|
654
667
|
let {
|
|
655
668
|
intercept
|
|
656
|
-
} =
|
|
669
|
+
} = _ref62;
|
|
657
670
|
return `The X-intercept is at ${intercept} comma 0.`;
|
|
658
671
|
},
|
|
659
|
-
srQuadraticYIntercept:
|
|
672
|
+
srQuadraticYIntercept: _ref63 => {
|
|
660
673
|
let {
|
|
661
674
|
intercept
|
|
662
|
-
} =
|
|
675
|
+
} = _ref63;
|
|
663
676
|
return `The Y-intercept is at 0 comma ${intercept}.`;
|
|
664
677
|
},
|
|
665
|
-
srQuadraticPointOrigin:
|
|
678
|
+
srQuadraticPointOrigin: _ref64 => {
|
|
666
679
|
let {
|
|
667
680
|
pointNumber
|
|
668
|
-
} =
|
|
681
|
+
} = _ref64;
|
|
669
682
|
return `Point ${pointNumber} on parabola at the origin.`;
|
|
670
683
|
},
|
|
671
|
-
srQuadraticPointAxis:
|
|
684
|
+
srQuadraticPointAxis: _ref65 => {
|
|
672
685
|
let {
|
|
673
686
|
pointNumber,
|
|
674
687
|
x,
|
|
675
688
|
y
|
|
676
|
-
} =
|
|
689
|
+
} = _ref65;
|
|
677
690
|
return `Point ${pointNumber} on parabola at ${x} comma ${y}.`;
|
|
678
691
|
},
|
|
679
|
-
srQuadraticPointQuadrant:
|
|
692
|
+
srQuadraticPointQuadrant: _ref66 => {
|
|
680
693
|
let {
|
|
681
694
|
pointNumber,
|
|
682
695
|
x,
|
|
683
696
|
y,
|
|
684
697
|
quadrant
|
|
685
|
-
} =
|
|
698
|
+
} = _ref66;
|
|
686
699
|
return `Point ${pointNumber} on parabola in quadrant ${quadrant} at ${x} comma ${y}.`;
|
|
687
700
|
},
|
|
688
|
-
srQuadraticInteractiveElements:
|
|
701
|
+
srQuadraticInteractiveElements: _ref67 => {
|
|
689
702
|
let {
|
|
690
703
|
point1X,
|
|
691
704
|
point1Y,
|
|
@@ -693,83 +706,97 @@ const mockStrings = {
|
|
|
693
706
|
point2Y,
|
|
694
707
|
point3X,
|
|
695
708
|
point3Y
|
|
696
|
-
} =
|
|
709
|
+
} = _ref67;
|
|
697
710
|
return `Parabola with points at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, and ${point3X} comma ${point3Y}.`;
|
|
698
711
|
},
|
|
699
712
|
srPolygonGraph: "A polygon.",
|
|
700
713
|
srPolygonGraphCoordinatePlane: "A polygon on a coordinate plane.",
|
|
701
|
-
srPolygonGraphPointsNum:
|
|
714
|
+
srPolygonGraphPointsNum: _ref68 => {
|
|
702
715
|
let {
|
|
703
716
|
num
|
|
704
|
-
} =
|
|
717
|
+
} = _ref68;
|
|
705
718
|
return `The polygon has ${num} points.`;
|
|
706
719
|
},
|
|
707
720
|
srPolygonGraphPointsOne: "The polygon has 1 point.",
|
|
708
|
-
srPolygonElementsNum:
|
|
721
|
+
srPolygonElementsNum: _ref69 => {
|
|
709
722
|
let {
|
|
710
723
|
num
|
|
711
|
-
} =
|
|
724
|
+
} = _ref69;
|
|
712
725
|
return `A polygon with ${num} points.`;
|
|
713
726
|
},
|
|
714
727
|
srPolygonElementsOne: "A polygon with 1 point.",
|
|
715
|
-
srPolygonPointAngleApprox:
|
|
728
|
+
srPolygonPointAngleApprox: _ref70 => {
|
|
716
729
|
let {
|
|
717
730
|
angle
|
|
718
|
-
} =
|
|
731
|
+
} = _ref70;
|
|
719
732
|
return `Angle approximately equal to ${angle} degrees.`;
|
|
720
733
|
},
|
|
721
|
-
srPolygonPointAngle:
|
|
734
|
+
srPolygonPointAngle: _ref71 => {
|
|
722
735
|
let {
|
|
723
736
|
angle
|
|
724
|
-
} =
|
|
737
|
+
} = _ref71;
|
|
725
738
|
return `Angle equal to ${angle} degrees.`;
|
|
726
739
|
},
|
|
727
|
-
srPolygonSideLength:
|
|
740
|
+
srPolygonSideLength: _ref72 => {
|
|
728
741
|
let {
|
|
729
742
|
pointNum,
|
|
730
743
|
length
|
|
731
|
-
} =
|
|
744
|
+
} = _ref72;
|
|
732
745
|
return `A line segment, length equal to ${length} units, connects to point ${pointNum}.`;
|
|
733
746
|
},
|
|
734
|
-
srPolygonSideLengthApprox:
|
|
747
|
+
srPolygonSideLengthApprox: _ref73 => {
|
|
735
748
|
let {
|
|
736
749
|
pointNum,
|
|
737
750
|
length
|
|
738
|
-
} =
|
|
751
|
+
} = _ref73;
|
|
739
752
|
return `A line segment, length approximately equal to ${length} units, connects to point ${pointNum}.`;
|
|
740
753
|
},
|
|
741
754
|
srUnlimitedPolygonEmpty: "An empty coordinate plane.",
|
|
742
755
|
srSinusoidGraph: "A sinusoid function on a coordinate plane.",
|
|
743
|
-
srSinusoidRootPoint:
|
|
756
|
+
srSinusoidRootPoint: _ref74 => {
|
|
744
757
|
let {
|
|
745
758
|
x,
|
|
746
759
|
y
|
|
747
|
-
} =
|
|
760
|
+
} = _ref74;
|
|
748
761
|
return `Midline intersection at ${x} comma ${y}.`;
|
|
749
762
|
},
|
|
750
|
-
|
|
763
|
+
srSinusoidMaxPoint: _ref75 => {
|
|
751
764
|
let {
|
|
752
765
|
x,
|
|
753
766
|
y
|
|
754
|
-
} =
|
|
755
|
-
return `
|
|
767
|
+
} = _ref75;
|
|
768
|
+
return `Maximum point at ${x} comma ${y}.`;
|
|
769
|
+
},
|
|
770
|
+
srSinusoidMinPoint: _ref76 => {
|
|
771
|
+
let {
|
|
772
|
+
x,
|
|
773
|
+
y
|
|
774
|
+
} = _ref76;
|
|
775
|
+
return `Minimum point at ${x} comma ${y}.`;
|
|
756
776
|
},
|
|
757
|
-
|
|
777
|
+
srSinusoidFlatPoint: _ref77 => {
|
|
778
|
+
let {
|
|
779
|
+
x,
|
|
780
|
+
y
|
|
781
|
+
} = _ref77;
|
|
782
|
+
return `Line through point at ${x} comma ${y}.`;
|
|
783
|
+
},
|
|
784
|
+
srSinusoidDescription: _ref78 => {
|
|
758
785
|
let {
|
|
759
786
|
minValue,
|
|
760
787
|
maxValue,
|
|
761
788
|
cycleStart,
|
|
762
789
|
cycleEnd
|
|
763
|
-
} =
|
|
790
|
+
} = _ref78;
|
|
764
791
|
return `The graph shows a wave with a minimum value of ${minValue} and a maximum value of ${maxValue}. The wave completes a full cycle from ${cycleStart} to ${cycleEnd}.`;
|
|
765
792
|
},
|
|
766
|
-
srSinusoidInteractiveElements:
|
|
793
|
+
srSinusoidInteractiveElements: _ref79 => {
|
|
767
794
|
let {
|
|
768
795
|
point1X,
|
|
769
796
|
point1Y,
|
|
770
797
|
point2X,
|
|
771
798
|
point2Y
|
|
772
|
-
} =
|
|
799
|
+
} = _ref79;
|
|
773
800
|
return `Sinusoid graph with midline intersection point at ${point1X} comma ${point1Y} and extremum point at ${point2X} comma ${point2Y}.`;
|
|
774
801
|
}
|
|
775
802
|
// The above strings are used for interactive graph SR descriptions.
|
|
@@ -1103,7 +1130,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
1103
1130
|
}, this.context.strings.mathInputDescription), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
|
|
1104
1131
|
closeButtonVisible: true,
|
|
1105
1132
|
style: styles$D.popoverContent
|
|
1106
|
-
}, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad,
|
|
1133
|
+
}, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends__default["default"]({
|
|
1107
1134
|
onAnalyticsEvent: this.props.onAnalyticsEvent,
|
|
1108
1135
|
extraKeys: this.props.extraKeys,
|
|
1109
1136
|
onClickKey: this.handleKeypadPress,
|
|
@@ -1118,7 +1145,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
1118
1145
|
"aria-label": this.state.keypadOpen ? this.context.strings.closeKeypad : this.context.strings.openKeypad,
|
|
1119
1146
|
role: "button",
|
|
1120
1147
|
onClick: () => this.state.keypadOpen ? this.closeKeypad() : this.openKeypad()
|
|
1121
|
-
}, props => /*#__PURE__*/React__namespace.createElement(MathInputIcon,
|
|
1148
|
+
}, props => /*#__PURE__*/React__namespace.createElement(MathInputIcon, _extends__default["default"]({
|
|
1122
1149
|
active: this.state.keypadOpen
|
|
1123
1150
|
}, props))))));
|
|
1124
1151
|
}
|
|
@@ -1143,7 +1170,7 @@ class MathInput extends React__namespace.Component {
|
|
|
1143
1170
|
this.inputRef.current?.insert(value);
|
|
1144
1171
|
}
|
|
1145
1172
|
render() {
|
|
1146
|
-
return /*#__PURE__*/React__namespace.createElement(InnerMathInput,
|
|
1173
|
+
return /*#__PURE__*/React__namespace.createElement(InnerMathInput, _extends__default["default"]({}, this.props, {
|
|
1147
1174
|
ref: this.inputRef,
|
|
1148
1175
|
mathInputStrings: this.context.strings
|
|
1149
1176
|
}));
|
|
@@ -1285,11 +1312,11 @@ const useDependencies = () => {
|
|
|
1285
1312
|
};
|
|
1286
1313
|
|
|
1287
1314
|
var dependencies = /*#__PURE__*/Object.freeze({
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1315
|
+
__proto__: null,
|
|
1316
|
+
setDependencies: setDependencies,
|
|
1317
|
+
getDependencies: getDependencies,
|
|
1318
|
+
DependenciesContext: DependenciesContext,
|
|
1319
|
+
useDependencies: useDependencies
|
|
1293
1320
|
});
|
|
1294
1321
|
|
|
1295
1322
|
/**
|
|
@@ -1393,9 +1420,9 @@ const propTypes = {
|
|
|
1393
1420
|
};
|
|
1394
1421
|
|
|
1395
1422
|
var changeable = /*#__PURE__*/Object.freeze({
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1423
|
+
__proto__: null,
|
|
1424
|
+
change: change,
|
|
1425
|
+
propTypes: propTypes
|
|
1399
1426
|
});
|
|
1400
1427
|
|
|
1401
1428
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -2054,7 +2081,7 @@ const keypadConfigurationForProps = widgetOptions => {
|
|
|
2054
2081
|
};
|
|
2055
2082
|
const ExpressionWithDependencies = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
2056
2083
|
const deps = useDependencies();
|
|
2057
|
-
return /*#__PURE__*/React__namespace.createElement(Expression,
|
|
2084
|
+
return /*#__PURE__*/React__namespace.createElement(Expression, _extends__default["default"]({
|
|
2058
2085
|
ref: ref,
|
|
2059
2086
|
analytics: deps.analytics
|
|
2060
2087
|
}, props));
|
|
@@ -2105,6 +2132,174 @@ var Expression$1 = {
|
|
|
2105
2132
|
}
|
|
2106
2133
|
};
|
|
2107
2134
|
|
|
2135
|
+
class SimpleKeypadInput extends React__namespace.Component {
|
|
2136
|
+
static contextType = keypadContext.KeypadContext;
|
|
2137
|
+
_isMounted = false;
|
|
2138
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
2139
|
+
componentDidMount() {
|
|
2140
|
+
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
2141
|
+
// this.isMounted() but is still considered an anti-pattern.
|
|
2142
|
+
this._isMounted = true;
|
|
2143
|
+
}
|
|
2144
|
+
componentWillUnmount() {
|
|
2145
|
+
this._isMounted = false;
|
|
2146
|
+
}
|
|
2147
|
+
focus() {
|
|
2148
|
+
// The inputRef is a ref to a MathInput, which
|
|
2149
|
+
// also controls the keypad state during focus events.
|
|
2150
|
+
this.inputRef.current?.focus(this.context.setKeypadActive);
|
|
2151
|
+
}
|
|
2152
|
+
blur() {
|
|
2153
|
+
this.inputRef.current?.blur();
|
|
2154
|
+
}
|
|
2155
|
+
getValue() {
|
|
2156
|
+
return this.props.value;
|
|
2157
|
+
}
|
|
2158
|
+
render() {
|
|
2159
|
+
const _this = this;
|
|
2160
|
+
// Intercept the `onFocus` prop, as we need to configure the keypad
|
|
2161
|
+
// before continuing with the default focus logic for Perseus inputs.
|
|
2162
|
+
// Intercept the `value` prop so as to map `null` to the empty string,
|
|
2163
|
+
// as the `KeypadInput` does not support `null` values.
|
|
2164
|
+
const {
|
|
2165
|
+
keypadElement,
|
|
2166
|
+
onFocus,
|
|
2167
|
+
value,
|
|
2168
|
+
...rest
|
|
2169
|
+
} = _this.props;
|
|
2170
|
+
return (
|
|
2171
|
+
/*#__PURE__*/
|
|
2172
|
+
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
2173
|
+
React__namespace.createElement(mathInput.KeypadInput, _extends__default["default"]({
|
|
2174
|
+
ref: this.inputRef,
|
|
2175
|
+
keypadElement: keypadElement,
|
|
2176
|
+
onFocus: () => {
|
|
2177
|
+
if (keypadElement) {
|
|
2178
|
+
keypadElement.configure({
|
|
2179
|
+
keypadType: mathInput.KeypadType.FRACTION
|
|
2180
|
+
}, () => {
|
|
2181
|
+
if (_this._isMounted) {
|
|
2182
|
+
onFocus?.();
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2185
|
+
} else {
|
|
2186
|
+
onFocus?.();
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
value: value == null ? "" : "" + value
|
|
2190
|
+
}, rest))
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
// @ts-expect-error - TS2339 - Property 'propTypes' does not exist on type 'typeof SimpleKeypadInput'.
|
|
2196
|
+
SimpleKeypadInput.propTypes = {
|
|
2197
|
+
keypadElement: mathInput.keypadElementPropType,
|
|
2198
|
+
onFocus: PropTypes__default["default"].func,
|
|
2199
|
+
value: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number])
|
|
2200
|
+
};
|
|
2201
|
+
|
|
2202
|
+
const getPromptJSON$s = (renderProps, userInput) => {
|
|
2203
|
+
return {
|
|
2204
|
+
type: "input-number",
|
|
2205
|
+
options: {
|
|
2206
|
+
simplify: renderProps.simplify,
|
|
2207
|
+
answerType: renderProps.answerType
|
|
2208
|
+
},
|
|
2209
|
+
userInput: {
|
|
2210
|
+
value: userInput.currentValue
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
};
|
|
2214
|
+
|
|
2215
|
+
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
2216
|
+
let lastId = 0;
|
|
2217
|
+
function uniqueIdForInput() {
|
|
2218
|
+
let prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "input-";
|
|
2219
|
+
lastId++;
|
|
2220
|
+
return `${prefix}${lastId}`;
|
|
2221
|
+
}
|
|
2222
|
+
class TextInput extends React__namespace.Component {
|
|
2223
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
2224
|
+
static defaultProps = {
|
|
2225
|
+
value: "",
|
|
2226
|
+
disabled: false
|
|
2227
|
+
};
|
|
2228
|
+
id;
|
|
2229
|
+
constructor(props) {
|
|
2230
|
+
super(props);
|
|
2231
|
+
if (props.id) {
|
|
2232
|
+
this.id = props.id;
|
|
2233
|
+
} else {
|
|
2234
|
+
this.id = uniqueIdForInput();
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
_getInput = () => {
|
|
2238
|
+
if (!this.inputRef.current) {
|
|
2239
|
+
throw new perseusCore.PerseusError("Input ref accessed before set", perseusCore.Errors.Internal);
|
|
2240
|
+
}
|
|
2241
|
+
return this.inputRef.current;
|
|
2242
|
+
};
|
|
2243
|
+
focus = () => {
|
|
2244
|
+
this._getInput().focus();
|
|
2245
|
+
};
|
|
2246
|
+
blur = () => {
|
|
2247
|
+
this._getInput().blur();
|
|
2248
|
+
};
|
|
2249
|
+
getValue = () => {
|
|
2250
|
+
return this.inputRef.current?.value;
|
|
2251
|
+
};
|
|
2252
|
+
getStringValue = () => {
|
|
2253
|
+
return this.inputRef.current?.value.toString();
|
|
2254
|
+
};
|
|
2255
|
+
setSelectionRange = (selectionStart, selectionEnd) => {
|
|
2256
|
+
this._getInput().setSelectionRange(selectionStart, selectionEnd);
|
|
2257
|
+
};
|
|
2258
|
+
getSelectionStart = () => {
|
|
2259
|
+
return this._getInput().selectionStart;
|
|
2260
|
+
};
|
|
2261
|
+
getSelectionEnd = () => {
|
|
2262
|
+
return this._getInput().selectionEnd;
|
|
2263
|
+
};
|
|
2264
|
+
render() {
|
|
2265
|
+
const {
|
|
2266
|
+
labelText,
|
|
2267
|
+
value,
|
|
2268
|
+
onFocus,
|
|
2269
|
+
onBlur,
|
|
2270
|
+
disabled,
|
|
2271
|
+
placeholder,
|
|
2272
|
+
onKeyDown,
|
|
2273
|
+
style
|
|
2274
|
+
} = this.props;
|
|
2275
|
+
const formattedValue = value === null ? "" : value.toString();
|
|
2276
|
+
|
|
2277
|
+
// Some of our content was saved with empty strings as the label text,
|
|
2278
|
+
// and we don't want to render an empty aria-label attribute.
|
|
2279
|
+
const ariaLabel = labelText || undefined;
|
|
2280
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
2281
|
+
ref: this.inputRef,
|
|
2282
|
+
style: style,
|
|
2283
|
+
disabled: disabled,
|
|
2284
|
+
id: this.id,
|
|
2285
|
+
value: formattedValue,
|
|
2286
|
+
type: "text",
|
|
2287
|
+
"aria-label": ariaLabel,
|
|
2288
|
+
"aria-describedby": this.props["aria-describedby"],
|
|
2289
|
+
onChange: value => this.props.onChange(value),
|
|
2290
|
+
placeholder: placeholder,
|
|
2291
|
+
onFocus: onFocus,
|
|
2292
|
+
onBlur: onBlur,
|
|
2293
|
+
onKeyDown: onKeyDown
|
|
2294
|
+
// @ts-expect-error - TS2322 - Type '{ style: StyleType; disabled: boolean | undefined; id: string; value: string; type: "text"; "aria-label": string | undefined; onChange: (value: string) => void; placeholder: string | undefined; ... 5 more ...; autoComplete: string; }' is not assignable to type 'IntrinsicAttributes & ExportProps & RefAttributes<HTMLInputElement>'.
|
|
2295
|
+
,
|
|
2296
|
+
autoCorrect: "off",
|
|
2297
|
+
autoCapitalize: "off",
|
|
2298
|
+
autoComplete: "off"
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2108
2303
|
/**
|
|
2109
2304
|
* A React context for keeping track of whether an component is fully
|
|
2110
2305
|
* loaded. This is used to know when SvgImage and (Zoomable)TeX are finished
|
|
@@ -2667,9 +2862,11 @@ const Util = {
|
|
|
2667
2862
|
// TODO(LP-11481): Change the primary API we use for logging in Perseus to use
|
|
2668
2863
|
// getDependencies() internally... simplify usage to just using a "singleton"
|
|
2669
2864
|
// which get's the injected logger.
|
|
2865
|
+
|
|
2670
2866
|
/**
|
|
2671
2867
|
* Provides logging infrastructure for Perseus
|
|
2672
2868
|
*/
|
|
2869
|
+
|
|
2673
2870
|
const Log = {
|
|
2674
2871
|
// Logs a message
|
|
2675
2872
|
log: (message, extra) => {
|
|
@@ -3343,40 +3540,40 @@ const articleMaxWidthInPx = 688;
|
|
|
3343
3540
|
const articleMaxWidthTableInPx = 512;
|
|
3344
3541
|
|
|
3345
3542
|
var constants = /*#__PURE__*/Object.freeze({
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3543
|
+
__proto__: null,
|
|
3544
|
+
baseFontFamily: baseFontFamily,
|
|
3545
|
+
boldFontFamily: boldFontFamily,
|
|
3546
|
+
kaGreen: kaGreen,
|
|
3547
|
+
white: white,
|
|
3548
|
+
gray97: gray97,
|
|
3549
|
+
gray85: gray85,
|
|
3550
|
+
gray76: gray76,
|
|
3551
|
+
gray68: gray68,
|
|
3552
|
+
gray17: gray17,
|
|
3553
|
+
pureSmMin: pureSmMin$1,
|
|
3554
|
+
pureMdMin: pureMdMin$1,
|
|
3555
|
+
pureLgMin: pureLgMin$1,
|
|
3556
|
+
pureXlMin: pureXlMin$1,
|
|
3557
|
+
pureXsMax: pureXsMax$1,
|
|
3558
|
+
pureSmMax: pureSmMax$1,
|
|
3559
|
+
pureMdMax: pureMdMax$1,
|
|
3560
|
+
pureLgMax: pureLgMax$1,
|
|
3561
|
+
tableBackgroundAccent: tableBackgroundAccent,
|
|
3562
|
+
phoneMargin: phoneMargin,
|
|
3563
|
+
negativePhoneMargin: negativePhoneMargin,
|
|
3564
|
+
hintBorderWidth: hintBorderWidth,
|
|
3565
|
+
baseUnitPx: baseUnitPx,
|
|
3566
|
+
interactiveSizes: interactiveSizes$1,
|
|
3567
|
+
circleSize: circleSize$1,
|
|
3568
|
+
radioMarginWidth: radioMarginWidth$1,
|
|
3569
|
+
warningColor: warningColor,
|
|
3570
|
+
warningColorHover: warningColorHover,
|
|
3571
|
+
warningColorActive: warningColorActive,
|
|
3572
|
+
publishBlockingErrorColor: publishBlockingErrorColor,
|
|
3573
|
+
radioBorderColor: radioBorderColor$1,
|
|
3574
|
+
checkedColor: checkedColor$1,
|
|
3575
|
+
articleMaxWidthInPx: articleMaxWidthInPx,
|
|
3576
|
+
articleMaxWidthTableInPx: articleMaxWidthTableInPx
|
|
3380
3577
|
});
|
|
3381
3578
|
|
|
3382
3579
|
/**
|
|
@@ -3791,7 +3988,7 @@ var Raphael$1 = (function () {
|
|
|
3791
3988
|
appendChild = "appendChild",
|
|
3792
3989
|
apply = "apply",
|
|
3793
3990
|
concat = "concat",
|
|
3794
|
-
supportsTouch =
|
|
3991
|
+
supportsTouch = "createTouch" in doc,
|
|
3795
3992
|
E = "",
|
|
3796
3993
|
S = " ",
|
|
3797
3994
|
Str = String,
|
|
@@ -5396,10 +5593,10 @@ var Raphael$1 = (function () {
|
|
|
5396
5593
|
});
|
|
5397
5594
|
break;
|
|
5398
5595
|
case "gradient":
|
|
5399
|
-
(
|
|
5596
|
+
({
|
|
5400
5597
|
circle: 1,
|
|
5401
5598
|
ellipse: 1
|
|
5402
|
-
}
|
|
5599
|
+
}[has](o.type) || Str(value).charAt() != "r") && addGradientFill(node, value, o.paper);
|
|
5403
5600
|
break;
|
|
5404
5601
|
case "opacity":
|
|
5405
5602
|
if (attrs.gradient && !attrs[has]("stroke-opacity")) {
|
|
@@ -9232,8 +9429,10 @@ const labelDirections = {
|
|
|
9232
9429
|
// is equivalent to [[-5, 5], [-10, 10]].
|
|
9233
9430
|
// - A single magnitude to be used for both x and y. E.g. 10 is equivalent to
|
|
9234
9431
|
// [[-10, 10], [-10, 10]]
|
|
9432
|
+
|
|
9235
9433
|
// Overload normalizeRange to specify that it only returns undefined if its
|
|
9236
9434
|
// argument is undefined.
|
|
9435
|
+
|
|
9237
9436
|
// normalizeRange converts a RangeSpecifier into a pair of Intervals that give
|
|
9238
9437
|
// the x and y ranges, respectively
|
|
9239
9438
|
function normalizeRange(range) {
|
|
@@ -9425,7 +9624,7 @@ const GraphUtils = {
|
|
|
9425
9624
|
clickBlockList = [],
|
|
9426
9625
|
blockMouseTriggers = false,
|
|
9427
9626
|
blockTouchTriggers = false,
|
|
9428
|
-
eventCaptureSupported =
|
|
9627
|
+
eventCaptureSupported = "addEventListener" in document,
|
|
9429
9628
|
$document = $(document),
|
|
9430
9629
|
nextTouchID = 1,
|
|
9431
9630
|
lastTouchID = 0;
|
|
@@ -10120,7 +10319,6 @@ function scaledPolarRad(radius, radians) {
|
|
|
10120
10319
|
return [radius * Math.cos(radians), radius * Math.sin(radians) * -1 // SVG flips y axis
|
|
10121
10320
|
];
|
|
10122
10321
|
}
|
|
10123
|
-
|
|
10124
10322
|
function scaledPolarDeg(radius, degrees) {
|
|
10125
10323
|
const radians = degrees * Math.PI / 180;
|
|
10126
10324
|
return scaledPolarRad(radius, radians);
|
|
@@ -11938,7 +12136,6 @@ ___default["default"].extend(GraphUtils.Graphie.prototype, {
|
|
|
11938
12136
|
if (hideArrow) {
|
|
11939
12137
|
return; // Don't draw anything!
|
|
11940
12138
|
}
|
|
11941
|
-
|
|
11942
12139
|
const handleVec = kmath.vector.subtract(handleCoord, rotatePoint.coord);
|
|
11943
12140
|
const handlePolar = kmath.vector.polarDegFromCart(handleVec);
|
|
11944
12141
|
const angle = handlePolar[1];
|
|
@@ -12902,7 +13099,6 @@ ___default["default"].extend(MovableAngle.prototype, {
|
|
|
12902
13099
|
// clockwise to the first point
|
|
12903
13100
|
coords[1] // the vertex parameter is last
|
|
12904
13101
|
);
|
|
12905
|
-
|
|
12906
13102
|
const clockwiseAngle = rawAngle + 360 % 360;
|
|
12907
13103
|
return clockwiseAngle;
|
|
12908
13104
|
},
|
|
@@ -14262,7 +14458,6 @@ class MovablePoint$5 {
|
|
|
14262
14458
|
// We only update props here, because we want things on state to
|
|
14263
14459
|
// be persistent, and updated appropriately in modify()
|
|
14264
14460
|
),
|
|
14265
|
-
|
|
14266
14461
|
...DEFAULT_PROPS$1
|
|
14267
14462
|
};
|
|
14268
14463
|
}
|
|
@@ -14314,11 +14509,11 @@ class MovablePoint$5 {
|
|
|
14314
14509
|
const showTrashTooltip = () => {
|
|
14315
14510
|
this._showTooltip(container => {
|
|
14316
14511
|
// eslint-disable-next-line import/no-deprecated
|
|
14317
|
-
render(
|
|
14512
|
+
render(/*#__PURE__*/React__namespace.createElement("span", {
|
|
14318
14513
|
style: {
|
|
14319
14514
|
fontSize: "2em"
|
|
14320
14515
|
}
|
|
14321
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
14516
|
+
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconTrash, {
|
|
14322
14517
|
style: {
|
|
14323
14518
|
position: "static",
|
|
14324
14519
|
color: KhanColors.INTERACTIVE,
|
|
@@ -15117,7 +15312,6 @@ const DEFAULT_PROPS = {
|
|
|
15117
15312
|
// likewise
|
|
15118
15313
|
labelStyle: null // likewise
|
|
15119
15314
|
};
|
|
15120
|
-
|
|
15121
15315
|
const DEFAULT_STATE = {
|
|
15122
15316
|
added: false,
|
|
15123
15317
|
hasMoved: false,
|
|
@@ -16019,7 +16213,7 @@ class ImageLoader extends React__namespace.Component {
|
|
|
16019
16213
|
return (
|
|
16020
16214
|
/*#__PURE__*/
|
|
16021
16215
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
16022
|
-
React__namespace.createElement("img",
|
|
16216
|
+
React__namespace.createElement("img", _extends__default["default"]({
|
|
16023
16217
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
|
|
16024
16218
|
tabIndex: 0,
|
|
16025
16219
|
src: staticUrl(src),
|
|
@@ -17793,7 +17987,7 @@ class TranslationLinter {
|
|
|
17793
17987
|
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
17794
17988
|
* to things is does.
|
|
17795
17989
|
*/
|
|
17796
|
-
var preprocessTex =
|
|
17990
|
+
var preprocessTex = texCode => texCode
|
|
17797
17991
|
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
17798
17992
|
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
17799
17993
|
// the same is supported by KaTeX. It does the same for align*.
|
|
@@ -17803,7 +17997,7 @@ var preprocessTex = (texCode => texCode
|
|
|
17803
17997
|
// "aligned").
|
|
17804
17998
|
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
17805
17999
|
// Replace non-breaking spaces with regular spaces.
|
|
17806
|
-
.replace(/[\u00a0]/g, " ")
|
|
18000
|
+
.replace(/[\u00a0]/g, " ");
|
|
17807
18001
|
|
|
17808
18002
|
const {
|
|
17809
18003
|
interactiveSizes
|
|
@@ -18062,29 +18256,29 @@ const isLintable = type => {
|
|
|
18062
18256
|
};
|
|
18063
18257
|
|
|
18064
18258
|
var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
18065
|
-
|
|
18066
|
-
|
|
18067
|
-
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
|
|
18072
|
-
|
|
18073
|
-
|
|
18074
|
-
|
|
18075
|
-
|
|
18076
|
-
|
|
18077
|
-
|
|
18078
|
-
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
|
|
18087
|
-
|
|
18259
|
+
__proto__: null,
|
|
18260
|
+
registerWidget: registerWidget,
|
|
18261
|
+
registerWidgets: registerWidgets,
|
|
18262
|
+
replaceWidget: replaceWidget,
|
|
18263
|
+
replaceDeprecatedWidgets: replaceDeprecatedWidgets,
|
|
18264
|
+
registerEditors: registerEditors,
|
|
18265
|
+
replaceEditor: replaceEditor,
|
|
18266
|
+
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
18267
|
+
getWidget: getWidget,
|
|
18268
|
+
getWidgetExport: getWidgetExport,
|
|
18269
|
+
getEditor: getEditor,
|
|
18270
|
+
getTransform: getTransform,
|
|
18271
|
+
getVersion: getVersion,
|
|
18272
|
+
getVersionVector: getVersionVector,
|
|
18273
|
+
getPublicWidgets: getPublicWidgets,
|
|
18274
|
+
isAccessible: isAccessible,
|
|
18275
|
+
getAllWidgetTypes: getAllWidgetTypes,
|
|
18276
|
+
getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
|
|
18277
|
+
traverseChildWidgets: traverseChildWidgets$3,
|
|
18278
|
+
supportsStaticMode: supportsStaticMode,
|
|
18279
|
+
getStaticTransform: getStaticTransform,
|
|
18280
|
+
getTracking: getTracking,
|
|
18281
|
+
isLintable: isLintable
|
|
18088
18282
|
});
|
|
18089
18283
|
|
|
18090
18284
|
class WidgetContainer extends React__namespace.Component {
|
|
@@ -18119,7 +18313,6 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
18119
18313
|
/* eslint-enable react/no-did-mount-set-state */
|
|
18120
18314
|
}
|
|
18121
18315
|
}
|
|
18122
|
-
|
|
18123
18316
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
18124
18317
|
if (this.props.type !== nextProps.type) {
|
|
18125
18318
|
throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
|
|
@@ -18242,7 +18435,7 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
18242
18435
|
}
|
|
18243
18436
|
});
|
|
18244
18437
|
}
|
|
18245
|
-
}, /*#__PURE__*/React__namespace.createElement(WidgetType,
|
|
18438
|
+
}, /*#__PURE__*/React__namespace.createElement(WidgetType, _extends__default["default"]({}, this.state.widgetProps, {
|
|
18246
18439
|
linterContext: linterContext,
|
|
18247
18440
|
containerSizeClass: this.state.sizeClass,
|
|
18248
18441
|
ref: this.widgetRef
|
|
@@ -19111,7 +19304,7 @@ class Renderer extends React__namespace.Component {
|
|
|
19111
19304
|
let {
|
|
19112
19305
|
setAssetStatus
|
|
19113
19306
|
} = _ref4;
|
|
19114
|
-
return /*#__PURE__*/React__namespace.createElement(SvgImage,
|
|
19307
|
+
return /*#__PURE__*/React__namespace.createElement(SvgImage, _extends__default["default"]({
|
|
19115
19308
|
setAssetStatus: setAssetStatus
|
|
19116
19309
|
// @ts-expect-error - TS2322 - Type 'string | null | undefined' is not assignable to type 'string | undefined'.
|
|
19117
19310
|
,
|
|
@@ -19635,429 +19828,84 @@ const styles$A = {
|
|
|
19635
19828
|
}
|
|
19636
19829
|
};
|
|
19637
19830
|
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19643
|
-
|
|
19644
|
-
}
|
|
19645
|
-
class TextInput extends React__namespace.Component {
|
|
19646
|
-
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
19647
|
-
static defaultProps = {
|
|
19648
|
-
value: "",
|
|
19649
|
-
disabled: false
|
|
19650
|
-
};
|
|
19651
|
-
id;
|
|
19652
|
-
constructor(props) {
|
|
19653
|
-
super(props);
|
|
19654
|
-
if (props.id) {
|
|
19655
|
-
this.id = props.id;
|
|
19656
|
-
} else {
|
|
19657
|
-
this.id = uniqueIdForInput();
|
|
19658
|
-
}
|
|
19659
|
-
}
|
|
19660
|
-
_getInput = () => {
|
|
19661
|
-
if (!this.inputRef.current) {
|
|
19662
|
-
throw new perseusCore.PerseusError("Input ref accessed before set", perseusCore.Errors.Internal);
|
|
19663
|
-
}
|
|
19664
|
-
return this.inputRef.current;
|
|
19665
|
-
};
|
|
19666
|
-
focus = () => {
|
|
19667
|
-
this._getInput().focus();
|
|
19668
|
-
};
|
|
19669
|
-
blur = () => {
|
|
19670
|
-
this._getInput().blur();
|
|
19671
|
-
};
|
|
19672
|
-
getValue = () => {
|
|
19673
|
-
return this.inputRef.current?.value;
|
|
19674
|
-
};
|
|
19675
|
-
getStringValue = () => {
|
|
19676
|
-
return this.inputRef.current?.value.toString();
|
|
19677
|
-
};
|
|
19678
|
-
setSelectionRange = (selectionStart, selectionEnd) => {
|
|
19679
|
-
this._getInput().setSelectionRange(selectionStart, selectionEnd);
|
|
19680
|
-
};
|
|
19681
|
-
getSelectionStart = () => {
|
|
19682
|
-
return this._getInput().selectionStart;
|
|
19683
|
-
};
|
|
19684
|
-
getSelectionEnd = () => {
|
|
19685
|
-
return this._getInput().selectionEnd;
|
|
19686
|
-
};
|
|
19687
|
-
render() {
|
|
19688
|
-
const {
|
|
19689
|
-
labelText,
|
|
19690
|
-
value,
|
|
19691
|
-
onFocus,
|
|
19692
|
-
onBlur,
|
|
19693
|
-
disabled,
|
|
19694
|
-
placeholder,
|
|
19695
|
-
onKeyDown,
|
|
19696
|
-
style
|
|
19697
|
-
} = this.props;
|
|
19698
|
-
const formattedValue = value === null ? "" : value.toString();
|
|
19699
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
19700
|
-
ref: this.inputRef,
|
|
19701
|
-
style: style,
|
|
19702
|
-
disabled: disabled,
|
|
19703
|
-
id: this.id,
|
|
19704
|
-
value: formattedValue,
|
|
19705
|
-
type: "text",
|
|
19706
|
-
"aria-label": labelText,
|
|
19707
|
-
"aria-describedby": this.props["aria-describedby"],
|
|
19708
|
-
onChange: value => this.props.onChange(value),
|
|
19709
|
-
placeholder: placeholder,
|
|
19710
|
-
onFocus: onFocus,
|
|
19711
|
-
onBlur: onBlur,
|
|
19712
|
-
onKeyDown: onKeyDown
|
|
19713
|
-
// @ts-expect-error - TS2322 - Type '{ style: StyleType; disabled: boolean | undefined; id: string; value: string; type: "text"; "aria-label": string | undefined; onChange: (value: string) => void; placeholder: string | undefined; ... 5 more ...; autoComplete: string; }' is not assignable to type 'IntrinsicAttributes & ExportProps & RefAttributes<HTMLInputElement>'.
|
|
19714
|
-
,
|
|
19715
|
-
autoCorrect: "off",
|
|
19716
|
-
autoCapitalize: "off",
|
|
19717
|
-
autoComplete: "off"
|
|
19718
|
-
});
|
|
19719
|
-
}
|
|
19720
|
-
}
|
|
19721
|
-
|
|
19722
|
-
/* eslint-disable react/no-unsafe */
|
|
19723
|
-
const zIndex = 10;
|
|
19724
|
-
let HorizontalDirection = /*#__PURE__*/function (HorizontalDirection) {
|
|
19725
|
-
HorizontalDirection["Left"] = "left";
|
|
19726
|
-
HorizontalDirection["Right"] = "right";
|
|
19727
|
-
return HorizontalDirection;
|
|
19728
|
-
}({});
|
|
19729
|
-
let VerticalDirection = /*#__PURE__*/function (VerticalDirection) {
|
|
19730
|
-
VerticalDirection["Top"] = "top";
|
|
19731
|
-
VerticalDirection["Bottom"] = "bottom";
|
|
19732
|
-
return VerticalDirection;
|
|
19733
|
-
}({});
|
|
19734
|
-
const Triangle = props => {
|
|
19735
|
-
let borderLeft;
|
|
19736
|
-
let borderRight;
|
|
19737
|
-
let borderTop;
|
|
19738
|
-
let borderBottom;
|
|
19739
|
-
const hBorder = `${props.width}px solid transparent`;
|
|
19740
|
-
if (props.horizontalDirection === "right") {
|
|
19741
|
-
borderLeft = hBorder;
|
|
19742
|
-
} else {
|
|
19743
|
-
borderRight = hBorder;
|
|
19744
|
-
}
|
|
19745
|
-
const vBorder = `${props.height}px solid ${props.color}`;
|
|
19746
|
-
if (props.verticalDirection === "top") {
|
|
19747
|
-
borderTop = vBorder;
|
|
19748
|
-
} else {
|
|
19749
|
-
borderBottom = vBorder;
|
|
19750
|
-
}
|
|
19751
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
19752
|
-
style: {
|
|
19753
|
-
display: "block",
|
|
19754
|
-
height: 0,
|
|
19755
|
-
width: 0,
|
|
19756
|
-
position: "absolute",
|
|
19757
|
-
left: props.left,
|
|
19758
|
-
top: props.top,
|
|
19759
|
-
borderLeft: borderLeft,
|
|
19760
|
-
borderRight: borderRight,
|
|
19761
|
-
borderTop: borderTop,
|
|
19762
|
-
borderBottom: borderBottom
|
|
19763
|
-
}
|
|
19764
|
-
});
|
|
19765
|
-
};
|
|
19766
|
-
const TooltipArrow = _ref => {
|
|
19767
|
-
let {
|
|
19768
|
-
position = "relative",
|
|
19769
|
-
visibility = "visible",
|
|
19770
|
-
left = 100,
|
|
19771
|
-
top = 0,
|
|
19772
|
-
...props
|
|
19773
|
-
} = _ref;
|
|
19774
|
-
// TODO(aria): Think about adding a box-shadow to the triangle here
|
|
19775
|
-
// See http://css-tricks.com/triangle-with-shadow/
|
|
19831
|
+
const {
|
|
19832
|
+
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
19833
|
+
} = Util;
|
|
19834
|
+
// [LEMS-2411](Jan 2025) Third: This component has been moved to the NumericInput
|
|
19835
|
+
// folder as we are actively working towards removing the InputNumber widget.
|
|
19836
|
+
// This comment can be removed as part of LEMS-2411.
|
|
19776
19837
|
|
|
19777
|
-
//const isRight = (this.props.horizontalDirection === "right");
|
|
19778
|
-
const isTop = props.verticalDirection === "top";
|
|
19779
|
-
const frontTopOffset = isTop ? 0 : 1;
|
|
19780
|
-
const borderTopOffset = isTop ? 0 : -1;
|
|
19781
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
19782
|
-
style: {
|
|
19783
|
-
display: "block",
|
|
19784
|
-
position: position,
|
|
19785
|
-
visibility: visibility,
|
|
19786
|
-
left: left,
|
|
19787
|
-
top: top,
|
|
19788
|
-
width: props.width + 2,
|
|
19789
|
-
height: props.height + 1,
|
|
19790
|
-
marginTop: -1,
|
|
19791
|
-
marginBottom: -2,
|
|
19792
|
-
zIndex: zIndex
|
|
19793
|
-
}
|
|
19794
|
-
}, /*#__PURE__*/React__namespace.createElement(Triangle, {
|
|
19795
|
-
horizontalDirection: props.horizontalDirection,
|
|
19796
|
-
verticalDirection: props.verticalDirection,
|
|
19797
|
-
color: props.border,
|
|
19798
|
-
left: 0,
|
|
19799
|
-
top: borderTopOffset,
|
|
19800
|
-
width: props.width + 2 // one extra for the diagonal
|
|
19801
|
-
,
|
|
19802
|
-
height: props.height + 2
|
|
19803
|
-
}), /*#__PURE__*/React__namespace.createElement(Triangle, {
|
|
19804
|
-
horizontalDirection: props.horizontalDirection,
|
|
19805
|
-
verticalDirection: props.verticalDirection,
|
|
19806
|
-
color: props.color,
|
|
19807
|
-
left: 1,
|
|
19808
|
-
top: frontTopOffset,
|
|
19809
|
-
width: props.width,
|
|
19810
|
-
height: props.height
|
|
19811
|
-
}));
|
|
19812
|
-
};
|
|
19813
|
-
const VERTICAL_CORNERS = {
|
|
19814
|
-
top: {
|
|
19815
|
-
top: "-100%"
|
|
19816
|
-
},
|
|
19817
|
-
bottom: {
|
|
19818
|
-
top: 0
|
|
19819
|
-
}
|
|
19820
|
-
};
|
|
19821
|
-
const HORIZONTAL_CORNERS = {
|
|
19822
|
-
left: {
|
|
19823
|
-
targetLeft: 0
|
|
19824
|
-
},
|
|
19825
|
-
right: {
|
|
19826
|
-
targetLeft: "100%"
|
|
19827
|
-
}
|
|
19828
|
-
};
|
|
19829
|
-
const HORIZONTAL_ALIGNMNENTS = {
|
|
19830
|
-
left: {
|
|
19831
|
-
tooltipLeft: 0,
|
|
19832
|
-
arrowLeft: arrowSize => 0
|
|
19833
|
-
},
|
|
19834
|
-
right: {
|
|
19835
|
-
tooltipLeft: "-100%",
|
|
19836
|
-
arrowLeft: arrowSize => -arrowSize - 2
|
|
19837
|
-
}
|
|
19838
|
-
};
|
|
19839
19838
|
/**
|
|
19840
|
-
*
|
|
19841
|
-
*
|
|
19842
|
-
*
|
|
19843
|
-
*
|
|
19844
|
-
* ```
|
|
19845
|
-
* import Tooltip from "./tooltip";
|
|
19846
|
-
* <Tooltip
|
|
19847
|
-
* className="class-for-tooltip-contents"
|
|
19848
|
-
* horizontalPosition={HoriziontalDirection.Left}
|
|
19849
|
-
* horizontalAlign={HoriziontalDirection.Left}
|
|
19850
|
-
* verticalPosition={VerticalDirection.Top}
|
|
19851
|
-
* arrowSize={10} // arrow size in pixels
|
|
19852
|
-
* borderColor="#ccc" // color of the border for the tooltip
|
|
19853
|
-
* show={true} // whether the tooltip should currently be visible
|
|
19854
|
-
* targetContainerStyle={targetContainerStyle}
|
|
19855
|
-
* >
|
|
19856
|
-
* <TargetElementOfTheTooltip />
|
|
19857
|
-
* <TooltipContents1 />
|
|
19858
|
-
* <TooltipContents2 />
|
|
19859
|
-
* </Tooltip>
|
|
19860
|
-
* ```
|
|
19861
|
-
*
|
|
19862
|
-
* To show/hide the tooltip, the parent component should call the
|
|
19863
|
-
* `.show()` and `.hide()` methods of the tooltip when appropriate.
|
|
19864
|
-
* (These are usually set up as handlers of events on the target element.)
|
|
19865
|
-
*
|
|
19866
|
-
* Notes:
|
|
19867
|
-
* `className` should not specify a border; that is handled by `borderColor`
|
|
19868
|
-
* so that the arrow and tooltip match
|
|
19869
|
-
*
|
|
19870
|
-
* ```
|
|
19871
|
-
* __,,--``\\
|
|
19872
|
-
* _,,-''`` \\ ,
|
|
19873
|
-
* '----------_.------'-.___|\__
|
|
19874
|
-
* _.--''`` `)__ )__ @\__
|
|
19875
|
-
* ( .. ''---/___,,E/__,E'------`
|
|
19876
|
-
* `-''`''
|
|
19877
|
-
* Here be dragons.
|
|
19878
|
-
* ```
|
|
19839
|
+
* The InputWithExamples component is a child component of the NumericInput
|
|
19840
|
+
* and InputNumber components. It is responsible for rendering the UI elements
|
|
19841
|
+
* for the desktop versions of these widgets, and displays a tooltip with
|
|
19842
|
+
* examples of how to input the selected answer forms.
|
|
19879
19843
|
*/
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
|
|
19883
|
-
|
|
19884
|
-
|
|
19885
|
-
|
|
19886
|
-
|
|
19887
|
-
|
|
19888
|
-
|
|
19889
|
-
|
|
19890
|
-
|
|
19891
|
-
|
|
19892
|
-
|
|
19893
|
-
|
|
19894
|
-
|
|
19895
|
-
|
|
19896
|
-
|
|
19897
|
-
|
|
19898
|
-
|
|
19899
|
-
|
|
19900
|
-
|
|
19901
|
-
|
|
19902
|
-
|
|
19903
|
-
|
|
19904
|
-
|
|
19905
|
-
this._updateHeight();
|
|
19906
|
-
}
|
|
19907
|
-
_renderToolTipDiv(isTooltipAbove) {
|
|
19908
|
-
const settings = Object.assign({}, HORIZONTAL_CORNERS[this.props.horizontalPosition], HORIZONTAL_ALIGNMNENTS[this.props.horizontalAlign], VERTICAL_CORNERS[this.props.verticalPosition]);
|
|
19909
|
-
let arrowAbove;
|
|
19910
|
-
let arrowBelow;
|
|
19911
|
-
if (isTooltipAbove) {
|
|
19912
|
-
// We put an absolutely positioned arrow in the correct place
|
|
19913
|
-
arrowAbove = /*#__PURE__*/React__namespace.createElement(TooltipArrow, {
|
|
19914
|
-
verticalDirection: VerticalDirection.Top,
|
|
19915
|
-
horizontalDirection: this.props.horizontalAlign,
|
|
19916
|
-
position: "absolute",
|
|
19917
|
-
color: "white",
|
|
19918
|
-
border: this.props.borderColor,
|
|
19919
|
-
left: settings.arrowLeft(this.props.arrowSize),
|
|
19920
|
-
top: -this.props.arrowSize + 2,
|
|
19921
|
-
width: this.props.arrowSize,
|
|
19922
|
-
height: this.props.arrowSize,
|
|
19923
|
-
zIndex: zIndex
|
|
19924
|
-
});
|
|
19925
|
-
|
|
19926
|
-
// And we use a visibility: hidden arrow below to shift up the
|
|
19927
|
-
// content by the correct amount
|
|
19928
|
-
arrowBelow = /*#__PURE__*/React__namespace.createElement(TooltipArrow, {
|
|
19929
|
-
verticalDirection: VerticalDirection.Top,
|
|
19930
|
-
horizontalDirection: this.props.horizontalAlign,
|
|
19931
|
-
visibility: "hidden",
|
|
19932
|
-
color: "white",
|
|
19933
|
-
border: this.props.borderColor,
|
|
19934
|
-
left: settings.arrowLeft(this.props.arrowSize),
|
|
19935
|
-
top: -1,
|
|
19936
|
-
width: this.props.arrowSize,
|
|
19937
|
-
height: this.props.arrowSize,
|
|
19938
|
-
zIndex: zIndex
|
|
19939
|
-
});
|
|
19940
|
-
} else {
|
|
19941
|
-
arrowAbove = /*#__PURE__*/React__namespace.createElement(TooltipArrow, {
|
|
19942
|
-
verticalDirection: VerticalDirection.Bottom,
|
|
19943
|
-
horizontalDirection: this.props.horizontalAlign,
|
|
19944
|
-
color: "white",
|
|
19945
|
-
border: this.props.borderColor,
|
|
19946
|
-
left: settings.arrowLeft(this.props.arrowSize),
|
|
19947
|
-
top: -1,
|
|
19948
|
-
width: this.props.arrowSize,
|
|
19949
|
-
height: this.props.arrowSize,
|
|
19950
|
-
zIndex: zIndex
|
|
19951
|
-
});
|
|
19952
|
-
arrowBelow = null;
|
|
19953
|
-
}
|
|
19954
|
-
|
|
19955
|
-
/* A positioned div below the input to be the parent for our
|
|
19956
|
-
tooltip */
|
|
19957
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
19958
|
-
style: {
|
|
19959
|
-
position: "relative",
|
|
19960
|
-
height: 0,
|
|
19961
|
-
display: this.props.show ? "block" : "none"
|
|
19844
|
+
const InputWithExamples = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
19845
|
+
// Desctructure the props to set default values
|
|
19846
|
+
const {
|
|
19847
|
+
shouldShowExamples = true,
|
|
19848
|
+
onFocus = () => {},
|
|
19849
|
+
onBlur = () => {},
|
|
19850
|
+
disabled = false,
|
|
19851
|
+
linterContext = PerseusLinter__namespace.linterContextDefault,
|
|
19852
|
+
className = ""
|
|
19853
|
+
} = props;
|
|
19854
|
+
const context = React__namespace.useContext(PerseusI18nContext);
|
|
19855
|
+
const inputRef = React__namespace.useRef(null);
|
|
19856
|
+
const [inputFocused, setInputFocused] = React__namespace.useState(false);
|
|
19857
|
+
const id = React.useId();
|
|
19858
|
+
const ariaId = `aria-for-${id}`;
|
|
19859
|
+
React.useImperativeHandle(ref, () => ({
|
|
19860
|
+
current: inputRef.current,
|
|
19861
|
+
focus: () => {
|
|
19862
|
+
if (inputRef.current) {
|
|
19863
|
+
inputRef.current.focus();
|
|
19864
|
+
}
|
|
19865
|
+
},
|
|
19866
|
+
blur: () => {
|
|
19867
|
+
if (inputRef.current) {
|
|
19868
|
+
inputRef.current.blur();
|
|
19962
19869
|
}
|
|
19963
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
19964
|
-
ref: this.tooltipContainerRef,
|
|
19965
|
-
className: "tooltipContainer",
|
|
19966
|
-
role: "tooltip",
|
|
19967
|
-
style: {
|
|
19968
|
-
position: "absolute",
|
|
19969
|
-
// height must start out undefined, not null, so that
|
|
19970
|
-
// we can measure the actual height with jquery.
|
|
19971
|
-
// This is used to position the tooltip with top: -100%
|
|
19972
|
-
// when in verticalPosition: "top" mode
|
|
19973
|
-
height: this.state.height || undefined,
|
|
19974
|
-
left: settings.targetLeft
|
|
19975
|
-
}
|
|
19976
|
-
}, arrowAbove, /*#__PURE__*/React__namespace.createElement("div", {
|
|
19977
|
-
className: this.props.className
|
|
19978
|
-
// eslint-disable-next-line react/no-string-refs
|
|
19979
|
-
,
|
|
19980
|
-
ref: "tooltipContent",
|
|
19981
|
-
style: {
|
|
19982
|
-
position: "relative",
|
|
19983
|
-
top: settings["top"],
|
|
19984
|
-
left: settings.tooltipLeft,
|
|
19985
|
-
border: "1px solid " + this.props.borderColor,
|
|
19986
|
-
boxShadow: "0 1px 3px " + this.props.borderColor,
|
|
19987
|
-
zIndex: zIndex - 1
|
|
19988
|
-
}
|
|
19989
|
-
}, this.props.children.slice(1)), arrowBelow));
|
|
19990
|
-
}
|
|
19991
|
-
_updateHeight() {
|
|
19992
|
-
const tooltipContainer = this.tooltipContainerRef.current;
|
|
19993
|
-
const height = tooltipContainer?.offsetHeight || 0;
|
|
19994
|
-
if (height !== this.state.height) {
|
|
19995
|
-
this.setState({
|
|
19996
|
-
height
|
|
19997
|
-
});
|
|
19998
19870
|
}
|
|
19999
|
-
}
|
|
20000
|
-
|
|
20001
|
-
|
|
20002
|
-
|
|
20003
|
-
|
|
20004
|
-
return /*#__PURE__*/React__namespace.createElement("span", null, isTooltipAbove && this._renderToolTipDiv(isTooltipAbove), /*#__PURE__*/React__namespace.createElement("div", {
|
|
20005
|
-
style: this.props.targetContainerStyle
|
|
20006
|
-
}, this.props.children[0]), !isTooltipAbove && this._renderToolTipDiv());
|
|
20007
|
-
}
|
|
20008
|
-
}
|
|
20009
|
-
|
|
20010
|
-
const {
|
|
20011
|
-
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
20012
|
-
} = Util;
|
|
20013
|
-
class InputWithExamples extends React__namespace.Component {
|
|
20014
|
-
static contextType = PerseusI18nContext;
|
|
20015
|
-
static defaultProps = {
|
|
20016
|
-
shouldShowExamples: true,
|
|
20017
|
-
onFocus: function () {},
|
|
20018
|
-
onBlur: function () {},
|
|
20019
|
-
disabled: false,
|
|
20020
|
-
linterContext: PerseusLinter__namespace.linterContextDefault,
|
|
20021
|
-
className: ""
|
|
20022
|
-
};
|
|
20023
|
-
state = {
|
|
20024
|
-
focused: false,
|
|
20025
|
-
showExamples: false
|
|
20026
|
-
};
|
|
20027
|
-
_getUniqueId = () => {
|
|
20028
|
-
return `input-with-examples-${btoa(this.props.id).replace(/=/g, "")}`;
|
|
20029
|
-
};
|
|
20030
|
-
_getInputClassName = () => {
|
|
20031
|
-
// Otherwise, we need to add these INPUT and FOCUSED tags here.
|
|
20032
|
-
let className = ClassNames.INPUT;
|
|
20033
|
-
if (this.state.focused) {
|
|
20034
|
-
className += " " + ClassNames.FOCUSED;
|
|
19871
|
+
}));
|
|
19872
|
+
const getInputClassName = () => {
|
|
19873
|
+
let inputClassName = ClassNames.INPUT;
|
|
19874
|
+
if (inputFocused) {
|
|
19875
|
+
inputClassName += " " + ClassNames.FOCUSED;
|
|
20035
19876
|
}
|
|
20036
|
-
if (
|
|
20037
|
-
|
|
19877
|
+
if (className) {
|
|
19878
|
+
inputClassName += " " + className;
|
|
20038
19879
|
}
|
|
20039
|
-
return
|
|
19880
|
+
return inputClassName;
|
|
19881
|
+
};
|
|
19882
|
+
const handleFocus = () => {
|
|
19883
|
+
onFocus();
|
|
19884
|
+
setInputFocused(true);
|
|
19885
|
+
};
|
|
19886
|
+
const handleBlur = () => {
|
|
19887
|
+
onBlur();
|
|
19888
|
+
setInputFocused(false);
|
|
20040
19889
|
};
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
const
|
|
20044
|
-
|
|
20045
|
-
const examplesAria = this.props.examples.length === 7 ? "" : `${this.props.examples[0]}
|
|
20046
|
-
${this.props.examples.slice(1).join(", or\n")}`
|
|
19890
|
+
const renderInput = () => {
|
|
19891
|
+
// Generate the provided examples in simple language for screen readers.
|
|
19892
|
+
const examplesAria = props.shouldShowExamples ? `${props.examples[0]}
|
|
19893
|
+
${props.examples.slice(1).join(", or\n")}`
|
|
20047
19894
|
// @ts-expect-error TS2550: Property replaceAll does not exist on type string.
|
|
20048
|
-
.replaceAll("*", "").replaceAll("$", "").replaceAll("\\ \\text{pi}", " pi").replaceAll("\\ ", " and ");
|
|
19895
|
+
.replaceAll("*", "").replaceAll("$", "").replaceAll("\\ \\text{pi}", " pi").replaceAll("\\ ", " and ") : "";
|
|
20049
19896
|
const inputProps = {
|
|
20050
19897
|
id: id,
|
|
20051
|
-
|
|
20052
|
-
|
|
20053
|
-
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
|
|
20058
|
-
|
|
20059
|
-
|
|
20060
|
-
|
|
19898
|
+
// If we have examples, we want to provide the aria-describedby attribute
|
|
19899
|
+
"aria-describedby": props.shouldShowExamples ? ariaId : undefined,
|
|
19900
|
+
ref: inputRef,
|
|
19901
|
+
className: getInputClassName(),
|
|
19902
|
+
labelText: props.labelText,
|
|
19903
|
+
value: props.value,
|
|
19904
|
+
onFocus: handleFocus,
|
|
19905
|
+
onBlur: handleBlur,
|
|
19906
|
+
disabled: disabled,
|
|
19907
|
+
style: props.style,
|
|
19908
|
+
onChange: props.onChange,
|
|
20061
19909
|
onTouchStart: captureScratchpadTouchStart$2,
|
|
20062
19910
|
autoCapitalize: "off",
|
|
20063
19911
|
autoComplete: "off",
|
|
@@ -20071,158 +19919,32 @@ class InputWithExamples extends React__namespace.Component {
|
|
|
20071
19919
|
}
|
|
20072
19920
|
}, examplesAria));
|
|
20073
19921
|
};
|
|
20074
|
-
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
showExamples: true
|
|
20079
|
-
});
|
|
20080
|
-
};
|
|
20081
|
-
show = () => {
|
|
20082
|
-
this.setState({
|
|
20083
|
-
showExamples: true
|
|
20084
|
-
});
|
|
20085
|
-
};
|
|
20086
|
-
hide = () => {
|
|
20087
|
-
this.setState({
|
|
20088
|
-
showExamples: false
|
|
20089
|
-
});
|
|
20090
|
-
};
|
|
20091
|
-
_handleBlur = () => {
|
|
20092
|
-
this.props.onBlur();
|
|
20093
|
-
this.setState({
|
|
20094
|
-
focused: false,
|
|
20095
|
-
showExamples: false
|
|
20096
|
-
});
|
|
20097
|
-
};
|
|
20098
|
-
focus = () => {
|
|
20099
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20100
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
20101
|
-
this.refs.input.focus();
|
|
20102
|
-
};
|
|
20103
|
-
blur = () => {
|
|
20104
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20105
|
-
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
20106
|
-
this.refs.input.blur();
|
|
20107
|
-
};
|
|
20108
|
-
handleChange = e => {
|
|
20109
|
-
this.props.onChange(e.target.value);
|
|
20110
|
-
};
|
|
20111
|
-
render() {
|
|
20112
|
-
const input = this._renderInput();
|
|
20113
|
-
const examplesContent = this.props.examples.length <= 2 ? this.props.examples.join(" ") // A single item (with or without leading text) is not a "list"
|
|
20114
|
-
: this.props.examples // 2 or more items should display as a list
|
|
20115
|
-
.map((example, index) => {
|
|
20116
|
-
// If the first example is bold, then it is most likely a heading/leading text.
|
|
20117
|
-
// So, it shouldn't be part of the list.
|
|
20118
|
-
return index === 0 && example.startsWith("**") ? `${example}\n` : `- ${example}`;
|
|
20119
|
-
}).join("\n");
|
|
20120
|
-
const showExamples = this.props.shouldShowExamples && this.state.showExamples;
|
|
20121
|
-
return /*#__PURE__*/React__namespace.createElement(Tooltip, {
|
|
20122
|
-
className: "perseus-formats-tooltip preview-measure",
|
|
20123
|
-
horizontalPosition: HorizontalDirection.Left,
|
|
20124
|
-
horizontalAlign: HorizontalDirection.Left,
|
|
20125
|
-
verticalPosition: VerticalDirection.Bottom,
|
|
20126
|
-
arrowSize: 10,
|
|
20127
|
-
borderColor: "#ccc",
|
|
20128
|
-
show: showExamples
|
|
20129
|
-
}, input, /*#__PURE__*/React__namespace.createElement("div", {
|
|
20130
|
-
id: this._getUniqueId()
|
|
19922
|
+
const renderTooltipContent = () => {
|
|
19923
|
+
return /*#__PURE__*/React__namespace.createElement(Tooltip.TooltipContent, null, /*#__PURE__*/React__namespace.createElement("div", {
|
|
19924
|
+
id: id,
|
|
19925
|
+
className: "input-with-examples-tooltip"
|
|
20131
19926
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
20132
19927
|
content: examplesContent,
|
|
20133
|
-
linterContext: PerseusLinter__namespace.pushContextStack(
|
|
20134
|
-
strings:
|
|
19928
|
+
linterContext: PerseusLinter__namespace.pushContextStack(linterContext, "input-with-examples"),
|
|
19929
|
+
strings: context.strings
|
|
20135
19930
|
})));
|
|
20136
|
-
}
|
|
20137
|
-
}
|
|
20138
|
-
|
|
20139
|
-
class SimpleKeypadInput extends React__namespace.Component {
|
|
20140
|
-
_isMounted = false;
|
|
20141
|
-
componentDidMount() {
|
|
20142
|
-
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
20143
|
-
// this.isMounted() but is still considered an anti-pattern.
|
|
20144
|
-
this._isMounted = true;
|
|
20145
|
-
}
|
|
20146
|
-
componentWillUnmount() {
|
|
20147
|
-
this._isMounted = false;
|
|
20148
|
-
}
|
|
20149
|
-
focus() {
|
|
20150
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
20151
|
-
this.refs.input.focus(); // eslint-disable-line react/no-string-refs
|
|
20152
|
-
}
|
|
20153
|
-
|
|
20154
|
-
blur() {
|
|
20155
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20156
|
-
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
20157
|
-
if (typeof this.refs.input?.blur === "function") {
|
|
20158
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20159
|
-
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
20160
|
-
this.refs.input?.blur();
|
|
20161
|
-
}
|
|
20162
|
-
}
|
|
20163
|
-
getValue() {
|
|
20164
|
-
return this.props.value;
|
|
20165
|
-
}
|
|
20166
|
-
render() {
|
|
20167
|
-
const _this = this;
|
|
20168
|
-
// Intercept the `onFocus` prop, as we need to configure the keypad
|
|
20169
|
-
// before continuing with the default focus logic for Perseus inputs.
|
|
20170
|
-
// Intercept the `value` prop so as to map `null` to the empty string,
|
|
20171
|
-
// as the `KeypadInput` does not support `null` values.
|
|
20172
|
-
const {
|
|
20173
|
-
keypadElement,
|
|
20174
|
-
onFocus,
|
|
20175
|
-
value,
|
|
20176
|
-
...rest
|
|
20177
|
-
} = _this.props;
|
|
20178
|
-
return (
|
|
20179
|
-
/*#__PURE__*/
|
|
20180
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
20181
|
-
React__namespace.createElement(mathInput.KeypadInput
|
|
20182
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20183
|
-
, _extends({
|
|
20184
|
-
ref: "input",
|
|
20185
|
-
keypadElement: keypadElement,
|
|
20186
|
-
onFocus: () => {
|
|
20187
|
-
if (keypadElement) {
|
|
20188
|
-
keypadElement.configure({
|
|
20189
|
-
keypadType: mathInput.KeypadType.FRACTION
|
|
20190
|
-
}, () => {
|
|
20191
|
-
if (_this._isMounted) {
|
|
20192
|
-
onFocus?.();
|
|
20193
|
-
}
|
|
20194
|
-
});
|
|
20195
|
-
} else {
|
|
20196
|
-
onFocus?.();
|
|
20197
|
-
}
|
|
20198
|
-
},
|
|
20199
|
-
value: value == null ? "" : "" + value
|
|
20200
|
-
}, rest))
|
|
20201
|
-
);
|
|
20202
|
-
}
|
|
20203
|
-
}
|
|
20204
|
-
|
|
20205
|
-
// @ts-expect-error - TS2339 - Property 'propTypes' does not exist on type 'typeof SimpleKeypadInput'.
|
|
20206
|
-
SimpleKeypadInput.propTypes = {
|
|
20207
|
-
keypadElement: mathInput.keypadElementPropType,
|
|
20208
|
-
onFocus: PropTypes__default["default"].func,
|
|
20209
|
-
value: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number])
|
|
20210
|
-
};
|
|
20211
|
-
|
|
20212
|
-
const getPromptJSON$s = (renderProps, userInput) => {
|
|
20213
|
-
return {
|
|
20214
|
-
type: "input-number",
|
|
20215
|
-
options: {
|
|
20216
|
-
simplify: renderProps.simplify,
|
|
20217
|
-
answerType: renderProps.answerType
|
|
20218
|
-
},
|
|
20219
|
-
userInput: {
|
|
20220
|
-
value: userInput.currentValue
|
|
20221
|
-
}
|
|
20222
19931
|
};
|
|
20223
|
-
|
|
19932
|
+
// Display the examples as a string when there are less than or equal to 2 examples.
|
|
19933
|
+
// Otherwise, display the examples as a list.
|
|
19934
|
+
const examplesContent = props.examples.length <= 2 ? props.examples.join(" ") : props.examples.map((example, index) => {
|
|
19935
|
+
return index === 0 && example.startsWith("**") ? `${example}\n` : `- ${example}`;
|
|
19936
|
+
}).join("\n");
|
|
20224
19937
|
|
|
20225
|
-
|
|
19938
|
+
// Display the examples when they are enabled (shouldShowExamples) and the input is focused.
|
|
19939
|
+
const showExamplesTooltip = shouldShowExamples && inputFocused;
|
|
19940
|
+
return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
19941
|
+
content: renderTooltipContent(),
|
|
19942
|
+
opened: showExamplesTooltip,
|
|
19943
|
+
placement: "bottom"
|
|
19944
|
+
}, renderInput());
|
|
19945
|
+
});
|
|
19946
|
+
|
|
19947
|
+
const formExamples = {
|
|
20226
19948
|
integer: function (options, strings) {
|
|
20227
19949
|
return strings.integerExample;
|
|
20228
19950
|
},
|
|
@@ -20334,7 +20056,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
20334
20056
|
} = this.context;
|
|
20335
20057
|
const type = this.props.answerType;
|
|
20336
20058
|
const forms = perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);
|
|
20337
|
-
const examples = ___default["default"].map(forms, form => formExamples
|
|
20059
|
+
const examples = ___default["default"].map(forms, form => formExamples[form](this.props, strings));
|
|
20338
20060
|
return [strings.yourAnswer].concat(examples);
|
|
20339
20061
|
}
|
|
20340
20062
|
render() {
|
|
@@ -20448,7 +20170,11 @@ const getPromptJSON$r = (renderProps, userInput) => {
|
|
|
20448
20170
|
};
|
|
20449
20171
|
};
|
|
20450
20172
|
|
|
20451
|
-
|
|
20173
|
+
/**
|
|
20174
|
+
* The full list of available strings for the numeric input widget,
|
|
20175
|
+
* based on whether the Content Creator has specified that the answer must be simplified.
|
|
20176
|
+
*/
|
|
20177
|
+
const NumericExampleStrings = {
|
|
20452
20178
|
integer: (form, strings) => strings.integerExample,
|
|
20453
20179
|
proper: (form, strings) => form.simplify === "optional" ? strings.properExample : strings.simplifiedProperExample,
|
|
20454
20180
|
improper: (form, strings) => form.simplify === "optional" ? strings.improperExample : strings.simplifiedImproperExample,
|
|
@@ -20456,9 +20182,182 @@ const formExamples = {
|
|
|
20456
20182
|
decimal: (form, strings) => strings.decimalExample,
|
|
20457
20183
|
pi: (form, strings) => strings.piExample
|
|
20458
20184
|
};
|
|
20185
|
+
|
|
20186
|
+
/**
|
|
20187
|
+
* Generates the specific set of examples for the current question.
|
|
20188
|
+
* This string is shown as examples to the user in a tooltip.
|
|
20189
|
+
*/
|
|
20190
|
+
const generateExamples = (answerForms, strings) => {
|
|
20191
|
+
// If the Content Creator has not specified any answer forms,
|
|
20192
|
+
// we do not need to show any examples.
|
|
20193
|
+
if (answerForms.length === 0) {
|
|
20194
|
+
return [];
|
|
20195
|
+
}
|
|
20196
|
+
|
|
20197
|
+
// Generate a list of the unique answer forms.
|
|
20198
|
+
const uniqueForms = getUniqueAnswerForms(answerForms);
|
|
20199
|
+
|
|
20200
|
+
// Generate the example strings for each unique form.
|
|
20201
|
+
const examples = uniqueForms.map(form => {
|
|
20202
|
+
return NumericExampleStrings[form.name](form, strings);
|
|
20203
|
+
});
|
|
20204
|
+
|
|
20205
|
+
// Add the "Your answer" string to the beginning of the examples list.
|
|
20206
|
+
return [strings.yourAnswer].concat(examples);
|
|
20207
|
+
};
|
|
20208
|
+
|
|
20209
|
+
/**
|
|
20210
|
+
* Determines whether to show examples of how to input the various supported answer forms.
|
|
20211
|
+
* We do not show examples if all forms are accepted or if no forms are accepted.
|
|
20212
|
+
*/
|
|
20213
|
+
const shouldShowExamples = answerForms => {
|
|
20214
|
+
// If the Content Creator has not specified any answer forms,
|
|
20215
|
+
// we do not need to show any examples.
|
|
20216
|
+
if (answerForms.length === 0) {
|
|
20217
|
+
return false;
|
|
20218
|
+
}
|
|
20219
|
+
|
|
20220
|
+
// Generate a list of the unique names of the selected answer forms.
|
|
20221
|
+
const answerFormNames = getUniqueAnswerForms(answerForms).map(form => form.name);
|
|
20222
|
+
|
|
20223
|
+
// If all forms are accepted, we do not need to show any examples.
|
|
20224
|
+
const allFormsAccepted = answerFormNames.length >= Object.keys(NumericExampleStrings).length;
|
|
20225
|
+
return !allFormsAccepted;
|
|
20226
|
+
};
|
|
20227
|
+
|
|
20228
|
+
/**
|
|
20229
|
+
* uniqueAnswerForms takes a list of answer forms and returns a list of unique
|
|
20230
|
+
* answer forms. This is useful for ensuring that we don't show duplicate examples
|
|
20231
|
+
* to the user.
|
|
20232
|
+
*/
|
|
20233
|
+
const getUniqueAnswerForms = function (list) {
|
|
20234
|
+
// We use a Set to keep track of the forms we've already seen.
|
|
20235
|
+
const foundForms = new Set();
|
|
20236
|
+
return list.filter(form => {
|
|
20237
|
+
// If we've already seen this form, skip it.
|
|
20238
|
+
if (foundForms.has(form.name)) {
|
|
20239
|
+
return false;
|
|
20240
|
+
}
|
|
20241
|
+
// Otherwise, add it to the set and return true.
|
|
20242
|
+
foundForms.add(form.name);
|
|
20243
|
+
return true;
|
|
20244
|
+
});
|
|
20245
|
+
};
|
|
20246
|
+
|
|
20247
|
+
/**
|
|
20248
|
+
* Takes a list of lists of answer forms, and returns a list of the forms
|
|
20249
|
+
* in each of these lists in the same order that they're listed in the
|
|
20250
|
+
* `formExamples` forms from above.
|
|
20251
|
+
*/
|
|
20252
|
+
const unionAnswerForms = function (answerFormsList) {
|
|
20253
|
+
// Pull out all of the forms from the different lists.
|
|
20254
|
+
const allForms = answerFormsList.flat();
|
|
20255
|
+
// Pull out the unique forms using getUniqueAnswerForms.
|
|
20256
|
+
const uniqueForms = getUniqueAnswerForms(allForms);
|
|
20257
|
+
// Sort them by the order they appear in the `formExamples` list.
|
|
20258
|
+
const formExampleKeys = Object.keys(NumericExampleStrings);
|
|
20259
|
+
return uniqueForms.sort((a, b) => {
|
|
20260
|
+
return formExampleKeys.indexOf(a.name) - formExampleKeys.indexOf(b.name);
|
|
20261
|
+
});
|
|
20262
|
+
};
|
|
20263
|
+
|
|
20264
|
+
/**
|
|
20265
|
+
* The NumericInputComponent is a child component of the NumericInput class
|
|
20266
|
+
* component. It is responsible for rendering the UI elements of the Numeric
|
|
20267
|
+
* Input widget.
|
|
20268
|
+
*/
|
|
20269
|
+
const NumericInputComponent = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
20270
|
+
const context = React.useContext(PerseusI18nContext);
|
|
20271
|
+
const inputRef = React.useRef(null);
|
|
20272
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
20273
|
+
|
|
20274
|
+
// Pass the focus and blur methods to the Numeric Input Class component
|
|
20275
|
+
React.useImperativeHandle(ref, () => ({
|
|
20276
|
+
current: inputRef.current,
|
|
20277
|
+
focus: () => {
|
|
20278
|
+
if (inputRef.current) {
|
|
20279
|
+
inputRef.current?.focus();
|
|
20280
|
+
setIsFocused(true);
|
|
20281
|
+
}
|
|
20282
|
+
},
|
|
20283
|
+
blur: () => {
|
|
20284
|
+
if (inputRef.current) {
|
|
20285
|
+
inputRef.current?.blur();
|
|
20286
|
+
setIsFocused(false);
|
|
20287
|
+
}
|
|
20288
|
+
}
|
|
20289
|
+
}));
|
|
20290
|
+
const handleChange = (newValue, cb) => {
|
|
20291
|
+
props.onChange({
|
|
20292
|
+
currentValue: newValue
|
|
20293
|
+
}, cb);
|
|
20294
|
+
props.trackInteraction();
|
|
20295
|
+
};
|
|
20296
|
+
const handleFocus = () => {
|
|
20297
|
+
props.onFocus([]);
|
|
20298
|
+
setIsFocused(true);
|
|
20299
|
+
};
|
|
20300
|
+
const handleBlur = () => {
|
|
20301
|
+
props.onBlur([]);
|
|
20302
|
+
setIsFocused(false);
|
|
20303
|
+
};
|
|
20304
|
+
|
|
20305
|
+
// Styles for the InputWithExamples
|
|
20306
|
+
const styles = aphrodite.StyleSheet.create({
|
|
20307
|
+
inputWithExamples: {
|
|
20308
|
+
borderRadius: "3px",
|
|
20309
|
+
borderWidth: isFocused ? "2px" : "1px",
|
|
20310
|
+
display: "inline-block",
|
|
20311
|
+
fontFamily: `Symbola, "Times New Roman", serif`,
|
|
20312
|
+
fontSize: "18px",
|
|
20313
|
+
height: "32px",
|
|
20314
|
+
lineHeight: "18px",
|
|
20315
|
+
padding: isFocused ? "4px" : "4px 5px",
|
|
20316
|
+
textAlign: props.rightAlign ? "right" : "left",
|
|
20317
|
+
width: props.size === "small" ? 40 : 80
|
|
20318
|
+
}
|
|
20319
|
+
});
|
|
20320
|
+
|
|
20321
|
+
// (mobile-only) If the custom keypad is enabled, use the SimpleKeypadInput component
|
|
20322
|
+
if (props.apiOptions.customKeypad) {
|
|
20323
|
+
const alignmentClass = props.rightAlign ? "perseus-input-right-align" : undefined;
|
|
20324
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
20325
|
+
className: alignmentClass
|
|
20326
|
+
}, /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, {
|
|
20327
|
+
ref: inputRef,
|
|
20328
|
+
value: props.currentValue,
|
|
20329
|
+
keypadElement: props.keypadElement,
|
|
20330
|
+
onChange: handleChange,
|
|
20331
|
+
onFocus: handleFocus,
|
|
20332
|
+
onBlur: handleBlur
|
|
20333
|
+
}));
|
|
20334
|
+
}
|
|
20335
|
+
// (desktop-only) Otherwise, use the InputWithExamples component
|
|
20336
|
+
return /*#__PURE__*/React__namespace.createElement(InputWithExamples, {
|
|
20337
|
+
ref: inputRef,
|
|
20338
|
+
value: props.currentValue,
|
|
20339
|
+
onChange: handleChange,
|
|
20340
|
+
labelText: props.labelText,
|
|
20341
|
+
examples: generateExamples(props.answerForms, context.strings),
|
|
20342
|
+
shouldShowExamples: shouldShowExamples(props.answerForms),
|
|
20343
|
+
onFocus: handleFocus,
|
|
20344
|
+
onBlur: handleBlur,
|
|
20345
|
+
id: props.widgetId,
|
|
20346
|
+
disabled: props.apiOptions.readOnly,
|
|
20347
|
+
style: styles.inputWithExamples
|
|
20348
|
+
});
|
|
20349
|
+
});
|
|
20350
|
+
|
|
20351
|
+
/**
|
|
20352
|
+
* The NumericInput widget is a numeric input field that supports a variety of
|
|
20353
|
+
* answer forms, including integers, decimals, fractions, and mixed numbers.
|
|
20354
|
+
*
|
|
20355
|
+
* [Jan 2025] We're currenly migrating from class-based components to functional
|
|
20356
|
+
* components. While we cannot fully migrate this component yet, we can start
|
|
20357
|
+
* by using the functional component for the rendering the UI of the widget.
|
|
20358
|
+
*/
|
|
20459
20359
|
class NumericInput extends React__namespace.Component {
|
|
20460
|
-
|
|
20461
|
-
inputRef;
|
|
20360
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
20462
20361
|
static defaultProps = {
|
|
20463
20362
|
currentValue: "",
|
|
20464
20363
|
size: "normal",
|
|
@@ -20474,51 +20373,15 @@ class NumericInput extends React__namespace.Component {
|
|
|
20474
20373
|
currentValue: props.currentValue
|
|
20475
20374
|
};
|
|
20476
20375
|
}
|
|
20477
|
-
state = {
|
|
20478
|
-
// keeps track of the other set of values when switching
|
|
20479
|
-
// between 0 and finite solutions
|
|
20480
|
-
previousValues: [""],
|
|
20481
|
-
isFocused: false
|
|
20482
|
-
};
|
|
20483
|
-
|
|
20484
|
-
/**
|
|
20485
|
-
* Generates a string that demonstrates how to input the various supported
|
|
20486
|
-
* answer forms.
|
|
20487
|
-
*/
|
|
20488
|
-
examples() {
|
|
20489
|
-
// if the set of specified forms are empty, allow all forms
|
|
20490
|
-
const forms = this.props.answerForms?.length !== 0 ? this.props.answerForms : Object.keys(formExamples).map(name => {
|
|
20491
|
-
return {
|
|
20492
|
-
name: name,
|
|
20493
|
-
simplify: "required"
|
|
20494
|
-
};
|
|
20495
|
-
});
|
|
20496
|
-
let examples = ___default["default"].map(forms, form => {
|
|
20497
|
-
return formExamples[form.name](form, this.context.strings);
|
|
20498
|
-
});
|
|
20499
|
-
// Ensure no duplicate tooltip text from simplified and unsimplified
|
|
20500
|
-
// versions of the same format
|
|
20501
|
-
examples = ___default["default"].uniq(examples);
|
|
20502
|
-
return [this.context.strings.yourAnswer].concat(examples);
|
|
20503
|
-
}
|
|
20504
|
-
shouldShowExamples = () => {
|
|
20505
|
-
const noFormsAccepted = this.props.answerForms?.length === 0;
|
|
20506
|
-
// To check if all answer forms are accepted, we must first
|
|
20507
|
-
// find the *names* of all accepted forms, and see if they are
|
|
20508
|
-
// all present, ignoring duplicates
|
|
20509
|
-
const answerFormNames = ___default["default"].uniq(this.props.answerForms?.map(form => form.name));
|
|
20510
|
-
const allFormsAccepted = answerFormNames.length >= Object.keys(formExamples).length;
|
|
20511
|
-
return !noFormsAccepted && !allFormsAccepted;
|
|
20512
|
-
};
|
|
20513
20376
|
focus = () => {
|
|
20514
|
-
this.inputRef?.focus();
|
|
20377
|
+
this.inputRef.current?.focus();
|
|
20515
20378
|
return true;
|
|
20516
20379
|
};
|
|
20517
20380
|
focusInputPath = () => {
|
|
20518
|
-
this.inputRef?.focus();
|
|
20381
|
+
this.inputRef.current?.focus();
|
|
20519
20382
|
};
|
|
20520
20383
|
blurInputPath = () => {
|
|
20521
|
-
this.inputRef?.blur();
|
|
20384
|
+
this.inputRef.current?.blur();
|
|
20522
20385
|
};
|
|
20523
20386
|
getInputPaths = () => {
|
|
20524
20387
|
// The widget itself is an input, so we return a single empty list to
|
|
@@ -20526,152 +20389,57 @@ class NumericInput extends React__namespace.Component {
|
|
|
20526
20389
|
/* c8 ignore next */
|
|
20527
20390
|
return [[]];
|
|
20528
20391
|
};
|
|
20392
|
+
|
|
20393
|
+
/**
|
|
20394
|
+
* Sets the value of the input at the given path.
|
|
20395
|
+
*/
|
|
20529
20396
|
setInputValue = (path, newValue, cb) => {
|
|
20530
|
-
/* c8 ignore next */
|
|
20531
20397
|
this.props.onChange({
|
|
20532
20398
|
currentValue: newValue
|
|
20533
20399
|
}, cb);
|
|
20534
20400
|
};
|
|
20401
|
+
|
|
20402
|
+
/**
|
|
20403
|
+
* Returns the value the user has currently input for this widget.
|
|
20404
|
+
*/
|
|
20535
20405
|
getUserInput() {
|
|
20536
20406
|
return NumericInput.getUserInputFromProps(this.props);
|
|
20537
20407
|
}
|
|
20408
|
+
|
|
20409
|
+
/**
|
|
20410
|
+
* Returns the JSON representation of the prompt for this widget.
|
|
20411
|
+
* This is used by the AI to determine the prompt for the widget.
|
|
20412
|
+
*/
|
|
20538
20413
|
getPromptJSON() {
|
|
20539
20414
|
return getPromptJSON$r(this.props, this.getUserInput());
|
|
20540
20415
|
}
|
|
20541
|
-
handleChange = (newValue, cb) => {
|
|
20542
|
-
this.props.onChange({
|
|
20543
|
-
currentValue: newValue
|
|
20544
|
-
}, cb);
|
|
20545
|
-
this.props.trackInteraction();
|
|
20546
|
-
};
|
|
20547
|
-
_handleFocus = () => {
|
|
20548
|
-
this.props.onFocus([]);
|
|
20549
|
-
this.setState(currentState => {
|
|
20550
|
-
return {
|
|
20551
|
-
...currentState,
|
|
20552
|
-
isFocused: true
|
|
20553
|
-
};
|
|
20554
|
-
});
|
|
20555
|
-
};
|
|
20556
|
-
_handleBlur = () => {
|
|
20557
|
-
this.props.onBlur([]);
|
|
20558
|
-
this.setState(currentState => {
|
|
20559
|
-
return {
|
|
20560
|
-
...currentState,
|
|
20561
|
-
isFocused: false
|
|
20562
|
-
};
|
|
20563
|
-
});
|
|
20564
|
-
};
|
|
20565
20416
|
render() {
|
|
20566
|
-
|
|
20567
|
-
|
|
20568
|
-
|
|
20569
|
-
}
|
|
20570
|
-
|
|
20571
|
-
// To right align a custom keypad we need to wrap it.
|
|
20572
|
-
const maybeRightAlignKeypadInput = keypadInput => {
|
|
20573
|
-
return this.props.rightAlign ? /*#__PURE__*/React__namespace.createElement("div", {
|
|
20574
|
-
className: "perseus-input-right-align"
|
|
20575
|
-
}, keypadInput) : keypadInput;
|
|
20576
|
-
};
|
|
20577
|
-
if (this.props.apiOptions.customKeypad) {
|
|
20578
|
-
// TODO(charlie): Support "Review Mode".
|
|
20579
|
-
return maybeRightAlignKeypadInput( /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, {
|
|
20580
|
-
ref: ref => this.inputRef = ref,
|
|
20581
|
-
value: this.props.currentValue,
|
|
20582
|
-
keypadElement: this.props.keypadElement,
|
|
20583
|
-
onChange: this.handleChange,
|
|
20584
|
-
onFocus: this._handleFocus,
|
|
20585
|
-
onBlur: this._handleBlur
|
|
20586
|
-
}));
|
|
20587
|
-
}
|
|
20588
|
-
|
|
20589
|
-
// Note: This is _very_ similar to what `input-number.jsx` does. If
|
|
20590
|
-
// you modify this, double-check if you also need to modify that
|
|
20591
|
-
// component.
|
|
20592
|
-
const styles = aphrodite.StyleSheet.create({
|
|
20593
|
-
input: {
|
|
20594
|
-
borderRadius: "3px",
|
|
20595
|
-
borderWidth: this.state.isFocused ? "2px" : "1px",
|
|
20596
|
-
display: "inline-block",
|
|
20597
|
-
fontFamily: `Symbola, "Times New Roman", serif`,
|
|
20598
|
-
fontSize: "18px",
|
|
20599
|
-
height: "32px",
|
|
20600
|
-
lineHeight: "18px",
|
|
20601
|
-
padding: this.state.isFocused ? "4px" : "4px 5px",
|
|
20602
|
-
// account for added focus border thickness
|
|
20603
|
-
textAlign: this.props.rightAlign ? "right" : "left",
|
|
20604
|
-
width: this.props.size === "small" ? 40 : 80
|
|
20605
|
-
}
|
|
20606
|
-
});
|
|
20607
|
-
return /*#__PURE__*/React__namespace.createElement(InputWithExamples, {
|
|
20608
|
-
ref: ref => this.inputRef = ref,
|
|
20609
|
-
value: this.props.currentValue,
|
|
20610
|
-
onChange: this.handleChange,
|
|
20611
|
-
labelText: labelText,
|
|
20612
|
-
examples: this.examples(),
|
|
20613
|
-
shouldShowExamples: this.shouldShowExamples(),
|
|
20614
|
-
onFocus: this._handleFocus,
|
|
20615
|
-
onBlur: this._handleBlur,
|
|
20616
|
-
id: this.props.widgetId,
|
|
20617
|
-
disabled: this.props.apiOptions.readOnly,
|
|
20618
|
-
style: styles.input
|
|
20619
|
-
});
|
|
20417
|
+
return /*#__PURE__*/React__namespace.createElement(NumericInputComponent, _extends__default["default"]({}, this.props, {
|
|
20418
|
+
ref: this.inputRef
|
|
20419
|
+
}));
|
|
20620
20420
|
}
|
|
20621
20421
|
}
|
|
20622
|
-
|
|
20623
|
-
// TODO(thomas): Currently we receive a list of lists of acceptable answer types
|
|
20624
|
-
// and union them down into a single set. It's worth considering whether it
|
|
20625
|
-
// wouldn't make more sense to have a single set of acceptable answer types for
|
|
20626
|
-
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
20627
|
-
// When should two answers to a problem take different answer types?
|
|
20628
|
-
// See D27790 for more discussion.
|
|
20629
|
-
const unionAnswerForms = function (answerFormsList) {
|
|
20630
|
-
// Takes a list of lists of answer forms, and returns a list of the forms
|
|
20631
|
-
// in each of these lists in the same order that they're listed in the
|
|
20632
|
-
// `formExamples` forms from above.
|
|
20633
|
-
|
|
20634
|
-
// uniqueBy takes a list of elements and a function which compares whether
|
|
20635
|
-
// two elements are equal, and returns a list of unique elements. This is
|
|
20636
|
-
// just a helper function here, but works generally.
|
|
20637
|
-
const uniqueBy = function (list, iteratee) {
|
|
20638
|
-
// @ts-expect-error - TS2347 - Untyped function calls may not accept type arguments.
|
|
20639
|
-
return list.reduce((uniqueList, element) => {
|
|
20640
|
-
// For each element, decide whether it's already in the list of
|
|
20641
|
-
// unique items.
|
|
20642
|
-
const inList = ___default["default"].find(uniqueList, iteratee.bind(null, element));
|
|
20643
|
-
if (inList) {
|
|
20644
|
-
return uniqueList;
|
|
20645
|
-
}
|
|
20646
|
-
return uniqueList.concat([element]);
|
|
20647
|
-
}, []);
|
|
20648
|
-
};
|
|
20649
|
-
|
|
20650
|
-
// Pull out all of the forms from the different lists.
|
|
20651
|
-
const allForms = answerFormsList.flat();
|
|
20652
|
-
// Pull out the unique forms using uniqueBy.
|
|
20653
|
-
const uniqueForms = uniqueBy(allForms, ___default["default"].isEqual);
|
|
20654
|
-
// Sort them by the order they appear in the `formExamples` list.
|
|
20655
|
-
const formExampleKeys = Object.keys(formExamples);
|
|
20656
|
-
return ___default["default"].sortBy(uniqueForms, form => {
|
|
20657
|
-
return formExampleKeys.indexOf(form.name);
|
|
20658
|
-
});
|
|
20659
|
-
};
|
|
20422
|
+
// Transforms the widget options to the props used to render the widget.
|
|
20660
20423
|
const propsTransform = function (widgetOptions) {
|
|
20661
|
-
|
|
20424
|
+
// Omit the answers from the widget options since they are
|
|
20425
|
+
// not needed for rendering the widget.
|
|
20426
|
+
const {
|
|
20427
|
+
answers: _,
|
|
20428
|
+
...rendererProps
|
|
20429
|
+
} = {
|
|
20430
|
+
...widgetOptions,
|
|
20662
20431
|
answerForms: unionAnswerForms(
|
|
20663
|
-
//
|
|
20664
|
-
//
|
|
20665
|
-
widgetOptions.answers.map(answer => {
|
|
20666
|
-
|
|
20667
|
-
return ___default["default"].map(answer.answerForms, form => {
|
|
20432
|
+
// Filter out the correct answers and map them to the answer forms
|
|
20433
|
+
// so that we can generate the examples for the widget.
|
|
20434
|
+
widgetOptions.answers.filter(answer => answer.status === "correct").map(answer => {
|
|
20435
|
+
return (answer.answerForms || []).map(form => {
|
|
20668
20436
|
return {
|
|
20669
20437
|
simplify: answer.simplify,
|
|
20670
20438
|
name: form
|
|
20671
20439
|
};
|
|
20672
20440
|
});
|
|
20673
20441
|
}))
|
|
20674
|
-
}
|
|
20442
|
+
};
|
|
20675
20443
|
return rendererProps;
|
|
20676
20444
|
};
|
|
20677
20445
|
var NumericInput$1 = {
|
|
@@ -20686,23 +20454,11 @@ var NumericInput$1 = {
|
|
|
20686
20454
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
20687
20455
|
const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
|
|
20688
20456
|
const answerStrings = correctAnswers.map(answer => {
|
|
20689
|
-
//
|
|
20690
|
-
|
|
20691
|
-
let format = "decimal";
|
|
20692
|
-
if (answer.answerForms && answer.answerForms[0]) {
|
|
20693
|
-
// NOTE(johnsullivan): This isn't exactly ideal, but
|
|
20694
|
-
// it does behave well for all the currently known
|
|
20695
|
-
// problems. See D14742 for some discussion on
|
|
20696
|
-
// alternate strategies.
|
|
20697
|
-
format = answer.answerForms[0];
|
|
20698
|
-
}
|
|
20699
|
-
|
|
20700
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
20457
|
+
// Either get the first answer form or default to decimal
|
|
20458
|
+
const format = answer.answerForms && answer.answerForms[0] ? answer.answerForms[0] : "decimal";
|
|
20701
20459
|
let answerString = kmath.KhanMath.toNumericString(answer.value, format);
|
|
20702
20460
|
if (answer.maxError) {
|
|
20703
|
-
answerString += " \u00B1 " +
|
|
20704
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
20705
|
-
kmath.KhanMath.toNumericString(answer.maxError, format);
|
|
20461
|
+
answerString += " \u00B1 " + kmath.KhanMath.toNumericString(answer.maxError, format);
|
|
20706
20462
|
}
|
|
20707
20463
|
return answerString;
|
|
20708
20464
|
});
|
|
@@ -23237,6 +22993,7 @@ const BASE_ICON_SIZE = 10;
|
|
|
23237
22993
|
// If you pass in an object you need to specify an SVG path to
|
|
23238
22994
|
// render along with the width and height of the path (to ensure
|
|
23239
22995
|
// that it gets scaled correctly).
|
|
22996
|
+
|
|
23240
22997
|
/**
|
|
23241
22998
|
* An SVG Icon
|
|
23242
22999
|
*
|
|
@@ -23494,7 +23251,7 @@ function ChoiceInner(props) {
|
|
|
23494
23251
|
return /*#__PURE__*/React__namespace.createElement("span", null, letter);
|
|
23495
23252
|
}
|
|
23496
23253
|
if (correct) {
|
|
23497
|
-
return /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
23254
|
+
return /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconCheck, {
|
|
23498
23255
|
style: {
|
|
23499
23256
|
position: "relative",
|
|
23500
23257
|
top: -1
|
|
@@ -23950,7 +23707,7 @@ const styles$p = aphrodite.StyleSheet.create({
|
|
|
23950
23707
|
}
|
|
23951
23708
|
}
|
|
23952
23709
|
});
|
|
23953
|
-
var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(Choice,
|
|
23710
|
+
var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(Choice, _extends__default["default"]({}, props, {
|
|
23954
23711
|
forwardedRef: ref
|
|
23955
23712
|
})));
|
|
23956
23713
|
|
|
@@ -23984,11 +23741,11 @@ const ChoiceNoneAbove = function (_ref) {
|
|
|
23984
23741
|
strings: strings
|
|
23985
23742
|
})
|
|
23986
23743
|
};
|
|
23987
|
-
return /*#__PURE__*/React__namespace.createElement(Choice$1,
|
|
23744
|
+
return /*#__PURE__*/React__namespace.createElement(Choice$1, _extends__default["default"]({}, choiceProps, {
|
|
23988
23745
|
ref: forwardedRef
|
|
23989
23746
|
}));
|
|
23990
23747
|
};
|
|
23991
|
-
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove,
|
|
23748
|
+
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove, _extends__default["default"]({}, props, {
|
|
23992
23749
|
forwardedRef: ref
|
|
23993
23750
|
})));
|
|
23994
23751
|
|
|
@@ -24238,7 +23995,7 @@ const BaseRadio = function (_ref) {
|
|
|
24238
23995
|
className: className,
|
|
24239
23996
|
onClick: clickHandler,
|
|
24240
23997
|
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
24241
|
-
}, /*#__PURE__*/React__namespace.createElement(Element,
|
|
23998
|
+
}, /*#__PURE__*/React__namespace.createElement(Element, _extends__default["default"]({}, elementProps, {
|
|
24242
23999
|
ref: ref
|
|
24243
24000
|
})))
|
|
24244
24001
|
);
|
|
@@ -24330,7 +24087,6 @@ const styles$o = aphrodite.StyleSheet.create({
|
|
|
24330
24087
|
paddingLeft: phoneMargin
|
|
24331
24088
|
// paddingRight is handled by responsiveFieldset
|
|
24332
24089
|
},
|
|
24333
|
-
|
|
24334
24090
|
responsiveFieldset: {
|
|
24335
24091
|
paddingRight: phoneMargin,
|
|
24336
24092
|
minWidth: "auto"
|
|
@@ -24574,7 +24330,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24574
24330
|
);
|
|
24575
24331
|
}
|
|
24576
24332
|
};
|
|
24577
|
-
|
|
24578
24333
|
render() {
|
|
24579
24334
|
const {
|
|
24580
24335
|
choices
|
|
@@ -24751,7 +24506,7 @@ const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
|
24751
24506
|
// 1) we randomize the order first
|
|
24752
24507
|
_maybeRandomize(choices)));
|
|
24753
24508
|
};
|
|
24754
|
-
const transform = (widgetOptions, strings, problemNum) => {
|
|
24509
|
+
const transform$1 = (widgetOptions, strings, problemNum) => {
|
|
24755
24510
|
const choices = _choiceTransform(widgetOptions, strings, problemNum);
|
|
24756
24511
|
const numCorrect = ___default["default"].reduce(widgetOptions.choices, function (memo, choice) {
|
|
24757
24512
|
return choice.correct ? memo + 1 : memo;
|
|
@@ -24777,8 +24532,8 @@ var Radio = {
|
|
|
24777
24532
|
displayName: "Radio / Multiple choice",
|
|
24778
24533
|
accessible: true,
|
|
24779
24534
|
widget: Radio$1,
|
|
24780
|
-
transform: transform,
|
|
24781
|
-
staticTransform: transform,
|
|
24535
|
+
transform: transform$1,
|
|
24536
|
+
staticTransform: transform$1,
|
|
24782
24537
|
version: perseusCore.radioLogic.version,
|
|
24783
24538
|
propUpgrades: perseusCore.radioLogic.widgetOptionsUpgrades,
|
|
24784
24539
|
isLintable: true
|
|
@@ -25360,6 +25115,7 @@ var Definition$1 = {
|
|
|
25360
25115
|
|
|
25361
25116
|
// There are no required props, but this component can receive props from any
|
|
25362
25117
|
// deprecated widget
|
|
25118
|
+
|
|
25363
25119
|
class DeprecatedStandin extends React__default["default"].Component {
|
|
25364
25120
|
static contextType = PerseusI18nContext;
|
|
25365
25121
|
// this just helps with TS weak typing when a Widget
|
|
@@ -25480,20 +25236,20 @@ class Dropdown extends React__namespace.Component {
|
|
|
25480
25236
|
}, children)));
|
|
25481
25237
|
}
|
|
25482
25238
|
}
|
|
25483
|
-
|
|
25239
|
+
function transform(widgetOptions) {
|
|
25484
25240
|
return {
|
|
25485
25241
|
placeholder: widgetOptions.placeholder,
|
|
25486
25242
|
visibleLabel: widgetOptions.visibleLabel,
|
|
25487
25243
|
ariaLabel: widgetOptions.ariaLabel,
|
|
25488
25244
|
choices: widgetOptions.choices.map(choice => choice.content)
|
|
25489
25245
|
};
|
|
25490
|
-
}
|
|
25246
|
+
}
|
|
25491
25247
|
var Dropdown$1 = {
|
|
25492
25248
|
name: "dropdown",
|
|
25493
25249
|
displayName: "Drop down",
|
|
25494
25250
|
accessible: true,
|
|
25495
25251
|
widget: Dropdown,
|
|
25496
|
-
transform
|
|
25252
|
+
transform
|
|
25497
25253
|
};
|
|
25498
25254
|
|
|
25499
25255
|
const getPromptJSON$j = renderProps => {
|
|
@@ -25569,7 +25325,6 @@ class Explanation extends React__namespace.Component {
|
|
|
25569
25325
|
// adds space between the right border and any text that follows
|
|
25570
25326
|
paddingLeft: "2px" // adds space between the left border and the button text
|
|
25571
25327
|
};
|
|
25572
|
-
|
|
25573
25328
|
const labelStyle = {
|
|
25574
25329
|
fontSize: "18px",
|
|
25575
25330
|
lineHeight: "inherit",
|
|
@@ -25725,7 +25480,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
25725
25480
|
fontSize: 28,
|
|
25726
25481
|
color: wonderBlocksTokens.color.green
|
|
25727
25482
|
}
|
|
25728
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25483
|
+
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconStar, {
|
|
25729
25484
|
style: {
|
|
25730
25485
|
marginBottom: 5
|
|
25731
25486
|
}
|
|
@@ -25918,7 +25673,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25918
25673
|
if (this.state.status === GRADING_STATUSES.correct) {
|
|
25919
25674
|
// TODO(jeremy): update to a WB colour
|
|
25920
25675
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
25921
|
-
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25676
|
+
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconOk, {
|
|
25922
25677
|
style: {
|
|
25923
25678
|
color: "#526f03"
|
|
25924
25679
|
}
|
|
@@ -25927,7 +25682,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25927
25682
|
} else if (this.state.status === GRADING_STATUSES.incorrect) {
|
|
25928
25683
|
// TODO(jeremy): update to a WB colour
|
|
25929
25684
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
25930
|
-
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25685
|
+
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconRemove, {
|
|
25931
25686
|
style: {
|
|
25932
25687
|
color: "#ff5454"
|
|
25933
25688
|
}
|
|
@@ -25954,7 +25709,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25954
25709
|
className: classes
|
|
25955
25710
|
}, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
|
|
25956
25711
|
className: aphrodite.css(styles$i.title)
|
|
25957
|
-
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
25712
|
+
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, this.props, {
|
|
25958
25713
|
ref: this.rendererRef,
|
|
25959
25714
|
apiOptions: {
|
|
25960
25715
|
...apiOptions,
|
|
@@ -25997,7 +25752,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25997
25752
|
showHint: false
|
|
25998
25753
|
});
|
|
25999
25754
|
}
|
|
26000
|
-
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
25755
|
+
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, this.props.hint, {
|
|
26001
25756
|
ref: this.hintRendererRef,
|
|
26002
25757
|
apiOptions: apiOptions,
|
|
26003
25758
|
linterContext: this.props.linterContext,
|
|
@@ -26222,7 +25977,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
26222
25977
|
// TODO(jeremy): Don't spread this.props, instead
|
|
26223
25978
|
// pass in all props GradedGroup needs explicilty
|
|
26224
25979
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
26225
|
-
React__namespace.createElement(GradedGroup,
|
|
25980
|
+
React__namespace.createElement(GradedGroup, _extends__default["default"]({
|
|
26226
25981
|
key: i
|
|
26227
25982
|
}, this.props, gradedGroup, {
|
|
26228
25983
|
inGradedGroupSet: false,
|
|
@@ -26251,7 +26006,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
26251
26006
|
onChangeCurrentGroup: currentGroup => this.setState({
|
|
26252
26007
|
currentGroup
|
|
26253
26008
|
})
|
|
26254
|
-
})), /*#__PURE__*/React__namespace.createElement(GradedGroup,
|
|
26009
|
+
})), /*#__PURE__*/React__namespace.createElement(GradedGroup, _extends__default["default"]({
|
|
26255
26010
|
key: this.state.currentGroup
|
|
26256
26011
|
// @ts-expect-error - TS2322 - Type 'GradedGroup | null' is not assignable to type 'GradedGroup'.
|
|
26257
26012
|
// Type 'null' is not assignable to type 'GradedGroup'.
|
|
@@ -26647,7 +26402,7 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26647
26402
|
}
|
|
26648
26403
|
const functionProps = model.getPropsForCoeffs(coeffs, xRange);
|
|
26649
26404
|
const Movable = movableTypeToComponent[model.movable];
|
|
26650
|
-
return /*#__PURE__*/React__namespace.createElement(Movable,
|
|
26405
|
+
return /*#__PURE__*/React__namespace.createElement(Movable, _extends__default["default"]({}, functionProps, {
|
|
26651
26406
|
key: this.props.model.url,
|
|
26652
26407
|
range: xRange,
|
|
26653
26408
|
style: style
|
|
@@ -26780,7 +26535,7 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26780
26535
|
width: box[0],
|
|
26781
26536
|
height: box[1]
|
|
26782
26537
|
}
|
|
26783
|
-
}, image, /*#__PURE__*/React__namespace.createElement(Graphie,
|
|
26538
|
+
}, image, /*#__PURE__*/React__namespace.createElement(Graphie, _extends__default["default"]({}, this.props.graph, {
|
|
26784
26539
|
setDrawingAreaAvailable: this.props.setDrawingAreaAvailable
|
|
26785
26540
|
}), this.props.model && this.renderPlot(), this.props.model && this.renderAsymptote(), this.props.model && points)));
|
|
26786
26541
|
}
|
|
@@ -27924,7 +27679,6 @@ class Interaction extends React__namespace.Component {
|
|
|
27924
27679
|
}
|
|
27925
27680
|
});
|
|
27926
27681
|
}
|
|
27927
|
-
|
|
27928
27682
|
if (element.type === "parametric") {
|
|
27929
27683
|
const fn = t => {
|
|
27930
27684
|
return [
|
|
@@ -27977,7 +27731,6 @@ class Interaction extends React__namespace.Component {
|
|
|
27977
27731
|
}
|
|
27978
27732
|
});
|
|
27979
27733
|
}
|
|
27980
|
-
|
|
27981
27734
|
if (element.type === "label") {
|
|
27982
27735
|
const coord = [
|
|
27983
27736
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
@@ -28309,7 +28062,6 @@ function scaleCommandBy(scaleFactor) {
|
|
|
28309
28062
|
command.args[6] * scaleFactor // end y
|
|
28310
28063
|
]
|
|
28311
28064
|
};
|
|
28312
|
-
|
|
28313
28065
|
default:
|
|
28314
28066
|
return {
|
|
28315
28067
|
...command,
|
|
@@ -29069,7 +28821,6 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
29069
28821
|
userSelect: "none",
|
|
29070
28822
|
borderWidth: 0 // <button> gives us a border by default
|
|
29071
28823
|
},
|
|
29072
|
-
|
|
29073
28824
|
// We want to render the element in-place in our fixtures, so allow us to
|
|
29074
28825
|
// render in the bottom corner in production and in-place in testing.
|
|
29075
28826
|
hudFixedPosition: {
|
|
@@ -29099,7 +28850,6 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
29099
28850
|
":hover": {
|
|
29100
28851
|
backgroundColor: "#a1a5a9" // in between those two grays
|
|
29101
28852
|
},
|
|
29102
|
-
|
|
29103
28853
|
":active": {
|
|
29104
28854
|
backgroundColor: gray68
|
|
29105
28855
|
}
|
|
@@ -29144,7 +28894,6 @@ class InfoTip extends React__namespace.Component {
|
|
|
29144
28894
|
});
|
|
29145
28895
|
/* eslint-enable react/no-did-mount-set-state */
|
|
29146
28896
|
}
|
|
29147
|
-
|
|
29148
28897
|
render() {
|
|
29149
28898
|
if (this.state.didMount) {
|
|
29150
28899
|
return /*#__PURE__*/React__namespace.createElement(InfoTipBase, this.props);
|
|
@@ -29410,7 +29159,6 @@ class NumberInput extends React__namespace.Component {
|
|
|
29410
29159
|
if (val !== Math.floor(val)) {
|
|
29411
29160
|
return; // bail if not an integer
|
|
29412
29161
|
}
|
|
29413
|
-
|
|
29414
29162
|
if (e.key === "ArrowUp") {
|
|
29415
29163
|
val = val + 1;
|
|
29416
29164
|
} else if (e.key === "ArrowDown") {
|
|
@@ -29443,7 +29191,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
29443
29191
|
useArrowKeys,
|
|
29444
29192
|
...restProps
|
|
29445
29193
|
} = this.props;
|
|
29446
|
-
return /*#__PURE__*/React__namespace.createElement("input",
|
|
29194
|
+
return /*#__PURE__*/React__namespace.createElement("input", _extends__default["default"]({}, restProps, {
|
|
29447
29195
|
className: classes,
|
|
29448
29196
|
type: "text",
|
|
29449
29197
|
ref: this.inputRef,
|
|
@@ -29488,7 +29236,7 @@ class RangeInput extends React__namespace.Component {
|
|
|
29488
29236
|
const checkValidity = this.props.checkValidity || truth;
|
|
29489
29237
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
29490
29238
|
className: "range-input"
|
|
29491
|
-
}, /*#__PURE__*/React__namespace.createElement(NumberInput,
|
|
29239
|
+
}, /*#__PURE__*/React__namespace.createElement(NumberInput, _extends__default["default"]({}, this.props, {
|
|
29492
29240
|
value: value[0],
|
|
29493
29241
|
checkValidity: val => checkValidity([val, value[1]])
|
|
29494
29242
|
// eslint-disable-next-line react/jsx-no-bind
|
|
@@ -29496,7 +29244,7 @@ class RangeInput extends React__namespace.Component {
|
|
|
29496
29244
|
onChange: this.onChange.bind(this, 0),
|
|
29497
29245
|
placeholder: this.props.placeholder[0],
|
|
29498
29246
|
allowPiTruncation: this.props.allowPiTruncation
|
|
29499
|
-
})), /*#__PURE__*/React__namespace.createElement(NumberInput,
|
|
29247
|
+
})), /*#__PURE__*/React__namespace.createElement(NumberInput, _extends__default["default"]({}, this.props, {
|
|
29500
29248
|
value: value[1],
|
|
29501
29249
|
checkValidity: val => checkValidity([value[0], val])
|
|
29502
29250
|
// eslint-disable-next-line react/jsx-no-bind
|
|
@@ -29509,20 +29257,20 @@ class RangeInput extends React__namespace.Component {
|
|
|
29509
29257
|
}
|
|
29510
29258
|
|
|
29511
29259
|
var components = /*#__PURE__*/Object.freeze({
|
|
29512
|
-
|
|
29513
|
-
|
|
29514
|
-
|
|
29515
|
-
|
|
29516
|
-
|
|
29517
|
-
|
|
29518
|
-
|
|
29519
|
-
|
|
29520
|
-
|
|
29521
|
-
|
|
29522
|
-
|
|
29523
|
-
|
|
29524
|
-
|
|
29525
|
-
|
|
29260
|
+
__proto__: null,
|
|
29261
|
+
ButtonGroup: ButtonGroup,
|
|
29262
|
+
Graphie: Graphie,
|
|
29263
|
+
HUD: HUD,
|
|
29264
|
+
Icon: Icon,
|
|
29265
|
+
InfoTip: InfoTip,
|
|
29266
|
+
InlineIcon: InlineIcon,
|
|
29267
|
+
MathInput: MathInput,
|
|
29268
|
+
MultiButtonGroup: MultiButtonGroup,
|
|
29269
|
+
NumberInput: NumberInput,
|
|
29270
|
+
RangeInput: RangeInput,
|
|
29271
|
+
SvgImage: SvgImage,
|
|
29272
|
+
TextInput: TextInput,
|
|
29273
|
+
TextListEditor: TextListEditor
|
|
29526
29274
|
});
|
|
29527
29275
|
|
|
29528
29276
|
/**
|
|
@@ -29598,17 +29346,17 @@ function GraphLockedLabelsLayer(props) {
|
|
|
29598
29346
|
} = props;
|
|
29599
29347
|
return lockedFigures.map((figure, i) => {
|
|
29600
29348
|
if (figure.type === "label") {
|
|
29601
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29349
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29602
29350
|
key: `label-${i}`
|
|
29603
29351
|
}, figure));
|
|
29604
29352
|
}
|
|
29605
29353
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, {
|
|
29606
29354
|
key: i
|
|
29607
|
-
}, figure.labels?.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29355
|
+
}, figure.labels?.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29608
29356
|
key: `${i}-label-${j}`
|
|
29609
|
-
}, label))), figure.type === "line" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, figure.points[0].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29357
|
+
}, label))), figure.type === "line" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, figure.points[0].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29610
29358
|
key: `locked-figure-${i}-point-1-label-${k}`
|
|
29611
|
-
}, label))), figure.points[1].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29359
|
+
}, label))), figure.points[1].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29612
29360
|
key: `locked-figure-${i}-point-2-label-${k}`
|
|
29613
29361
|
}, label)))));
|
|
29614
29362
|
});
|
|
@@ -29654,9 +29402,9 @@ const LockedFunction = props => {
|
|
|
29654
29402
|
const {
|
|
29655
29403
|
color,
|
|
29656
29404
|
strokeStyle,
|
|
29657
|
-
directionalAxis
|
|
29405
|
+
directionalAxis,
|
|
29406
|
+
domain
|
|
29658
29407
|
} = props;
|
|
29659
|
-
const domain = props.domain ? [Number.isFinite(props.domain[0]) ? props.domain[0] : -Infinity, Number.isFinite(props.domain[1]) ? props.domain[1] : Infinity] : undefined;
|
|
29660
29408
|
const plotProps = {
|
|
29661
29409
|
color: perseusCore.lockedFigureColors[color],
|
|
29662
29410
|
style: strokeStyle,
|
|
@@ -29676,11 +29424,11 @@ const LockedFunction = props => {
|
|
|
29676
29424
|
"aria-label": hasAria ? props.ariaLabel : undefined,
|
|
29677
29425
|
"aria-hidden": !hasAria,
|
|
29678
29426
|
role: "img"
|
|
29679
|
-
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX,
|
|
29427
|
+
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, _extends__default["default"]({
|
|
29680
29428
|
y: x => equation.eval({
|
|
29681
29429
|
x
|
|
29682
29430
|
})
|
|
29683
|
-
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY,
|
|
29431
|
+
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY, _extends__default["default"]({
|
|
29684
29432
|
x: y => equation.eval({
|
|
29685
29433
|
y
|
|
29686
29434
|
})
|
|
@@ -30254,28 +30002,28 @@ const GraphLockedLayer = props => {
|
|
|
30254
30002
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lockedFigures.map((figure, index) => {
|
|
30255
30003
|
switch (figure.type) {
|
|
30256
30004
|
case "point":
|
|
30257
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPoint,
|
|
30005
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPoint, _extends__default["default"]({
|
|
30258
30006
|
key: `point-${index}`
|
|
30259
30007
|
}, figure));
|
|
30260
30008
|
case "line":
|
|
30261
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLine,
|
|
30009
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLine, _extends__default["default"]({
|
|
30262
30010
|
key: `line-${index}`,
|
|
30263
30011
|
range: props.range
|
|
30264
30012
|
}, figure));
|
|
30265
30013
|
case "vector":
|
|
30266
|
-
return /*#__PURE__*/React__namespace.createElement(LockedVector,
|
|
30014
|
+
return /*#__PURE__*/React__namespace.createElement(LockedVector, _extends__default["default"]({
|
|
30267
30015
|
key: `vector-${index}`
|
|
30268
30016
|
}, figure));
|
|
30269
30017
|
case "ellipse":
|
|
30270
|
-
return /*#__PURE__*/React__namespace.createElement(LockedEllipse,
|
|
30018
|
+
return /*#__PURE__*/React__namespace.createElement(LockedEllipse, _extends__default["default"]({
|
|
30271
30019
|
key: `ellipse-${index}`
|
|
30272
30020
|
}, figure));
|
|
30273
30021
|
case "polygon":
|
|
30274
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPolygon,
|
|
30022
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPolygon, _extends__default["default"]({
|
|
30275
30023
|
key: `polygon-${index}`
|
|
30276
30024
|
}, figure));
|
|
30277
30025
|
case "function":
|
|
30278
|
-
return /*#__PURE__*/React__namespace.createElement(LockedFunction,
|
|
30026
|
+
return /*#__PURE__*/React__namespace.createElement(LockedFunction, _extends__default["default"]({
|
|
30279
30027
|
key: `function-${index}`
|
|
30280
30028
|
}, figure));
|
|
30281
30029
|
case "label":
|
|
@@ -30506,7 +30254,7 @@ const TextLabel = _ref => {
|
|
|
30506
30254
|
children,
|
|
30507
30255
|
...rest
|
|
30508
30256
|
} = _ref;
|
|
30509
|
-
return /*#__PURE__*/React__default["default"].createElement(mafs.Text,
|
|
30257
|
+
return /*#__PURE__*/React__default["default"].createElement(mafs.Text, _extends__default["default"]({
|
|
30510
30258
|
size: 16,
|
|
30511
30259
|
svgTextProps: {
|
|
30512
30260
|
filter: "url(#background)",
|
|
@@ -31217,6 +30965,9 @@ const MovableLine = props => {
|
|
|
31217
30965
|
onMoveLine = () => {},
|
|
31218
30966
|
onMovePoint = () => {}
|
|
31219
30967
|
} = props;
|
|
30968
|
+
const {
|
|
30969
|
+
snapStep
|
|
30970
|
+
} = useGraphConfig();
|
|
31220
30971
|
|
|
31221
30972
|
// Aria live states for (0) point 1, (1) point 2, and (2) grab handle.
|
|
31222
30973
|
// When moving an element, set its aria live to "polite" and the others
|
|
@@ -31248,7 +30999,8 @@ const MovableLine = props => {
|
|
|
31248
30999
|
onMove: p => {
|
|
31249
31000
|
setAriaLives(["polite", "off", "off"]);
|
|
31250
31001
|
onMovePoint(0, p);
|
|
31251
|
-
}
|
|
31002
|
+
},
|
|
31003
|
+
constrain: getMovableLineKeyboardConstraint([start, end], snapStep, 0)
|
|
31252
31004
|
});
|
|
31253
31005
|
const {
|
|
31254
31006
|
visiblePoint: visiblePoint2,
|
|
@@ -31263,7 +31015,8 @@ const MovableLine = props => {
|
|
|
31263
31015
|
onMove: p => {
|
|
31264
31016
|
setAriaLives(["off", "polite", "off"]);
|
|
31265
31017
|
onMovePoint(1, p);
|
|
31266
|
-
}
|
|
31018
|
+
},
|
|
31019
|
+
constrain: getMovableLineKeyboardConstraint([start, end], snapStep, 1)
|
|
31267
31020
|
});
|
|
31268
31021
|
const line = /*#__PURE__*/React__namespace.createElement(Line$1, {
|
|
31269
31022
|
ariaLabel: ariaLabels?.grabHandleAriaLabel,
|
|
@@ -31369,6 +31122,34 @@ const Line$1 = props => {
|
|
|
31369
31122
|
color: stroke
|
|
31370
31123
|
}));
|
|
31371
31124
|
};
|
|
31125
|
+
const getMovableLineKeyboardConstraint = (line, snapStep, pointIndex) => {
|
|
31126
|
+
// Separate the two points into their own variables, and determine which point is being moved
|
|
31127
|
+
const coordToBeMoved = line[pointIndex];
|
|
31128
|
+
const otherPoint = line[1 - pointIndex];
|
|
31129
|
+
|
|
31130
|
+
// Create a helper function that moves the point and then checks
|
|
31131
|
+
// if it overlaps with the other point in the line after the move.
|
|
31132
|
+
const movePointWithConstraint = moveFunc => {
|
|
31133
|
+
// Move the point
|
|
31134
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
31135
|
+
// If the moved point overlaps with the other point in the line,
|
|
31136
|
+
// move the point again.
|
|
31137
|
+
if (mafs.vec.dist(movedCoord, otherPoint) === 0) {
|
|
31138
|
+
movedCoord = moveFunc(movedCoord);
|
|
31139
|
+
}
|
|
31140
|
+
return movedCoord;
|
|
31141
|
+
};
|
|
31142
|
+
|
|
31143
|
+
// Check if the new point will overlap the other point.
|
|
31144
|
+
// If it will, we need to snap the point to the left or right an additional
|
|
31145
|
+
// snapStep to avoid overlap.
|
|
31146
|
+
return {
|
|
31147
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
31148
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
31149
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
31150
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
31151
|
+
};
|
|
31152
|
+
};
|
|
31372
31153
|
function trimRange(range, graphDimensionsInPixels) {
|
|
31373
31154
|
const pixelsToTrim = 4;
|
|
31374
31155
|
const [xRange, yRange] = range;
|
|
@@ -31725,7 +31506,8 @@ function CircleGraph(props) {
|
|
|
31725
31506
|
} = props;
|
|
31726
31507
|
const {
|
|
31727
31508
|
center,
|
|
31728
|
-
radiusPoint
|
|
31509
|
+
radiusPoint,
|
|
31510
|
+
snapStep
|
|
31729
31511
|
} = graphState;
|
|
31730
31512
|
const {
|
|
31731
31513
|
strings,
|
|
@@ -31788,7 +31570,8 @@ function CircleGraph(props) {
|
|
|
31788
31570
|
onMove: newRadiusPoint => {
|
|
31789
31571
|
setRadiusPointAriaLive("polite");
|
|
31790
31572
|
dispatch(actions.circle.moveRadiusPoint(newRadiusPoint));
|
|
31791
|
-
}
|
|
31573
|
+
},
|
|
31574
|
+
constrain: getCircleKeyboardConstraint(center, radiusPoint, snapStep)
|
|
31792
31575
|
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
31793
31576
|
id: radiusId,
|
|
31794
31577
|
style: a11y.srOnly
|
|
@@ -31899,6 +31682,30 @@ function getCircleGraphDescription(state, i18n) {
|
|
|
31899
31682
|
const strings = describeCircleGraph(state, i18n);
|
|
31900
31683
|
return strings.srCircleInteractiveElement;
|
|
31901
31684
|
}
|
|
31685
|
+
const getCircleKeyboardConstraint = (center, radiusPoint, snapStep) => {
|
|
31686
|
+
// Create a helper function that moves the point and then checks
|
|
31687
|
+
// if it overlaps with the center point after the move.
|
|
31688
|
+
const movePointWithConstraint = moveFunc => {
|
|
31689
|
+
// Move the point
|
|
31690
|
+
let movedCoord = moveFunc(radiusPoint);
|
|
31691
|
+
// If the moved point overlaps with the center point,
|
|
31692
|
+
// move the point again.
|
|
31693
|
+
if (mafs.vec.dist(movedCoord, center) === 0) {
|
|
31694
|
+
movedCoord = moveFunc(movedCoord);
|
|
31695
|
+
}
|
|
31696
|
+
return movedCoord;
|
|
31697
|
+
};
|
|
31698
|
+
|
|
31699
|
+
// Check if the new point overlaps the center point.
|
|
31700
|
+
// If it does, we need to snap the point to the left
|
|
31701
|
+
// or right an additional snapStep to avoid the overlap.
|
|
31702
|
+
return {
|
|
31703
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
31704
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
31705
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
31706
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
31707
|
+
};
|
|
31708
|
+
};
|
|
31902
31709
|
|
|
31903
31710
|
// Exported for testing
|
|
31904
31711
|
function describeCircleGraph(state, i18n) {
|
|
@@ -31911,6 +31718,7 @@ function describeCircleGraph(state, i18n) {
|
|
|
31911
31718
|
radiusPoint
|
|
31912
31719
|
} = state;
|
|
31913
31720
|
const radius = getRadius(state);
|
|
31721
|
+
const isRadiusOnRight = radiusPoint[X] >= center[X];
|
|
31914
31722
|
|
|
31915
31723
|
// Aria label strings
|
|
31916
31724
|
const srCircleGraph = strings.srCircleGraph;
|
|
@@ -31918,7 +31726,10 @@ function describeCircleGraph(state, i18n) {
|
|
|
31918
31726
|
centerX: srFormatNumber(center[0], locale),
|
|
31919
31727
|
centerY: srFormatNumber(center[1], locale)
|
|
31920
31728
|
});
|
|
31921
|
-
const srCircleRadiusPoint = strings.
|
|
31729
|
+
const srCircleRadiusPoint = isRadiusOnRight ? strings.srCircleRadiusPointRight({
|
|
31730
|
+
radiusPointX: srFormatNumber(radiusPoint[0], locale),
|
|
31731
|
+
radiusPointY: srFormatNumber(radiusPoint[1], locale)
|
|
31732
|
+
}) : strings.srCircleRadiusPointLeft({
|
|
31922
31733
|
radiusPointX: srFormatNumber(radiusPoint[0], locale),
|
|
31923
31734
|
radiusPointY: srFormatNumber(radiusPoint[1], locale)
|
|
31924
31735
|
});
|
|
@@ -32084,6 +31895,12 @@ const LinearSystemGraph = props => {
|
|
|
32084
31895
|
locale
|
|
32085
31896
|
} = usePerseusI18n();
|
|
32086
31897
|
const id = React__namespace.useId();
|
|
31898
|
+
const intersectionId = `${id}-intersection`;
|
|
31899
|
+
const intersectionPoint = kmath.geometry.getLineIntersection(lines[0], lines[1]);
|
|
31900
|
+
const intersectionDescription = intersectionPoint ? strings.srLinearSystemIntersection({
|
|
31901
|
+
x: srFormatNumber(intersectionPoint[0], locale),
|
|
31902
|
+
y: srFormatNumber(intersectionPoint[1], locale)
|
|
31903
|
+
}) : strings.srLinearSystemParallel;
|
|
32087
31904
|
const linesAriaInfo = lines.map((line, i) => {
|
|
32088
31905
|
return {
|
|
32089
31906
|
pointsDescriptionId: `${id}-line${i + 1}-points`,
|
|
@@ -32100,16 +31917,17 @@ const LinearSystemGraph = props => {
|
|
|
32100
31917
|
slopeDescription: getSlopeStringForLine(line, strings)
|
|
32101
31918
|
};
|
|
32102
31919
|
});
|
|
31920
|
+
const individualLineDescriptions = linesAriaInfo.map(_ref => {
|
|
31921
|
+
let {
|
|
31922
|
+
pointsDescriptionId,
|
|
31923
|
+
interceptDescriptionId,
|
|
31924
|
+
slopeDescriptionId
|
|
31925
|
+
} = _ref;
|
|
31926
|
+
return `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`;
|
|
31927
|
+
}).join(" ");
|
|
32103
31928
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
32104
31929
|
"aria-label": strings.srLinearSystemGraph,
|
|
32105
|
-
"aria-describedby":
|
|
32106
|
-
let {
|
|
32107
|
-
pointsDescriptionId,
|
|
32108
|
-
interceptDescriptionId,
|
|
32109
|
-
slopeDescriptionId
|
|
32110
|
-
} = _ref;
|
|
32111
|
-
return `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`;
|
|
32112
|
-
}).join(" ")
|
|
31930
|
+
"aria-describedby": `${individualLineDescriptions} ${intersectionId}`
|
|
32113
31931
|
}, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
32114
31932
|
key: i,
|
|
32115
31933
|
points: line,
|
|
@@ -32126,9 +31944,15 @@ const LinearSystemGraph = props => {
|
|
|
32126
31944
|
x: srFormatNumber(line[1][0], locale),
|
|
32127
31945
|
y: srFormatNumber(line[1][1], locale)
|
|
32128
31946
|
}),
|
|
32129
|
-
grabHandleAriaLabel:
|
|
31947
|
+
grabHandleAriaLabel: strings.srLinearSystemGrabHandle({
|
|
31948
|
+
lineNumber: i + 1,
|
|
31949
|
+
point1X: srFormatNumber(line[0][0], locale),
|
|
31950
|
+
point1Y: srFormatNumber(line[0][1], locale),
|
|
31951
|
+
point2X: srFormatNumber(line[1][0], locale),
|
|
31952
|
+
point2Y: srFormatNumber(line[1][1], locale)
|
|
31953
|
+
})
|
|
32130
31954
|
},
|
|
32131
|
-
ariaDescribedBy: `${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId}`,
|
|
31955
|
+
ariaDescribedBy: `${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId} ${intersectionId}`,
|
|
32132
31956
|
onMoveLine: delta => {
|
|
32133
31957
|
dispatch(actions.linearSystem.moveLine(i, delta));
|
|
32134
31958
|
},
|
|
@@ -32160,7 +31984,10 @@ const LinearSystemGraph = props => {
|
|
|
32160
31984
|
id: slopeDescriptionId,
|
|
32161
31985
|
style: a11y.srOnly
|
|
32162
31986
|
}, slopeDescription));
|
|
32163
|
-
})
|
|
31987
|
+
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
31988
|
+
id: intersectionId,
|
|
31989
|
+
style: a11y.srOnly
|
|
31990
|
+
}, intersectionDescription));
|
|
32164
31991
|
};
|
|
32165
31992
|
|
|
32166
31993
|
// Exported for testing
|
|
@@ -32826,7 +32653,8 @@ function QuadraticGraph(props) {
|
|
|
32826
32653
|
graphState
|
|
32827
32654
|
} = props;
|
|
32828
32655
|
const {
|
|
32829
|
-
coords
|
|
32656
|
+
coords,
|
|
32657
|
+
snapStep
|
|
32830
32658
|
} = graphState;
|
|
32831
32659
|
const {
|
|
32832
32660
|
strings,
|
|
@@ -32879,6 +32707,7 @@ function QuadraticGraph(props) {
|
|
|
32879
32707
|
ariaLabel: `${srQuadraticPoint}${srVertex}`,
|
|
32880
32708
|
point: coord,
|
|
32881
32709
|
sequenceNumber: i + 1,
|
|
32710
|
+
constrain: getQuadraticKeyboardConstraint(coords, snapStep, i),
|
|
32882
32711
|
onMove: destination => dispatch(actions.quadratic.movePoint(i, destination))
|
|
32883
32712
|
});
|
|
32884
32713
|
}), srQuadraticDirection && /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -32967,6 +32796,60 @@ function describeQuadraticGraph(state, i18n) {
|
|
|
32967
32796
|
srQuadraticInteractiveElements
|
|
32968
32797
|
};
|
|
32969
32798
|
}
|
|
32799
|
+
const getQuadraticKeyboardConstraint = (coords, snapStep, pointMoved) => {
|
|
32800
|
+
// Make newCoords mutable
|
|
32801
|
+
const newCoords = [coords[0], coords[1], coords[2]];
|
|
32802
|
+
|
|
32803
|
+
// Get the point that is being moved
|
|
32804
|
+
const coordToBeMoved = newCoords[pointMoved];
|
|
32805
|
+
|
|
32806
|
+
// Create a function to validate and adjust the movement of the point
|
|
32807
|
+
const movePointWithConstraint = moveFunc => {
|
|
32808
|
+
// Move the point the desired direction
|
|
32809
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
32810
|
+
newCoords[pointMoved] = movedCoord;
|
|
32811
|
+
|
|
32812
|
+
// If these new coordinates are valid, return the moved coord
|
|
32813
|
+
if (areCoordsValid(newCoords)) {
|
|
32814
|
+
return movedCoord;
|
|
32815
|
+
}
|
|
32816
|
+
|
|
32817
|
+
// If the new coordinates are invalid, we need to move the point an additional
|
|
32818
|
+
// snapStep to avoid creating an invalid quadratic graph.
|
|
32819
|
+
movedCoord = moveFunc(movedCoord);
|
|
32820
|
+
newCoords[pointMoved] = movedCoord;
|
|
32821
|
+
|
|
32822
|
+
// If these updated coordinates are valid now, we can return the new coordinates.
|
|
32823
|
+
if (areCoordsValid(newCoords)) {
|
|
32824
|
+
return movedCoord;
|
|
32825
|
+
}
|
|
32826
|
+
|
|
32827
|
+
// Otherwise, if the new coordinates are still invalid, we need to move the point one final snapStep.
|
|
32828
|
+
// This is to support the edge case where all of the points are each exactly one snapStep away
|
|
32829
|
+
// from each other.
|
|
32830
|
+
// Eg. When coords = [[0, 0], [1, 0], [2, 0]], snapStep = [1, 1], and we're moving coords[0] to the right.
|
|
32831
|
+
return moveFunc(movedCoord);
|
|
32832
|
+
};
|
|
32833
|
+
return {
|
|
32834
|
+
up: mafs.vec.add(coordToBeMoved, [0, snapStep[1]]),
|
|
32835
|
+
down: mafs.vec.sub(coordToBeMoved, [0, snapStep[1]]),
|
|
32836
|
+
// For horizontal movement, we need to ensure that the points are not on the same vertical line.
|
|
32837
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
32838
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
32839
|
+
};
|
|
32840
|
+
};
|
|
32841
|
+
const areCoordsValid = coords => {
|
|
32842
|
+
const p1 = coords[0];
|
|
32843
|
+
const p2 = coords[1];
|
|
32844
|
+
const p3 = coords[2];
|
|
32845
|
+
|
|
32846
|
+
// If any of the points share the same x-coordinate,
|
|
32847
|
+
// we are unable to calculate the coefficients, and the graph is invalid.
|
|
32848
|
+
if (p1[0] === p2[0] || p2[0] === p3[0] || p1[0] === p3[0]) {
|
|
32849
|
+
return false;
|
|
32850
|
+
}
|
|
32851
|
+
return true;
|
|
32852
|
+
};
|
|
32970
32853
|
|
|
32971
32854
|
function renderRayGraph(state, dispatch, i18n) {
|
|
32972
32855
|
return {
|
|
@@ -33222,7 +33105,8 @@ function SinusoidGraph(props) {
|
|
|
33222
33105
|
// Note: The order of the coordinates is important:
|
|
33223
33106
|
// The coords[0] is the root and the coords[1] is the first peak
|
|
33224
33107
|
const {
|
|
33225
|
-
coords
|
|
33108
|
+
coords,
|
|
33109
|
+
snapStep
|
|
33226
33110
|
} = graphState;
|
|
33227
33111
|
|
|
33228
33112
|
// The coefficients are used to calculate the sinusoid equation, plot the graph, and to indicate
|
|
@@ -33261,11 +33145,37 @@ function SinusoidGraph(props) {
|
|
|
33261
33145
|
key: "point-" + i,
|
|
33262
33146
|
point: coord,
|
|
33263
33147
|
sequenceNumber: i + 1,
|
|
33148
|
+
constrain: getSinusoidKeyboardConstraint(coords, snapStep, i),
|
|
33264
33149
|
onMove: destination => dispatch(actions.sinusoid.movePoint(i, destination))
|
|
33265
33150
|
})), /*#__PURE__*/React__namespace.createElement("g", {
|
|
33266
33151
|
id: descriptionId
|
|
33267
33152
|
}, srSinusoidDescription));
|
|
33268
33153
|
}
|
|
33154
|
+
const getSinusoidKeyboardConstraint = (coords, snapStep, pointIndex) => {
|
|
33155
|
+
// Separate the two points into their own variables, and determine which point is being moved
|
|
33156
|
+
const coordToBeMoved = coords[pointIndex];
|
|
33157
|
+
const otherPoint = coords[1 - pointIndex];
|
|
33158
|
+
|
|
33159
|
+
// Create a helper function that checks if the new point is on the same
|
|
33160
|
+
// vertical line as the other point. If it is, we need to move the point
|
|
33161
|
+
// an additional snapStep.
|
|
33162
|
+
const movePointWithConstraint = moveFunc => {
|
|
33163
|
+
// Move the point
|
|
33164
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
33165
|
+
// If the moved point overlaps with the other point in the line,
|
|
33166
|
+
// move the point again.
|
|
33167
|
+
if (movedCoord[X] === otherPoint[X]) {
|
|
33168
|
+
movedCoord = moveFunc(movedCoord);
|
|
33169
|
+
}
|
|
33170
|
+
return movedCoord;
|
|
33171
|
+
};
|
|
33172
|
+
return {
|
|
33173
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
33174
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
33175
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
33176
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
33177
|
+
};
|
|
33178
|
+
};
|
|
33269
33179
|
|
|
33270
33180
|
// Plot a sinusoid of the form: f(x) = a * sin(b * x - c) + d
|
|
33271
33181
|
const computeSine = function (x,
|
|
@@ -33317,6 +33227,14 @@ function describeSinusoidGraph(state, i18n) {
|
|
|
33317
33227
|
const [root, peak] = coords;
|
|
33318
33228
|
const diffX = Math.abs(peak[X] - root[X]);
|
|
33319
33229
|
const diffY = Math.abs(peak[Y] - root[Y]);
|
|
33230
|
+
const formattedRoot = {
|
|
33231
|
+
x: srFormatNumber(root[X], locale),
|
|
33232
|
+
y: srFormatNumber(root[Y], locale)
|
|
33233
|
+
};
|
|
33234
|
+
const formattedPeak = {
|
|
33235
|
+
x: srFormatNumber(peak[X], locale),
|
|
33236
|
+
y: srFormatNumber(peak[Y], locale)
|
|
33237
|
+
};
|
|
33320
33238
|
const srSinusoidGraph = strings.srSinusoidGraph;
|
|
33321
33239
|
const srSinusoidDescription = strings.srSinusoidDescription({
|
|
33322
33240
|
minValue: srFormatNumber(root[Y] - diffY, locale),
|
|
@@ -33324,14 +33242,8 @@ function describeSinusoidGraph(state, i18n) {
|
|
|
33324
33242
|
cycleStart: srFormatNumber(root[X] - 2 * diffX, locale),
|
|
33325
33243
|
cycleEnd: srFormatNumber(root[X] + 2 * diffX, locale)
|
|
33326
33244
|
});
|
|
33327
|
-
const srSinusoidRootPoint = strings.srSinusoidRootPoint(
|
|
33328
|
-
|
|
33329
|
-
y: srFormatNumber(root[Y], locale)
|
|
33330
|
-
});
|
|
33331
|
-
const srSinusoidPeakPoint = strings.srSinusoidPeakPoint({
|
|
33332
|
-
x: srFormatNumber(peak[X], locale),
|
|
33333
|
-
y: srFormatNumber(peak[Y], locale)
|
|
33334
|
-
});
|
|
33245
|
+
const srSinusoidRootPoint = strings.srSinusoidRootPoint(formattedRoot);
|
|
33246
|
+
const srSinusoidPeakPoint = peak[Y] === root[Y] ? strings.srSinusoidFlatPoint(formattedPeak) : peak[Y] > root[Y] ? strings.srSinusoidMaxPoint(formattedPeak) : strings.srSinusoidMinPoint(formattedPeak);
|
|
33335
33247
|
const srSinusoidInteractiveElements = strings.srInteractiveElements({
|
|
33336
33248
|
elements: strings.srSinusoidInteractiveElements({
|
|
33337
33249
|
point1X: srFormatNumber(root[X], locale),
|
|
@@ -33353,16 +33265,17 @@ const {
|
|
|
33353
33265
|
calculateAngleInDegrees,
|
|
33354
33266
|
convertDegreesToRadians
|
|
33355
33267
|
} = kmath.angles;
|
|
33356
|
-
const protractorImage = "https://
|
|
33268
|
+
const protractorImage = "https://cdn.kastatic.org/images/perseus/protractor.svg";
|
|
33357
33269
|
|
|
33358
33270
|
// The vector from the center of the protractor to the top left corner of the
|
|
33359
33271
|
// protractor image, in pixels. Used for positioning.
|
|
33360
|
-
const centerToTopLeft = [-
|
|
33272
|
+
const centerToTopLeft = [-195, -190];
|
|
33361
33273
|
|
|
33362
33274
|
// The vector from the center of the protractor to the center of the rotation
|
|
33363
33275
|
// handle.
|
|
33364
|
-
const centerToRotationHandle = [-
|
|
33276
|
+
const centerToRotationHandle = [-201, -15];
|
|
33365
33277
|
function Protractor() {
|
|
33278
|
+
const staticUrl = getDependencies().staticUrl;
|
|
33366
33279
|
const {
|
|
33367
33280
|
range,
|
|
33368
33281
|
snapStep
|
|
@@ -33374,7 +33287,9 @@ function Protractor() {
|
|
|
33374
33287
|
const [center, setCenter] = React.useState(initialCenter);
|
|
33375
33288
|
const [rotationHandleOffset, setRotationHandleOffset] = React.useState(centerToRotationHandle);
|
|
33376
33289
|
const draggableRef = React.useRef(null);
|
|
33377
|
-
|
|
33290
|
+
const {
|
|
33291
|
+
dragging
|
|
33292
|
+
} = useDraggable({
|
|
33378
33293
|
gestureTarget: draggableRef,
|
|
33379
33294
|
onMove: setCenter,
|
|
33380
33295
|
point: center,
|
|
@@ -33398,10 +33313,11 @@ function Protractor() {
|
|
|
33398
33313
|
ref: draggableRef,
|
|
33399
33314
|
transform: `translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,
|
|
33400
33315
|
style: {
|
|
33401
|
-
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px
|
|
33316
|
+
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`,
|
|
33317
|
+
cursor: dragging ? "grabbing" : "grab"
|
|
33402
33318
|
}
|
|
33403
33319
|
}, /*#__PURE__*/React__namespace.createElement("image", {
|
|
33404
|
-
href: protractorImage
|
|
33320
|
+
href: staticUrl(protractorImage)
|
|
33405
33321
|
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
33406
33322
|
transform: `translate(5, ${-centerToTopLeft[1]})`,
|
|
33407
33323
|
ref: rotationHandleRef
|
|
@@ -35333,8 +35249,8 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
35333
35249
|
|
|
35334
35250
|
// If the graph is static, it always displays the correct answer. This is
|
|
35335
35251
|
// standard behavior for Perseus widgets (e.g. compare the Radio widget).
|
|
35336
|
-
if (props.static) {
|
|
35337
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph,
|
|
35252
|
+
if (props.static && props.correct) {
|
|
35253
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends__default["default"]({}, props, {
|
|
35338
35254
|
state: initializeGraphState({
|
|
35339
35255
|
...props,
|
|
35340
35256
|
graph: props.correct
|
|
@@ -35342,7 +35258,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
35342
35258
|
dispatch: dispatch
|
|
35343
35259
|
}));
|
|
35344
35260
|
}
|
|
35345
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph,
|
|
35261
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends__default["default"]({}, props, {
|
|
35346
35262
|
state: state,
|
|
35347
35263
|
dispatch: dispatch
|
|
35348
35264
|
}));
|
|
@@ -35353,7 +35269,7 @@ const {
|
|
|
35353
35269
|
} = kmath.angles;
|
|
35354
35270
|
const {
|
|
35355
35271
|
getLineEquation,
|
|
35356
|
-
|
|
35272
|
+
getLineIntersectionString,
|
|
35357
35273
|
magnitude,
|
|
35358
35274
|
vector
|
|
35359
35275
|
} = kmath.geometry;
|
|
@@ -35435,7 +35351,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35435
35351
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
35436
35352
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
35437
35353
|
const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
|
|
35438
|
-
return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph,
|
|
35354
|
+
return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph, _extends__default["default"]({}, this.props, {
|
|
35439
35355
|
ref: this.mafsRef,
|
|
35440
35356
|
gridStep: gridStep,
|
|
35441
35357
|
snapStep: snapStep,
|
|
@@ -35718,7 +35634,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35718
35634
|
}
|
|
35719
35635
|
static getLinearSystemEquationString(props) {
|
|
35720
35636
|
const coords = InteractiveGraph.getLinearSystemCoords(props.graph, props);
|
|
35721
|
-
return "\n" + getLineEquation(coords[0][0], coords[0][1]) + "\n" + getLineEquation(coords[1][0], coords[1][1]) + "\n" +
|
|
35637
|
+
return "\n" + getLineEquation(coords[0][0], coords[0][1]) + "\n" + getLineEquation(coords[1][0], coords[1][1]) + "\n" + getLineIntersectionString(coords[0], coords[1]);
|
|
35722
35638
|
}
|
|
35723
35639
|
static getPointEquationString(props) {
|
|
35724
35640
|
if (props.graph.type !== "point") {
|
|
@@ -35870,10 +35786,10 @@ const AnswerChoices = props => {
|
|
|
35870
35786
|
onToggle,
|
|
35871
35787
|
disabled
|
|
35872
35788
|
};
|
|
35873
|
-
return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect,
|
|
35789
|
+
return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect, _extends__default["default"]({}, args, {
|
|
35874
35790
|
selectedValues: selectedValues,
|
|
35875
35791
|
onChange: selected => onAnswerChange(selected)
|
|
35876
|
-
})) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect,
|
|
35792
|
+
})) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, _extends__default["default"]({}, args, {
|
|
35877
35793
|
selectedValue: selectedValues[0],
|
|
35878
35794
|
onChange: selected => onAnswerChange([selected]),
|
|
35879
35795
|
placeholder: props.choices[0].content // not visible, but required
|
|
@@ -36159,7 +36075,6 @@ const styles$a = aphrodite.StyleSheet.create({
|
|
|
36159
36075
|
markerCorrect: {
|
|
36160
36076
|
background: "#00880b" // WB green darkened by 18%
|
|
36161
36077
|
},
|
|
36162
|
-
|
|
36163
36078
|
markerIncorrect: {
|
|
36164
36079
|
background: wonderBlocksTokens.color.offBlack64
|
|
36165
36080
|
}
|
|
@@ -36556,7 +36471,6 @@ class LabelImage extends React__namespace.Component {
|
|
|
36556
36471
|
const adjustPillDistance = {
|
|
36557
36472
|
[`margin${markerPosition.charAt(0).toUpperCase() + markerPosition.slice(1)}`]: 10 // move pill further from marker
|
|
36558
36473
|
};
|
|
36559
|
-
|
|
36560
36474
|
const answerChoicesActive = index === activeMarkerIndex;
|
|
36561
36475
|
const showAnswerChoice = marker.selected && !answerChoicesActive && !this.state.hideAnswers;
|
|
36562
36476
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
@@ -36605,7 +36519,7 @@ class LabelImage extends React__namespace.Component {
|
|
|
36605
36519
|
focused,
|
|
36606
36520
|
pressed
|
|
36607
36521
|
} = _ref2;
|
|
36608
|
-
return /*#__PURE__*/React__namespace.createElement(Marker,
|
|
36522
|
+
return /*#__PURE__*/React__namespace.createElement(Marker, _extends__default["default"]({}, marker, {
|
|
36609
36523
|
showCorrectness: showCorrectness,
|
|
36610
36524
|
showSelected: opened,
|
|
36611
36525
|
showPulsate: !markersInteracted,
|
|
@@ -36750,7 +36664,7 @@ const styles$9 = aphrodite.StyleSheet.create({
|
|
|
36750
36664
|
});
|
|
36751
36665
|
const LabelImageWithDependencies = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
36752
36666
|
const deps = useDependencies();
|
|
36753
|
-
return /*#__PURE__*/React__namespace.createElement(LabelImage,
|
|
36667
|
+
return /*#__PURE__*/React__namespace.createElement(LabelImage, _extends__default["default"]({
|
|
36754
36668
|
ref: ref,
|
|
36755
36669
|
analytics: deps.analytics
|
|
36756
36670
|
}, props));
|
|
@@ -37012,7 +36926,6 @@ class Draggable extends React__namespace.Component {
|
|
|
37012
36926
|
if (this.props.width) {
|
|
37013
36927
|
style.width = this.props.width + 1; // Fix for non-integer widths
|
|
37014
36928
|
}
|
|
37015
|
-
|
|
37016
36929
|
if (this.props.height) {
|
|
37017
36930
|
style.height = this.props.height;
|
|
37018
36931
|
}
|
|
@@ -37356,8 +37269,7 @@ class Sortable extends React__namespace.Component {
|
|
|
37356
37269
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
37357
37270
|
margin = "0 0 " + this.props.margin + "px 0"; // bottom
|
|
37358
37271
|
}
|
|
37359
|
-
|
|
37360
|
-
cards.push( /*#__PURE__*/React__namespace.createElement(Draggable, {
|
|
37272
|
+
cards.push(/*#__PURE__*/React__namespace.createElement(Draggable, {
|
|
37361
37273
|
content: item.option,
|
|
37362
37274
|
key: item.key,
|
|
37363
37275
|
state: item.state
|
|
@@ -37410,7 +37322,7 @@ class Sortable extends React__namespace.Component {
|
|
|
37410
37322
|
this, item.key)
|
|
37411
37323
|
}));
|
|
37412
37324
|
if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
|
|
37413
|
-
cards.push(
|
|
37325
|
+
cards.push(/*#__PURE__*/React__namespace.createElement(Placeholder, {
|
|
37414
37326
|
key: "placeholder_" + item.key,
|
|
37415
37327
|
ref: "placeholder_" + item.key,
|
|
37416
37328
|
width: item.width,
|
|
@@ -38024,7 +37936,7 @@ class Matrix extends React__namespace.Component {
|
|
|
38024
37936
|
boxSizing: "border-box",
|
|
38025
37937
|
backgroundColor: outside ? "#f3f3f3" : "#fff"
|
|
38026
37938
|
};
|
|
38027
|
-
MatrixInput = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput,
|
|
37939
|
+
MatrixInput = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, _extends__default["default"]({}, inputProps, {
|
|
38028
37940
|
style: style,
|
|
38029
37941
|
scrollable: true,
|
|
38030
37942
|
keypadElement: this.props.keypadElement
|
|
@@ -39185,7 +39097,6 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
39185
39097
|
if (!___default["default"].isFinite(props.tickStep) || props.tickStep <= 0) {
|
|
39186
39098
|
return []; // this has screwed me for the last time!
|
|
39187
39099
|
}
|
|
39188
|
-
|
|
39189
39100
|
const results = [];
|
|
39190
39101
|
|
|
39191
39102
|
// For convenience, extract some props into separate variables
|
|
@@ -39256,6 +39167,7 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
39256
39167
|
|
|
39257
39168
|
// TODO: most widgets use some like Widget<Something, PerseusNumberLineWidgetOptions>
|
|
39258
39169
|
// should this one?
|
|
39170
|
+
|
|
39259
39171
|
class NumberLine extends React__namespace.Component {
|
|
39260
39172
|
static contextType = PerseusI18nContext;
|
|
39261
39173
|
static defaultProps = {
|
|
@@ -39400,7 +39312,7 @@ class NumberLine extends React__namespace.Component {
|
|
|
39400
39312
|
setup: this._setupGraphie,
|
|
39401
39313
|
setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable,
|
|
39402
39314
|
isMobile: this.props.apiOptions.isMobile
|
|
39403
|
-
}, /*#__PURE__*/React__namespace.createElement(TickMarks,
|
|
39315
|
+
}, /*#__PURE__*/React__namespace.createElement(TickMarks, _extends__default["default"]({}, ___default["default"].pick(props, ["range", "numDivisions", "labelTicks", "labelStyle", "labelRange", "tickStep"]), {
|
|
39404
39316
|
isMobile: this.props.apiOptions.isMobile
|
|
39405
39317
|
})), this._renderInequality(props), this._renderNumberLinePoint(props));
|
|
39406
39318
|
};
|
|
@@ -39627,7 +39539,6 @@ const numberLineTransform = editorProps => {
|
|
|
39627
39539
|
} else {
|
|
39628
39540
|
numDivisions = undefined; // send to getDefaultProps()
|
|
39629
39541
|
}
|
|
39630
|
-
|
|
39631
39542
|
___default["default"].extend(props, {
|
|
39632
39543
|
numLinePosition: numLinePosition,
|
|
39633
39544
|
numDivisions: numDivisions,
|
|
@@ -39652,7 +39563,6 @@ const staticTransform$1 = editorProps => {
|
|
|
39652
39563
|
} else {
|
|
39653
39564
|
numDivisions = undefined; // send to getDefaultProps()
|
|
39654
39565
|
}
|
|
39655
|
-
|
|
39656
39566
|
___default["default"].extend(props, {
|
|
39657
39567
|
numLinePosition: numLinePosition,
|
|
39658
39568
|
numDivisions: numDivisions,
|
|
@@ -39847,7 +39757,7 @@ class Card extends React__namespace.Component {
|
|
|
39847
39757
|
onTouchCancel: this.onMouseUp
|
|
39848
39758
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
39849
39759
|
className: className.join(" ")
|
|
39850
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
39760
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, rendererProps, {
|
|
39851
39761
|
linterContext: this.props.linterContext,
|
|
39852
39762
|
strings: this.context.strings
|
|
39853
39763
|
}))))
|
|
@@ -40672,7 +40582,6 @@ class Plotter extends React__namespace.Component {
|
|
|
40672
40582
|
const initialY = isMobile ? c.scaleY : 0;
|
|
40673
40583
|
for (let y = initialY; y <= c.dimY; y += c.scaleY) {
|
|
40674
40584
|
graphie.label([0, y], kmath.KhanMath.roundToApprox(y, 2), "left", /* isTeX */true /* for the \approx symbol */);
|
|
40675
|
-
|
|
40676
40585
|
graphie.style({
|
|
40677
40586
|
stroke: isMobile ? "#e9ebec" : "#000",
|
|
40678
40587
|
strokeWidth: 1,
|
|
@@ -41634,7 +41543,7 @@ class Table extends React__namespace.Component {
|
|
|
41634
41543
|
}, ___default["default"](columns).times(c => {
|
|
41635
41544
|
return /*#__PURE__*/React__namespace.createElement("td", {
|
|
41636
41545
|
key: c
|
|
41637
|
-
}, /*#__PURE__*/React__namespace.createElement(InputComponent,
|
|
41546
|
+
}, /*#__PURE__*/React__namespace.createElement(InputComponent, _extends__default["default"]({
|
|
41638
41547
|
ref: getRefForPath(getInputPath(r, c)),
|
|
41639
41548
|
type: "text",
|
|
41640
41549
|
value: this.props.answers[r][c],
|
|
@@ -41845,10 +41754,51 @@ const init = function () {
|
|
|
41845
41754
|
replaceDeprecatedWidgets();
|
|
41846
41755
|
};
|
|
41847
41756
|
|
|
41757
|
+
/**
|
|
41758
|
+
* Adds the given perseus library version information to the __perseus_debug__
|
|
41759
|
+
* object and ensures that the object is attached to `globalThis` (`window` in
|
|
41760
|
+
* browser environments).
|
|
41761
|
+
*
|
|
41762
|
+
* This allows each library to provide runtime version information to assist in
|
|
41763
|
+
* debugging in production environments.
|
|
41764
|
+
*/
|
|
41765
|
+
const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
41766
|
+
// If the library version is the default value, then we don't want to
|
|
41767
|
+
// prefix it with a "v" to indicate that it is a version number.
|
|
41768
|
+
let prefix = "v";
|
|
41769
|
+
if (libraryVersion === "__lib_version__") {
|
|
41770
|
+
prefix = "";
|
|
41771
|
+
}
|
|
41772
|
+
const formattedVersion = `${prefix}${libraryVersion}`;
|
|
41773
|
+
if (typeof globalThis !== "undefined") {
|
|
41774
|
+
globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
|
|
41775
|
+
const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
|
|
41776
|
+
if (existingVersionEntry) {
|
|
41777
|
+
// If we already have an entry and it doesn't match the registered
|
|
41778
|
+
// version, we morph the entry into an array and log a warning.
|
|
41779
|
+
if (existingVersionEntry !== formattedVersion) {
|
|
41780
|
+
// Existing entry might be an array already (oops, at least 2
|
|
41781
|
+
// versions of the library already loaded!).
|
|
41782
|
+
const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
|
|
41783
|
+
allVersions.push(formattedVersion);
|
|
41784
|
+
globalThis.__perseus_debug__[libraryName] = allVersions;
|
|
41785
|
+
|
|
41786
|
+
// eslint-disable-next-line no-console
|
|
41787
|
+
console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
|
|
41788
|
+
}
|
|
41789
|
+
} else {
|
|
41790
|
+
globalThis.__perseus_debug__[libraryName] = formattedVersion;
|
|
41791
|
+
}
|
|
41792
|
+
} else {
|
|
41793
|
+
// eslint-disable-next-line no-console
|
|
41794
|
+
console.warn(`globalThis not found found (${formattedVersion})`);
|
|
41795
|
+
}
|
|
41796
|
+
};
|
|
41797
|
+
|
|
41848
41798
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
41849
41799
|
const libName = "@khanacademy/perseus";
|
|
41850
|
-
const libVersion = "
|
|
41851
|
-
|
|
41800
|
+
const libVersion = "55.0.0";
|
|
41801
|
+
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
41852
41802
|
|
|
41853
41803
|
const apiVersion = {
|
|
41854
41804
|
major: 12,
|
|
@@ -42004,7 +41954,7 @@ class ArticleRenderer extends React__namespace.Component {
|
|
|
42004
41954
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
42005
41955
|
key: sectionIndex,
|
|
42006
41956
|
className: "clearfix"
|
|
42007
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
41957
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, section, {
|
|
42008
41958
|
ref: elem => {
|
|
42009
41959
|
if (elem) {
|
|
42010
41960
|
this.sectionRenderers[sectionIndex] = elem;
|
|
@@ -42179,7 +42129,6 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
42179
42129
|
ReactDOM__default["default"].findDOMNode(this.refs["hintRenderer" + pos]).focus(); // eslint-disable-line react/no-string-refs
|
|
42180
42130
|
}
|
|
42181
42131
|
}
|
|
42182
|
-
|
|
42183
42132
|
_hintsVisible = () => {
|
|
42184
42133
|
if (this.props.hintsVisible == null || this.props.hintsVisible === -1) {
|
|
42185
42134
|
return this.props.hints.length;
|
|
@@ -42668,7 +42617,7 @@ class ServerItemRenderer extends React__namespace.Component {
|
|
|
42668
42617
|
};
|
|
42669
42618
|
const questionRenderer = /*#__PURE__*/React__namespace.createElement(context$1.Provider, {
|
|
42670
42619
|
value: contextValue
|
|
42671
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
42620
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({
|
|
42672
42621
|
keypadElement: this.props.keypadElement,
|
|
42673
42622
|
problemNum: this.props.problemNum,
|
|
42674
42623
|
onInteractWithWidget: this.handleInteractWithWidget,
|
|
@@ -42717,7 +42666,7 @@ const ref = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__
|
|
|
42717
42666
|
let {
|
|
42718
42667
|
onRendered
|
|
42719
42668
|
} = _ref;
|
|
42720
|
-
return /*#__PURE__*/React__namespace.createElement(ServerItemRenderer,
|
|
42669
|
+
return /*#__PURE__*/React__namespace.createElement(ServerItemRenderer, _extends__default["default"]({}, props, {
|
|
42721
42670
|
onRendered: onRendered,
|
|
42722
42671
|
ref: ref
|
|
42723
42672
|
}));
|
|
@@ -44148,24 +44097,24 @@ const ScoringUtil = {
|
|
|
44148
44097
|
*/
|
|
44149
44098
|
|
|
44150
44099
|
Object.defineProperty(exports, 'isFailure', {
|
|
44151
|
-
|
|
44152
|
-
|
|
44100
|
+
enumerable: true,
|
|
44101
|
+
get: function () { return perseusCore.isFailure; }
|
|
44153
44102
|
});
|
|
44154
44103
|
Object.defineProperty(exports, 'isSuccess', {
|
|
44155
|
-
|
|
44156
|
-
|
|
44104
|
+
enumerable: true,
|
|
44105
|
+
get: function () { return perseusCore.isSuccess; }
|
|
44157
44106
|
});
|
|
44158
44107
|
Object.defineProperty(exports, 'parseAndMigratePerseusArticle', {
|
|
44159
|
-
|
|
44160
|
-
|
|
44108
|
+
enumerable: true,
|
|
44109
|
+
get: function () { return perseusCore.parseAndMigratePerseusArticle; }
|
|
44161
44110
|
});
|
|
44162
44111
|
Object.defineProperty(exports, 'parseAndMigratePerseusItem', {
|
|
44163
|
-
|
|
44164
|
-
|
|
44112
|
+
enumerable: true,
|
|
44113
|
+
get: function () { return perseusCore.parseAndMigratePerseusItem; }
|
|
44165
44114
|
});
|
|
44166
44115
|
Object.defineProperty(exports, 'parsePerseusItem', {
|
|
44167
|
-
|
|
44168
|
-
|
|
44116
|
+
enumerable: true,
|
|
44117
|
+
get: function () { return perseusCore.parsePerseusItem; }
|
|
44169
44118
|
});
|
|
44170
44119
|
exports.ApiOptions = ApiOptions;
|
|
44171
44120
|
exports.ArticleRenderer = ArticleRenderer;
|