@khanacademy/perseus 54.1.0 → 55.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +902 -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 +1036 -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,175 @@ 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
|
+
testId: "input-with-examples",
|
|
2292
|
+
onFocus: onFocus,
|
|
2293
|
+
onBlur: onBlur,
|
|
2294
|
+
onKeyDown: onKeyDown
|
|
2295
|
+
// @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>'.
|
|
2296
|
+
,
|
|
2297
|
+
autoCorrect: "off",
|
|
2298
|
+
autoCapitalize: "off",
|
|
2299
|
+
autoComplete: "off"
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2108
2304
|
/**
|
|
2109
2305
|
* A React context for keeping track of whether an component is fully
|
|
2110
2306
|
* loaded. This is used to know when SvgImage and (Zoomable)TeX are finished
|
|
@@ -2667,9 +2863,11 @@ const Util = {
|
|
|
2667
2863
|
// TODO(LP-11481): Change the primary API we use for logging in Perseus to use
|
|
2668
2864
|
// getDependencies() internally... simplify usage to just using a "singleton"
|
|
2669
2865
|
// which get's the injected logger.
|
|
2866
|
+
|
|
2670
2867
|
/**
|
|
2671
2868
|
* Provides logging infrastructure for Perseus
|
|
2672
2869
|
*/
|
|
2870
|
+
|
|
2673
2871
|
const Log = {
|
|
2674
2872
|
// Logs a message
|
|
2675
2873
|
log: (message, extra) => {
|
|
@@ -3343,40 +3541,40 @@ const articleMaxWidthInPx = 688;
|
|
|
3343
3541
|
const articleMaxWidthTableInPx = 512;
|
|
3344
3542
|
|
|
3345
3543
|
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
|
-
|
|
3544
|
+
__proto__: null,
|
|
3545
|
+
baseFontFamily: baseFontFamily,
|
|
3546
|
+
boldFontFamily: boldFontFamily,
|
|
3547
|
+
kaGreen: kaGreen,
|
|
3548
|
+
white: white,
|
|
3549
|
+
gray97: gray97,
|
|
3550
|
+
gray85: gray85,
|
|
3551
|
+
gray76: gray76,
|
|
3552
|
+
gray68: gray68,
|
|
3553
|
+
gray17: gray17,
|
|
3554
|
+
pureSmMin: pureSmMin$1,
|
|
3555
|
+
pureMdMin: pureMdMin$1,
|
|
3556
|
+
pureLgMin: pureLgMin$1,
|
|
3557
|
+
pureXlMin: pureXlMin$1,
|
|
3558
|
+
pureXsMax: pureXsMax$1,
|
|
3559
|
+
pureSmMax: pureSmMax$1,
|
|
3560
|
+
pureMdMax: pureMdMax$1,
|
|
3561
|
+
pureLgMax: pureLgMax$1,
|
|
3562
|
+
tableBackgroundAccent: tableBackgroundAccent,
|
|
3563
|
+
phoneMargin: phoneMargin,
|
|
3564
|
+
negativePhoneMargin: negativePhoneMargin,
|
|
3565
|
+
hintBorderWidth: hintBorderWidth,
|
|
3566
|
+
baseUnitPx: baseUnitPx,
|
|
3567
|
+
interactiveSizes: interactiveSizes$1,
|
|
3568
|
+
circleSize: circleSize$1,
|
|
3569
|
+
radioMarginWidth: radioMarginWidth$1,
|
|
3570
|
+
warningColor: warningColor,
|
|
3571
|
+
warningColorHover: warningColorHover,
|
|
3572
|
+
warningColorActive: warningColorActive,
|
|
3573
|
+
publishBlockingErrorColor: publishBlockingErrorColor,
|
|
3574
|
+
radioBorderColor: radioBorderColor$1,
|
|
3575
|
+
checkedColor: checkedColor$1,
|
|
3576
|
+
articleMaxWidthInPx: articleMaxWidthInPx,
|
|
3577
|
+
articleMaxWidthTableInPx: articleMaxWidthTableInPx
|
|
3380
3578
|
});
|
|
3381
3579
|
|
|
3382
3580
|
/**
|
|
@@ -3791,7 +3989,7 @@ var Raphael$1 = (function () {
|
|
|
3791
3989
|
appendChild = "appendChild",
|
|
3792
3990
|
apply = "apply",
|
|
3793
3991
|
concat = "concat",
|
|
3794
|
-
supportsTouch =
|
|
3992
|
+
supportsTouch = "createTouch" in doc,
|
|
3795
3993
|
E = "",
|
|
3796
3994
|
S = " ",
|
|
3797
3995
|
Str = String,
|
|
@@ -5396,10 +5594,10 @@ var Raphael$1 = (function () {
|
|
|
5396
5594
|
});
|
|
5397
5595
|
break;
|
|
5398
5596
|
case "gradient":
|
|
5399
|
-
(
|
|
5597
|
+
({
|
|
5400
5598
|
circle: 1,
|
|
5401
5599
|
ellipse: 1
|
|
5402
|
-
}
|
|
5600
|
+
}[has](o.type) || Str(value).charAt() != "r") && addGradientFill(node, value, o.paper);
|
|
5403
5601
|
break;
|
|
5404
5602
|
case "opacity":
|
|
5405
5603
|
if (attrs.gradient && !attrs[has]("stroke-opacity")) {
|
|
@@ -9232,8 +9430,10 @@ const labelDirections = {
|
|
|
9232
9430
|
// is equivalent to [[-5, 5], [-10, 10]].
|
|
9233
9431
|
// - A single magnitude to be used for both x and y. E.g. 10 is equivalent to
|
|
9234
9432
|
// [[-10, 10], [-10, 10]]
|
|
9433
|
+
|
|
9235
9434
|
// Overload normalizeRange to specify that it only returns undefined if its
|
|
9236
9435
|
// argument is undefined.
|
|
9436
|
+
|
|
9237
9437
|
// normalizeRange converts a RangeSpecifier into a pair of Intervals that give
|
|
9238
9438
|
// the x and y ranges, respectively
|
|
9239
9439
|
function normalizeRange(range) {
|
|
@@ -9425,7 +9625,7 @@ const GraphUtils = {
|
|
|
9425
9625
|
clickBlockList = [],
|
|
9426
9626
|
blockMouseTriggers = false,
|
|
9427
9627
|
blockTouchTriggers = false,
|
|
9428
|
-
eventCaptureSupported =
|
|
9628
|
+
eventCaptureSupported = "addEventListener" in document,
|
|
9429
9629
|
$document = $(document),
|
|
9430
9630
|
nextTouchID = 1,
|
|
9431
9631
|
lastTouchID = 0;
|
|
@@ -10120,7 +10320,6 @@ function scaledPolarRad(radius, radians) {
|
|
|
10120
10320
|
return [radius * Math.cos(radians), radius * Math.sin(radians) * -1 // SVG flips y axis
|
|
10121
10321
|
];
|
|
10122
10322
|
}
|
|
10123
|
-
|
|
10124
10323
|
function scaledPolarDeg(radius, degrees) {
|
|
10125
10324
|
const radians = degrees * Math.PI / 180;
|
|
10126
10325
|
return scaledPolarRad(radius, radians);
|
|
@@ -11938,7 +12137,6 @@ ___default["default"].extend(GraphUtils.Graphie.prototype, {
|
|
|
11938
12137
|
if (hideArrow) {
|
|
11939
12138
|
return; // Don't draw anything!
|
|
11940
12139
|
}
|
|
11941
|
-
|
|
11942
12140
|
const handleVec = kmath.vector.subtract(handleCoord, rotatePoint.coord);
|
|
11943
12141
|
const handlePolar = kmath.vector.polarDegFromCart(handleVec);
|
|
11944
12142
|
const angle = handlePolar[1];
|
|
@@ -12902,7 +13100,6 @@ ___default["default"].extend(MovableAngle.prototype, {
|
|
|
12902
13100
|
// clockwise to the first point
|
|
12903
13101
|
coords[1] // the vertex parameter is last
|
|
12904
13102
|
);
|
|
12905
|
-
|
|
12906
13103
|
const clockwiseAngle = rawAngle + 360 % 360;
|
|
12907
13104
|
return clockwiseAngle;
|
|
12908
13105
|
},
|
|
@@ -14262,7 +14459,6 @@ class MovablePoint$5 {
|
|
|
14262
14459
|
// We only update props here, because we want things on state to
|
|
14263
14460
|
// be persistent, and updated appropriately in modify()
|
|
14264
14461
|
),
|
|
14265
|
-
|
|
14266
14462
|
...DEFAULT_PROPS$1
|
|
14267
14463
|
};
|
|
14268
14464
|
}
|
|
@@ -14314,11 +14510,11 @@ class MovablePoint$5 {
|
|
|
14314
14510
|
const showTrashTooltip = () => {
|
|
14315
14511
|
this._showTooltip(container => {
|
|
14316
14512
|
// eslint-disable-next-line import/no-deprecated
|
|
14317
|
-
render(
|
|
14513
|
+
render(/*#__PURE__*/React__namespace.createElement("span", {
|
|
14318
14514
|
style: {
|
|
14319
14515
|
fontSize: "2em"
|
|
14320
14516
|
}
|
|
14321
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
14517
|
+
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconTrash, {
|
|
14322
14518
|
style: {
|
|
14323
14519
|
position: "static",
|
|
14324
14520
|
color: KhanColors.INTERACTIVE,
|
|
@@ -15117,7 +15313,6 @@ const DEFAULT_PROPS = {
|
|
|
15117
15313
|
// likewise
|
|
15118
15314
|
labelStyle: null // likewise
|
|
15119
15315
|
};
|
|
15120
|
-
|
|
15121
15316
|
const DEFAULT_STATE = {
|
|
15122
15317
|
added: false,
|
|
15123
15318
|
hasMoved: false,
|
|
@@ -16019,7 +16214,7 @@ class ImageLoader extends React__namespace.Component {
|
|
|
16019
16214
|
return (
|
|
16020
16215
|
/*#__PURE__*/
|
|
16021
16216
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
16022
|
-
React__namespace.createElement("img",
|
|
16217
|
+
React__namespace.createElement("img", _extends__default["default"]({
|
|
16023
16218
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
|
|
16024
16219
|
tabIndex: 0,
|
|
16025
16220
|
src: staticUrl(src),
|
|
@@ -17793,7 +17988,7 @@ class TranslationLinter {
|
|
|
17793
17988
|
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
17794
17989
|
* to things is does.
|
|
17795
17990
|
*/
|
|
17796
|
-
var preprocessTex =
|
|
17991
|
+
var preprocessTex = texCode => texCode
|
|
17797
17992
|
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
17798
17993
|
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
17799
17994
|
// the same is supported by KaTeX. It does the same for align*.
|
|
@@ -17803,7 +17998,7 @@ var preprocessTex = (texCode => texCode
|
|
|
17803
17998
|
// "aligned").
|
|
17804
17999
|
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
17805
18000
|
// Replace non-breaking spaces with regular spaces.
|
|
17806
|
-
.replace(/[\u00a0]/g, " ")
|
|
18001
|
+
.replace(/[\u00a0]/g, " ");
|
|
17807
18002
|
|
|
17808
18003
|
const {
|
|
17809
18004
|
interactiveSizes
|
|
@@ -18062,29 +18257,29 @@ const isLintable = type => {
|
|
|
18062
18257
|
};
|
|
18063
18258
|
|
|
18064
18259
|
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
|
-
|
|
18260
|
+
__proto__: null,
|
|
18261
|
+
registerWidget: registerWidget,
|
|
18262
|
+
registerWidgets: registerWidgets,
|
|
18263
|
+
replaceWidget: replaceWidget,
|
|
18264
|
+
replaceDeprecatedWidgets: replaceDeprecatedWidgets,
|
|
18265
|
+
registerEditors: registerEditors,
|
|
18266
|
+
replaceEditor: replaceEditor,
|
|
18267
|
+
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
18268
|
+
getWidget: getWidget,
|
|
18269
|
+
getWidgetExport: getWidgetExport,
|
|
18270
|
+
getEditor: getEditor,
|
|
18271
|
+
getTransform: getTransform,
|
|
18272
|
+
getVersion: getVersion,
|
|
18273
|
+
getVersionVector: getVersionVector,
|
|
18274
|
+
getPublicWidgets: getPublicWidgets,
|
|
18275
|
+
isAccessible: isAccessible,
|
|
18276
|
+
getAllWidgetTypes: getAllWidgetTypes,
|
|
18277
|
+
getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
|
|
18278
|
+
traverseChildWidgets: traverseChildWidgets$3,
|
|
18279
|
+
supportsStaticMode: supportsStaticMode,
|
|
18280
|
+
getStaticTransform: getStaticTransform,
|
|
18281
|
+
getTracking: getTracking,
|
|
18282
|
+
isLintable: isLintable
|
|
18088
18283
|
});
|
|
18089
18284
|
|
|
18090
18285
|
class WidgetContainer extends React__namespace.Component {
|
|
@@ -18119,7 +18314,6 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
18119
18314
|
/* eslint-enable react/no-did-mount-set-state */
|
|
18120
18315
|
}
|
|
18121
18316
|
}
|
|
18122
|
-
|
|
18123
18317
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
18124
18318
|
if (this.props.type !== nextProps.type) {
|
|
18125
18319
|
throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
|
|
@@ -18242,7 +18436,7 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
18242
18436
|
}
|
|
18243
18437
|
});
|
|
18244
18438
|
}
|
|
18245
|
-
}, /*#__PURE__*/React__namespace.createElement(WidgetType,
|
|
18439
|
+
}, /*#__PURE__*/React__namespace.createElement(WidgetType, _extends__default["default"]({}, this.state.widgetProps, {
|
|
18246
18440
|
linterContext: linterContext,
|
|
18247
18441
|
containerSizeClass: this.state.sizeClass,
|
|
18248
18442
|
ref: this.widgetRef
|
|
@@ -19111,7 +19305,7 @@ class Renderer extends React__namespace.Component {
|
|
|
19111
19305
|
let {
|
|
19112
19306
|
setAssetStatus
|
|
19113
19307
|
} = _ref4;
|
|
19114
|
-
return /*#__PURE__*/React__namespace.createElement(SvgImage,
|
|
19308
|
+
return /*#__PURE__*/React__namespace.createElement(SvgImage, _extends__default["default"]({
|
|
19115
19309
|
setAssetStatus: setAssetStatus
|
|
19116
19310
|
// @ts-expect-error - TS2322 - Type 'string | null | undefined' is not assignable to type 'string | undefined'.
|
|
19117
19311
|
,
|
|
@@ -19635,429 +19829,84 @@ const styles$A = {
|
|
|
19635
19829
|
}
|
|
19636
19830
|
};
|
|
19637
19831
|
|
|
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/
|
|
19832
|
+
const {
|
|
19833
|
+
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
19834
|
+
} = Util;
|
|
19835
|
+
// [LEMS-2411](Jan 2025) Third: This component has been moved to the NumericInput
|
|
19836
|
+
// folder as we are actively working towards removing the InputNumber widget.
|
|
19837
|
+
// This comment can be removed as part of LEMS-2411.
|
|
19776
19838
|
|
|
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
19839
|
/**
|
|
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
|
-
* ```
|
|
19840
|
+
* The InputWithExamples component is a child component of the NumericInput
|
|
19841
|
+
* and InputNumber components. It is responsible for rendering the UI elements
|
|
19842
|
+
* for the desktop versions of these widgets, and displays a tooltip with
|
|
19843
|
+
* examples of how to input the selected answer forms.
|
|
19879
19844
|
*/
|
|
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"
|
|
19845
|
+
const InputWithExamples = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
19846
|
+
// Desctructure the props to set default values
|
|
19847
|
+
const {
|
|
19848
|
+
shouldShowExamples = true,
|
|
19849
|
+
onFocus = () => {},
|
|
19850
|
+
onBlur = () => {},
|
|
19851
|
+
disabled = false,
|
|
19852
|
+
linterContext = PerseusLinter__namespace.linterContextDefault,
|
|
19853
|
+
className = ""
|
|
19854
|
+
} = props;
|
|
19855
|
+
const context = React__namespace.useContext(PerseusI18nContext);
|
|
19856
|
+
const inputRef = React__namespace.useRef(null);
|
|
19857
|
+
const [inputFocused, setInputFocused] = React__namespace.useState(false);
|
|
19858
|
+
const id = React.useId();
|
|
19859
|
+
const ariaId = `aria-for-${id}`;
|
|
19860
|
+
React.useImperativeHandle(ref, () => ({
|
|
19861
|
+
current: inputRef.current,
|
|
19862
|
+
focus: () => {
|
|
19863
|
+
if (inputRef.current) {
|
|
19864
|
+
inputRef.current.focus();
|
|
19865
|
+
}
|
|
19866
|
+
},
|
|
19867
|
+
blur: () => {
|
|
19868
|
+
if (inputRef.current) {
|
|
19869
|
+
inputRef.current.blur();
|
|
19962
19870
|
}
|
|
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
19871
|
}
|
|
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;
|
|
19872
|
+
}));
|
|
19873
|
+
const getInputClassName = () => {
|
|
19874
|
+
let inputClassName = ClassNames.INPUT;
|
|
19875
|
+
if (inputFocused) {
|
|
19876
|
+
inputClassName += " " + ClassNames.FOCUSED;
|
|
20035
19877
|
}
|
|
20036
|
-
if (
|
|
20037
|
-
|
|
19878
|
+
if (className) {
|
|
19879
|
+
inputClassName += " " + className;
|
|
20038
19880
|
}
|
|
20039
|
-
return
|
|
19881
|
+
return inputClassName;
|
|
19882
|
+
};
|
|
19883
|
+
const handleFocus = () => {
|
|
19884
|
+
onFocus();
|
|
19885
|
+
setInputFocused(true);
|
|
19886
|
+
};
|
|
19887
|
+
const handleBlur = () => {
|
|
19888
|
+
onBlur();
|
|
19889
|
+
setInputFocused(false);
|
|
20040
19890
|
};
|
|
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")}`
|
|
19891
|
+
const renderInput = () => {
|
|
19892
|
+
// Generate the provided examples in simple language for screen readers.
|
|
19893
|
+
const examplesAria = props.shouldShowExamples ? `${props.examples[0]}
|
|
19894
|
+
${props.examples.slice(1).join(", or\n")}`
|
|
20047
19895
|
// @ts-expect-error TS2550: Property replaceAll does not exist on type string.
|
|
20048
|
-
.replaceAll("*", "").replaceAll("$", "").replaceAll("\\ \\text{pi}", " pi").replaceAll("\\ ", " and ");
|
|
19896
|
+
.replaceAll("*", "").replaceAll("$", "").replaceAll("\\ \\text{pi}", " pi").replaceAll("\\ ", " and ") : "";
|
|
20049
19897
|
const inputProps = {
|
|
20050
19898
|
id: id,
|
|
20051
|
-
|
|
20052
|
-
|
|
20053
|
-
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
|
|
20058
|
-
|
|
20059
|
-
|
|
20060
|
-
|
|
19899
|
+
// If we have examples, we want to provide the aria-describedby attribute
|
|
19900
|
+
"aria-describedby": props.shouldShowExamples ? ariaId : undefined,
|
|
19901
|
+
ref: inputRef,
|
|
19902
|
+
className: getInputClassName(),
|
|
19903
|
+
labelText: props.labelText,
|
|
19904
|
+
value: props.value,
|
|
19905
|
+
onFocus: handleFocus,
|
|
19906
|
+
onBlur: handleBlur,
|
|
19907
|
+
disabled: disabled,
|
|
19908
|
+
style: props.style,
|
|
19909
|
+
onChange: props.onChange,
|
|
20061
19910
|
onTouchStart: captureScratchpadTouchStart$2,
|
|
20062
19911
|
autoCapitalize: "off",
|
|
20063
19912
|
autoComplete: "off",
|
|
@@ -20071,158 +19920,32 @@ class InputWithExamples extends React__namespace.Component {
|
|
|
20071
19920
|
}
|
|
20072
19921
|
}, examplesAria));
|
|
20073
19922
|
};
|
|
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()
|
|
19923
|
+
const renderTooltipContent = () => {
|
|
19924
|
+
return /*#__PURE__*/React__namespace.createElement(Tooltip.TooltipContent, null, /*#__PURE__*/React__namespace.createElement("div", {
|
|
19925
|
+
id: id,
|
|
19926
|
+
className: "input-with-examples-tooltip"
|
|
20131
19927
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
20132
19928
|
content: examplesContent,
|
|
20133
|
-
linterContext: PerseusLinter__namespace.pushContextStack(
|
|
20134
|
-
strings:
|
|
19929
|
+
linterContext: PerseusLinter__namespace.pushContextStack(linterContext, "input-with-examples"),
|
|
19930
|
+
strings: context.strings
|
|
20135
19931
|
})));
|
|
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
19932
|
};
|
|
20223
|
-
|
|
19933
|
+
// Display the examples as a string when there are less than or equal to 2 examples.
|
|
19934
|
+
// Otherwise, display the examples as a list.
|
|
19935
|
+
const examplesContent = props.examples.length <= 2 ? props.examples.join(" ") : props.examples.map((example, index) => {
|
|
19936
|
+
return index === 0 && example.startsWith("**") ? `${example}\n` : `- ${example}`;
|
|
19937
|
+
}).join("\n");
|
|
20224
19938
|
|
|
20225
|
-
|
|
19939
|
+
// Display the examples when they are enabled (shouldShowExamples) and the input is focused.
|
|
19940
|
+
const showExamplesTooltip = shouldShowExamples && inputFocused;
|
|
19941
|
+
return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
19942
|
+
content: renderTooltipContent(),
|
|
19943
|
+
opened: showExamplesTooltip,
|
|
19944
|
+
placement: "bottom"
|
|
19945
|
+
}, renderInput());
|
|
19946
|
+
});
|
|
19947
|
+
|
|
19948
|
+
const formExamples = {
|
|
20226
19949
|
integer: function (options, strings) {
|
|
20227
19950
|
return strings.integerExample;
|
|
20228
19951
|
},
|
|
@@ -20334,7 +20057,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
20334
20057
|
} = this.context;
|
|
20335
20058
|
const type = this.props.answerType;
|
|
20336
20059
|
const forms = perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);
|
|
20337
|
-
const examples = ___default["default"].map(forms, form => formExamples
|
|
20060
|
+
const examples = ___default["default"].map(forms, form => formExamples[form](this.props, strings));
|
|
20338
20061
|
return [strings.yourAnswer].concat(examples);
|
|
20339
20062
|
}
|
|
20340
20063
|
render() {
|
|
@@ -20448,7 +20171,11 @@ const getPromptJSON$r = (renderProps, userInput) => {
|
|
|
20448
20171
|
};
|
|
20449
20172
|
};
|
|
20450
20173
|
|
|
20451
|
-
|
|
20174
|
+
/**
|
|
20175
|
+
* The full list of available strings for the numeric input widget,
|
|
20176
|
+
* based on whether the Content Creator has specified that the answer must be simplified.
|
|
20177
|
+
*/
|
|
20178
|
+
const NumericExampleStrings = {
|
|
20452
20179
|
integer: (form, strings) => strings.integerExample,
|
|
20453
20180
|
proper: (form, strings) => form.simplify === "optional" ? strings.properExample : strings.simplifiedProperExample,
|
|
20454
20181
|
improper: (form, strings) => form.simplify === "optional" ? strings.improperExample : strings.simplifiedImproperExample,
|
|
@@ -20456,9 +20183,182 @@ const formExamples = {
|
|
|
20456
20183
|
decimal: (form, strings) => strings.decimalExample,
|
|
20457
20184
|
pi: (form, strings) => strings.piExample
|
|
20458
20185
|
};
|
|
20186
|
+
|
|
20187
|
+
/**
|
|
20188
|
+
* Generates the specific set of examples for the current question.
|
|
20189
|
+
* This string is shown as examples to the user in a tooltip.
|
|
20190
|
+
*/
|
|
20191
|
+
const generateExamples = (answerForms, strings) => {
|
|
20192
|
+
// If the Content Creator has not specified any answer forms,
|
|
20193
|
+
// we do not need to show any examples.
|
|
20194
|
+
if (answerForms.length === 0) {
|
|
20195
|
+
return [];
|
|
20196
|
+
}
|
|
20197
|
+
|
|
20198
|
+
// Generate a list of the unique answer forms.
|
|
20199
|
+
const uniqueForms = getUniqueAnswerForms(answerForms);
|
|
20200
|
+
|
|
20201
|
+
// Generate the example strings for each unique form.
|
|
20202
|
+
const examples = uniqueForms.map(form => {
|
|
20203
|
+
return NumericExampleStrings[form.name](form, strings);
|
|
20204
|
+
});
|
|
20205
|
+
|
|
20206
|
+
// Add the "Your answer" string to the beginning of the examples list.
|
|
20207
|
+
return [strings.yourAnswer].concat(examples);
|
|
20208
|
+
};
|
|
20209
|
+
|
|
20210
|
+
/**
|
|
20211
|
+
* Determines whether to show examples of how to input the various supported answer forms.
|
|
20212
|
+
* We do not show examples if all forms are accepted or if no forms are accepted.
|
|
20213
|
+
*/
|
|
20214
|
+
const shouldShowExamples = answerForms => {
|
|
20215
|
+
// If the Content Creator has not specified any answer forms,
|
|
20216
|
+
// we do not need to show any examples.
|
|
20217
|
+
if (answerForms.length === 0) {
|
|
20218
|
+
return false;
|
|
20219
|
+
}
|
|
20220
|
+
|
|
20221
|
+
// Generate a list of the unique names of the selected answer forms.
|
|
20222
|
+
const answerFormNames = getUniqueAnswerForms(answerForms).map(form => form.name);
|
|
20223
|
+
|
|
20224
|
+
// If all forms are accepted, we do not need to show any examples.
|
|
20225
|
+
const allFormsAccepted = answerFormNames.length >= Object.keys(NumericExampleStrings).length;
|
|
20226
|
+
return !allFormsAccepted;
|
|
20227
|
+
};
|
|
20228
|
+
|
|
20229
|
+
/**
|
|
20230
|
+
* uniqueAnswerForms takes a list of answer forms and returns a list of unique
|
|
20231
|
+
* answer forms. This is useful for ensuring that we don't show duplicate examples
|
|
20232
|
+
* to the user.
|
|
20233
|
+
*/
|
|
20234
|
+
const getUniqueAnswerForms = function (list) {
|
|
20235
|
+
// We use a Set to keep track of the forms we've already seen.
|
|
20236
|
+
const foundForms = new Set();
|
|
20237
|
+
return list.filter(form => {
|
|
20238
|
+
// If we've already seen this form, skip it.
|
|
20239
|
+
if (foundForms.has(form.name)) {
|
|
20240
|
+
return false;
|
|
20241
|
+
}
|
|
20242
|
+
// Otherwise, add it to the set and return true.
|
|
20243
|
+
foundForms.add(form.name);
|
|
20244
|
+
return true;
|
|
20245
|
+
});
|
|
20246
|
+
};
|
|
20247
|
+
|
|
20248
|
+
/**
|
|
20249
|
+
* Takes a list of lists of answer forms, and returns a list of the forms
|
|
20250
|
+
* in each of these lists in the same order that they're listed in the
|
|
20251
|
+
* `formExamples` forms from above.
|
|
20252
|
+
*/
|
|
20253
|
+
const unionAnswerForms = function (answerFormsList) {
|
|
20254
|
+
// Pull out all of the forms from the different lists.
|
|
20255
|
+
const allForms = answerFormsList.flat();
|
|
20256
|
+
// Pull out the unique forms using getUniqueAnswerForms.
|
|
20257
|
+
const uniqueForms = getUniqueAnswerForms(allForms);
|
|
20258
|
+
// Sort them by the order they appear in the `formExamples` list.
|
|
20259
|
+
const formExampleKeys = Object.keys(NumericExampleStrings);
|
|
20260
|
+
return uniqueForms.sort((a, b) => {
|
|
20261
|
+
return formExampleKeys.indexOf(a.name) - formExampleKeys.indexOf(b.name);
|
|
20262
|
+
});
|
|
20263
|
+
};
|
|
20264
|
+
|
|
20265
|
+
/**
|
|
20266
|
+
* The NumericInputComponent is a child component of the NumericInput class
|
|
20267
|
+
* component. It is responsible for rendering the UI elements of the Numeric
|
|
20268
|
+
* Input widget.
|
|
20269
|
+
*/
|
|
20270
|
+
const NumericInputComponent = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
20271
|
+
const context = React.useContext(PerseusI18nContext);
|
|
20272
|
+
const inputRef = React.useRef(null);
|
|
20273
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
20274
|
+
|
|
20275
|
+
// Pass the focus and blur methods to the Numeric Input Class component
|
|
20276
|
+
React.useImperativeHandle(ref, () => ({
|
|
20277
|
+
current: inputRef.current,
|
|
20278
|
+
focus: () => {
|
|
20279
|
+
if (inputRef.current) {
|
|
20280
|
+
inputRef.current?.focus();
|
|
20281
|
+
setIsFocused(true);
|
|
20282
|
+
}
|
|
20283
|
+
},
|
|
20284
|
+
blur: () => {
|
|
20285
|
+
if (inputRef.current) {
|
|
20286
|
+
inputRef.current?.blur();
|
|
20287
|
+
setIsFocused(false);
|
|
20288
|
+
}
|
|
20289
|
+
}
|
|
20290
|
+
}));
|
|
20291
|
+
const handleChange = (newValue, cb) => {
|
|
20292
|
+
props.onChange({
|
|
20293
|
+
currentValue: newValue
|
|
20294
|
+
}, cb);
|
|
20295
|
+
props.trackInteraction();
|
|
20296
|
+
};
|
|
20297
|
+
const handleFocus = () => {
|
|
20298
|
+
props.onFocus([]);
|
|
20299
|
+
setIsFocused(true);
|
|
20300
|
+
};
|
|
20301
|
+
const handleBlur = () => {
|
|
20302
|
+
props.onBlur([]);
|
|
20303
|
+
setIsFocused(false);
|
|
20304
|
+
};
|
|
20305
|
+
|
|
20306
|
+
// Styles for the InputWithExamples
|
|
20307
|
+
const styles = aphrodite.StyleSheet.create({
|
|
20308
|
+
inputWithExamples: {
|
|
20309
|
+
borderRadius: "3px",
|
|
20310
|
+
borderWidth: isFocused ? "2px" : "1px",
|
|
20311
|
+
display: "inline-block",
|
|
20312
|
+
fontFamily: `Symbola, "Times New Roman", serif`,
|
|
20313
|
+
fontSize: "18px",
|
|
20314
|
+
height: "32px",
|
|
20315
|
+
lineHeight: "18px",
|
|
20316
|
+
padding: isFocused ? "4px" : "4px 5px",
|
|
20317
|
+
textAlign: props.rightAlign ? "right" : "left",
|
|
20318
|
+
width: props.size === "small" ? 40 : 80
|
|
20319
|
+
}
|
|
20320
|
+
});
|
|
20321
|
+
|
|
20322
|
+
// (mobile-only) If the custom keypad is enabled, use the SimpleKeypadInput component
|
|
20323
|
+
if (props.apiOptions.customKeypad) {
|
|
20324
|
+
const alignmentClass = props.rightAlign ? "perseus-input-right-align" : undefined;
|
|
20325
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
20326
|
+
className: alignmentClass
|
|
20327
|
+
}, /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, {
|
|
20328
|
+
ref: inputRef,
|
|
20329
|
+
value: props.currentValue,
|
|
20330
|
+
keypadElement: props.keypadElement,
|
|
20331
|
+
onChange: handleChange,
|
|
20332
|
+
onFocus: handleFocus,
|
|
20333
|
+
onBlur: handleBlur
|
|
20334
|
+
}));
|
|
20335
|
+
}
|
|
20336
|
+
// (desktop-only) Otherwise, use the InputWithExamples component
|
|
20337
|
+
return /*#__PURE__*/React__namespace.createElement(InputWithExamples, {
|
|
20338
|
+
ref: inputRef,
|
|
20339
|
+
value: props.currentValue,
|
|
20340
|
+
onChange: handleChange,
|
|
20341
|
+
labelText: props.labelText,
|
|
20342
|
+
examples: generateExamples(props.answerForms, context.strings),
|
|
20343
|
+
shouldShowExamples: shouldShowExamples(props.answerForms),
|
|
20344
|
+
onFocus: handleFocus,
|
|
20345
|
+
onBlur: handleBlur,
|
|
20346
|
+
id: props.widgetId,
|
|
20347
|
+
disabled: props.apiOptions.readOnly,
|
|
20348
|
+
style: styles.inputWithExamples
|
|
20349
|
+
});
|
|
20350
|
+
});
|
|
20351
|
+
|
|
20352
|
+
/**
|
|
20353
|
+
* The NumericInput widget is a numeric input field that supports a variety of
|
|
20354
|
+
* answer forms, including integers, decimals, fractions, and mixed numbers.
|
|
20355
|
+
*
|
|
20356
|
+
* [Jan 2025] We're currenly migrating from class-based components to functional
|
|
20357
|
+
* components. While we cannot fully migrate this component yet, we can start
|
|
20358
|
+
* by using the functional component for the rendering the UI of the widget.
|
|
20359
|
+
*/
|
|
20459
20360
|
class NumericInput extends React__namespace.Component {
|
|
20460
|
-
|
|
20461
|
-
inputRef;
|
|
20361
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
20462
20362
|
static defaultProps = {
|
|
20463
20363
|
currentValue: "",
|
|
20464
20364
|
size: "normal",
|
|
@@ -20474,51 +20374,15 @@ class NumericInput extends React__namespace.Component {
|
|
|
20474
20374
|
currentValue: props.currentValue
|
|
20475
20375
|
};
|
|
20476
20376
|
}
|
|
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
20377
|
focus = () => {
|
|
20514
|
-
this.inputRef?.focus();
|
|
20378
|
+
this.inputRef.current?.focus();
|
|
20515
20379
|
return true;
|
|
20516
20380
|
};
|
|
20517
20381
|
focusInputPath = () => {
|
|
20518
|
-
this.inputRef?.focus();
|
|
20382
|
+
this.inputRef.current?.focus();
|
|
20519
20383
|
};
|
|
20520
20384
|
blurInputPath = () => {
|
|
20521
|
-
this.inputRef?.blur();
|
|
20385
|
+
this.inputRef.current?.blur();
|
|
20522
20386
|
};
|
|
20523
20387
|
getInputPaths = () => {
|
|
20524
20388
|
// The widget itself is an input, so we return a single empty list to
|
|
@@ -20526,152 +20390,57 @@ class NumericInput extends React__namespace.Component {
|
|
|
20526
20390
|
/* c8 ignore next */
|
|
20527
20391
|
return [[]];
|
|
20528
20392
|
};
|
|
20393
|
+
|
|
20394
|
+
/**
|
|
20395
|
+
* Sets the value of the input at the given path.
|
|
20396
|
+
*/
|
|
20529
20397
|
setInputValue = (path, newValue, cb) => {
|
|
20530
|
-
/* c8 ignore next */
|
|
20531
20398
|
this.props.onChange({
|
|
20532
20399
|
currentValue: newValue
|
|
20533
20400
|
}, cb);
|
|
20534
20401
|
};
|
|
20402
|
+
|
|
20403
|
+
/**
|
|
20404
|
+
* Returns the value the user has currently input for this widget.
|
|
20405
|
+
*/
|
|
20535
20406
|
getUserInput() {
|
|
20536
20407
|
return NumericInput.getUserInputFromProps(this.props);
|
|
20537
20408
|
}
|
|
20409
|
+
|
|
20410
|
+
/**
|
|
20411
|
+
* Returns the JSON representation of the prompt for this widget.
|
|
20412
|
+
* This is used by the AI to determine the prompt for the widget.
|
|
20413
|
+
*/
|
|
20538
20414
|
getPromptJSON() {
|
|
20539
20415
|
return getPromptJSON$r(this.props, this.getUserInput());
|
|
20540
20416
|
}
|
|
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
20417
|
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
|
-
});
|
|
20418
|
+
return /*#__PURE__*/React__namespace.createElement(NumericInputComponent, _extends__default["default"]({}, this.props, {
|
|
20419
|
+
ref: this.inputRef
|
|
20420
|
+
}));
|
|
20620
20421
|
}
|
|
20621
20422
|
}
|
|
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
|
-
};
|
|
20423
|
+
// Transforms the widget options to the props used to render the widget.
|
|
20660
20424
|
const propsTransform = function (widgetOptions) {
|
|
20661
|
-
|
|
20425
|
+
// Omit the answers from the widget options since they are
|
|
20426
|
+
// not needed for rendering the widget.
|
|
20427
|
+
const {
|
|
20428
|
+
answers: _,
|
|
20429
|
+
...rendererProps
|
|
20430
|
+
} = {
|
|
20431
|
+
...widgetOptions,
|
|
20662
20432
|
answerForms: unionAnswerForms(
|
|
20663
|
-
//
|
|
20664
|
-
//
|
|
20665
|
-
widgetOptions.answers.map(answer => {
|
|
20666
|
-
|
|
20667
|
-
return ___default["default"].map(answer.answerForms, form => {
|
|
20433
|
+
// Filter out the correct answers and map them to the answer forms
|
|
20434
|
+
// so that we can generate the examples for the widget.
|
|
20435
|
+
widgetOptions.answers.filter(answer => answer.status === "correct").map(answer => {
|
|
20436
|
+
return (answer.answerForms || []).map(form => {
|
|
20668
20437
|
return {
|
|
20669
20438
|
simplify: answer.simplify,
|
|
20670
20439
|
name: form
|
|
20671
20440
|
};
|
|
20672
20441
|
});
|
|
20673
20442
|
}))
|
|
20674
|
-
}
|
|
20443
|
+
};
|
|
20675
20444
|
return rendererProps;
|
|
20676
20445
|
};
|
|
20677
20446
|
var NumericInput$1 = {
|
|
@@ -20686,23 +20455,11 @@ var NumericInput$1 = {
|
|
|
20686
20455
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
20687
20456
|
const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
|
|
20688
20457
|
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'.
|
|
20458
|
+
// Either get the first answer form or default to decimal
|
|
20459
|
+
const format = answer.answerForms && answer.answerForms[0] ? answer.answerForms[0] : "decimal";
|
|
20701
20460
|
let answerString = kmath.KhanMath.toNumericString(answer.value, format);
|
|
20702
20461
|
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);
|
|
20462
|
+
answerString += " \u00B1 " + kmath.KhanMath.toNumericString(answer.maxError, format);
|
|
20706
20463
|
}
|
|
20707
20464
|
return answerString;
|
|
20708
20465
|
});
|
|
@@ -23237,6 +22994,7 @@ const BASE_ICON_SIZE = 10;
|
|
|
23237
22994
|
// If you pass in an object you need to specify an SVG path to
|
|
23238
22995
|
// render along with the width and height of the path (to ensure
|
|
23239
22996
|
// that it gets scaled correctly).
|
|
22997
|
+
|
|
23240
22998
|
/**
|
|
23241
22999
|
* An SVG Icon
|
|
23242
23000
|
*
|
|
@@ -23494,7 +23252,7 @@ function ChoiceInner(props) {
|
|
|
23494
23252
|
return /*#__PURE__*/React__namespace.createElement("span", null, letter);
|
|
23495
23253
|
}
|
|
23496
23254
|
if (correct) {
|
|
23497
|
-
return /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
23255
|
+
return /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconCheck, {
|
|
23498
23256
|
style: {
|
|
23499
23257
|
position: "relative",
|
|
23500
23258
|
top: -1
|
|
@@ -23950,7 +23708,7 @@ const styles$p = aphrodite.StyleSheet.create({
|
|
|
23950
23708
|
}
|
|
23951
23709
|
}
|
|
23952
23710
|
});
|
|
23953
|
-
var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(Choice,
|
|
23711
|
+
var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(Choice, _extends__default["default"]({}, props, {
|
|
23954
23712
|
forwardedRef: ref
|
|
23955
23713
|
})));
|
|
23956
23714
|
|
|
@@ -23984,11 +23742,11 @@ const ChoiceNoneAbove = function (_ref) {
|
|
|
23984
23742
|
strings: strings
|
|
23985
23743
|
})
|
|
23986
23744
|
};
|
|
23987
|
-
return /*#__PURE__*/React__namespace.createElement(Choice$1,
|
|
23745
|
+
return /*#__PURE__*/React__namespace.createElement(Choice$1, _extends__default["default"]({}, choiceProps, {
|
|
23988
23746
|
ref: forwardedRef
|
|
23989
23747
|
}));
|
|
23990
23748
|
};
|
|
23991
|
-
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove,
|
|
23749
|
+
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove, _extends__default["default"]({}, props, {
|
|
23992
23750
|
forwardedRef: ref
|
|
23993
23751
|
})));
|
|
23994
23752
|
|
|
@@ -24238,7 +23996,7 @@ const BaseRadio = function (_ref) {
|
|
|
24238
23996
|
className: className,
|
|
24239
23997
|
onClick: clickHandler,
|
|
24240
23998
|
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
24241
|
-
}, /*#__PURE__*/React__namespace.createElement(Element,
|
|
23999
|
+
}, /*#__PURE__*/React__namespace.createElement(Element, _extends__default["default"]({}, elementProps, {
|
|
24242
24000
|
ref: ref
|
|
24243
24001
|
})))
|
|
24244
24002
|
);
|
|
@@ -24330,7 +24088,6 @@ const styles$o = aphrodite.StyleSheet.create({
|
|
|
24330
24088
|
paddingLeft: phoneMargin
|
|
24331
24089
|
// paddingRight is handled by responsiveFieldset
|
|
24332
24090
|
},
|
|
24333
|
-
|
|
24334
24091
|
responsiveFieldset: {
|
|
24335
24092
|
paddingRight: phoneMargin,
|
|
24336
24093
|
minWidth: "auto"
|
|
@@ -24574,7 +24331,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24574
24331
|
);
|
|
24575
24332
|
}
|
|
24576
24333
|
};
|
|
24577
|
-
|
|
24578
24334
|
render() {
|
|
24579
24335
|
const {
|
|
24580
24336
|
choices
|
|
@@ -24751,7 +24507,7 @@ const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
|
24751
24507
|
// 1) we randomize the order first
|
|
24752
24508
|
_maybeRandomize(choices)));
|
|
24753
24509
|
};
|
|
24754
|
-
const transform = (widgetOptions, strings, problemNum) => {
|
|
24510
|
+
const transform$1 = (widgetOptions, strings, problemNum) => {
|
|
24755
24511
|
const choices = _choiceTransform(widgetOptions, strings, problemNum);
|
|
24756
24512
|
const numCorrect = ___default["default"].reduce(widgetOptions.choices, function (memo, choice) {
|
|
24757
24513
|
return choice.correct ? memo + 1 : memo;
|
|
@@ -24777,8 +24533,8 @@ var Radio = {
|
|
|
24777
24533
|
displayName: "Radio / Multiple choice",
|
|
24778
24534
|
accessible: true,
|
|
24779
24535
|
widget: Radio$1,
|
|
24780
|
-
transform: transform,
|
|
24781
|
-
staticTransform: transform,
|
|
24536
|
+
transform: transform$1,
|
|
24537
|
+
staticTransform: transform$1,
|
|
24782
24538
|
version: perseusCore.radioLogic.version,
|
|
24783
24539
|
propUpgrades: perseusCore.radioLogic.widgetOptionsUpgrades,
|
|
24784
24540
|
isLintable: true
|
|
@@ -25360,6 +25116,7 @@ var Definition$1 = {
|
|
|
25360
25116
|
|
|
25361
25117
|
// There are no required props, but this component can receive props from any
|
|
25362
25118
|
// deprecated widget
|
|
25119
|
+
|
|
25363
25120
|
class DeprecatedStandin extends React__default["default"].Component {
|
|
25364
25121
|
static contextType = PerseusI18nContext;
|
|
25365
25122
|
// this just helps with TS weak typing when a Widget
|
|
@@ -25480,20 +25237,20 @@ class Dropdown extends React__namespace.Component {
|
|
|
25480
25237
|
}, children)));
|
|
25481
25238
|
}
|
|
25482
25239
|
}
|
|
25483
|
-
|
|
25240
|
+
function transform(widgetOptions) {
|
|
25484
25241
|
return {
|
|
25485
25242
|
placeholder: widgetOptions.placeholder,
|
|
25486
25243
|
visibleLabel: widgetOptions.visibleLabel,
|
|
25487
25244
|
ariaLabel: widgetOptions.ariaLabel,
|
|
25488
25245
|
choices: widgetOptions.choices.map(choice => choice.content)
|
|
25489
25246
|
};
|
|
25490
|
-
}
|
|
25247
|
+
}
|
|
25491
25248
|
var Dropdown$1 = {
|
|
25492
25249
|
name: "dropdown",
|
|
25493
25250
|
displayName: "Drop down",
|
|
25494
25251
|
accessible: true,
|
|
25495
25252
|
widget: Dropdown,
|
|
25496
|
-
transform
|
|
25253
|
+
transform
|
|
25497
25254
|
};
|
|
25498
25255
|
|
|
25499
25256
|
const getPromptJSON$j = renderProps => {
|
|
@@ -25569,7 +25326,6 @@ class Explanation extends React__namespace.Component {
|
|
|
25569
25326
|
// adds space between the right border and any text that follows
|
|
25570
25327
|
paddingLeft: "2px" // adds space between the left border and the button text
|
|
25571
25328
|
};
|
|
25572
|
-
|
|
25573
25329
|
const labelStyle = {
|
|
25574
25330
|
fontSize: "18px",
|
|
25575
25331
|
lineHeight: "inherit",
|
|
@@ -25725,7 +25481,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
25725
25481
|
fontSize: 28,
|
|
25726
25482
|
color: wonderBlocksTokens.color.green
|
|
25727
25483
|
}
|
|
25728
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25484
|
+
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconStar, {
|
|
25729
25485
|
style: {
|
|
25730
25486
|
marginBottom: 5
|
|
25731
25487
|
}
|
|
@@ -25918,7 +25674,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25918
25674
|
if (this.state.status === GRADING_STATUSES.correct) {
|
|
25919
25675
|
// TODO(jeremy): update to a WB colour
|
|
25920
25676
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
25921
|
-
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25677
|
+
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconOk, {
|
|
25922
25678
|
style: {
|
|
25923
25679
|
color: "#526f03"
|
|
25924
25680
|
}
|
|
@@ -25927,7 +25683,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25927
25683
|
} else if (this.state.status === GRADING_STATUSES.incorrect) {
|
|
25928
25684
|
// TODO(jeremy): update to a WB colour
|
|
25929
25685
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
25930
|
-
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25686
|
+
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconRemove, {
|
|
25931
25687
|
style: {
|
|
25932
25688
|
color: "#ff5454"
|
|
25933
25689
|
}
|
|
@@ -25954,7 +25710,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25954
25710
|
className: classes
|
|
25955
25711
|
}, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
|
|
25956
25712
|
className: aphrodite.css(styles$i.title)
|
|
25957
|
-
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
25713
|
+
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, this.props, {
|
|
25958
25714
|
ref: this.rendererRef,
|
|
25959
25715
|
apiOptions: {
|
|
25960
25716
|
...apiOptions,
|
|
@@ -25997,7 +25753,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25997
25753
|
showHint: false
|
|
25998
25754
|
});
|
|
25999
25755
|
}
|
|
26000
|
-
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
25756
|
+
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, this.props.hint, {
|
|
26001
25757
|
ref: this.hintRendererRef,
|
|
26002
25758
|
apiOptions: apiOptions,
|
|
26003
25759
|
linterContext: this.props.linterContext,
|
|
@@ -26222,7 +25978,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
26222
25978
|
// TODO(jeremy): Don't spread this.props, instead
|
|
26223
25979
|
// pass in all props GradedGroup needs explicilty
|
|
26224
25980
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
26225
|
-
React__namespace.createElement(GradedGroup,
|
|
25981
|
+
React__namespace.createElement(GradedGroup, _extends__default["default"]({
|
|
26226
25982
|
key: i
|
|
26227
25983
|
}, this.props, gradedGroup, {
|
|
26228
25984
|
inGradedGroupSet: false,
|
|
@@ -26251,7 +26007,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
26251
26007
|
onChangeCurrentGroup: currentGroup => this.setState({
|
|
26252
26008
|
currentGroup
|
|
26253
26009
|
})
|
|
26254
|
-
})), /*#__PURE__*/React__namespace.createElement(GradedGroup,
|
|
26010
|
+
})), /*#__PURE__*/React__namespace.createElement(GradedGroup, _extends__default["default"]({
|
|
26255
26011
|
key: this.state.currentGroup
|
|
26256
26012
|
// @ts-expect-error - TS2322 - Type 'GradedGroup | null' is not assignable to type 'GradedGroup'.
|
|
26257
26013
|
// Type 'null' is not assignable to type 'GradedGroup'.
|
|
@@ -26647,7 +26403,7 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26647
26403
|
}
|
|
26648
26404
|
const functionProps = model.getPropsForCoeffs(coeffs, xRange);
|
|
26649
26405
|
const Movable = movableTypeToComponent[model.movable];
|
|
26650
|
-
return /*#__PURE__*/React__namespace.createElement(Movable,
|
|
26406
|
+
return /*#__PURE__*/React__namespace.createElement(Movable, _extends__default["default"]({}, functionProps, {
|
|
26651
26407
|
key: this.props.model.url,
|
|
26652
26408
|
range: xRange,
|
|
26653
26409
|
style: style
|
|
@@ -26780,7 +26536,7 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26780
26536
|
width: box[0],
|
|
26781
26537
|
height: box[1]
|
|
26782
26538
|
}
|
|
26783
|
-
}, image, /*#__PURE__*/React__namespace.createElement(Graphie,
|
|
26539
|
+
}, image, /*#__PURE__*/React__namespace.createElement(Graphie, _extends__default["default"]({}, this.props.graph, {
|
|
26784
26540
|
setDrawingAreaAvailable: this.props.setDrawingAreaAvailable
|
|
26785
26541
|
}), this.props.model && this.renderPlot(), this.props.model && this.renderAsymptote(), this.props.model && points)));
|
|
26786
26542
|
}
|
|
@@ -27924,7 +27680,6 @@ class Interaction extends React__namespace.Component {
|
|
|
27924
27680
|
}
|
|
27925
27681
|
});
|
|
27926
27682
|
}
|
|
27927
|
-
|
|
27928
27683
|
if (element.type === "parametric") {
|
|
27929
27684
|
const fn = t => {
|
|
27930
27685
|
return [
|
|
@@ -27977,7 +27732,6 @@ class Interaction extends React__namespace.Component {
|
|
|
27977
27732
|
}
|
|
27978
27733
|
});
|
|
27979
27734
|
}
|
|
27980
|
-
|
|
27981
27735
|
if (element.type === "label") {
|
|
27982
27736
|
const coord = [
|
|
27983
27737
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
@@ -28309,7 +28063,6 @@ function scaleCommandBy(scaleFactor) {
|
|
|
28309
28063
|
command.args[6] * scaleFactor // end y
|
|
28310
28064
|
]
|
|
28311
28065
|
};
|
|
28312
|
-
|
|
28313
28066
|
default:
|
|
28314
28067
|
return {
|
|
28315
28068
|
...command,
|
|
@@ -29069,7 +28822,6 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
29069
28822
|
userSelect: "none",
|
|
29070
28823
|
borderWidth: 0 // <button> gives us a border by default
|
|
29071
28824
|
},
|
|
29072
|
-
|
|
29073
28825
|
// We want to render the element in-place in our fixtures, so allow us to
|
|
29074
28826
|
// render in the bottom corner in production and in-place in testing.
|
|
29075
28827
|
hudFixedPosition: {
|
|
@@ -29099,7 +28851,6 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
29099
28851
|
":hover": {
|
|
29100
28852
|
backgroundColor: "#a1a5a9" // in between those two grays
|
|
29101
28853
|
},
|
|
29102
|
-
|
|
29103
28854
|
":active": {
|
|
29104
28855
|
backgroundColor: gray68
|
|
29105
28856
|
}
|
|
@@ -29144,7 +28895,6 @@ class InfoTip extends React__namespace.Component {
|
|
|
29144
28895
|
});
|
|
29145
28896
|
/* eslint-enable react/no-did-mount-set-state */
|
|
29146
28897
|
}
|
|
29147
|
-
|
|
29148
28898
|
render() {
|
|
29149
28899
|
if (this.state.didMount) {
|
|
29150
28900
|
return /*#__PURE__*/React__namespace.createElement(InfoTipBase, this.props);
|
|
@@ -29410,7 +29160,6 @@ class NumberInput extends React__namespace.Component {
|
|
|
29410
29160
|
if (val !== Math.floor(val)) {
|
|
29411
29161
|
return; // bail if not an integer
|
|
29412
29162
|
}
|
|
29413
|
-
|
|
29414
29163
|
if (e.key === "ArrowUp") {
|
|
29415
29164
|
val = val + 1;
|
|
29416
29165
|
} else if (e.key === "ArrowDown") {
|
|
@@ -29443,7 +29192,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
29443
29192
|
useArrowKeys,
|
|
29444
29193
|
...restProps
|
|
29445
29194
|
} = this.props;
|
|
29446
|
-
return /*#__PURE__*/React__namespace.createElement("input",
|
|
29195
|
+
return /*#__PURE__*/React__namespace.createElement("input", _extends__default["default"]({}, restProps, {
|
|
29447
29196
|
className: classes,
|
|
29448
29197
|
type: "text",
|
|
29449
29198
|
ref: this.inputRef,
|
|
@@ -29488,7 +29237,7 @@ class RangeInput extends React__namespace.Component {
|
|
|
29488
29237
|
const checkValidity = this.props.checkValidity || truth;
|
|
29489
29238
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
29490
29239
|
className: "range-input"
|
|
29491
|
-
}, /*#__PURE__*/React__namespace.createElement(NumberInput,
|
|
29240
|
+
}, /*#__PURE__*/React__namespace.createElement(NumberInput, _extends__default["default"]({}, this.props, {
|
|
29492
29241
|
value: value[0],
|
|
29493
29242
|
checkValidity: val => checkValidity([val, value[1]])
|
|
29494
29243
|
// eslint-disable-next-line react/jsx-no-bind
|
|
@@ -29496,7 +29245,7 @@ class RangeInput extends React__namespace.Component {
|
|
|
29496
29245
|
onChange: this.onChange.bind(this, 0),
|
|
29497
29246
|
placeholder: this.props.placeholder[0],
|
|
29498
29247
|
allowPiTruncation: this.props.allowPiTruncation
|
|
29499
|
-
})), /*#__PURE__*/React__namespace.createElement(NumberInput,
|
|
29248
|
+
})), /*#__PURE__*/React__namespace.createElement(NumberInput, _extends__default["default"]({}, this.props, {
|
|
29500
29249
|
value: value[1],
|
|
29501
29250
|
checkValidity: val => checkValidity([value[0], val])
|
|
29502
29251
|
// eslint-disable-next-line react/jsx-no-bind
|
|
@@ -29509,20 +29258,20 @@ class RangeInput extends React__namespace.Component {
|
|
|
29509
29258
|
}
|
|
29510
29259
|
|
|
29511
29260
|
var components = /*#__PURE__*/Object.freeze({
|
|
29512
|
-
|
|
29513
|
-
|
|
29514
|
-
|
|
29515
|
-
|
|
29516
|
-
|
|
29517
|
-
|
|
29518
|
-
|
|
29519
|
-
|
|
29520
|
-
|
|
29521
|
-
|
|
29522
|
-
|
|
29523
|
-
|
|
29524
|
-
|
|
29525
|
-
|
|
29261
|
+
__proto__: null,
|
|
29262
|
+
ButtonGroup: ButtonGroup,
|
|
29263
|
+
Graphie: Graphie,
|
|
29264
|
+
HUD: HUD,
|
|
29265
|
+
Icon: Icon,
|
|
29266
|
+
InfoTip: InfoTip,
|
|
29267
|
+
InlineIcon: InlineIcon,
|
|
29268
|
+
MathInput: MathInput,
|
|
29269
|
+
MultiButtonGroup: MultiButtonGroup,
|
|
29270
|
+
NumberInput: NumberInput,
|
|
29271
|
+
RangeInput: RangeInput,
|
|
29272
|
+
SvgImage: SvgImage,
|
|
29273
|
+
TextInput: TextInput,
|
|
29274
|
+
TextListEditor: TextListEditor
|
|
29526
29275
|
});
|
|
29527
29276
|
|
|
29528
29277
|
/**
|
|
@@ -29598,17 +29347,17 @@ function GraphLockedLabelsLayer(props) {
|
|
|
29598
29347
|
} = props;
|
|
29599
29348
|
return lockedFigures.map((figure, i) => {
|
|
29600
29349
|
if (figure.type === "label") {
|
|
29601
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29350
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29602
29351
|
key: `label-${i}`
|
|
29603
29352
|
}, figure));
|
|
29604
29353
|
}
|
|
29605
29354
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, {
|
|
29606
29355
|
key: i
|
|
29607
|
-
}, figure.labels?.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29356
|
+
}, figure.labels?.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29608
29357
|
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,
|
|
29358
|
+
}, 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
29359
|
key: `locked-figure-${i}-point-1-label-${k}`
|
|
29611
|
-
}, label))), figure.points[1].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29360
|
+
}, label))), figure.points[1].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29612
29361
|
key: `locked-figure-${i}-point-2-label-${k}`
|
|
29613
29362
|
}, label)))));
|
|
29614
29363
|
});
|
|
@@ -29654,9 +29403,9 @@ const LockedFunction = props => {
|
|
|
29654
29403
|
const {
|
|
29655
29404
|
color,
|
|
29656
29405
|
strokeStyle,
|
|
29657
|
-
directionalAxis
|
|
29406
|
+
directionalAxis,
|
|
29407
|
+
domain
|
|
29658
29408
|
} = 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
29409
|
const plotProps = {
|
|
29661
29410
|
color: perseusCore.lockedFigureColors[color],
|
|
29662
29411
|
style: strokeStyle,
|
|
@@ -29676,11 +29425,11 @@ const LockedFunction = props => {
|
|
|
29676
29425
|
"aria-label": hasAria ? props.ariaLabel : undefined,
|
|
29677
29426
|
"aria-hidden": !hasAria,
|
|
29678
29427
|
role: "img"
|
|
29679
|
-
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX,
|
|
29428
|
+
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, _extends__default["default"]({
|
|
29680
29429
|
y: x => equation.eval({
|
|
29681
29430
|
x
|
|
29682
29431
|
})
|
|
29683
|
-
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY,
|
|
29432
|
+
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY, _extends__default["default"]({
|
|
29684
29433
|
x: y => equation.eval({
|
|
29685
29434
|
y
|
|
29686
29435
|
})
|
|
@@ -30254,28 +30003,28 @@ const GraphLockedLayer = props => {
|
|
|
30254
30003
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lockedFigures.map((figure, index) => {
|
|
30255
30004
|
switch (figure.type) {
|
|
30256
30005
|
case "point":
|
|
30257
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPoint,
|
|
30006
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPoint, _extends__default["default"]({
|
|
30258
30007
|
key: `point-${index}`
|
|
30259
30008
|
}, figure));
|
|
30260
30009
|
case "line":
|
|
30261
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLine,
|
|
30010
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLine, _extends__default["default"]({
|
|
30262
30011
|
key: `line-${index}`,
|
|
30263
30012
|
range: props.range
|
|
30264
30013
|
}, figure));
|
|
30265
30014
|
case "vector":
|
|
30266
|
-
return /*#__PURE__*/React__namespace.createElement(LockedVector,
|
|
30015
|
+
return /*#__PURE__*/React__namespace.createElement(LockedVector, _extends__default["default"]({
|
|
30267
30016
|
key: `vector-${index}`
|
|
30268
30017
|
}, figure));
|
|
30269
30018
|
case "ellipse":
|
|
30270
|
-
return /*#__PURE__*/React__namespace.createElement(LockedEllipse,
|
|
30019
|
+
return /*#__PURE__*/React__namespace.createElement(LockedEllipse, _extends__default["default"]({
|
|
30271
30020
|
key: `ellipse-${index}`
|
|
30272
30021
|
}, figure));
|
|
30273
30022
|
case "polygon":
|
|
30274
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPolygon,
|
|
30023
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPolygon, _extends__default["default"]({
|
|
30275
30024
|
key: `polygon-${index}`
|
|
30276
30025
|
}, figure));
|
|
30277
30026
|
case "function":
|
|
30278
|
-
return /*#__PURE__*/React__namespace.createElement(LockedFunction,
|
|
30027
|
+
return /*#__PURE__*/React__namespace.createElement(LockedFunction, _extends__default["default"]({
|
|
30279
30028
|
key: `function-${index}`
|
|
30280
30029
|
}, figure));
|
|
30281
30030
|
case "label":
|
|
@@ -30506,7 +30255,7 @@ const TextLabel = _ref => {
|
|
|
30506
30255
|
children,
|
|
30507
30256
|
...rest
|
|
30508
30257
|
} = _ref;
|
|
30509
|
-
return /*#__PURE__*/React__default["default"].createElement(mafs.Text,
|
|
30258
|
+
return /*#__PURE__*/React__default["default"].createElement(mafs.Text, _extends__default["default"]({
|
|
30510
30259
|
size: 16,
|
|
30511
30260
|
svgTextProps: {
|
|
30512
30261
|
filter: "url(#background)",
|
|
@@ -31217,6 +30966,9 @@ const MovableLine = props => {
|
|
|
31217
30966
|
onMoveLine = () => {},
|
|
31218
30967
|
onMovePoint = () => {}
|
|
31219
30968
|
} = props;
|
|
30969
|
+
const {
|
|
30970
|
+
snapStep
|
|
30971
|
+
} = useGraphConfig();
|
|
31220
30972
|
|
|
31221
30973
|
// Aria live states for (0) point 1, (1) point 2, and (2) grab handle.
|
|
31222
30974
|
// When moving an element, set its aria live to "polite" and the others
|
|
@@ -31248,7 +31000,8 @@ const MovableLine = props => {
|
|
|
31248
31000
|
onMove: p => {
|
|
31249
31001
|
setAriaLives(["polite", "off", "off"]);
|
|
31250
31002
|
onMovePoint(0, p);
|
|
31251
|
-
}
|
|
31003
|
+
},
|
|
31004
|
+
constrain: getMovableLineKeyboardConstraint([start, end], snapStep, 0)
|
|
31252
31005
|
});
|
|
31253
31006
|
const {
|
|
31254
31007
|
visiblePoint: visiblePoint2,
|
|
@@ -31263,7 +31016,8 @@ const MovableLine = props => {
|
|
|
31263
31016
|
onMove: p => {
|
|
31264
31017
|
setAriaLives(["off", "polite", "off"]);
|
|
31265
31018
|
onMovePoint(1, p);
|
|
31266
|
-
}
|
|
31019
|
+
},
|
|
31020
|
+
constrain: getMovableLineKeyboardConstraint([start, end], snapStep, 1)
|
|
31267
31021
|
});
|
|
31268
31022
|
const line = /*#__PURE__*/React__namespace.createElement(Line$1, {
|
|
31269
31023
|
ariaLabel: ariaLabels?.grabHandleAriaLabel,
|
|
@@ -31369,6 +31123,34 @@ const Line$1 = props => {
|
|
|
31369
31123
|
color: stroke
|
|
31370
31124
|
}));
|
|
31371
31125
|
};
|
|
31126
|
+
const getMovableLineKeyboardConstraint = (line, snapStep, pointIndex) => {
|
|
31127
|
+
// Separate the two points into their own variables, and determine which point is being moved
|
|
31128
|
+
const coordToBeMoved = line[pointIndex];
|
|
31129
|
+
const otherPoint = line[1 - pointIndex];
|
|
31130
|
+
|
|
31131
|
+
// Create a helper function that moves the point and then checks
|
|
31132
|
+
// if it overlaps with the other point in the line after the move.
|
|
31133
|
+
const movePointWithConstraint = moveFunc => {
|
|
31134
|
+
// Move the point
|
|
31135
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
31136
|
+
// If the moved point overlaps with the other point in the line,
|
|
31137
|
+
// move the point again.
|
|
31138
|
+
if (mafs.vec.dist(movedCoord, otherPoint) === 0) {
|
|
31139
|
+
movedCoord = moveFunc(movedCoord);
|
|
31140
|
+
}
|
|
31141
|
+
return movedCoord;
|
|
31142
|
+
};
|
|
31143
|
+
|
|
31144
|
+
// Check if the new point will overlap the other point.
|
|
31145
|
+
// If it will, we need to snap the point to the left or right an additional
|
|
31146
|
+
// snapStep to avoid overlap.
|
|
31147
|
+
return {
|
|
31148
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
31149
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
31150
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
31151
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
31152
|
+
};
|
|
31153
|
+
};
|
|
31372
31154
|
function trimRange(range, graphDimensionsInPixels) {
|
|
31373
31155
|
const pixelsToTrim = 4;
|
|
31374
31156
|
const [xRange, yRange] = range;
|
|
@@ -31725,7 +31507,8 @@ function CircleGraph(props) {
|
|
|
31725
31507
|
} = props;
|
|
31726
31508
|
const {
|
|
31727
31509
|
center,
|
|
31728
|
-
radiusPoint
|
|
31510
|
+
radiusPoint,
|
|
31511
|
+
snapStep
|
|
31729
31512
|
} = graphState;
|
|
31730
31513
|
const {
|
|
31731
31514
|
strings,
|
|
@@ -31788,7 +31571,8 @@ function CircleGraph(props) {
|
|
|
31788
31571
|
onMove: newRadiusPoint => {
|
|
31789
31572
|
setRadiusPointAriaLive("polite");
|
|
31790
31573
|
dispatch(actions.circle.moveRadiusPoint(newRadiusPoint));
|
|
31791
|
-
}
|
|
31574
|
+
},
|
|
31575
|
+
constrain: getCircleKeyboardConstraint(center, radiusPoint, snapStep)
|
|
31792
31576
|
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
31793
31577
|
id: radiusId,
|
|
31794
31578
|
style: a11y.srOnly
|
|
@@ -31899,6 +31683,30 @@ function getCircleGraphDescription(state, i18n) {
|
|
|
31899
31683
|
const strings = describeCircleGraph(state, i18n);
|
|
31900
31684
|
return strings.srCircleInteractiveElement;
|
|
31901
31685
|
}
|
|
31686
|
+
const getCircleKeyboardConstraint = (center, radiusPoint, snapStep) => {
|
|
31687
|
+
// Create a helper function that moves the point and then checks
|
|
31688
|
+
// if it overlaps with the center point after the move.
|
|
31689
|
+
const movePointWithConstraint = moveFunc => {
|
|
31690
|
+
// Move the point
|
|
31691
|
+
let movedCoord = moveFunc(radiusPoint);
|
|
31692
|
+
// If the moved point overlaps with the center point,
|
|
31693
|
+
// move the point again.
|
|
31694
|
+
if (mafs.vec.dist(movedCoord, center) === 0) {
|
|
31695
|
+
movedCoord = moveFunc(movedCoord);
|
|
31696
|
+
}
|
|
31697
|
+
return movedCoord;
|
|
31698
|
+
};
|
|
31699
|
+
|
|
31700
|
+
// Check if the new point overlaps the center point.
|
|
31701
|
+
// If it does, we need to snap the point to the left
|
|
31702
|
+
// or right an additional snapStep to avoid the overlap.
|
|
31703
|
+
return {
|
|
31704
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
31705
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
31706
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
31707
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
31708
|
+
};
|
|
31709
|
+
};
|
|
31902
31710
|
|
|
31903
31711
|
// Exported for testing
|
|
31904
31712
|
function describeCircleGraph(state, i18n) {
|
|
@@ -31911,6 +31719,7 @@ function describeCircleGraph(state, i18n) {
|
|
|
31911
31719
|
radiusPoint
|
|
31912
31720
|
} = state;
|
|
31913
31721
|
const radius = getRadius(state);
|
|
31722
|
+
const isRadiusOnRight = radiusPoint[X] >= center[X];
|
|
31914
31723
|
|
|
31915
31724
|
// Aria label strings
|
|
31916
31725
|
const srCircleGraph = strings.srCircleGraph;
|
|
@@ -31918,7 +31727,10 @@ function describeCircleGraph(state, i18n) {
|
|
|
31918
31727
|
centerX: srFormatNumber(center[0], locale),
|
|
31919
31728
|
centerY: srFormatNumber(center[1], locale)
|
|
31920
31729
|
});
|
|
31921
|
-
const srCircleRadiusPoint = strings.
|
|
31730
|
+
const srCircleRadiusPoint = isRadiusOnRight ? strings.srCircleRadiusPointRight({
|
|
31731
|
+
radiusPointX: srFormatNumber(radiusPoint[0], locale),
|
|
31732
|
+
radiusPointY: srFormatNumber(radiusPoint[1], locale)
|
|
31733
|
+
}) : strings.srCircleRadiusPointLeft({
|
|
31922
31734
|
radiusPointX: srFormatNumber(radiusPoint[0], locale),
|
|
31923
31735
|
radiusPointY: srFormatNumber(radiusPoint[1], locale)
|
|
31924
31736
|
});
|
|
@@ -32084,6 +31896,12 @@ const LinearSystemGraph = props => {
|
|
|
32084
31896
|
locale
|
|
32085
31897
|
} = usePerseusI18n();
|
|
32086
31898
|
const id = React__namespace.useId();
|
|
31899
|
+
const intersectionId = `${id}-intersection`;
|
|
31900
|
+
const intersectionPoint = kmath.geometry.getLineIntersection(lines[0], lines[1]);
|
|
31901
|
+
const intersectionDescription = intersectionPoint ? strings.srLinearSystemIntersection({
|
|
31902
|
+
x: srFormatNumber(intersectionPoint[0], locale),
|
|
31903
|
+
y: srFormatNumber(intersectionPoint[1], locale)
|
|
31904
|
+
}) : strings.srLinearSystemParallel;
|
|
32087
31905
|
const linesAriaInfo = lines.map((line, i) => {
|
|
32088
31906
|
return {
|
|
32089
31907
|
pointsDescriptionId: `${id}-line${i + 1}-points`,
|
|
@@ -32100,16 +31918,17 @@ const LinearSystemGraph = props => {
|
|
|
32100
31918
|
slopeDescription: getSlopeStringForLine(line, strings)
|
|
32101
31919
|
};
|
|
32102
31920
|
});
|
|
31921
|
+
const individualLineDescriptions = linesAriaInfo.map(_ref => {
|
|
31922
|
+
let {
|
|
31923
|
+
pointsDescriptionId,
|
|
31924
|
+
interceptDescriptionId,
|
|
31925
|
+
slopeDescriptionId
|
|
31926
|
+
} = _ref;
|
|
31927
|
+
return `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`;
|
|
31928
|
+
}).join(" ");
|
|
32103
31929
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
32104
31930
|
"aria-label": strings.srLinearSystemGraph,
|
|
32105
|
-
"aria-describedby":
|
|
32106
|
-
let {
|
|
32107
|
-
pointsDescriptionId,
|
|
32108
|
-
interceptDescriptionId,
|
|
32109
|
-
slopeDescriptionId
|
|
32110
|
-
} = _ref;
|
|
32111
|
-
return `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`;
|
|
32112
|
-
}).join(" ")
|
|
31931
|
+
"aria-describedby": `${individualLineDescriptions} ${intersectionId}`
|
|
32113
31932
|
}, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
32114
31933
|
key: i,
|
|
32115
31934
|
points: line,
|
|
@@ -32126,9 +31945,15 @@ const LinearSystemGraph = props => {
|
|
|
32126
31945
|
x: srFormatNumber(line[1][0], locale),
|
|
32127
31946
|
y: srFormatNumber(line[1][1], locale)
|
|
32128
31947
|
}),
|
|
32129
|
-
grabHandleAriaLabel:
|
|
31948
|
+
grabHandleAriaLabel: strings.srLinearSystemGrabHandle({
|
|
31949
|
+
lineNumber: i + 1,
|
|
31950
|
+
point1X: srFormatNumber(line[0][0], locale),
|
|
31951
|
+
point1Y: srFormatNumber(line[0][1], locale),
|
|
31952
|
+
point2X: srFormatNumber(line[1][0], locale),
|
|
31953
|
+
point2Y: srFormatNumber(line[1][1], locale)
|
|
31954
|
+
})
|
|
32130
31955
|
},
|
|
32131
|
-
ariaDescribedBy: `${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId}`,
|
|
31956
|
+
ariaDescribedBy: `${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId} ${intersectionId}`,
|
|
32132
31957
|
onMoveLine: delta => {
|
|
32133
31958
|
dispatch(actions.linearSystem.moveLine(i, delta));
|
|
32134
31959
|
},
|
|
@@ -32160,7 +31985,10 @@ const LinearSystemGraph = props => {
|
|
|
32160
31985
|
id: slopeDescriptionId,
|
|
32161
31986
|
style: a11y.srOnly
|
|
32162
31987
|
}, slopeDescription));
|
|
32163
|
-
})
|
|
31988
|
+
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
31989
|
+
id: intersectionId,
|
|
31990
|
+
style: a11y.srOnly
|
|
31991
|
+
}, intersectionDescription));
|
|
32164
31992
|
};
|
|
32165
31993
|
|
|
32166
31994
|
// Exported for testing
|
|
@@ -32826,7 +32654,8 @@ function QuadraticGraph(props) {
|
|
|
32826
32654
|
graphState
|
|
32827
32655
|
} = props;
|
|
32828
32656
|
const {
|
|
32829
|
-
coords
|
|
32657
|
+
coords,
|
|
32658
|
+
snapStep
|
|
32830
32659
|
} = graphState;
|
|
32831
32660
|
const {
|
|
32832
32661
|
strings,
|
|
@@ -32879,6 +32708,7 @@ function QuadraticGraph(props) {
|
|
|
32879
32708
|
ariaLabel: `${srQuadraticPoint}${srVertex}`,
|
|
32880
32709
|
point: coord,
|
|
32881
32710
|
sequenceNumber: i + 1,
|
|
32711
|
+
constrain: getQuadraticKeyboardConstraint(coords, snapStep, i),
|
|
32882
32712
|
onMove: destination => dispatch(actions.quadratic.movePoint(i, destination))
|
|
32883
32713
|
});
|
|
32884
32714
|
}), srQuadraticDirection && /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -32967,6 +32797,60 @@ function describeQuadraticGraph(state, i18n) {
|
|
|
32967
32797
|
srQuadraticInteractiveElements
|
|
32968
32798
|
};
|
|
32969
32799
|
}
|
|
32800
|
+
const getQuadraticKeyboardConstraint = (coords, snapStep, pointMoved) => {
|
|
32801
|
+
// Make newCoords mutable
|
|
32802
|
+
const newCoords = [coords[0], coords[1], coords[2]];
|
|
32803
|
+
|
|
32804
|
+
// Get the point that is being moved
|
|
32805
|
+
const coordToBeMoved = newCoords[pointMoved];
|
|
32806
|
+
|
|
32807
|
+
// Create a function to validate and adjust the movement of the point
|
|
32808
|
+
const movePointWithConstraint = moveFunc => {
|
|
32809
|
+
// Move the point the desired direction
|
|
32810
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
32811
|
+
newCoords[pointMoved] = movedCoord;
|
|
32812
|
+
|
|
32813
|
+
// If these new coordinates are valid, return the moved coord
|
|
32814
|
+
if (areCoordsValid(newCoords)) {
|
|
32815
|
+
return movedCoord;
|
|
32816
|
+
}
|
|
32817
|
+
|
|
32818
|
+
// If the new coordinates are invalid, we need to move the point an additional
|
|
32819
|
+
// snapStep to avoid creating an invalid quadratic graph.
|
|
32820
|
+
movedCoord = moveFunc(movedCoord);
|
|
32821
|
+
newCoords[pointMoved] = movedCoord;
|
|
32822
|
+
|
|
32823
|
+
// If these updated coordinates are valid now, we can return the new coordinates.
|
|
32824
|
+
if (areCoordsValid(newCoords)) {
|
|
32825
|
+
return movedCoord;
|
|
32826
|
+
}
|
|
32827
|
+
|
|
32828
|
+
// Otherwise, if the new coordinates are still invalid, we need to move the point one final snapStep.
|
|
32829
|
+
// This is to support the edge case where all of the points are each exactly one snapStep away
|
|
32830
|
+
// from each other.
|
|
32831
|
+
// Eg. When coords = [[0, 0], [1, 0], [2, 0]], snapStep = [1, 1], and we're moving coords[0] to the right.
|
|
32832
|
+
return moveFunc(movedCoord);
|
|
32833
|
+
};
|
|
32834
|
+
return {
|
|
32835
|
+
up: mafs.vec.add(coordToBeMoved, [0, snapStep[1]]),
|
|
32836
|
+
down: mafs.vec.sub(coordToBeMoved, [0, snapStep[1]]),
|
|
32837
|
+
// For horizontal movement, we need to ensure that the points are not on the same vertical line.
|
|
32838
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
32839
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
32840
|
+
};
|
|
32841
|
+
};
|
|
32842
|
+
const areCoordsValid = coords => {
|
|
32843
|
+
const p1 = coords[0];
|
|
32844
|
+
const p2 = coords[1];
|
|
32845
|
+
const p3 = coords[2];
|
|
32846
|
+
|
|
32847
|
+
// If any of the points share the same x-coordinate,
|
|
32848
|
+
// we are unable to calculate the coefficients, and the graph is invalid.
|
|
32849
|
+
if (p1[0] === p2[0] || p2[0] === p3[0] || p1[0] === p3[0]) {
|
|
32850
|
+
return false;
|
|
32851
|
+
}
|
|
32852
|
+
return true;
|
|
32853
|
+
};
|
|
32970
32854
|
|
|
32971
32855
|
function renderRayGraph(state, dispatch, i18n) {
|
|
32972
32856
|
return {
|
|
@@ -33222,7 +33106,8 @@ function SinusoidGraph(props) {
|
|
|
33222
33106
|
// Note: The order of the coordinates is important:
|
|
33223
33107
|
// The coords[0] is the root and the coords[1] is the first peak
|
|
33224
33108
|
const {
|
|
33225
|
-
coords
|
|
33109
|
+
coords,
|
|
33110
|
+
snapStep
|
|
33226
33111
|
} = graphState;
|
|
33227
33112
|
|
|
33228
33113
|
// The coefficients are used to calculate the sinusoid equation, plot the graph, and to indicate
|
|
@@ -33261,11 +33146,37 @@ function SinusoidGraph(props) {
|
|
|
33261
33146
|
key: "point-" + i,
|
|
33262
33147
|
point: coord,
|
|
33263
33148
|
sequenceNumber: i + 1,
|
|
33149
|
+
constrain: getSinusoidKeyboardConstraint(coords, snapStep, i),
|
|
33264
33150
|
onMove: destination => dispatch(actions.sinusoid.movePoint(i, destination))
|
|
33265
33151
|
})), /*#__PURE__*/React__namespace.createElement("g", {
|
|
33266
33152
|
id: descriptionId
|
|
33267
33153
|
}, srSinusoidDescription));
|
|
33268
33154
|
}
|
|
33155
|
+
const getSinusoidKeyboardConstraint = (coords, snapStep, pointIndex) => {
|
|
33156
|
+
// Separate the two points into their own variables, and determine which point is being moved
|
|
33157
|
+
const coordToBeMoved = coords[pointIndex];
|
|
33158
|
+
const otherPoint = coords[1 - pointIndex];
|
|
33159
|
+
|
|
33160
|
+
// Create a helper function that checks if the new point is on the same
|
|
33161
|
+
// vertical line as the other point. If it is, we need to move the point
|
|
33162
|
+
// an additional snapStep.
|
|
33163
|
+
const movePointWithConstraint = moveFunc => {
|
|
33164
|
+
// Move the point
|
|
33165
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
33166
|
+
// If the moved point overlaps with the other point in the line,
|
|
33167
|
+
// move the point again.
|
|
33168
|
+
if (movedCoord[X] === otherPoint[X]) {
|
|
33169
|
+
movedCoord = moveFunc(movedCoord);
|
|
33170
|
+
}
|
|
33171
|
+
return movedCoord;
|
|
33172
|
+
};
|
|
33173
|
+
return {
|
|
33174
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
33175
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
33176
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
33177
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
33178
|
+
};
|
|
33179
|
+
};
|
|
33269
33180
|
|
|
33270
33181
|
// Plot a sinusoid of the form: f(x) = a * sin(b * x - c) + d
|
|
33271
33182
|
const computeSine = function (x,
|
|
@@ -33317,6 +33228,14 @@ function describeSinusoidGraph(state, i18n) {
|
|
|
33317
33228
|
const [root, peak] = coords;
|
|
33318
33229
|
const diffX = Math.abs(peak[X] - root[X]);
|
|
33319
33230
|
const diffY = Math.abs(peak[Y] - root[Y]);
|
|
33231
|
+
const formattedRoot = {
|
|
33232
|
+
x: srFormatNumber(root[X], locale),
|
|
33233
|
+
y: srFormatNumber(root[Y], locale)
|
|
33234
|
+
};
|
|
33235
|
+
const formattedPeak = {
|
|
33236
|
+
x: srFormatNumber(peak[X], locale),
|
|
33237
|
+
y: srFormatNumber(peak[Y], locale)
|
|
33238
|
+
};
|
|
33320
33239
|
const srSinusoidGraph = strings.srSinusoidGraph;
|
|
33321
33240
|
const srSinusoidDescription = strings.srSinusoidDescription({
|
|
33322
33241
|
minValue: srFormatNumber(root[Y] - diffY, locale),
|
|
@@ -33324,14 +33243,8 @@ function describeSinusoidGraph(state, i18n) {
|
|
|
33324
33243
|
cycleStart: srFormatNumber(root[X] - 2 * diffX, locale),
|
|
33325
33244
|
cycleEnd: srFormatNumber(root[X] + 2 * diffX, locale)
|
|
33326
33245
|
});
|
|
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
|
-
});
|
|
33246
|
+
const srSinusoidRootPoint = strings.srSinusoidRootPoint(formattedRoot);
|
|
33247
|
+
const srSinusoidPeakPoint = peak[Y] === root[Y] ? strings.srSinusoidFlatPoint(formattedPeak) : peak[Y] > root[Y] ? strings.srSinusoidMaxPoint(formattedPeak) : strings.srSinusoidMinPoint(formattedPeak);
|
|
33335
33248
|
const srSinusoidInteractiveElements = strings.srInteractiveElements({
|
|
33336
33249
|
elements: strings.srSinusoidInteractiveElements({
|
|
33337
33250
|
point1X: srFormatNumber(root[X], locale),
|
|
@@ -33353,16 +33266,17 @@ const {
|
|
|
33353
33266
|
calculateAngleInDegrees,
|
|
33354
33267
|
convertDegreesToRadians
|
|
33355
33268
|
} = kmath.angles;
|
|
33356
|
-
const protractorImage = "https://
|
|
33269
|
+
const protractorImage = "https://cdn.kastatic.org/images/perseus/protractor.svg";
|
|
33357
33270
|
|
|
33358
33271
|
// The vector from the center of the protractor to the top left corner of the
|
|
33359
33272
|
// protractor image, in pixels. Used for positioning.
|
|
33360
|
-
const centerToTopLeft = [-
|
|
33273
|
+
const centerToTopLeft = [-195, -190];
|
|
33361
33274
|
|
|
33362
33275
|
// The vector from the center of the protractor to the center of the rotation
|
|
33363
33276
|
// handle.
|
|
33364
|
-
const centerToRotationHandle = [-
|
|
33277
|
+
const centerToRotationHandle = [-201, -15];
|
|
33365
33278
|
function Protractor() {
|
|
33279
|
+
const staticUrl = getDependencies().staticUrl;
|
|
33366
33280
|
const {
|
|
33367
33281
|
range,
|
|
33368
33282
|
snapStep
|
|
@@ -33374,7 +33288,9 @@ function Protractor() {
|
|
|
33374
33288
|
const [center, setCenter] = React.useState(initialCenter);
|
|
33375
33289
|
const [rotationHandleOffset, setRotationHandleOffset] = React.useState(centerToRotationHandle);
|
|
33376
33290
|
const draggableRef = React.useRef(null);
|
|
33377
|
-
|
|
33291
|
+
const {
|
|
33292
|
+
dragging
|
|
33293
|
+
} = useDraggable({
|
|
33378
33294
|
gestureTarget: draggableRef,
|
|
33379
33295
|
onMove: setCenter,
|
|
33380
33296
|
point: center,
|
|
@@ -33398,10 +33314,11 @@ function Protractor() {
|
|
|
33398
33314
|
ref: draggableRef,
|
|
33399
33315
|
transform: `translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,
|
|
33400
33316
|
style: {
|
|
33401
|
-
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px
|
|
33317
|
+
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`,
|
|
33318
|
+
cursor: dragging ? "grabbing" : "grab"
|
|
33402
33319
|
}
|
|
33403
33320
|
}, /*#__PURE__*/React__namespace.createElement("image", {
|
|
33404
|
-
href: protractorImage
|
|
33321
|
+
href: staticUrl(protractorImage)
|
|
33405
33322
|
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
33406
33323
|
transform: `translate(5, ${-centerToTopLeft[1]})`,
|
|
33407
33324
|
ref: rotationHandleRef
|
|
@@ -35333,8 +35250,8 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
35333
35250
|
|
|
35334
35251
|
// If the graph is static, it always displays the correct answer. This is
|
|
35335
35252
|
// standard behavior for Perseus widgets (e.g. compare the Radio widget).
|
|
35336
|
-
if (props.static) {
|
|
35337
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph,
|
|
35253
|
+
if (props.static && props.correct) {
|
|
35254
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends__default["default"]({}, props, {
|
|
35338
35255
|
state: initializeGraphState({
|
|
35339
35256
|
...props,
|
|
35340
35257
|
graph: props.correct
|
|
@@ -35342,7 +35259,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
35342
35259
|
dispatch: dispatch
|
|
35343
35260
|
}));
|
|
35344
35261
|
}
|
|
35345
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph,
|
|
35262
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends__default["default"]({}, props, {
|
|
35346
35263
|
state: state,
|
|
35347
35264
|
dispatch: dispatch
|
|
35348
35265
|
}));
|
|
@@ -35353,7 +35270,7 @@ const {
|
|
|
35353
35270
|
} = kmath.angles;
|
|
35354
35271
|
const {
|
|
35355
35272
|
getLineEquation,
|
|
35356
|
-
|
|
35273
|
+
getLineIntersectionString,
|
|
35357
35274
|
magnitude,
|
|
35358
35275
|
vector
|
|
35359
35276
|
} = kmath.geometry;
|
|
@@ -35435,7 +35352,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35435
35352
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
35436
35353
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
35437
35354
|
const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
|
|
35438
|
-
return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph,
|
|
35355
|
+
return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph, _extends__default["default"]({}, this.props, {
|
|
35439
35356
|
ref: this.mafsRef,
|
|
35440
35357
|
gridStep: gridStep,
|
|
35441
35358
|
snapStep: snapStep,
|
|
@@ -35718,7 +35635,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35718
35635
|
}
|
|
35719
35636
|
static getLinearSystemEquationString(props) {
|
|
35720
35637
|
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" +
|
|
35638
|
+
return "\n" + getLineEquation(coords[0][0], coords[0][1]) + "\n" + getLineEquation(coords[1][0], coords[1][1]) + "\n" + getLineIntersectionString(coords[0], coords[1]);
|
|
35722
35639
|
}
|
|
35723
35640
|
static getPointEquationString(props) {
|
|
35724
35641
|
if (props.graph.type !== "point") {
|
|
@@ -35870,10 +35787,10 @@ const AnswerChoices = props => {
|
|
|
35870
35787
|
onToggle,
|
|
35871
35788
|
disabled
|
|
35872
35789
|
};
|
|
35873
|
-
return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect,
|
|
35790
|
+
return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect, _extends__default["default"]({}, args, {
|
|
35874
35791
|
selectedValues: selectedValues,
|
|
35875
35792
|
onChange: selected => onAnswerChange(selected)
|
|
35876
|
-
})) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect,
|
|
35793
|
+
})) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, _extends__default["default"]({}, args, {
|
|
35877
35794
|
selectedValue: selectedValues[0],
|
|
35878
35795
|
onChange: selected => onAnswerChange([selected]),
|
|
35879
35796
|
placeholder: props.choices[0].content // not visible, but required
|
|
@@ -36159,7 +36076,6 @@ const styles$a = aphrodite.StyleSheet.create({
|
|
|
36159
36076
|
markerCorrect: {
|
|
36160
36077
|
background: "#00880b" // WB green darkened by 18%
|
|
36161
36078
|
},
|
|
36162
|
-
|
|
36163
36079
|
markerIncorrect: {
|
|
36164
36080
|
background: wonderBlocksTokens.color.offBlack64
|
|
36165
36081
|
}
|
|
@@ -36556,7 +36472,6 @@ class LabelImage extends React__namespace.Component {
|
|
|
36556
36472
|
const adjustPillDistance = {
|
|
36557
36473
|
[`margin${markerPosition.charAt(0).toUpperCase() + markerPosition.slice(1)}`]: 10 // move pill further from marker
|
|
36558
36474
|
};
|
|
36559
|
-
|
|
36560
36475
|
const answerChoicesActive = index === activeMarkerIndex;
|
|
36561
36476
|
const showAnswerChoice = marker.selected && !answerChoicesActive && !this.state.hideAnswers;
|
|
36562
36477
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
@@ -36605,7 +36520,7 @@ class LabelImage extends React__namespace.Component {
|
|
|
36605
36520
|
focused,
|
|
36606
36521
|
pressed
|
|
36607
36522
|
} = _ref2;
|
|
36608
|
-
return /*#__PURE__*/React__namespace.createElement(Marker,
|
|
36523
|
+
return /*#__PURE__*/React__namespace.createElement(Marker, _extends__default["default"]({}, marker, {
|
|
36609
36524
|
showCorrectness: showCorrectness,
|
|
36610
36525
|
showSelected: opened,
|
|
36611
36526
|
showPulsate: !markersInteracted,
|
|
@@ -36750,7 +36665,7 @@ const styles$9 = aphrodite.StyleSheet.create({
|
|
|
36750
36665
|
});
|
|
36751
36666
|
const LabelImageWithDependencies = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
36752
36667
|
const deps = useDependencies();
|
|
36753
|
-
return /*#__PURE__*/React__namespace.createElement(LabelImage,
|
|
36668
|
+
return /*#__PURE__*/React__namespace.createElement(LabelImage, _extends__default["default"]({
|
|
36754
36669
|
ref: ref,
|
|
36755
36670
|
analytics: deps.analytics
|
|
36756
36671
|
}, props));
|
|
@@ -37012,7 +36927,6 @@ class Draggable extends React__namespace.Component {
|
|
|
37012
36927
|
if (this.props.width) {
|
|
37013
36928
|
style.width = this.props.width + 1; // Fix for non-integer widths
|
|
37014
36929
|
}
|
|
37015
|
-
|
|
37016
36930
|
if (this.props.height) {
|
|
37017
36931
|
style.height = this.props.height;
|
|
37018
36932
|
}
|
|
@@ -37356,8 +37270,7 @@ class Sortable extends React__namespace.Component {
|
|
|
37356
37270
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
37357
37271
|
margin = "0 0 " + this.props.margin + "px 0"; // bottom
|
|
37358
37272
|
}
|
|
37359
|
-
|
|
37360
|
-
cards.push( /*#__PURE__*/React__namespace.createElement(Draggable, {
|
|
37273
|
+
cards.push(/*#__PURE__*/React__namespace.createElement(Draggable, {
|
|
37361
37274
|
content: item.option,
|
|
37362
37275
|
key: item.key,
|
|
37363
37276
|
state: item.state
|
|
@@ -37410,7 +37323,7 @@ class Sortable extends React__namespace.Component {
|
|
|
37410
37323
|
this, item.key)
|
|
37411
37324
|
}));
|
|
37412
37325
|
if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
|
|
37413
|
-
cards.push(
|
|
37326
|
+
cards.push(/*#__PURE__*/React__namespace.createElement(Placeholder, {
|
|
37414
37327
|
key: "placeholder_" + item.key,
|
|
37415
37328
|
ref: "placeholder_" + item.key,
|
|
37416
37329
|
width: item.width,
|
|
@@ -38024,7 +37937,7 @@ class Matrix extends React__namespace.Component {
|
|
|
38024
37937
|
boxSizing: "border-box",
|
|
38025
37938
|
backgroundColor: outside ? "#f3f3f3" : "#fff"
|
|
38026
37939
|
};
|
|
38027
|
-
MatrixInput = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput,
|
|
37940
|
+
MatrixInput = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, _extends__default["default"]({}, inputProps, {
|
|
38028
37941
|
style: style,
|
|
38029
37942
|
scrollable: true,
|
|
38030
37943
|
keypadElement: this.props.keypadElement
|
|
@@ -39185,7 +39098,6 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
39185
39098
|
if (!___default["default"].isFinite(props.tickStep) || props.tickStep <= 0) {
|
|
39186
39099
|
return []; // this has screwed me for the last time!
|
|
39187
39100
|
}
|
|
39188
|
-
|
|
39189
39101
|
const results = [];
|
|
39190
39102
|
|
|
39191
39103
|
// For convenience, extract some props into separate variables
|
|
@@ -39256,6 +39168,7 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
39256
39168
|
|
|
39257
39169
|
// TODO: most widgets use some like Widget<Something, PerseusNumberLineWidgetOptions>
|
|
39258
39170
|
// should this one?
|
|
39171
|
+
|
|
39259
39172
|
class NumberLine extends React__namespace.Component {
|
|
39260
39173
|
static contextType = PerseusI18nContext;
|
|
39261
39174
|
static defaultProps = {
|
|
@@ -39400,7 +39313,7 @@ class NumberLine extends React__namespace.Component {
|
|
|
39400
39313
|
setup: this._setupGraphie,
|
|
39401
39314
|
setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable,
|
|
39402
39315
|
isMobile: this.props.apiOptions.isMobile
|
|
39403
|
-
}, /*#__PURE__*/React__namespace.createElement(TickMarks,
|
|
39316
|
+
}, /*#__PURE__*/React__namespace.createElement(TickMarks, _extends__default["default"]({}, ___default["default"].pick(props, ["range", "numDivisions", "labelTicks", "labelStyle", "labelRange", "tickStep"]), {
|
|
39404
39317
|
isMobile: this.props.apiOptions.isMobile
|
|
39405
39318
|
})), this._renderInequality(props), this._renderNumberLinePoint(props));
|
|
39406
39319
|
};
|
|
@@ -39627,7 +39540,6 @@ const numberLineTransform = editorProps => {
|
|
|
39627
39540
|
} else {
|
|
39628
39541
|
numDivisions = undefined; // send to getDefaultProps()
|
|
39629
39542
|
}
|
|
39630
|
-
|
|
39631
39543
|
___default["default"].extend(props, {
|
|
39632
39544
|
numLinePosition: numLinePosition,
|
|
39633
39545
|
numDivisions: numDivisions,
|
|
@@ -39652,7 +39564,6 @@ const staticTransform$1 = editorProps => {
|
|
|
39652
39564
|
} else {
|
|
39653
39565
|
numDivisions = undefined; // send to getDefaultProps()
|
|
39654
39566
|
}
|
|
39655
|
-
|
|
39656
39567
|
___default["default"].extend(props, {
|
|
39657
39568
|
numLinePosition: numLinePosition,
|
|
39658
39569
|
numDivisions: numDivisions,
|
|
@@ -39847,7 +39758,7 @@ class Card extends React__namespace.Component {
|
|
|
39847
39758
|
onTouchCancel: this.onMouseUp
|
|
39848
39759
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
39849
39760
|
className: className.join(" ")
|
|
39850
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
39761
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, rendererProps, {
|
|
39851
39762
|
linterContext: this.props.linterContext,
|
|
39852
39763
|
strings: this.context.strings
|
|
39853
39764
|
}))))
|
|
@@ -40672,7 +40583,6 @@ class Plotter extends React__namespace.Component {
|
|
|
40672
40583
|
const initialY = isMobile ? c.scaleY : 0;
|
|
40673
40584
|
for (let y = initialY; y <= c.dimY; y += c.scaleY) {
|
|
40674
40585
|
graphie.label([0, y], kmath.KhanMath.roundToApprox(y, 2), "left", /* isTeX */true /* for the \approx symbol */);
|
|
40675
|
-
|
|
40676
40586
|
graphie.style({
|
|
40677
40587
|
stroke: isMobile ? "#e9ebec" : "#000",
|
|
40678
40588
|
strokeWidth: 1,
|
|
@@ -41634,7 +41544,7 @@ class Table extends React__namespace.Component {
|
|
|
41634
41544
|
}, ___default["default"](columns).times(c => {
|
|
41635
41545
|
return /*#__PURE__*/React__namespace.createElement("td", {
|
|
41636
41546
|
key: c
|
|
41637
|
-
}, /*#__PURE__*/React__namespace.createElement(InputComponent,
|
|
41547
|
+
}, /*#__PURE__*/React__namespace.createElement(InputComponent, _extends__default["default"]({
|
|
41638
41548
|
ref: getRefForPath(getInputPath(r, c)),
|
|
41639
41549
|
type: "text",
|
|
41640
41550
|
value: this.props.answers[r][c],
|
|
@@ -41845,10 +41755,51 @@ const init = function () {
|
|
|
41845
41755
|
replaceDeprecatedWidgets();
|
|
41846
41756
|
};
|
|
41847
41757
|
|
|
41758
|
+
/**
|
|
41759
|
+
* Adds the given perseus library version information to the __perseus_debug__
|
|
41760
|
+
* object and ensures that the object is attached to `globalThis` (`window` in
|
|
41761
|
+
* browser environments).
|
|
41762
|
+
*
|
|
41763
|
+
* This allows each library to provide runtime version information to assist in
|
|
41764
|
+
* debugging in production environments.
|
|
41765
|
+
*/
|
|
41766
|
+
const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
41767
|
+
// If the library version is the default value, then we don't want to
|
|
41768
|
+
// prefix it with a "v" to indicate that it is a version number.
|
|
41769
|
+
let prefix = "v";
|
|
41770
|
+
if (libraryVersion === "__lib_version__") {
|
|
41771
|
+
prefix = "";
|
|
41772
|
+
}
|
|
41773
|
+
const formattedVersion = `${prefix}${libraryVersion}`;
|
|
41774
|
+
if (typeof globalThis !== "undefined") {
|
|
41775
|
+
globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
|
|
41776
|
+
const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
|
|
41777
|
+
if (existingVersionEntry) {
|
|
41778
|
+
// If we already have an entry and it doesn't match the registered
|
|
41779
|
+
// version, we morph the entry into an array and log a warning.
|
|
41780
|
+
if (existingVersionEntry !== formattedVersion) {
|
|
41781
|
+
// Existing entry might be an array already (oops, at least 2
|
|
41782
|
+
// versions of the library already loaded!).
|
|
41783
|
+
const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
|
|
41784
|
+
allVersions.push(formattedVersion);
|
|
41785
|
+
globalThis.__perseus_debug__[libraryName] = allVersions;
|
|
41786
|
+
|
|
41787
|
+
// eslint-disable-next-line no-console
|
|
41788
|
+
console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
|
|
41789
|
+
}
|
|
41790
|
+
} else {
|
|
41791
|
+
globalThis.__perseus_debug__[libraryName] = formattedVersion;
|
|
41792
|
+
}
|
|
41793
|
+
} else {
|
|
41794
|
+
// eslint-disable-next-line no-console
|
|
41795
|
+
console.warn(`globalThis not found found (${formattedVersion})`);
|
|
41796
|
+
}
|
|
41797
|
+
};
|
|
41798
|
+
|
|
41848
41799
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
41849
41800
|
const libName = "@khanacademy/perseus";
|
|
41850
|
-
const libVersion = "
|
|
41851
|
-
|
|
41801
|
+
const libVersion = "55.0.1";
|
|
41802
|
+
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
41852
41803
|
|
|
41853
41804
|
const apiVersion = {
|
|
41854
41805
|
major: 12,
|
|
@@ -42004,7 +41955,7 @@ class ArticleRenderer extends React__namespace.Component {
|
|
|
42004
41955
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
42005
41956
|
key: sectionIndex,
|
|
42006
41957
|
className: "clearfix"
|
|
42007
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
41958
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, section, {
|
|
42008
41959
|
ref: elem => {
|
|
42009
41960
|
if (elem) {
|
|
42010
41961
|
this.sectionRenderers[sectionIndex] = elem;
|
|
@@ -42179,7 +42130,6 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
42179
42130
|
ReactDOM__default["default"].findDOMNode(this.refs["hintRenderer" + pos]).focus(); // eslint-disable-line react/no-string-refs
|
|
42180
42131
|
}
|
|
42181
42132
|
}
|
|
42182
|
-
|
|
42183
42133
|
_hintsVisible = () => {
|
|
42184
42134
|
if (this.props.hintsVisible == null || this.props.hintsVisible === -1) {
|
|
42185
42135
|
return this.props.hints.length;
|
|
@@ -42668,7 +42618,7 @@ class ServerItemRenderer extends React__namespace.Component {
|
|
|
42668
42618
|
};
|
|
42669
42619
|
const questionRenderer = /*#__PURE__*/React__namespace.createElement(context$1.Provider, {
|
|
42670
42620
|
value: contextValue
|
|
42671
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
42621
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({
|
|
42672
42622
|
keypadElement: this.props.keypadElement,
|
|
42673
42623
|
problemNum: this.props.problemNum,
|
|
42674
42624
|
onInteractWithWidget: this.handleInteractWithWidget,
|
|
@@ -42717,7 +42667,7 @@ const ref = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__
|
|
|
42717
42667
|
let {
|
|
42718
42668
|
onRendered
|
|
42719
42669
|
} = _ref;
|
|
42720
|
-
return /*#__PURE__*/React__namespace.createElement(ServerItemRenderer,
|
|
42670
|
+
return /*#__PURE__*/React__namespace.createElement(ServerItemRenderer, _extends__default["default"]({}, props, {
|
|
42721
42671
|
onRendered: onRendered,
|
|
42722
42672
|
ref: ref
|
|
42723
42673
|
}));
|
|
@@ -44148,24 +44098,24 @@ const ScoringUtil = {
|
|
|
44148
44098
|
*/
|
|
44149
44099
|
|
|
44150
44100
|
Object.defineProperty(exports, 'isFailure', {
|
|
44151
|
-
|
|
44152
|
-
|
|
44101
|
+
enumerable: true,
|
|
44102
|
+
get: function () { return perseusCore.isFailure; }
|
|
44153
44103
|
});
|
|
44154
44104
|
Object.defineProperty(exports, 'isSuccess', {
|
|
44155
|
-
|
|
44156
|
-
|
|
44105
|
+
enumerable: true,
|
|
44106
|
+
get: function () { return perseusCore.isSuccess; }
|
|
44157
44107
|
});
|
|
44158
44108
|
Object.defineProperty(exports, 'parseAndMigratePerseusArticle', {
|
|
44159
|
-
|
|
44160
|
-
|
|
44109
|
+
enumerable: true,
|
|
44110
|
+
get: function () { return perseusCore.parseAndMigratePerseusArticle; }
|
|
44161
44111
|
});
|
|
44162
44112
|
Object.defineProperty(exports, 'parseAndMigratePerseusItem', {
|
|
44163
|
-
|
|
44164
|
-
|
|
44113
|
+
enumerable: true,
|
|
44114
|
+
get: function () { return perseusCore.parseAndMigratePerseusItem; }
|
|
44165
44115
|
});
|
|
44166
44116
|
Object.defineProperty(exports, 'parsePerseusItem', {
|
|
44167
|
-
|
|
44168
|
-
|
|
44117
|
+
enumerable: true,
|
|
44118
|
+
get: function () { return perseusCore.parsePerseusItem; }
|
|
44169
44119
|
});
|
|
44170
44120
|
exports.ApiOptions = ApiOptions;
|
|
44171
44121
|
exports.ArticleRenderer = ArticleRenderer;
|