@khanacademy/perseus 54.0.0 → 55.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -0
- package/dist/components/number-input.d.ts +9 -10
- package/dist/components/range-input.d.ts +5 -6
- package/dist/components/simple-keypad-input.d.ts +5 -0
- package/dist/components/stub-tag-editor.d.ts +3 -4
- package/dist/components/text-list-editor.d.ts +3 -4
- package/dist/es/index.css +16 -6
- package/dist/es/index.js +919 -1066
- 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 +1055 -1170
- 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/types.d.ts +3 -1
- package/dist/util.d.ts +0 -5
- package/dist/widget-ai-utils/numeric-input/prompt-utils.d.ts +1 -1
- package/dist/widgets/categorizer/categorizer.d.ts +1 -1
- package/dist/widgets/dropdown/dropdown.d.ts +5 -4
- package/dist/widgets/expression/expression.d.ts +0 -2
- 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/dist/widgets/radio/radio.d.ts +1 -1
- package/dist/widgets/sorter/sorter.d.ts +1 -1
- package/package.json +120 -124
- package/dist/components/input-with-examples.d.ts +0 -51
- package/dist/components/tooltip.d.ts +0 -85
package/dist/index.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var _extends = require('@babel/runtime/helpers/extends');
|
|
5
6
|
var KAS = require('@khanacademy/kas');
|
|
6
7
|
var mathInput = require('@khanacademy/math-input');
|
|
7
8
|
var perseusCore = require('@khanacademy/perseus-core');
|
|
8
9
|
var PerseusLinter = require('@khanacademy/perseus-linter');
|
|
9
10
|
var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
10
|
-
var Tooltip
|
|
11
|
+
var Tooltip = require('@khanacademy/wonder-blocks-tooltip');
|
|
11
12
|
var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
|
|
12
13
|
var aphrodite = require('aphrodite');
|
|
13
14
|
var classNames$1 = require('classnames');
|
|
@@ -21,12 +22,13 @@ var $ = require('jquery');
|
|
|
21
22
|
var uuid = require('uuid');
|
|
22
23
|
var PropTypes = require('prop-types');
|
|
23
24
|
var perseusScore = require('@khanacademy/perseus-score');
|
|
25
|
+
var keypadContext = require('@khanacademy/keypad-context');
|
|
26
|
+
var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
|
|
24
27
|
var wonderStuffCore = require('@khanacademy/wonder-stuff-core');
|
|
25
28
|
var wonderBlocksProgressSpinner = require('@khanacademy/wonder-blocks-progress-spinner');
|
|
26
29
|
var kmath = require('@khanacademy/kmath');
|
|
27
30
|
var SimpleMarkdown = require('@khanacademy/simple-markdown');
|
|
28
31
|
var pureMarkdown = require('@khanacademy/pure-markdown');
|
|
29
|
-
var wonderBlocksForm = require('@khanacademy/wonder-blocks-form');
|
|
30
32
|
var Button = require('@khanacademy/wonder-blocks-button');
|
|
31
33
|
var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
|
|
32
34
|
var Banner = require('@khanacademy/wonder-blocks-banner');
|
|
@@ -47,26 +49,27 @@ var Link = require('@khanacademy/wonder-blocks-link');
|
|
|
47
49
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
48
50
|
|
|
49
51
|
function _interopNamespace(e) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
if (e && e.__esModule) return e;
|
|
53
|
+
var n = Object.create(null);
|
|
54
|
+
if (e) {
|
|
55
|
+
Object.keys(e).forEach(function (k) {
|
|
56
|
+
if (k !== 'default') {
|
|
57
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
58
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function () { return e[k]; }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
59
63
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
n["default"] = e;
|
|
64
|
-
return Object.freeze(n);
|
|
64
|
+
}
|
|
65
|
+
n["default"] = e;
|
|
66
|
+
return Object.freeze(n);
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
|
|
67
70
|
var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
|
|
68
71
|
var PerseusLinter__namespace = /*#__PURE__*/_interopNamespace(PerseusLinter);
|
|
69
|
-
var Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip
|
|
72
|
+
var Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip);
|
|
70
73
|
var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames$1);
|
|
71
74
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
72
75
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
@@ -88,21 +91,6 @@ var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
|
88
91
|
var cornersOutIcon__default = /*#__PURE__*/_interopDefaultLegacy(cornersOutIcon);
|
|
89
92
|
var Link__default = /*#__PURE__*/_interopDefaultLegacy(Link);
|
|
90
93
|
|
|
91
|
-
function _extends() {
|
|
92
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
93
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
94
|
-
var source = arguments[i];
|
|
95
|
-
for (var key in source) {
|
|
96
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
97
|
-
target[key] = source[key];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return target;
|
|
102
|
-
};
|
|
103
|
-
return _extends.apply(this, arguments);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
94
|
/**
|
|
107
95
|
* The translated strings that are used to render Perseus.
|
|
108
96
|
*/
|
|
@@ -398,20 +386,27 @@ const mockStrings = {
|
|
|
398
386
|
} = _ref29;
|
|
399
387
|
return `Circle. The center point is at ${centerX} comma ${centerY}.`;
|
|
400
388
|
},
|
|
401
|
-
|
|
389
|
+
srCircleRadiusPointRight: _ref30 => {
|
|
402
390
|
let {
|
|
403
391
|
radiusPointX,
|
|
404
392
|
radiusPointY
|
|
405
393
|
} = _ref30;
|
|
406
|
-
return `
|
|
394
|
+
return `Right radius endpoint at ${radiusPointX} comma ${radiusPointY}.`;
|
|
407
395
|
},
|
|
408
|
-
|
|
396
|
+
srCircleRadiusPointLeft: _ref31 => {
|
|
409
397
|
let {
|
|
410
|
-
|
|
398
|
+
radiusPointX,
|
|
399
|
+
radiusPointY
|
|
411
400
|
} = _ref31;
|
|
401
|
+
return `Left radius endpoint at ${radiusPointX} comma ${radiusPointY}.`;
|
|
402
|
+
},
|
|
403
|
+
srCircleRadius: _ref32 => {
|
|
404
|
+
let {
|
|
405
|
+
radius
|
|
406
|
+
} = _ref32;
|
|
412
407
|
return `Circle radius is ${radius}.`;
|
|
413
408
|
},
|
|
414
|
-
srCircleOuterPoints:
|
|
409
|
+
srCircleOuterPoints: _ref33 => {
|
|
415
410
|
let {
|
|
416
411
|
point1X,
|
|
417
412
|
point1Y,
|
|
@@ -421,83 +416,83 @@ const mockStrings = {
|
|
|
421
416
|
point3Y,
|
|
422
417
|
point4X,
|
|
423
418
|
point4Y
|
|
424
|
-
} =
|
|
419
|
+
} = _ref33;
|
|
425
420
|
return `Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`;
|
|
426
421
|
},
|
|
427
422
|
srLinearGraph: "A line on a coordinate plane.",
|
|
428
|
-
srLinearGraphPoints:
|
|
423
|
+
srLinearGraphPoints: _ref34 => {
|
|
429
424
|
let {
|
|
430
425
|
point1X,
|
|
431
426
|
point1Y,
|
|
432
427
|
point2X,
|
|
433
428
|
point2Y
|
|
434
|
-
} =
|
|
429
|
+
} = _ref34;
|
|
435
430
|
return `The line has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`;
|
|
436
431
|
},
|
|
437
432
|
srLinearGraphSlopeIncreasing: "Its slope increases from left to right.",
|
|
438
433
|
srLinearGraphSlopeDecreasing: "Its slope decreases from left to right.",
|
|
439
434
|
srLinearGraphSlopeHorizontal: "Its slope is zero.",
|
|
440
435
|
srLinearGraphSlopeVertical: "Its slope is undefined.",
|
|
441
|
-
srLinearGraphXOnlyIntercept:
|
|
436
|
+
srLinearGraphXOnlyIntercept: _ref35 => {
|
|
442
437
|
let {
|
|
443
438
|
xIntercept
|
|
444
|
-
} =
|
|
439
|
+
} = _ref35;
|
|
445
440
|
return `The line crosses the X-axis at ${xIntercept} comma 0.`;
|
|
446
441
|
},
|
|
447
|
-
srLinearGraphYOnlyIntercept:
|
|
442
|
+
srLinearGraphYOnlyIntercept: _ref36 => {
|
|
448
443
|
let {
|
|
449
444
|
yIntercept
|
|
450
|
-
} =
|
|
445
|
+
} = _ref36;
|
|
451
446
|
return `The line crosses the Y-axis at 0 comma ${yIntercept}.`;
|
|
452
447
|
},
|
|
453
|
-
srLinearGraphBothIntercepts:
|
|
448
|
+
srLinearGraphBothIntercepts: _ref37 => {
|
|
454
449
|
let {
|
|
455
450
|
xIntercept,
|
|
456
451
|
yIntercept
|
|
457
|
-
} =
|
|
452
|
+
} = _ref37;
|
|
458
453
|
return `The line crosses the X-axis at ${xIntercept} comma 0 and the Y-axis at 0 comma ${yIntercept}.`;
|
|
459
454
|
},
|
|
460
|
-
srLinearGraphOriginIntercept: "The line crosses the
|
|
461
|
-
srLinearGrabHandle:
|
|
455
|
+
srLinearGraphOriginIntercept: "The line crosses the X and Y axes at the graph's origin.",
|
|
456
|
+
srLinearGrabHandle: _ref38 => {
|
|
462
457
|
let {
|
|
463
458
|
point1X,
|
|
464
459
|
point1Y,
|
|
465
460
|
point2X,
|
|
466
461
|
point2Y
|
|
467
|
-
} =
|
|
468
|
-
return `Line
|
|
462
|
+
} = _ref38;
|
|
463
|
+
return `Line going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`;
|
|
469
464
|
},
|
|
470
|
-
srAngleStartingSide:
|
|
465
|
+
srAngleStartingSide: _ref39 => {
|
|
471
466
|
let {
|
|
472
467
|
x,
|
|
473
468
|
y
|
|
474
|
-
} =
|
|
469
|
+
} = _ref39;
|
|
475
470
|
return `Point 3, starting side at ${x} comma ${y}.`;
|
|
476
471
|
},
|
|
477
|
-
srAngleEndingSide:
|
|
472
|
+
srAngleEndingSide: _ref40 => {
|
|
478
473
|
let {
|
|
479
474
|
x,
|
|
480
475
|
y
|
|
481
|
-
} =
|
|
476
|
+
} = _ref40;
|
|
482
477
|
return `Point 2, ending side at ${x} comma ${y}.`;
|
|
483
478
|
},
|
|
484
|
-
srAngleVertex:
|
|
479
|
+
srAngleVertex: _ref41 => {
|
|
485
480
|
let {
|
|
486
481
|
x,
|
|
487
482
|
y
|
|
488
|
-
} =
|
|
483
|
+
} = _ref41;
|
|
489
484
|
return `Point 1, vertex at ${x} comma ${y}.`;
|
|
490
485
|
},
|
|
491
|
-
srAngleVertexWithAngleMeasure:
|
|
486
|
+
srAngleVertexWithAngleMeasure: _ref42 => {
|
|
492
487
|
let {
|
|
493
488
|
x,
|
|
494
489
|
y,
|
|
495
490
|
angleMeasure
|
|
496
|
-
} =
|
|
491
|
+
} = _ref42;
|
|
497
492
|
return `Point 1, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees.`;
|
|
498
493
|
},
|
|
499
494
|
srAngleGraphAriaLabel: "An angle on a coordinate plane.",
|
|
500
|
-
srAngleGraphAriaDescription:
|
|
495
|
+
srAngleGraphAriaDescription: _ref43 => {
|
|
501
496
|
let {
|
|
502
497
|
angleMeasure,
|
|
503
498
|
vertexX,
|
|
@@ -506,10 +501,10 @@ const mockStrings = {
|
|
|
506
501
|
startingSideY,
|
|
507
502
|
endingSideX,
|
|
508
503
|
endingSideY
|
|
509
|
-
} =
|
|
504
|
+
} = _ref43;
|
|
510
505
|
return `The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the starting side at ${startingSideX} comma ${startingSideY} and a point on the ending side at ${endingSideX} comma ${endingSideY}.`;
|
|
511
506
|
},
|
|
512
|
-
srAngleInteractiveElements:
|
|
507
|
+
srAngleInteractiveElements: _ref44 => {
|
|
513
508
|
let {
|
|
514
509
|
vertexX,
|
|
515
510
|
vertexY,
|
|
@@ -517,118 +512,136 @@ const mockStrings = {
|
|
|
517
512
|
startingSideY,
|
|
518
513
|
endingSideX,
|
|
519
514
|
endingSideY
|
|
520
|
-
} =
|
|
515
|
+
} = _ref44;
|
|
521
516
|
return `An angle formed by 3 points. The vertex is at ${vertexX} comma ${vertexY}. The starting side point is at ${startingSideX} comma ${startingSideY}. The ending side point is at ${endingSideX} comma ${endingSideY}.`;
|
|
522
517
|
},
|
|
523
518
|
srSingleSegmentGraphAriaLabel: "A line segment on a coordinate plane.",
|
|
524
|
-
srMultipleSegmentGraphAriaLabel:
|
|
519
|
+
srMultipleSegmentGraphAriaLabel: _ref45 => {
|
|
525
520
|
let {
|
|
526
521
|
countOfSegments
|
|
527
|
-
} =
|
|
522
|
+
} = _ref45;
|
|
528
523
|
return `${countOfSegments} segments on a coordinate plane.`;
|
|
529
524
|
},
|
|
530
|
-
srMultipleSegmentIndividualLabel:
|
|
525
|
+
srMultipleSegmentIndividualLabel: _ref46 => {
|
|
531
526
|
let {
|
|
532
527
|
point1X,
|
|
533
528
|
point1Y,
|
|
534
529
|
point2X,
|
|
535
530
|
point2Y,
|
|
536
531
|
indexOfSegment
|
|
537
|
-
} =
|
|
532
|
+
} = _ref46;
|
|
538
533
|
return `Segment ${indexOfSegment}: Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`;
|
|
539
534
|
},
|
|
540
|
-
srSingleSegmentLabel:
|
|
535
|
+
srSingleSegmentLabel: _ref47 => {
|
|
541
536
|
let {
|
|
542
537
|
point1X,
|
|
543
538
|
point1Y,
|
|
544
539
|
point2X,
|
|
545
540
|
point2Y
|
|
546
|
-
} =
|
|
541
|
+
} = _ref47;
|
|
547
542
|
return `Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`;
|
|
548
543
|
},
|
|
549
|
-
srSegmentLength:
|
|
544
|
+
srSegmentLength: _ref48 => {
|
|
550
545
|
let {
|
|
551
546
|
length
|
|
552
|
-
} =
|
|
547
|
+
} = _ref48;
|
|
553
548
|
return `Segment length ${length} units.`;
|
|
554
549
|
},
|
|
555
|
-
srSingleSegmentGraphEndpointAriaLabel:
|
|
550
|
+
srSingleSegmentGraphEndpointAriaLabel: _ref49 => {
|
|
556
551
|
let {
|
|
557
552
|
endpointNumber,
|
|
558
553
|
x,
|
|
559
554
|
y
|
|
560
|
-
} =
|
|
555
|
+
} = _ref49;
|
|
561
556
|
return `Endpoint ${endpointNumber} at ${x} comma ${y}.`;
|
|
562
557
|
},
|
|
563
|
-
srMultipleSegmentGraphEndpointAriaLabel:
|
|
558
|
+
srMultipleSegmentGraphEndpointAriaLabel: _ref50 => {
|
|
564
559
|
let {
|
|
565
560
|
endpointNumber,
|
|
566
561
|
x,
|
|
567
562
|
y,
|
|
568
563
|
indexOfSegment
|
|
569
|
-
} =
|
|
564
|
+
} = _ref50;
|
|
570
565
|
return `Endpoint ${endpointNumber} on segment ${indexOfSegment} at ${x} comma ${y}.`;
|
|
571
566
|
},
|
|
572
|
-
srSegmentGrabHandle:
|
|
567
|
+
srSegmentGrabHandle: _ref51 => {
|
|
573
568
|
let {
|
|
574
569
|
point1X,
|
|
575
570
|
point1Y,
|
|
576
571
|
point2X,
|
|
577
572
|
point2Y
|
|
578
|
-
} =
|
|
573
|
+
} = _ref51;
|
|
579
574
|
return `Segment from ${point1X} comma ${point1Y} to ${point2X} comma ${point2Y}.`;
|
|
580
575
|
},
|
|
581
576
|
srLinearSystemGraph: "Two lines on a coordinate plane.",
|
|
582
|
-
srLinearSystemPoints:
|
|
577
|
+
srLinearSystemPoints: _ref52 => {
|
|
583
578
|
let {
|
|
584
579
|
lineNumber,
|
|
585
580
|
point1X,
|
|
586
581
|
point1Y,
|
|
587
582
|
point2X,
|
|
588
583
|
point2Y
|
|
589
|
-
} =
|
|
584
|
+
} = _ref52;
|
|
590
585
|
return `Line ${lineNumber} has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`;
|
|
591
586
|
},
|
|
592
|
-
srLinearSystemPoint:
|
|
587
|
+
srLinearSystemPoint: _ref53 => {
|
|
593
588
|
let {
|
|
594
589
|
lineNumber,
|
|
595
590
|
pointSequence,
|
|
596
591
|
x,
|
|
597
592
|
y
|
|
598
|
-
} =
|
|
593
|
+
} = _ref53;
|
|
599
594
|
return `Point ${pointSequence} on line ${lineNumber} at ${x} comma ${y}.`;
|
|
600
595
|
},
|
|
596
|
+
srLinearSystemGrabHandle: _ref54 => {
|
|
597
|
+
let {
|
|
598
|
+
lineNumber,
|
|
599
|
+
point1X,
|
|
600
|
+
point1Y,
|
|
601
|
+
point2X,
|
|
602
|
+
point2Y
|
|
603
|
+
} = _ref54;
|
|
604
|
+
return `Line ${lineNumber} going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`;
|
|
605
|
+
},
|
|
606
|
+
srLinearSystemIntersection: _ref55 => {
|
|
607
|
+
let {
|
|
608
|
+
x,
|
|
609
|
+
y
|
|
610
|
+
} = _ref55;
|
|
611
|
+
return `Line 1 and line 2 intersect at point ${x} comma ${y}.`;
|
|
612
|
+
},
|
|
613
|
+
srLinearSystemParallel: "Line 1 and line 2 are parallel.",
|
|
601
614
|
srRayGraph: "A ray on a coordinate plane.",
|
|
602
|
-
srRayPoints:
|
|
615
|
+
srRayPoints: _ref56 => {
|
|
603
616
|
let {
|
|
604
617
|
point1X,
|
|
605
618
|
point1Y,
|
|
606
619
|
point2X,
|
|
607
620
|
point2Y
|
|
608
|
-
} =
|
|
621
|
+
} = _ref56;
|
|
609
622
|
return `The endpoint is at ${point1X} comma ${point1Y} and the ray goes through point ${point2X} comma ${point2Y}.`;
|
|
610
623
|
},
|
|
611
|
-
srRayGrabHandle:
|
|
624
|
+
srRayGrabHandle: _ref57 => {
|
|
612
625
|
let {
|
|
613
626
|
point1X,
|
|
614
627
|
point1Y,
|
|
615
628
|
point2X,
|
|
616
629
|
point2Y
|
|
617
|
-
} =
|
|
630
|
+
} = _ref57;
|
|
618
631
|
return `Ray with endpoint ${point1X} comma ${point1Y} going through point ${point2X} comma ${point2Y}.`;
|
|
619
632
|
},
|
|
620
|
-
srRayEndpoint:
|
|
633
|
+
srRayEndpoint: _ref58 => {
|
|
621
634
|
let {
|
|
622
635
|
x,
|
|
623
636
|
y
|
|
624
|
-
} =
|
|
637
|
+
} = _ref58;
|
|
625
638
|
return `Endpoint at ${x} comma ${y}.`;
|
|
626
639
|
},
|
|
627
|
-
srRayTerminalPoint:
|
|
640
|
+
srRayTerminalPoint: _ref59 => {
|
|
628
641
|
let {
|
|
629
642
|
x,
|
|
630
643
|
y
|
|
631
|
-
} =
|
|
644
|
+
} = _ref59;
|
|
632
645
|
return `Through point at ${x} comma ${y}.`;
|
|
633
646
|
},
|
|
634
647
|
srQuadraticGraph: "A parabola on a 4-quadrant coordinate plane.",
|
|
@@ -637,55 +650,55 @@ const mockStrings = {
|
|
|
637
650
|
srQuadraticGraphVertexOrigin: "Vertex is at the origin.",
|
|
638
651
|
srQuadraticGraphVertexXAxis: "Vertex is on the X-axis.",
|
|
639
652
|
srQuadraticGraphVertexYAxis: "Vertex is on the Y-axis.",
|
|
640
|
-
srQuadraticGraphVertexQuadrant:
|
|
653
|
+
srQuadraticGraphVertexQuadrant: _ref60 => {
|
|
641
654
|
let {
|
|
642
655
|
quadrant
|
|
643
|
-
} =
|
|
656
|
+
} = _ref60;
|
|
644
657
|
return `Vertex is in quadrant ${quadrant}.`;
|
|
645
658
|
},
|
|
646
|
-
srQuadraticTwoXIntercepts:
|
|
659
|
+
srQuadraticTwoXIntercepts: _ref61 => {
|
|
647
660
|
let {
|
|
648
661
|
intercept1,
|
|
649
662
|
intercept2
|
|
650
|
-
} =
|
|
663
|
+
} = _ref61;
|
|
651
664
|
return `The X-intercepts are at ${intercept1} comma 0 and ${intercept2} comma 0.`;
|
|
652
665
|
},
|
|
653
|
-
srQuadraticOneXIntercept:
|
|
666
|
+
srQuadraticOneXIntercept: _ref62 => {
|
|
654
667
|
let {
|
|
655
668
|
intercept
|
|
656
|
-
} =
|
|
669
|
+
} = _ref62;
|
|
657
670
|
return `The X-intercept is at ${intercept} comma 0.`;
|
|
658
671
|
},
|
|
659
|
-
srQuadraticYIntercept:
|
|
672
|
+
srQuadraticYIntercept: _ref63 => {
|
|
660
673
|
let {
|
|
661
674
|
intercept
|
|
662
|
-
} =
|
|
675
|
+
} = _ref63;
|
|
663
676
|
return `The Y-intercept is at 0 comma ${intercept}.`;
|
|
664
677
|
},
|
|
665
|
-
srQuadraticPointOrigin:
|
|
678
|
+
srQuadraticPointOrigin: _ref64 => {
|
|
666
679
|
let {
|
|
667
680
|
pointNumber
|
|
668
|
-
} =
|
|
681
|
+
} = _ref64;
|
|
669
682
|
return `Point ${pointNumber} on parabola at the origin.`;
|
|
670
683
|
},
|
|
671
|
-
srQuadraticPointAxis:
|
|
684
|
+
srQuadraticPointAxis: _ref65 => {
|
|
672
685
|
let {
|
|
673
686
|
pointNumber,
|
|
674
687
|
x,
|
|
675
688
|
y
|
|
676
|
-
} =
|
|
689
|
+
} = _ref65;
|
|
677
690
|
return `Point ${pointNumber} on parabola at ${x} comma ${y}.`;
|
|
678
691
|
},
|
|
679
|
-
srQuadraticPointQuadrant:
|
|
692
|
+
srQuadraticPointQuadrant: _ref66 => {
|
|
680
693
|
let {
|
|
681
694
|
pointNumber,
|
|
682
695
|
x,
|
|
683
696
|
y,
|
|
684
697
|
quadrant
|
|
685
|
-
} =
|
|
698
|
+
} = _ref66;
|
|
686
699
|
return `Point ${pointNumber} on parabola in quadrant ${quadrant} at ${x} comma ${y}.`;
|
|
687
700
|
},
|
|
688
|
-
srQuadraticInteractiveElements:
|
|
701
|
+
srQuadraticInteractiveElements: _ref67 => {
|
|
689
702
|
let {
|
|
690
703
|
point1X,
|
|
691
704
|
point1Y,
|
|
@@ -693,83 +706,97 @@ const mockStrings = {
|
|
|
693
706
|
point2Y,
|
|
694
707
|
point3X,
|
|
695
708
|
point3Y
|
|
696
|
-
} =
|
|
709
|
+
} = _ref67;
|
|
697
710
|
return `Parabola with points at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, and ${point3X} comma ${point3Y}.`;
|
|
698
711
|
},
|
|
699
712
|
srPolygonGraph: "A polygon.",
|
|
700
713
|
srPolygonGraphCoordinatePlane: "A polygon on a coordinate plane.",
|
|
701
|
-
srPolygonGraphPointsNum:
|
|
714
|
+
srPolygonGraphPointsNum: _ref68 => {
|
|
702
715
|
let {
|
|
703
716
|
num
|
|
704
|
-
} =
|
|
717
|
+
} = _ref68;
|
|
705
718
|
return `The polygon has ${num} points.`;
|
|
706
719
|
},
|
|
707
720
|
srPolygonGraphPointsOne: "The polygon has 1 point.",
|
|
708
|
-
srPolygonElementsNum:
|
|
721
|
+
srPolygonElementsNum: _ref69 => {
|
|
709
722
|
let {
|
|
710
723
|
num
|
|
711
|
-
} =
|
|
724
|
+
} = _ref69;
|
|
712
725
|
return `A polygon with ${num} points.`;
|
|
713
726
|
},
|
|
714
727
|
srPolygonElementsOne: "A polygon with 1 point.",
|
|
715
|
-
srPolygonPointAngleApprox:
|
|
728
|
+
srPolygonPointAngleApprox: _ref70 => {
|
|
716
729
|
let {
|
|
717
730
|
angle
|
|
718
|
-
} =
|
|
731
|
+
} = _ref70;
|
|
719
732
|
return `Angle approximately equal to ${angle} degrees.`;
|
|
720
733
|
},
|
|
721
|
-
srPolygonPointAngle:
|
|
734
|
+
srPolygonPointAngle: _ref71 => {
|
|
722
735
|
let {
|
|
723
736
|
angle
|
|
724
|
-
} =
|
|
737
|
+
} = _ref71;
|
|
725
738
|
return `Angle equal to ${angle} degrees.`;
|
|
726
739
|
},
|
|
727
|
-
srPolygonSideLength:
|
|
740
|
+
srPolygonSideLength: _ref72 => {
|
|
728
741
|
let {
|
|
729
742
|
pointNum,
|
|
730
743
|
length
|
|
731
|
-
} =
|
|
744
|
+
} = _ref72;
|
|
732
745
|
return `A line segment, length equal to ${length} units, connects to point ${pointNum}.`;
|
|
733
746
|
},
|
|
734
|
-
srPolygonSideLengthApprox:
|
|
747
|
+
srPolygonSideLengthApprox: _ref73 => {
|
|
735
748
|
let {
|
|
736
749
|
pointNum,
|
|
737
750
|
length
|
|
738
|
-
} =
|
|
751
|
+
} = _ref73;
|
|
739
752
|
return `A line segment, length approximately equal to ${length} units, connects to point ${pointNum}.`;
|
|
740
753
|
},
|
|
741
754
|
srUnlimitedPolygonEmpty: "An empty coordinate plane.",
|
|
742
755
|
srSinusoidGraph: "A sinusoid function on a coordinate plane.",
|
|
743
|
-
srSinusoidRootPoint:
|
|
756
|
+
srSinusoidRootPoint: _ref74 => {
|
|
744
757
|
let {
|
|
745
758
|
x,
|
|
746
759
|
y
|
|
747
|
-
} =
|
|
760
|
+
} = _ref74;
|
|
748
761
|
return `Midline intersection at ${x} comma ${y}.`;
|
|
749
762
|
},
|
|
750
|
-
|
|
763
|
+
srSinusoidMaxPoint: _ref75 => {
|
|
751
764
|
let {
|
|
752
765
|
x,
|
|
753
766
|
y
|
|
754
|
-
} =
|
|
755
|
-
return `
|
|
767
|
+
} = _ref75;
|
|
768
|
+
return `Maximum point at ${x} comma ${y}.`;
|
|
769
|
+
},
|
|
770
|
+
srSinusoidMinPoint: _ref76 => {
|
|
771
|
+
let {
|
|
772
|
+
x,
|
|
773
|
+
y
|
|
774
|
+
} = _ref76;
|
|
775
|
+
return `Minimum point at ${x} comma ${y}.`;
|
|
756
776
|
},
|
|
757
|
-
|
|
777
|
+
srSinusoidFlatPoint: _ref77 => {
|
|
778
|
+
let {
|
|
779
|
+
x,
|
|
780
|
+
y
|
|
781
|
+
} = _ref77;
|
|
782
|
+
return `Line through point at ${x} comma ${y}.`;
|
|
783
|
+
},
|
|
784
|
+
srSinusoidDescription: _ref78 => {
|
|
758
785
|
let {
|
|
759
786
|
minValue,
|
|
760
787
|
maxValue,
|
|
761
788
|
cycleStart,
|
|
762
789
|
cycleEnd
|
|
763
|
-
} =
|
|
790
|
+
} = _ref78;
|
|
764
791
|
return `The graph shows a wave with a minimum value of ${minValue} and a maximum value of ${maxValue}. The wave completes a full cycle from ${cycleStart} to ${cycleEnd}.`;
|
|
765
792
|
},
|
|
766
|
-
srSinusoidInteractiveElements:
|
|
793
|
+
srSinusoidInteractiveElements: _ref79 => {
|
|
767
794
|
let {
|
|
768
795
|
point1X,
|
|
769
796
|
point1Y,
|
|
770
797
|
point2X,
|
|
771
798
|
point2Y
|
|
772
|
-
} =
|
|
799
|
+
} = _ref79;
|
|
773
800
|
return `Sinusoid graph with midline intersection point at ${point1X} comma ${point1Y} and extremum point at ${point2X} comma ${point2Y}.`;
|
|
774
801
|
}
|
|
775
802
|
// The above strings are used for interactive graph SR descriptions.
|
|
@@ -1103,7 +1130,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
1103
1130
|
}, this.context.strings.mathInputDescription), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
|
|
1104
1131
|
closeButtonVisible: true,
|
|
1105
1132
|
style: styles$D.popoverContent
|
|
1106
|
-
}, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad,
|
|
1133
|
+
}, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends__default["default"]({
|
|
1107
1134
|
onAnalyticsEvent: this.props.onAnalyticsEvent,
|
|
1108
1135
|
extraKeys: this.props.extraKeys,
|
|
1109
1136
|
onClickKey: this.handleKeypadPress,
|
|
@@ -1118,7 +1145,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
1118
1145
|
"aria-label": this.state.keypadOpen ? this.context.strings.closeKeypad : this.context.strings.openKeypad,
|
|
1119
1146
|
role: "button",
|
|
1120
1147
|
onClick: () => this.state.keypadOpen ? this.closeKeypad() : this.openKeypad()
|
|
1121
|
-
}, props => /*#__PURE__*/React__namespace.createElement(MathInputIcon,
|
|
1148
|
+
}, props => /*#__PURE__*/React__namespace.createElement(MathInputIcon, _extends__default["default"]({
|
|
1122
1149
|
active: this.state.keypadOpen
|
|
1123
1150
|
}, props))))));
|
|
1124
1151
|
}
|
|
@@ -1143,7 +1170,7 @@ class MathInput extends React__namespace.Component {
|
|
|
1143
1170
|
this.inputRef.current?.insert(value);
|
|
1144
1171
|
}
|
|
1145
1172
|
render() {
|
|
1146
|
-
return /*#__PURE__*/React__namespace.createElement(InnerMathInput,
|
|
1173
|
+
return /*#__PURE__*/React__namespace.createElement(InnerMathInput, _extends__default["default"]({}, this.props, {
|
|
1147
1174
|
ref: this.inputRef,
|
|
1148
1175
|
mathInputStrings: this.context.strings
|
|
1149
1176
|
}));
|
|
@@ -1285,11 +1312,11 @@ const useDependencies = () => {
|
|
|
1285
1312
|
};
|
|
1286
1313
|
|
|
1287
1314
|
var dependencies = /*#__PURE__*/Object.freeze({
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1315
|
+
__proto__: null,
|
|
1316
|
+
setDependencies: setDependencies,
|
|
1317
|
+
getDependencies: getDependencies,
|
|
1318
|
+
DependenciesContext: DependenciesContext,
|
|
1319
|
+
useDependencies: useDependencies
|
|
1293
1320
|
});
|
|
1294
1321
|
|
|
1295
1322
|
/**
|
|
@@ -1393,9 +1420,9 @@ const propTypes = {
|
|
|
1393
1420
|
};
|
|
1394
1421
|
|
|
1395
1422
|
var changeable = /*#__PURE__*/Object.freeze({
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1423
|
+
__proto__: null,
|
|
1424
|
+
change: change,
|
|
1425
|
+
propTypes: propTypes
|
|
1399
1426
|
});
|
|
1400
1427
|
|
|
1401
1428
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -2054,7 +2081,7 @@ const keypadConfigurationForProps = widgetOptions => {
|
|
|
2054
2081
|
};
|
|
2055
2082
|
const ExpressionWithDependencies = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
2056
2083
|
const deps = useDependencies();
|
|
2057
|
-
return /*#__PURE__*/React__namespace.createElement(Expression,
|
|
2084
|
+
return /*#__PURE__*/React__namespace.createElement(Expression, _extends__default["default"]({
|
|
2058
2085
|
ref: ref,
|
|
2059
2086
|
analytics: deps.analytics
|
|
2060
2087
|
}, props));
|
|
@@ -2105,6 +2132,174 @@ var Expression$1 = {
|
|
|
2105
2132
|
}
|
|
2106
2133
|
};
|
|
2107
2134
|
|
|
2135
|
+
class SimpleKeypadInput extends React__namespace.Component {
|
|
2136
|
+
static contextType = keypadContext.KeypadContext;
|
|
2137
|
+
_isMounted = false;
|
|
2138
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
2139
|
+
componentDidMount() {
|
|
2140
|
+
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
2141
|
+
// this.isMounted() but is still considered an anti-pattern.
|
|
2142
|
+
this._isMounted = true;
|
|
2143
|
+
}
|
|
2144
|
+
componentWillUnmount() {
|
|
2145
|
+
this._isMounted = false;
|
|
2146
|
+
}
|
|
2147
|
+
focus() {
|
|
2148
|
+
// The inputRef is a ref to a MathInput, which
|
|
2149
|
+
// also controls the keypad state during focus events.
|
|
2150
|
+
this.inputRef.current?.focus(this.context.setKeypadActive);
|
|
2151
|
+
}
|
|
2152
|
+
blur() {
|
|
2153
|
+
this.inputRef.current?.blur();
|
|
2154
|
+
}
|
|
2155
|
+
getValue() {
|
|
2156
|
+
return this.props.value;
|
|
2157
|
+
}
|
|
2158
|
+
render() {
|
|
2159
|
+
const _this = this;
|
|
2160
|
+
// Intercept the `onFocus` prop, as we need to configure the keypad
|
|
2161
|
+
// before continuing with the default focus logic for Perseus inputs.
|
|
2162
|
+
// Intercept the `value` prop so as to map `null` to the empty string,
|
|
2163
|
+
// as the `KeypadInput` does not support `null` values.
|
|
2164
|
+
const {
|
|
2165
|
+
keypadElement,
|
|
2166
|
+
onFocus,
|
|
2167
|
+
value,
|
|
2168
|
+
...rest
|
|
2169
|
+
} = _this.props;
|
|
2170
|
+
return (
|
|
2171
|
+
/*#__PURE__*/
|
|
2172
|
+
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
2173
|
+
React__namespace.createElement(mathInput.KeypadInput, _extends__default["default"]({
|
|
2174
|
+
ref: this.inputRef,
|
|
2175
|
+
keypadElement: keypadElement,
|
|
2176
|
+
onFocus: () => {
|
|
2177
|
+
if (keypadElement) {
|
|
2178
|
+
keypadElement.configure({
|
|
2179
|
+
keypadType: mathInput.KeypadType.FRACTION
|
|
2180
|
+
}, () => {
|
|
2181
|
+
if (_this._isMounted) {
|
|
2182
|
+
onFocus?.();
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2185
|
+
} else {
|
|
2186
|
+
onFocus?.();
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
value: value == null ? "" : "" + value
|
|
2190
|
+
}, rest))
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
// @ts-expect-error - TS2339 - Property 'propTypes' does not exist on type 'typeof SimpleKeypadInput'.
|
|
2196
|
+
SimpleKeypadInput.propTypes = {
|
|
2197
|
+
keypadElement: mathInput.keypadElementPropType,
|
|
2198
|
+
onFocus: PropTypes__default["default"].func,
|
|
2199
|
+
value: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number])
|
|
2200
|
+
};
|
|
2201
|
+
|
|
2202
|
+
const getPromptJSON$s = (renderProps, userInput) => {
|
|
2203
|
+
return {
|
|
2204
|
+
type: "input-number",
|
|
2205
|
+
options: {
|
|
2206
|
+
simplify: renderProps.simplify,
|
|
2207
|
+
answerType: renderProps.answerType
|
|
2208
|
+
},
|
|
2209
|
+
userInput: {
|
|
2210
|
+
value: userInput.currentValue
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
};
|
|
2214
|
+
|
|
2215
|
+
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
2216
|
+
let lastId = 0;
|
|
2217
|
+
function uniqueIdForInput() {
|
|
2218
|
+
let prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "input-";
|
|
2219
|
+
lastId++;
|
|
2220
|
+
return `${prefix}${lastId}`;
|
|
2221
|
+
}
|
|
2222
|
+
class TextInput extends React__namespace.Component {
|
|
2223
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
2224
|
+
static defaultProps = {
|
|
2225
|
+
value: "",
|
|
2226
|
+
disabled: false
|
|
2227
|
+
};
|
|
2228
|
+
id;
|
|
2229
|
+
constructor(props) {
|
|
2230
|
+
super(props);
|
|
2231
|
+
if (props.id) {
|
|
2232
|
+
this.id = props.id;
|
|
2233
|
+
} else {
|
|
2234
|
+
this.id = uniqueIdForInput();
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
_getInput = () => {
|
|
2238
|
+
if (!this.inputRef.current) {
|
|
2239
|
+
throw new perseusCore.PerseusError("Input ref accessed before set", perseusCore.Errors.Internal);
|
|
2240
|
+
}
|
|
2241
|
+
return this.inputRef.current;
|
|
2242
|
+
};
|
|
2243
|
+
focus = () => {
|
|
2244
|
+
this._getInput().focus();
|
|
2245
|
+
};
|
|
2246
|
+
blur = () => {
|
|
2247
|
+
this._getInput().blur();
|
|
2248
|
+
};
|
|
2249
|
+
getValue = () => {
|
|
2250
|
+
return this.inputRef.current?.value;
|
|
2251
|
+
};
|
|
2252
|
+
getStringValue = () => {
|
|
2253
|
+
return this.inputRef.current?.value.toString();
|
|
2254
|
+
};
|
|
2255
|
+
setSelectionRange = (selectionStart, selectionEnd) => {
|
|
2256
|
+
this._getInput().setSelectionRange(selectionStart, selectionEnd);
|
|
2257
|
+
};
|
|
2258
|
+
getSelectionStart = () => {
|
|
2259
|
+
return this._getInput().selectionStart;
|
|
2260
|
+
};
|
|
2261
|
+
getSelectionEnd = () => {
|
|
2262
|
+
return this._getInput().selectionEnd;
|
|
2263
|
+
};
|
|
2264
|
+
render() {
|
|
2265
|
+
const {
|
|
2266
|
+
labelText,
|
|
2267
|
+
value,
|
|
2268
|
+
onFocus,
|
|
2269
|
+
onBlur,
|
|
2270
|
+
disabled,
|
|
2271
|
+
placeholder,
|
|
2272
|
+
onKeyDown,
|
|
2273
|
+
style
|
|
2274
|
+
} = this.props;
|
|
2275
|
+
const formattedValue = value === null ? "" : value.toString();
|
|
2276
|
+
|
|
2277
|
+
// Some of our content was saved with empty strings as the label text,
|
|
2278
|
+
// and we don't want to render an empty aria-label attribute.
|
|
2279
|
+
const ariaLabel = labelText || undefined;
|
|
2280
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
2281
|
+
ref: this.inputRef,
|
|
2282
|
+
style: style,
|
|
2283
|
+
disabled: disabled,
|
|
2284
|
+
id: this.id,
|
|
2285
|
+
value: formattedValue,
|
|
2286
|
+
type: "text",
|
|
2287
|
+
"aria-label": ariaLabel,
|
|
2288
|
+
"aria-describedby": this.props["aria-describedby"],
|
|
2289
|
+
onChange: value => this.props.onChange(value),
|
|
2290
|
+
placeholder: placeholder,
|
|
2291
|
+
onFocus: onFocus,
|
|
2292
|
+
onBlur: onBlur,
|
|
2293
|
+
onKeyDown: onKeyDown
|
|
2294
|
+
// @ts-expect-error - TS2322 - Type '{ style: StyleType; disabled: boolean | undefined; id: string; value: string; type: "text"; "aria-label": string | undefined; onChange: (value: string) => void; placeholder: string | undefined; ... 5 more ...; autoComplete: string; }' is not assignable to type 'IntrinsicAttributes & ExportProps & RefAttributes<HTMLInputElement>'.
|
|
2295
|
+
,
|
|
2296
|
+
autoCorrect: "off",
|
|
2297
|
+
autoCapitalize: "off",
|
|
2298
|
+
autoComplete: "off"
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2108
2303
|
/**
|
|
2109
2304
|
* A React context for keeping track of whether an component is fully
|
|
2110
2305
|
* loaded. This is used to know when SvgImage and (Zoomable)TeX are finished
|
|
@@ -2197,55 +2392,6 @@ const rWidgetRule = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
|
|
|
2197
2392
|
const rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
|
|
2198
2393
|
const rWidgetParts = new RegExp(rWidgetRule.source + "$");
|
|
2199
2394
|
const snowman = "\u2603";
|
|
2200
|
-
const seededRNG$1 = function (seed) {
|
|
2201
|
-
let randomSeed = seed;
|
|
2202
|
-
return function () {
|
|
2203
|
-
// Robert Jenkins' 32 bit integer hash function.
|
|
2204
|
-
let seed = randomSeed;
|
|
2205
|
-
seed = seed + 0x7ed55d16 + (seed << 12) & 0xffffffff;
|
|
2206
|
-
seed = (seed ^ 0xc761c23c ^ seed >>> 19) & 0xffffffff;
|
|
2207
|
-
seed = seed + 0x165667b1 + (seed << 5) & 0xffffffff;
|
|
2208
|
-
seed = (seed + 0xd3a2646c ^ seed << 9) & 0xffffffff;
|
|
2209
|
-
seed = seed + 0xfd7046c5 + (seed << 3) & 0xffffffff;
|
|
2210
|
-
seed = (seed ^ 0xb55a4f09 ^ seed >>> 16) & 0xffffffff;
|
|
2211
|
-
return (randomSeed = seed & 0xfffffff) / 0x10000000;
|
|
2212
|
-
};
|
|
2213
|
-
};
|
|
2214
|
-
|
|
2215
|
-
// Shuffle an array using a given random seed or function.
|
|
2216
|
-
// If `ensurePermuted` is true, the input and ouput are guaranteed to be
|
|
2217
|
-
// distinct permutations.
|
|
2218
|
-
function shuffle$3(array, randomSeed) {
|
|
2219
|
-
let ensurePermuted = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
2220
|
-
// Always return a copy of the input array
|
|
2221
|
-
const shuffled = ___default["default"].clone(array);
|
|
2222
|
-
|
|
2223
|
-
// Handle edge cases (input array is empty or uniform)
|
|
2224
|
-
if (!shuffled.length || ___default["default"].all(shuffled, function (value) {
|
|
2225
|
-
return ___default["default"].isEqual(value, shuffled[0]);
|
|
2226
|
-
})) {
|
|
2227
|
-
return shuffled;
|
|
2228
|
-
}
|
|
2229
|
-
let random;
|
|
2230
|
-
if (typeof randomSeed === "function") {
|
|
2231
|
-
random = randomSeed;
|
|
2232
|
-
} else {
|
|
2233
|
-
random = seededRNG$1(randomSeed);
|
|
2234
|
-
}
|
|
2235
|
-
do {
|
|
2236
|
-
// Fischer-Yates shuffle
|
|
2237
|
-
for (let top = shuffled.length; top > 0; top--) {
|
|
2238
|
-
const newEnd = Math.floor(random() * top);
|
|
2239
|
-
const temp = shuffled[newEnd];
|
|
2240
|
-
|
|
2241
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
2242
|
-
shuffled[newEnd] = shuffled[top - 1];
|
|
2243
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
2244
|
-
shuffled[top - 1] = temp;
|
|
2245
|
-
}
|
|
2246
|
-
} while (ensurePermuted && ___default["default"].isEqual(array, shuffled));
|
|
2247
|
-
return shuffled;
|
|
2248
|
-
}
|
|
2249
2395
|
|
|
2250
2396
|
/**
|
|
2251
2397
|
* TODO(somewhatabstract, FEI-3463):
|
|
@@ -2676,7 +2822,6 @@ const textarea = {
|
|
|
2676
2822
|
* to translate it but don't need the extra dollar signs.
|
|
2677
2823
|
*/
|
|
2678
2824
|
const unescapeMathMode$1 = label => label.startsWith("$") && label.endsWith("$") ? label.slice(1, -1) : label;
|
|
2679
|
-
const random$1 = seededRNG$1(new Date().getTime() & 0xffffffff);
|
|
2680
2825
|
const Util = {
|
|
2681
2826
|
inputPathsEqual,
|
|
2682
2827
|
nestedMap: nestedMap$2,
|
|
@@ -2684,8 +2829,6 @@ const Util = {
|
|
|
2684
2829
|
rTypeFromWidgetId,
|
|
2685
2830
|
rWidgetParts,
|
|
2686
2831
|
snowman,
|
|
2687
|
-
seededRNG: seededRNG$1,
|
|
2688
|
-
shuffle: shuffle$3,
|
|
2689
2832
|
split,
|
|
2690
2833
|
firstNumericalParse: firstNumericalParse$1,
|
|
2691
2834
|
stringArrayOfSize: stringArrayOfSize$1,
|
|
@@ -2713,16 +2856,17 @@ const Util = {
|
|
|
2713
2856
|
getSvgUrl: getSvgUrl,
|
|
2714
2857
|
getDataUrl: getDataUrl,
|
|
2715
2858
|
textarea,
|
|
2716
|
-
unescapeMathMode: unescapeMathMode$1
|
|
2717
|
-
random: random$1
|
|
2859
|
+
unescapeMathMode: unescapeMathMode$1
|
|
2718
2860
|
};
|
|
2719
2861
|
|
|
2720
2862
|
// TODO(LP-11481): Change the primary API we use for logging in Perseus to use
|
|
2721
2863
|
// getDependencies() internally... simplify usage to just using a "singleton"
|
|
2722
2864
|
// which get's the injected logger.
|
|
2865
|
+
|
|
2723
2866
|
/**
|
|
2724
2867
|
* Provides logging infrastructure for Perseus
|
|
2725
2868
|
*/
|
|
2869
|
+
|
|
2726
2870
|
const Log = {
|
|
2727
2871
|
// Logs a message
|
|
2728
2872
|
log: (message, extra) => {
|
|
@@ -3396,40 +3540,40 @@ const articleMaxWidthInPx = 688;
|
|
|
3396
3540
|
const articleMaxWidthTableInPx = 512;
|
|
3397
3541
|
|
|
3398
3542
|
var constants = /*#__PURE__*/Object.freeze({
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3543
|
+
__proto__: null,
|
|
3544
|
+
baseFontFamily: baseFontFamily,
|
|
3545
|
+
boldFontFamily: boldFontFamily,
|
|
3546
|
+
kaGreen: kaGreen,
|
|
3547
|
+
white: white,
|
|
3548
|
+
gray97: gray97,
|
|
3549
|
+
gray85: gray85,
|
|
3550
|
+
gray76: gray76,
|
|
3551
|
+
gray68: gray68,
|
|
3552
|
+
gray17: gray17,
|
|
3553
|
+
pureSmMin: pureSmMin$1,
|
|
3554
|
+
pureMdMin: pureMdMin$1,
|
|
3555
|
+
pureLgMin: pureLgMin$1,
|
|
3556
|
+
pureXlMin: pureXlMin$1,
|
|
3557
|
+
pureXsMax: pureXsMax$1,
|
|
3558
|
+
pureSmMax: pureSmMax$1,
|
|
3559
|
+
pureMdMax: pureMdMax$1,
|
|
3560
|
+
pureLgMax: pureLgMax$1,
|
|
3561
|
+
tableBackgroundAccent: tableBackgroundAccent,
|
|
3562
|
+
phoneMargin: phoneMargin,
|
|
3563
|
+
negativePhoneMargin: negativePhoneMargin,
|
|
3564
|
+
hintBorderWidth: hintBorderWidth,
|
|
3565
|
+
baseUnitPx: baseUnitPx,
|
|
3566
|
+
interactiveSizes: interactiveSizes$1,
|
|
3567
|
+
circleSize: circleSize$1,
|
|
3568
|
+
radioMarginWidth: radioMarginWidth$1,
|
|
3569
|
+
warningColor: warningColor,
|
|
3570
|
+
warningColorHover: warningColorHover,
|
|
3571
|
+
warningColorActive: warningColorActive,
|
|
3572
|
+
publishBlockingErrorColor: publishBlockingErrorColor,
|
|
3573
|
+
radioBorderColor: radioBorderColor$1,
|
|
3574
|
+
checkedColor: checkedColor$1,
|
|
3575
|
+
articleMaxWidthInPx: articleMaxWidthInPx,
|
|
3576
|
+
articleMaxWidthTableInPx: articleMaxWidthTableInPx
|
|
3433
3577
|
});
|
|
3434
3578
|
|
|
3435
3579
|
/**
|
|
@@ -3844,7 +3988,7 @@ var Raphael$1 = (function () {
|
|
|
3844
3988
|
appendChild = "appendChild",
|
|
3845
3989
|
apply = "apply",
|
|
3846
3990
|
concat = "concat",
|
|
3847
|
-
supportsTouch =
|
|
3991
|
+
supportsTouch = "createTouch" in doc,
|
|
3848
3992
|
E = "",
|
|
3849
3993
|
S = " ",
|
|
3850
3994
|
Str = String,
|
|
@@ -5449,10 +5593,10 @@ var Raphael$1 = (function () {
|
|
|
5449
5593
|
});
|
|
5450
5594
|
break;
|
|
5451
5595
|
case "gradient":
|
|
5452
|
-
(
|
|
5596
|
+
({
|
|
5453
5597
|
circle: 1,
|
|
5454
5598
|
ellipse: 1
|
|
5455
|
-
}
|
|
5599
|
+
}[has](o.type) || Str(value).charAt() != "r") && addGradientFill(node, value, o.paper);
|
|
5456
5600
|
break;
|
|
5457
5601
|
case "opacity":
|
|
5458
5602
|
if (attrs.gradient && !attrs[has]("stroke-opacity")) {
|
|
@@ -9285,8 +9429,10 @@ const labelDirections = {
|
|
|
9285
9429
|
// is equivalent to [[-5, 5], [-10, 10]].
|
|
9286
9430
|
// - A single magnitude to be used for both x and y. E.g. 10 is equivalent to
|
|
9287
9431
|
// [[-10, 10], [-10, 10]]
|
|
9432
|
+
|
|
9288
9433
|
// Overload normalizeRange to specify that it only returns undefined if its
|
|
9289
9434
|
// argument is undefined.
|
|
9435
|
+
|
|
9290
9436
|
// normalizeRange converts a RangeSpecifier into a pair of Intervals that give
|
|
9291
9437
|
// the x and y ranges, respectively
|
|
9292
9438
|
function normalizeRange(range) {
|
|
@@ -9478,7 +9624,7 @@ const GraphUtils = {
|
|
|
9478
9624
|
clickBlockList = [],
|
|
9479
9625
|
blockMouseTriggers = false,
|
|
9480
9626
|
blockTouchTriggers = false,
|
|
9481
|
-
eventCaptureSupported =
|
|
9627
|
+
eventCaptureSupported = "addEventListener" in document,
|
|
9482
9628
|
$document = $(document),
|
|
9483
9629
|
nextTouchID = 1,
|
|
9484
9630
|
lastTouchID = 0;
|
|
@@ -10173,7 +10319,6 @@ function scaledPolarRad(radius, radians) {
|
|
|
10173
10319
|
return [radius * Math.cos(radians), radius * Math.sin(radians) * -1 // SVG flips y axis
|
|
10174
10320
|
];
|
|
10175
10321
|
}
|
|
10176
|
-
|
|
10177
10322
|
function scaledPolarDeg(radius, degrees) {
|
|
10178
10323
|
const radians = degrees * Math.PI / 180;
|
|
10179
10324
|
return scaledPolarRad(radius, radians);
|
|
@@ -11991,7 +12136,6 @@ ___default["default"].extend(GraphUtils.Graphie.prototype, {
|
|
|
11991
12136
|
if (hideArrow) {
|
|
11992
12137
|
return; // Don't draw anything!
|
|
11993
12138
|
}
|
|
11994
|
-
|
|
11995
12139
|
const handleVec = kmath.vector.subtract(handleCoord, rotatePoint.coord);
|
|
11996
12140
|
const handlePolar = kmath.vector.polarDegFromCart(handleVec);
|
|
11997
12141
|
const angle = handlePolar[1];
|
|
@@ -12955,7 +13099,6 @@ ___default["default"].extend(MovableAngle.prototype, {
|
|
|
12955
13099
|
// clockwise to the first point
|
|
12956
13100
|
coords[1] // the vertex parameter is last
|
|
12957
13101
|
);
|
|
12958
|
-
|
|
12959
13102
|
const clockwiseAngle = rawAngle + 360 % 360;
|
|
12960
13103
|
return clockwiseAngle;
|
|
12961
13104
|
},
|
|
@@ -14315,7 +14458,6 @@ class MovablePoint$5 {
|
|
|
14315
14458
|
// We only update props here, because we want things on state to
|
|
14316
14459
|
// be persistent, and updated appropriately in modify()
|
|
14317
14460
|
),
|
|
14318
|
-
|
|
14319
14461
|
...DEFAULT_PROPS$1
|
|
14320
14462
|
};
|
|
14321
14463
|
}
|
|
@@ -14367,11 +14509,11 @@ class MovablePoint$5 {
|
|
|
14367
14509
|
const showTrashTooltip = () => {
|
|
14368
14510
|
this._showTooltip(container => {
|
|
14369
14511
|
// eslint-disable-next-line import/no-deprecated
|
|
14370
|
-
render(
|
|
14512
|
+
render(/*#__PURE__*/React__namespace.createElement("span", {
|
|
14371
14513
|
style: {
|
|
14372
14514
|
fontSize: "2em"
|
|
14373
14515
|
}
|
|
14374
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
14516
|
+
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconTrash, {
|
|
14375
14517
|
style: {
|
|
14376
14518
|
position: "static",
|
|
14377
14519
|
color: KhanColors.INTERACTIVE,
|
|
@@ -15170,7 +15312,6 @@ const DEFAULT_PROPS = {
|
|
|
15170
15312
|
// likewise
|
|
15171
15313
|
labelStyle: null // likewise
|
|
15172
15314
|
};
|
|
15173
|
-
|
|
15174
15315
|
const DEFAULT_STATE = {
|
|
15175
15316
|
added: false,
|
|
15176
15317
|
hasMoved: false,
|
|
@@ -16072,7 +16213,7 @@ class ImageLoader extends React__namespace.Component {
|
|
|
16072
16213
|
return (
|
|
16073
16214
|
/*#__PURE__*/
|
|
16074
16215
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
16075
|
-
React__namespace.createElement("img",
|
|
16216
|
+
React__namespace.createElement("img", _extends__default["default"]({
|
|
16076
16217
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
|
|
16077
16218
|
tabIndex: 0,
|
|
16078
16219
|
src: staticUrl(src),
|
|
@@ -17846,7 +17987,7 @@ class TranslationLinter {
|
|
|
17846
17987
|
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
17847
17988
|
* to things is does.
|
|
17848
17989
|
*/
|
|
17849
|
-
var preprocessTex =
|
|
17990
|
+
var preprocessTex = texCode => texCode
|
|
17850
17991
|
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
17851
17992
|
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
17852
17993
|
// the same is supported by KaTeX. It does the same for align*.
|
|
@@ -17856,7 +17997,7 @@ var preprocessTex = (texCode => texCode
|
|
|
17856
17997
|
// "aligned").
|
|
17857
17998
|
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
17858
17999
|
// Replace non-breaking spaces with regular spaces.
|
|
17859
|
-
.replace(/[\u00a0]/g, " ")
|
|
18000
|
+
.replace(/[\u00a0]/g, " ");
|
|
17860
18001
|
|
|
17861
18002
|
const {
|
|
17862
18003
|
interactiveSizes
|
|
@@ -18115,29 +18256,29 @@ const isLintable = type => {
|
|
|
18115
18256
|
};
|
|
18116
18257
|
|
|
18117
18258
|
var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
|
|
18124
|
-
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18134
|
-
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18139
|
-
|
|
18140
|
-
|
|
18259
|
+
__proto__: null,
|
|
18260
|
+
registerWidget: registerWidget,
|
|
18261
|
+
registerWidgets: registerWidgets,
|
|
18262
|
+
replaceWidget: replaceWidget,
|
|
18263
|
+
replaceDeprecatedWidgets: replaceDeprecatedWidgets,
|
|
18264
|
+
registerEditors: registerEditors,
|
|
18265
|
+
replaceEditor: replaceEditor,
|
|
18266
|
+
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
18267
|
+
getWidget: getWidget,
|
|
18268
|
+
getWidgetExport: getWidgetExport,
|
|
18269
|
+
getEditor: getEditor,
|
|
18270
|
+
getTransform: getTransform,
|
|
18271
|
+
getVersion: getVersion,
|
|
18272
|
+
getVersionVector: getVersionVector,
|
|
18273
|
+
getPublicWidgets: getPublicWidgets,
|
|
18274
|
+
isAccessible: isAccessible,
|
|
18275
|
+
getAllWidgetTypes: getAllWidgetTypes,
|
|
18276
|
+
getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
|
|
18277
|
+
traverseChildWidgets: traverseChildWidgets$3,
|
|
18278
|
+
supportsStaticMode: supportsStaticMode,
|
|
18279
|
+
getStaticTransform: getStaticTransform,
|
|
18280
|
+
getTracking: getTracking,
|
|
18281
|
+
isLintable: isLintable
|
|
18141
18282
|
});
|
|
18142
18283
|
|
|
18143
18284
|
class WidgetContainer extends React__namespace.Component {
|
|
@@ -18172,7 +18313,6 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
18172
18313
|
/* eslint-enable react/no-did-mount-set-state */
|
|
18173
18314
|
}
|
|
18174
18315
|
}
|
|
18175
|
-
|
|
18176
18316
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
18177
18317
|
if (this.props.type !== nextProps.type) {
|
|
18178
18318
|
throw new Error("WidgetContainer can't change widget type; set a different " + "key instead to recreate the container.");
|
|
@@ -18295,7 +18435,7 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
18295
18435
|
}
|
|
18296
18436
|
});
|
|
18297
18437
|
}
|
|
18298
|
-
}, /*#__PURE__*/React__namespace.createElement(WidgetType,
|
|
18438
|
+
}, /*#__PURE__*/React__namespace.createElement(WidgetType, _extends__default["default"]({}, this.state.widgetProps, {
|
|
18299
18439
|
linterContext: linterContext,
|
|
18300
18440
|
containerSizeClass: this.state.sizeClass,
|
|
18301
18441
|
ref: this.widgetRef
|
|
@@ -19164,7 +19304,7 @@ class Renderer extends React__namespace.Component {
|
|
|
19164
19304
|
let {
|
|
19165
19305
|
setAssetStatus
|
|
19166
19306
|
} = _ref4;
|
|
19167
|
-
return /*#__PURE__*/React__namespace.createElement(SvgImage,
|
|
19307
|
+
return /*#__PURE__*/React__namespace.createElement(SvgImage, _extends__default["default"]({
|
|
19168
19308
|
setAssetStatus: setAssetStatus
|
|
19169
19309
|
// @ts-expect-error - TS2322 - Type 'string | null | undefined' is not assignable to type 'string | undefined'.
|
|
19170
19310
|
,
|
|
@@ -19688,429 +19828,84 @@ const styles$A = {
|
|
|
19688
19828
|
}
|
|
19689
19829
|
};
|
|
19690
19830
|
|
|
19691
|
-
|
|
19692
|
-
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
}
|
|
19698
|
-
class TextInput extends React__namespace.Component {
|
|
19699
|
-
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
19700
|
-
static defaultProps = {
|
|
19701
|
-
value: "",
|
|
19702
|
-
disabled: false
|
|
19703
|
-
};
|
|
19704
|
-
id;
|
|
19705
|
-
constructor(props) {
|
|
19706
|
-
super(props);
|
|
19707
|
-
if (props.id) {
|
|
19708
|
-
this.id = props.id;
|
|
19709
|
-
} else {
|
|
19710
|
-
this.id = uniqueIdForInput();
|
|
19711
|
-
}
|
|
19712
|
-
}
|
|
19713
|
-
_getInput = () => {
|
|
19714
|
-
if (!this.inputRef.current) {
|
|
19715
|
-
throw new perseusCore.PerseusError("Input ref accessed before set", perseusCore.Errors.Internal);
|
|
19716
|
-
}
|
|
19717
|
-
return this.inputRef.current;
|
|
19718
|
-
};
|
|
19719
|
-
focus = () => {
|
|
19720
|
-
this._getInput().focus();
|
|
19721
|
-
};
|
|
19722
|
-
blur = () => {
|
|
19723
|
-
this._getInput().blur();
|
|
19724
|
-
};
|
|
19725
|
-
getValue = () => {
|
|
19726
|
-
return this.inputRef.current?.value;
|
|
19727
|
-
};
|
|
19728
|
-
getStringValue = () => {
|
|
19729
|
-
return this.inputRef.current?.value.toString();
|
|
19730
|
-
};
|
|
19731
|
-
setSelectionRange = (selectionStart, selectionEnd) => {
|
|
19732
|
-
this._getInput().setSelectionRange(selectionStart, selectionEnd);
|
|
19733
|
-
};
|
|
19734
|
-
getSelectionStart = () => {
|
|
19735
|
-
return this._getInput().selectionStart;
|
|
19736
|
-
};
|
|
19737
|
-
getSelectionEnd = () => {
|
|
19738
|
-
return this._getInput().selectionEnd;
|
|
19739
|
-
};
|
|
19740
|
-
render() {
|
|
19741
|
-
const {
|
|
19742
|
-
labelText,
|
|
19743
|
-
value,
|
|
19744
|
-
onFocus,
|
|
19745
|
-
onBlur,
|
|
19746
|
-
disabled,
|
|
19747
|
-
placeholder,
|
|
19748
|
-
onKeyDown,
|
|
19749
|
-
style
|
|
19750
|
-
} = this.props;
|
|
19751
|
-
const formattedValue = value === null ? "" : value.toString();
|
|
19752
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
19753
|
-
ref: this.inputRef,
|
|
19754
|
-
style: style,
|
|
19755
|
-
disabled: disabled,
|
|
19756
|
-
id: this.id,
|
|
19757
|
-
value: formattedValue,
|
|
19758
|
-
type: "text",
|
|
19759
|
-
"aria-label": labelText,
|
|
19760
|
-
"aria-describedby": this.props["aria-describedby"],
|
|
19761
|
-
onChange: value => this.props.onChange(value),
|
|
19762
|
-
placeholder: placeholder,
|
|
19763
|
-
onFocus: onFocus,
|
|
19764
|
-
onBlur: onBlur,
|
|
19765
|
-
onKeyDown: onKeyDown
|
|
19766
|
-
// @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>'.
|
|
19767
|
-
,
|
|
19768
|
-
autoCorrect: "off",
|
|
19769
|
-
autoCapitalize: "off",
|
|
19770
|
-
autoComplete: "off"
|
|
19771
|
-
});
|
|
19772
|
-
}
|
|
19773
|
-
}
|
|
19774
|
-
|
|
19775
|
-
/* eslint-disable react/no-unsafe */
|
|
19776
|
-
const zIndex = 10;
|
|
19777
|
-
let HorizontalDirection = /*#__PURE__*/function (HorizontalDirection) {
|
|
19778
|
-
HorizontalDirection["Left"] = "left";
|
|
19779
|
-
HorizontalDirection["Right"] = "right";
|
|
19780
|
-
return HorizontalDirection;
|
|
19781
|
-
}({});
|
|
19782
|
-
let VerticalDirection = /*#__PURE__*/function (VerticalDirection) {
|
|
19783
|
-
VerticalDirection["Top"] = "top";
|
|
19784
|
-
VerticalDirection["Bottom"] = "bottom";
|
|
19785
|
-
return VerticalDirection;
|
|
19786
|
-
}({});
|
|
19787
|
-
const Triangle = props => {
|
|
19788
|
-
let borderLeft;
|
|
19789
|
-
let borderRight;
|
|
19790
|
-
let borderTop;
|
|
19791
|
-
let borderBottom;
|
|
19792
|
-
const hBorder = `${props.width}px solid transparent`;
|
|
19793
|
-
if (props.horizontalDirection === "right") {
|
|
19794
|
-
borderLeft = hBorder;
|
|
19795
|
-
} else {
|
|
19796
|
-
borderRight = hBorder;
|
|
19797
|
-
}
|
|
19798
|
-
const vBorder = `${props.height}px solid ${props.color}`;
|
|
19799
|
-
if (props.verticalDirection === "top") {
|
|
19800
|
-
borderTop = vBorder;
|
|
19801
|
-
} else {
|
|
19802
|
-
borderBottom = vBorder;
|
|
19803
|
-
}
|
|
19804
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
19805
|
-
style: {
|
|
19806
|
-
display: "block",
|
|
19807
|
-
height: 0,
|
|
19808
|
-
width: 0,
|
|
19809
|
-
position: "absolute",
|
|
19810
|
-
left: props.left,
|
|
19811
|
-
top: props.top,
|
|
19812
|
-
borderLeft: borderLeft,
|
|
19813
|
-
borderRight: borderRight,
|
|
19814
|
-
borderTop: borderTop,
|
|
19815
|
-
borderBottom: borderBottom
|
|
19816
|
-
}
|
|
19817
|
-
});
|
|
19818
|
-
};
|
|
19819
|
-
const TooltipArrow = _ref => {
|
|
19820
|
-
let {
|
|
19821
|
-
position = "relative",
|
|
19822
|
-
visibility = "visible",
|
|
19823
|
-
left = 100,
|
|
19824
|
-
top = 0,
|
|
19825
|
-
...props
|
|
19826
|
-
} = _ref;
|
|
19827
|
-
// TODO(aria): Think about adding a box-shadow to the triangle here
|
|
19828
|
-
// See http://css-tricks.com/triangle-with-shadow/
|
|
19831
|
+
const {
|
|
19832
|
+
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
19833
|
+
} = Util;
|
|
19834
|
+
// [LEMS-2411](Jan 2025) Third: This component has been moved to the NumericInput
|
|
19835
|
+
// folder as we are actively working towards removing the InputNumber widget.
|
|
19836
|
+
// This comment can be removed as part of LEMS-2411.
|
|
19829
19837
|
|
|
19830
|
-
//const isRight = (this.props.horizontalDirection === "right");
|
|
19831
|
-
const isTop = props.verticalDirection === "top";
|
|
19832
|
-
const frontTopOffset = isTop ? 0 : 1;
|
|
19833
|
-
const borderTopOffset = isTop ? 0 : -1;
|
|
19834
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
19835
|
-
style: {
|
|
19836
|
-
display: "block",
|
|
19837
|
-
position: position,
|
|
19838
|
-
visibility: visibility,
|
|
19839
|
-
left: left,
|
|
19840
|
-
top: top,
|
|
19841
|
-
width: props.width + 2,
|
|
19842
|
-
height: props.height + 1,
|
|
19843
|
-
marginTop: -1,
|
|
19844
|
-
marginBottom: -2,
|
|
19845
|
-
zIndex: zIndex
|
|
19846
|
-
}
|
|
19847
|
-
}, /*#__PURE__*/React__namespace.createElement(Triangle, {
|
|
19848
|
-
horizontalDirection: props.horizontalDirection,
|
|
19849
|
-
verticalDirection: props.verticalDirection,
|
|
19850
|
-
color: props.border,
|
|
19851
|
-
left: 0,
|
|
19852
|
-
top: borderTopOffset,
|
|
19853
|
-
width: props.width + 2 // one extra for the diagonal
|
|
19854
|
-
,
|
|
19855
|
-
height: props.height + 2
|
|
19856
|
-
}), /*#__PURE__*/React__namespace.createElement(Triangle, {
|
|
19857
|
-
horizontalDirection: props.horizontalDirection,
|
|
19858
|
-
verticalDirection: props.verticalDirection,
|
|
19859
|
-
color: props.color,
|
|
19860
|
-
left: 1,
|
|
19861
|
-
top: frontTopOffset,
|
|
19862
|
-
width: props.width,
|
|
19863
|
-
height: props.height
|
|
19864
|
-
}));
|
|
19865
|
-
};
|
|
19866
|
-
const VERTICAL_CORNERS = {
|
|
19867
|
-
top: {
|
|
19868
|
-
top: "-100%"
|
|
19869
|
-
},
|
|
19870
|
-
bottom: {
|
|
19871
|
-
top: 0
|
|
19872
|
-
}
|
|
19873
|
-
};
|
|
19874
|
-
const HORIZONTAL_CORNERS = {
|
|
19875
|
-
left: {
|
|
19876
|
-
targetLeft: 0
|
|
19877
|
-
},
|
|
19878
|
-
right: {
|
|
19879
|
-
targetLeft: "100%"
|
|
19880
|
-
}
|
|
19881
|
-
};
|
|
19882
|
-
const HORIZONTAL_ALIGNMNENTS = {
|
|
19883
|
-
left: {
|
|
19884
|
-
tooltipLeft: 0,
|
|
19885
|
-
arrowLeft: arrowSize => 0
|
|
19886
|
-
},
|
|
19887
|
-
right: {
|
|
19888
|
-
tooltipLeft: "-100%",
|
|
19889
|
-
arrowLeft: arrowSize => -arrowSize - 2
|
|
19890
|
-
}
|
|
19891
|
-
};
|
|
19892
19838
|
/**
|
|
19893
|
-
*
|
|
19894
|
-
*
|
|
19895
|
-
*
|
|
19896
|
-
*
|
|
19897
|
-
* ```
|
|
19898
|
-
* import Tooltip from "./tooltip";
|
|
19899
|
-
* <Tooltip
|
|
19900
|
-
* className="class-for-tooltip-contents"
|
|
19901
|
-
* horizontalPosition={HoriziontalDirection.Left}
|
|
19902
|
-
* horizontalAlign={HoriziontalDirection.Left}
|
|
19903
|
-
* verticalPosition={VerticalDirection.Top}
|
|
19904
|
-
* arrowSize={10} // arrow size in pixels
|
|
19905
|
-
* borderColor="#ccc" // color of the border for the tooltip
|
|
19906
|
-
* show={true} // whether the tooltip should currently be visible
|
|
19907
|
-
* targetContainerStyle={targetContainerStyle}
|
|
19908
|
-
* >
|
|
19909
|
-
* <TargetElementOfTheTooltip />
|
|
19910
|
-
* <TooltipContents1 />
|
|
19911
|
-
* <TooltipContents2 />
|
|
19912
|
-
* </Tooltip>
|
|
19913
|
-
* ```
|
|
19914
|
-
*
|
|
19915
|
-
* To show/hide the tooltip, the parent component should call the
|
|
19916
|
-
* `.show()` and `.hide()` methods of the tooltip when appropriate.
|
|
19917
|
-
* (These are usually set up as handlers of events on the target element.)
|
|
19918
|
-
*
|
|
19919
|
-
* Notes:
|
|
19920
|
-
* `className` should not specify a border; that is handled by `borderColor`
|
|
19921
|
-
* so that the arrow and tooltip match
|
|
19922
|
-
*
|
|
19923
|
-
* ```
|
|
19924
|
-
* __,,--``\\
|
|
19925
|
-
* _,,-''`` \\ ,
|
|
19926
|
-
* '----------_.------'-.___|\__
|
|
19927
|
-
* _.--''`` `)__ )__ @\__
|
|
19928
|
-
* ( .. ''---/___,,E/__,E'------`
|
|
19929
|
-
* `-''`''
|
|
19930
|
-
* Here be dragons.
|
|
19931
|
-
* ```
|
|
19839
|
+
* The InputWithExamples component is a child component of the NumericInput
|
|
19840
|
+
* and InputNumber components. It is responsible for rendering the UI elements
|
|
19841
|
+
* for the desktop versions of these widgets, and displays a tooltip with
|
|
19842
|
+
* examples of how to input the selected answer forms.
|
|
19932
19843
|
*/
|
|
19933
|
-
|
|
19934
|
-
|
|
19935
|
-
|
|
19936
|
-
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19940
|
-
|
|
19941
|
-
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
|
|
19951
|
-
|
|
19952
|
-
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
this._updateHeight();
|
|
19959
|
-
}
|
|
19960
|
-
_renderToolTipDiv(isTooltipAbove) {
|
|
19961
|
-
const settings = Object.assign({}, HORIZONTAL_CORNERS[this.props.horizontalPosition], HORIZONTAL_ALIGNMNENTS[this.props.horizontalAlign], VERTICAL_CORNERS[this.props.verticalPosition]);
|
|
19962
|
-
let arrowAbove;
|
|
19963
|
-
let arrowBelow;
|
|
19964
|
-
if (isTooltipAbove) {
|
|
19965
|
-
// We put an absolutely positioned arrow in the correct place
|
|
19966
|
-
arrowAbove = /*#__PURE__*/React__namespace.createElement(TooltipArrow, {
|
|
19967
|
-
verticalDirection: VerticalDirection.Top,
|
|
19968
|
-
horizontalDirection: this.props.horizontalAlign,
|
|
19969
|
-
position: "absolute",
|
|
19970
|
-
color: "white",
|
|
19971
|
-
border: this.props.borderColor,
|
|
19972
|
-
left: settings.arrowLeft(this.props.arrowSize),
|
|
19973
|
-
top: -this.props.arrowSize + 2,
|
|
19974
|
-
width: this.props.arrowSize,
|
|
19975
|
-
height: this.props.arrowSize,
|
|
19976
|
-
zIndex: zIndex
|
|
19977
|
-
});
|
|
19978
|
-
|
|
19979
|
-
// And we use a visibility: hidden arrow below to shift up the
|
|
19980
|
-
// content by the correct amount
|
|
19981
|
-
arrowBelow = /*#__PURE__*/React__namespace.createElement(TooltipArrow, {
|
|
19982
|
-
verticalDirection: VerticalDirection.Top,
|
|
19983
|
-
horizontalDirection: this.props.horizontalAlign,
|
|
19984
|
-
visibility: "hidden",
|
|
19985
|
-
color: "white",
|
|
19986
|
-
border: this.props.borderColor,
|
|
19987
|
-
left: settings.arrowLeft(this.props.arrowSize),
|
|
19988
|
-
top: -1,
|
|
19989
|
-
width: this.props.arrowSize,
|
|
19990
|
-
height: this.props.arrowSize,
|
|
19991
|
-
zIndex: zIndex
|
|
19992
|
-
});
|
|
19993
|
-
} else {
|
|
19994
|
-
arrowAbove = /*#__PURE__*/React__namespace.createElement(TooltipArrow, {
|
|
19995
|
-
verticalDirection: VerticalDirection.Bottom,
|
|
19996
|
-
horizontalDirection: this.props.horizontalAlign,
|
|
19997
|
-
color: "white",
|
|
19998
|
-
border: this.props.borderColor,
|
|
19999
|
-
left: settings.arrowLeft(this.props.arrowSize),
|
|
20000
|
-
top: -1,
|
|
20001
|
-
width: this.props.arrowSize,
|
|
20002
|
-
height: this.props.arrowSize,
|
|
20003
|
-
zIndex: zIndex
|
|
20004
|
-
});
|
|
20005
|
-
arrowBelow = null;
|
|
20006
|
-
}
|
|
20007
|
-
|
|
20008
|
-
/* A positioned div below the input to be the parent for our
|
|
20009
|
-
tooltip */
|
|
20010
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
20011
|
-
style: {
|
|
20012
|
-
position: "relative",
|
|
20013
|
-
height: 0,
|
|
20014
|
-
display: this.props.show ? "block" : "none"
|
|
19844
|
+
const InputWithExamples = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
19845
|
+
// Desctructure the props to set default values
|
|
19846
|
+
const {
|
|
19847
|
+
shouldShowExamples = true,
|
|
19848
|
+
onFocus = () => {},
|
|
19849
|
+
onBlur = () => {},
|
|
19850
|
+
disabled = false,
|
|
19851
|
+
linterContext = PerseusLinter__namespace.linterContextDefault,
|
|
19852
|
+
className = ""
|
|
19853
|
+
} = props;
|
|
19854
|
+
const context = React__namespace.useContext(PerseusI18nContext);
|
|
19855
|
+
const inputRef = React__namespace.useRef(null);
|
|
19856
|
+
const [inputFocused, setInputFocused] = React__namespace.useState(false);
|
|
19857
|
+
const id = React.useId();
|
|
19858
|
+
const ariaId = `aria-for-${id}`;
|
|
19859
|
+
React.useImperativeHandle(ref, () => ({
|
|
19860
|
+
current: inputRef.current,
|
|
19861
|
+
focus: () => {
|
|
19862
|
+
if (inputRef.current) {
|
|
19863
|
+
inputRef.current.focus();
|
|
19864
|
+
}
|
|
19865
|
+
},
|
|
19866
|
+
blur: () => {
|
|
19867
|
+
if (inputRef.current) {
|
|
19868
|
+
inputRef.current.blur();
|
|
20015
19869
|
}
|
|
20016
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
20017
|
-
ref: this.tooltipContainerRef,
|
|
20018
|
-
className: "tooltipContainer",
|
|
20019
|
-
role: "tooltip",
|
|
20020
|
-
style: {
|
|
20021
|
-
position: "absolute",
|
|
20022
|
-
// height must start out undefined, not null, so that
|
|
20023
|
-
// we can measure the actual height with jquery.
|
|
20024
|
-
// This is used to position the tooltip with top: -100%
|
|
20025
|
-
// when in verticalPosition: "top" mode
|
|
20026
|
-
height: this.state.height || undefined,
|
|
20027
|
-
left: settings.targetLeft
|
|
20028
|
-
}
|
|
20029
|
-
}, arrowAbove, /*#__PURE__*/React__namespace.createElement("div", {
|
|
20030
|
-
className: this.props.className
|
|
20031
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20032
|
-
,
|
|
20033
|
-
ref: "tooltipContent",
|
|
20034
|
-
style: {
|
|
20035
|
-
position: "relative",
|
|
20036
|
-
top: settings["top"],
|
|
20037
|
-
left: settings.tooltipLeft,
|
|
20038
|
-
border: "1px solid " + this.props.borderColor,
|
|
20039
|
-
boxShadow: "0 1px 3px " + this.props.borderColor,
|
|
20040
|
-
zIndex: zIndex - 1
|
|
20041
|
-
}
|
|
20042
|
-
}, this.props.children.slice(1)), arrowBelow));
|
|
20043
|
-
}
|
|
20044
|
-
_updateHeight() {
|
|
20045
|
-
const tooltipContainer = this.tooltipContainerRef.current;
|
|
20046
|
-
const height = tooltipContainer?.offsetHeight || 0;
|
|
20047
|
-
if (height !== this.state.height) {
|
|
20048
|
-
this.setState({
|
|
20049
|
-
height
|
|
20050
|
-
});
|
|
20051
19870
|
}
|
|
20052
|
-
}
|
|
20053
|
-
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
return /*#__PURE__*/React__namespace.createElement("span", null, isTooltipAbove && this._renderToolTipDiv(isTooltipAbove), /*#__PURE__*/React__namespace.createElement("div", {
|
|
20058
|
-
style: this.props.targetContainerStyle
|
|
20059
|
-
}, this.props.children[0]), !isTooltipAbove && this._renderToolTipDiv());
|
|
20060
|
-
}
|
|
20061
|
-
}
|
|
20062
|
-
|
|
20063
|
-
const {
|
|
20064
|
-
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
20065
|
-
} = Util;
|
|
20066
|
-
class InputWithExamples extends React__namespace.Component {
|
|
20067
|
-
static contextType = PerseusI18nContext;
|
|
20068
|
-
static defaultProps = {
|
|
20069
|
-
shouldShowExamples: true,
|
|
20070
|
-
onFocus: function () {},
|
|
20071
|
-
onBlur: function () {},
|
|
20072
|
-
disabled: false,
|
|
20073
|
-
linterContext: PerseusLinter__namespace.linterContextDefault,
|
|
20074
|
-
className: ""
|
|
20075
|
-
};
|
|
20076
|
-
state = {
|
|
20077
|
-
focused: false,
|
|
20078
|
-
showExamples: false
|
|
20079
|
-
};
|
|
20080
|
-
_getUniqueId = () => {
|
|
20081
|
-
return `input-with-examples-${btoa(this.props.id).replace(/=/g, "")}`;
|
|
20082
|
-
};
|
|
20083
|
-
_getInputClassName = () => {
|
|
20084
|
-
// Otherwise, we need to add these INPUT and FOCUSED tags here.
|
|
20085
|
-
let className = ClassNames.INPUT;
|
|
20086
|
-
if (this.state.focused) {
|
|
20087
|
-
className += " " + ClassNames.FOCUSED;
|
|
19871
|
+
}));
|
|
19872
|
+
const getInputClassName = () => {
|
|
19873
|
+
let inputClassName = ClassNames.INPUT;
|
|
19874
|
+
if (inputFocused) {
|
|
19875
|
+
inputClassName += " " + ClassNames.FOCUSED;
|
|
20088
19876
|
}
|
|
20089
|
-
if (
|
|
20090
|
-
|
|
19877
|
+
if (className) {
|
|
19878
|
+
inputClassName += " " + className;
|
|
20091
19879
|
}
|
|
20092
|
-
return
|
|
19880
|
+
return inputClassName;
|
|
19881
|
+
};
|
|
19882
|
+
const handleFocus = () => {
|
|
19883
|
+
onFocus();
|
|
19884
|
+
setInputFocused(true);
|
|
20093
19885
|
};
|
|
20094
|
-
|
|
20095
|
-
|
|
20096
|
-
|
|
20097
|
-
|
|
20098
|
-
|
|
20099
|
-
|
|
19886
|
+
const handleBlur = () => {
|
|
19887
|
+
onBlur();
|
|
19888
|
+
setInputFocused(false);
|
|
19889
|
+
};
|
|
19890
|
+
const renderInput = () => {
|
|
19891
|
+
// Generate the provided examples in simple language for screen readers.
|
|
19892
|
+
const examplesAria = props.shouldShowExamples ? `${props.examples[0]}
|
|
19893
|
+
${props.examples.slice(1).join(", or\n")}`
|
|
20100
19894
|
// @ts-expect-error TS2550: Property replaceAll does not exist on type string.
|
|
20101
|
-
.replaceAll("*", "").replaceAll("$", "").replaceAll("\\ \\text{pi}", " pi").replaceAll("\\ ", " and ");
|
|
19895
|
+
.replaceAll("*", "").replaceAll("$", "").replaceAll("\\ \\text{pi}", " pi").replaceAll("\\ ", " and ") : "";
|
|
20102
19896
|
const inputProps = {
|
|
20103
19897
|
id: id,
|
|
20104
|
-
|
|
20105
|
-
|
|
20106
|
-
|
|
20107
|
-
|
|
20108
|
-
|
|
20109
|
-
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
|
|
20113
|
-
|
|
19898
|
+
// If we have examples, we want to provide the aria-describedby attribute
|
|
19899
|
+
"aria-describedby": props.shouldShowExamples ? ariaId : undefined,
|
|
19900
|
+
ref: inputRef,
|
|
19901
|
+
className: getInputClassName(),
|
|
19902
|
+
labelText: props.labelText,
|
|
19903
|
+
value: props.value,
|
|
19904
|
+
onFocus: handleFocus,
|
|
19905
|
+
onBlur: handleBlur,
|
|
19906
|
+
disabled: disabled,
|
|
19907
|
+
style: props.style,
|
|
19908
|
+
onChange: props.onChange,
|
|
20114
19909
|
onTouchStart: captureScratchpadTouchStart$2,
|
|
20115
19910
|
autoCapitalize: "off",
|
|
20116
19911
|
autoComplete: "off",
|
|
@@ -20124,158 +19919,32 @@ class InputWithExamples extends React__namespace.Component {
|
|
|
20124
19919
|
}
|
|
20125
19920
|
}, examplesAria));
|
|
20126
19921
|
};
|
|
20127
|
-
|
|
20128
|
-
|
|
20129
|
-
|
|
20130
|
-
|
|
20131
|
-
showExamples: true
|
|
20132
|
-
});
|
|
20133
|
-
};
|
|
20134
|
-
show = () => {
|
|
20135
|
-
this.setState({
|
|
20136
|
-
showExamples: true
|
|
20137
|
-
});
|
|
20138
|
-
};
|
|
20139
|
-
hide = () => {
|
|
20140
|
-
this.setState({
|
|
20141
|
-
showExamples: false
|
|
20142
|
-
});
|
|
20143
|
-
};
|
|
20144
|
-
_handleBlur = () => {
|
|
20145
|
-
this.props.onBlur();
|
|
20146
|
-
this.setState({
|
|
20147
|
-
focused: false,
|
|
20148
|
-
showExamples: false
|
|
20149
|
-
});
|
|
20150
|
-
};
|
|
20151
|
-
focus = () => {
|
|
20152
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20153
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
20154
|
-
this.refs.input.focus();
|
|
20155
|
-
};
|
|
20156
|
-
blur = () => {
|
|
20157
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20158
|
-
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
20159
|
-
this.refs.input.blur();
|
|
20160
|
-
};
|
|
20161
|
-
handleChange = e => {
|
|
20162
|
-
this.props.onChange(e.target.value);
|
|
20163
|
-
};
|
|
20164
|
-
render() {
|
|
20165
|
-
const input = this._renderInput();
|
|
20166
|
-
const examplesContent = this.props.examples.length <= 2 ? this.props.examples.join(" ") // A single item (with or without leading text) is not a "list"
|
|
20167
|
-
: this.props.examples // 2 or more items should display as a list
|
|
20168
|
-
.map((example, index) => {
|
|
20169
|
-
// If the first example is bold, then it is most likely a heading/leading text.
|
|
20170
|
-
// So, it shouldn't be part of the list.
|
|
20171
|
-
return index === 0 && example.startsWith("**") ? `${example}\n` : `- ${example}`;
|
|
20172
|
-
}).join("\n");
|
|
20173
|
-
const showExamples = this.props.shouldShowExamples && this.state.showExamples;
|
|
20174
|
-
return /*#__PURE__*/React__namespace.createElement(Tooltip, {
|
|
20175
|
-
className: "perseus-formats-tooltip preview-measure",
|
|
20176
|
-
horizontalPosition: HorizontalDirection.Left,
|
|
20177
|
-
horizontalAlign: HorizontalDirection.Left,
|
|
20178
|
-
verticalPosition: VerticalDirection.Bottom,
|
|
20179
|
-
arrowSize: 10,
|
|
20180
|
-
borderColor: "#ccc",
|
|
20181
|
-
show: showExamples
|
|
20182
|
-
}, input, /*#__PURE__*/React__namespace.createElement("div", {
|
|
20183
|
-
id: this._getUniqueId()
|
|
19922
|
+
const renderTooltipContent = () => {
|
|
19923
|
+
return /*#__PURE__*/React__namespace.createElement(Tooltip.TooltipContent, null, /*#__PURE__*/React__namespace.createElement("div", {
|
|
19924
|
+
id: id,
|
|
19925
|
+
className: "input-with-examples-tooltip"
|
|
20184
19926
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
20185
19927
|
content: examplesContent,
|
|
20186
|
-
linterContext: PerseusLinter__namespace.pushContextStack(
|
|
20187
|
-
strings:
|
|
19928
|
+
linterContext: PerseusLinter__namespace.pushContextStack(linterContext, "input-with-examples"),
|
|
19929
|
+
strings: context.strings
|
|
20188
19930
|
})));
|
|
20189
|
-
}
|
|
20190
|
-
}
|
|
20191
|
-
|
|
20192
|
-
class SimpleKeypadInput extends React__namespace.Component {
|
|
20193
|
-
_isMounted = false;
|
|
20194
|
-
componentDidMount() {
|
|
20195
|
-
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
20196
|
-
// this.isMounted() but is still considered an anti-pattern.
|
|
20197
|
-
this._isMounted = true;
|
|
20198
|
-
}
|
|
20199
|
-
componentWillUnmount() {
|
|
20200
|
-
this._isMounted = false;
|
|
20201
|
-
}
|
|
20202
|
-
focus() {
|
|
20203
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
20204
|
-
this.refs.input.focus(); // eslint-disable-line react/no-string-refs
|
|
20205
|
-
}
|
|
20206
|
-
|
|
20207
|
-
blur() {
|
|
20208
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20209
|
-
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
20210
|
-
if (typeof this.refs.input?.blur === "function") {
|
|
20211
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20212
|
-
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
20213
|
-
this.refs.input?.blur();
|
|
20214
|
-
}
|
|
20215
|
-
}
|
|
20216
|
-
getValue() {
|
|
20217
|
-
return this.props.value;
|
|
20218
|
-
}
|
|
20219
|
-
render() {
|
|
20220
|
-
const _this = this;
|
|
20221
|
-
// Intercept the `onFocus` prop, as we need to configure the keypad
|
|
20222
|
-
// before continuing with the default focus logic for Perseus inputs.
|
|
20223
|
-
// Intercept the `value` prop so as to map `null` to the empty string,
|
|
20224
|
-
// as the `KeypadInput` does not support `null` values.
|
|
20225
|
-
const {
|
|
20226
|
-
keypadElement,
|
|
20227
|
-
onFocus,
|
|
20228
|
-
value,
|
|
20229
|
-
...rest
|
|
20230
|
-
} = _this.props;
|
|
20231
|
-
return (
|
|
20232
|
-
/*#__PURE__*/
|
|
20233
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
20234
|
-
React__namespace.createElement(mathInput.KeypadInput
|
|
20235
|
-
// eslint-disable-next-line react/no-string-refs
|
|
20236
|
-
, _extends({
|
|
20237
|
-
ref: "input",
|
|
20238
|
-
keypadElement: keypadElement,
|
|
20239
|
-
onFocus: () => {
|
|
20240
|
-
if (keypadElement) {
|
|
20241
|
-
keypadElement.configure({
|
|
20242
|
-
keypadType: mathInput.KeypadType.FRACTION
|
|
20243
|
-
}, () => {
|
|
20244
|
-
if (_this._isMounted) {
|
|
20245
|
-
onFocus?.();
|
|
20246
|
-
}
|
|
20247
|
-
});
|
|
20248
|
-
} else {
|
|
20249
|
-
onFocus?.();
|
|
20250
|
-
}
|
|
20251
|
-
},
|
|
20252
|
-
value: value == null ? "" : "" + value
|
|
20253
|
-
}, rest))
|
|
20254
|
-
);
|
|
20255
|
-
}
|
|
20256
|
-
}
|
|
20257
|
-
|
|
20258
|
-
// @ts-expect-error - TS2339 - Property 'propTypes' does not exist on type 'typeof SimpleKeypadInput'.
|
|
20259
|
-
SimpleKeypadInput.propTypes = {
|
|
20260
|
-
keypadElement: mathInput.keypadElementPropType,
|
|
20261
|
-
onFocus: PropTypes__default["default"].func,
|
|
20262
|
-
value: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].number])
|
|
20263
|
-
};
|
|
20264
|
-
|
|
20265
|
-
const getPromptJSON$s = (renderProps, userInput) => {
|
|
20266
|
-
return {
|
|
20267
|
-
type: "input-number",
|
|
20268
|
-
options: {
|
|
20269
|
-
simplify: renderProps.simplify,
|
|
20270
|
-
answerType: renderProps.answerType
|
|
20271
|
-
},
|
|
20272
|
-
userInput: {
|
|
20273
|
-
value: userInput.currentValue
|
|
20274
|
-
}
|
|
20275
19931
|
};
|
|
20276
|
-
|
|
19932
|
+
// Display the examples as a string when there are less than or equal to 2 examples.
|
|
19933
|
+
// Otherwise, display the examples as a list.
|
|
19934
|
+
const examplesContent = props.examples.length <= 2 ? props.examples.join(" ") : props.examples.map((example, index) => {
|
|
19935
|
+
return index === 0 && example.startsWith("**") ? `${example}\n` : `- ${example}`;
|
|
19936
|
+
}).join("\n");
|
|
20277
19937
|
|
|
20278
|
-
|
|
19938
|
+
// Display the examples when they are enabled (shouldShowExamples) and the input is focused.
|
|
19939
|
+
const showExamplesTooltip = shouldShowExamples && inputFocused;
|
|
19940
|
+
return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
19941
|
+
content: renderTooltipContent(),
|
|
19942
|
+
opened: showExamplesTooltip,
|
|
19943
|
+
placement: "bottom"
|
|
19944
|
+
}, renderInput());
|
|
19945
|
+
});
|
|
19946
|
+
|
|
19947
|
+
const formExamples = {
|
|
20279
19948
|
integer: function (options, strings) {
|
|
20280
19949
|
return strings.integerExample;
|
|
20281
19950
|
},
|
|
@@ -20387,7 +20056,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
20387
20056
|
} = this.context;
|
|
20388
20057
|
const type = this.props.answerType;
|
|
20389
20058
|
const forms = perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);
|
|
20390
|
-
const examples = ___default["default"].map(forms, form => formExamples
|
|
20059
|
+
const examples = ___default["default"].map(forms, form => formExamples[form](this.props, strings));
|
|
20391
20060
|
return [strings.yourAnswer].concat(examples);
|
|
20392
20061
|
}
|
|
20393
20062
|
render() {
|
|
@@ -20501,7 +20170,11 @@ const getPromptJSON$r = (renderProps, userInput) => {
|
|
|
20501
20170
|
};
|
|
20502
20171
|
};
|
|
20503
20172
|
|
|
20504
|
-
|
|
20173
|
+
/**
|
|
20174
|
+
* The full list of available strings for the numeric input widget,
|
|
20175
|
+
* based on whether the Content Creator has specified that the answer must be simplified.
|
|
20176
|
+
*/
|
|
20177
|
+
const NumericExampleStrings = {
|
|
20505
20178
|
integer: (form, strings) => strings.integerExample,
|
|
20506
20179
|
proper: (form, strings) => form.simplify === "optional" ? strings.properExample : strings.simplifiedProperExample,
|
|
20507
20180
|
improper: (form, strings) => form.simplify === "optional" ? strings.improperExample : strings.simplifiedImproperExample,
|
|
@@ -20509,9 +20182,182 @@ const formExamples = {
|
|
|
20509
20182
|
decimal: (form, strings) => strings.decimalExample,
|
|
20510
20183
|
pi: (form, strings) => strings.piExample
|
|
20511
20184
|
};
|
|
20185
|
+
|
|
20186
|
+
/**
|
|
20187
|
+
* Generates the specific set of examples for the current question.
|
|
20188
|
+
* This string is shown as examples to the user in a tooltip.
|
|
20189
|
+
*/
|
|
20190
|
+
const generateExamples = (answerForms, strings) => {
|
|
20191
|
+
// If the Content Creator has not specified any answer forms,
|
|
20192
|
+
// we do not need to show any examples.
|
|
20193
|
+
if (answerForms.length === 0) {
|
|
20194
|
+
return [];
|
|
20195
|
+
}
|
|
20196
|
+
|
|
20197
|
+
// Generate a list of the unique answer forms.
|
|
20198
|
+
const uniqueForms = getUniqueAnswerForms(answerForms);
|
|
20199
|
+
|
|
20200
|
+
// Generate the example strings for each unique form.
|
|
20201
|
+
const examples = uniqueForms.map(form => {
|
|
20202
|
+
return NumericExampleStrings[form.name](form, strings);
|
|
20203
|
+
});
|
|
20204
|
+
|
|
20205
|
+
// Add the "Your answer" string to the beginning of the examples list.
|
|
20206
|
+
return [strings.yourAnswer].concat(examples);
|
|
20207
|
+
};
|
|
20208
|
+
|
|
20209
|
+
/**
|
|
20210
|
+
* Determines whether to show examples of how to input the various supported answer forms.
|
|
20211
|
+
* We do not show examples if all forms are accepted or if no forms are accepted.
|
|
20212
|
+
*/
|
|
20213
|
+
const shouldShowExamples = answerForms => {
|
|
20214
|
+
// If the Content Creator has not specified any answer forms,
|
|
20215
|
+
// we do not need to show any examples.
|
|
20216
|
+
if (answerForms.length === 0) {
|
|
20217
|
+
return false;
|
|
20218
|
+
}
|
|
20219
|
+
|
|
20220
|
+
// Generate a list of the unique names of the selected answer forms.
|
|
20221
|
+
const answerFormNames = getUniqueAnswerForms(answerForms).map(form => form.name);
|
|
20222
|
+
|
|
20223
|
+
// If all forms are accepted, we do not need to show any examples.
|
|
20224
|
+
const allFormsAccepted = answerFormNames.length >= Object.keys(NumericExampleStrings).length;
|
|
20225
|
+
return !allFormsAccepted;
|
|
20226
|
+
};
|
|
20227
|
+
|
|
20228
|
+
/**
|
|
20229
|
+
* uniqueAnswerForms takes a list of answer forms and returns a list of unique
|
|
20230
|
+
* answer forms. This is useful for ensuring that we don't show duplicate examples
|
|
20231
|
+
* to the user.
|
|
20232
|
+
*/
|
|
20233
|
+
const getUniqueAnswerForms = function (list) {
|
|
20234
|
+
// We use a Set to keep track of the forms we've already seen.
|
|
20235
|
+
const foundForms = new Set();
|
|
20236
|
+
return list.filter(form => {
|
|
20237
|
+
// If we've already seen this form, skip it.
|
|
20238
|
+
if (foundForms.has(form.name)) {
|
|
20239
|
+
return false;
|
|
20240
|
+
}
|
|
20241
|
+
// Otherwise, add it to the set and return true.
|
|
20242
|
+
foundForms.add(form.name);
|
|
20243
|
+
return true;
|
|
20244
|
+
});
|
|
20245
|
+
};
|
|
20246
|
+
|
|
20247
|
+
/**
|
|
20248
|
+
* Takes a list of lists of answer forms, and returns a list of the forms
|
|
20249
|
+
* in each of these lists in the same order that they're listed in the
|
|
20250
|
+
* `formExamples` forms from above.
|
|
20251
|
+
*/
|
|
20252
|
+
const unionAnswerForms = function (answerFormsList) {
|
|
20253
|
+
// Pull out all of the forms from the different lists.
|
|
20254
|
+
const allForms = answerFormsList.flat();
|
|
20255
|
+
// Pull out the unique forms using getUniqueAnswerForms.
|
|
20256
|
+
const uniqueForms = getUniqueAnswerForms(allForms);
|
|
20257
|
+
// Sort them by the order they appear in the `formExamples` list.
|
|
20258
|
+
const formExampleKeys = Object.keys(NumericExampleStrings);
|
|
20259
|
+
return uniqueForms.sort((a, b) => {
|
|
20260
|
+
return formExampleKeys.indexOf(a.name) - formExampleKeys.indexOf(b.name);
|
|
20261
|
+
});
|
|
20262
|
+
};
|
|
20263
|
+
|
|
20264
|
+
/**
|
|
20265
|
+
* The NumericInputComponent is a child component of the NumericInput class
|
|
20266
|
+
* component. It is responsible for rendering the UI elements of the Numeric
|
|
20267
|
+
* Input widget.
|
|
20268
|
+
*/
|
|
20269
|
+
const NumericInputComponent = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
20270
|
+
const context = React.useContext(PerseusI18nContext);
|
|
20271
|
+
const inputRef = React.useRef(null);
|
|
20272
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
20273
|
+
|
|
20274
|
+
// Pass the focus and blur methods to the Numeric Input Class component
|
|
20275
|
+
React.useImperativeHandle(ref, () => ({
|
|
20276
|
+
current: inputRef.current,
|
|
20277
|
+
focus: () => {
|
|
20278
|
+
if (inputRef.current) {
|
|
20279
|
+
inputRef.current?.focus();
|
|
20280
|
+
setIsFocused(true);
|
|
20281
|
+
}
|
|
20282
|
+
},
|
|
20283
|
+
blur: () => {
|
|
20284
|
+
if (inputRef.current) {
|
|
20285
|
+
inputRef.current?.blur();
|
|
20286
|
+
setIsFocused(false);
|
|
20287
|
+
}
|
|
20288
|
+
}
|
|
20289
|
+
}));
|
|
20290
|
+
const handleChange = (newValue, cb) => {
|
|
20291
|
+
props.onChange({
|
|
20292
|
+
currentValue: newValue
|
|
20293
|
+
}, cb);
|
|
20294
|
+
props.trackInteraction();
|
|
20295
|
+
};
|
|
20296
|
+
const handleFocus = () => {
|
|
20297
|
+
props.onFocus([]);
|
|
20298
|
+
setIsFocused(true);
|
|
20299
|
+
};
|
|
20300
|
+
const handleBlur = () => {
|
|
20301
|
+
props.onBlur([]);
|
|
20302
|
+
setIsFocused(false);
|
|
20303
|
+
};
|
|
20304
|
+
|
|
20305
|
+
// Styles for the InputWithExamples
|
|
20306
|
+
const styles = aphrodite.StyleSheet.create({
|
|
20307
|
+
inputWithExamples: {
|
|
20308
|
+
borderRadius: "3px",
|
|
20309
|
+
borderWidth: isFocused ? "2px" : "1px",
|
|
20310
|
+
display: "inline-block",
|
|
20311
|
+
fontFamily: `Symbola, "Times New Roman", serif`,
|
|
20312
|
+
fontSize: "18px",
|
|
20313
|
+
height: "32px",
|
|
20314
|
+
lineHeight: "18px",
|
|
20315
|
+
padding: isFocused ? "4px" : "4px 5px",
|
|
20316
|
+
textAlign: props.rightAlign ? "right" : "left",
|
|
20317
|
+
width: props.size === "small" ? 40 : 80
|
|
20318
|
+
}
|
|
20319
|
+
});
|
|
20320
|
+
|
|
20321
|
+
// (mobile-only) If the custom keypad is enabled, use the SimpleKeypadInput component
|
|
20322
|
+
if (props.apiOptions.customKeypad) {
|
|
20323
|
+
const alignmentClass = props.rightAlign ? "perseus-input-right-align" : undefined;
|
|
20324
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
20325
|
+
className: alignmentClass
|
|
20326
|
+
}, /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, {
|
|
20327
|
+
ref: inputRef,
|
|
20328
|
+
value: props.currentValue,
|
|
20329
|
+
keypadElement: props.keypadElement,
|
|
20330
|
+
onChange: handleChange,
|
|
20331
|
+
onFocus: handleFocus,
|
|
20332
|
+
onBlur: handleBlur
|
|
20333
|
+
}));
|
|
20334
|
+
}
|
|
20335
|
+
// (desktop-only) Otherwise, use the InputWithExamples component
|
|
20336
|
+
return /*#__PURE__*/React__namespace.createElement(InputWithExamples, {
|
|
20337
|
+
ref: inputRef,
|
|
20338
|
+
value: props.currentValue,
|
|
20339
|
+
onChange: handleChange,
|
|
20340
|
+
labelText: props.labelText,
|
|
20341
|
+
examples: generateExamples(props.answerForms, context.strings),
|
|
20342
|
+
shouldShowExamples: shouldShowExamples(props.answerForms),
|
|
20343
|
+
onFocus: handleFocus,
|
|
20344
|
+
onBlur: handleBlur,
|
|
20345
|
+
id: props.widgetId,
|
|
20346
|
+
disabled: props.apiOptions.readOnly,
|
|
20347
|
+
style: styles.inputWithExamples
|
|
20348
|
+
});
|
|
20349
|
+
});
|
|
20350
|
+
|
|
20351
|
+
/**
|
|
20352
|
+
* The NumericInput widget is a numeric input field that supports a variety of
|
|
20353
|
+
* answer forms, including integers, decimals, fractions, and mixed numbers.
|
|
20354
|
+
*
|
|
20355
|
+
* [Jan 2025] We're currenly migrating from class-based components to functional
|
|
20356
|
+
* components. While we cannot fully migrate this component yet, we can start
|
|
20357
|
+
* by using the functional component for the rendering the UI of the widget.
|
|
20358
|
+
*/
|
|
20512
20359
|
class NumericInput extends React__namespace.Component {
|
|
20513
|
-
|
|
20514
|
-
inputRef;
|
|
20360
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
20515
20361
|
static defaultProps = {
|
|
20516
20362
|
currentValue: "",
|
|
20517
20363
|
size: "normal",
|
|
@@ -20527,51 +20373,15 @@ class NumericInput extends React__namespace.Component {
|
|
|
20527
20373
|
currentValue: props.currentValue
|
|
20528
20374
|
};
|
|
20529
20375
|
}
|
|
20530
|
-
state = {
|
|
20531
|
-
// keeps track of the other set of values when switching
|
|
20532
|
-
// between 0 and finite solutions
|
|
20533
|
-
previousValues: [""],
|
|
20534
|
-
isFocused: false
|
|
20535
|
-
};
|
|
20536
|
-
|
|
20537
|
-
/**
|
|
20538
|
-
* Generates a string that demonstrates how to input the various supported
|
|
20539
|
-
* answer forms.
|
|
20540
|
-
*/
|
|
20541
|
-
examples() {
|
|
20542
|
-
// if the set of specified forms are empty, allow all forms
|
|
20543
|
-
const forms = this.props.answerForms?.length !== 0 ? this.props.answerForms : Object.keys(formExamples).map(name => {
|
|
20544
|
-
return {
|
|
20545
|
-
name: name,
|
|
20546
|
-
simplify: "required"
|
|
20547
|
-
};
|
|
20548
|
-
});
|
|
20549
|
-
let examples = ___default["default"].map(forms, form => {
|
|
20550
|
-
return formExamples[form.name](form, this.context.strings);
|
|
20551
|
-
});
|
|
20552
|
-
// Ensure no duplicate tooltip text from simplified and unsimplified
|
|
20553
|
-
// versions of the same format
|
|
20554
|
-
examples = ___default["default"].uniq(examples);
|
|
20555
|
-
return [this.context.strings.yourAnswer].concat(examples);
|
|
20556
|
-
}
|
|
20557
|
-
shouldShowExamples = () => {
|
|
20558
|
-
const noFormsAccepted = this.props.answerForms?.length === 0;
|
|
20559
|
-
// To check if all answer forms are accepted, we must first
|
|
20560
|
-
// find the *names* of all accepted forms, and see if they are
|
|
20561
|
-
// all present, ignoring duplicates
|
|
20562
|
-
const answerFormNames = ___default["default"].uniq(this.props.answerForms?.map(form => form.name));
|
|
20563
|
-
const allFormsAccepted = answerFormNames.length >= Object.keys(formExamples).length;
|
|
20564
|
-
return !noFormsAccepted && !allFormsAccepted;
|
|
20565
|
-
};
|
|
20566
20376
|
focus = () => {
|
|
20567
|
-
this.inputRef?.focus();
|
|
20377
|
+
this.inputRef.current?.focus();
|
|
20568
20378
|
return true;
|
|
20569
20379
|
};
|
|
20570
20380
|
focusInputPath = () => {
|
|
20571
|
-
this.inputRef?.focus();
|
|
20381
|
+
this.inputRef.current?.focus();
|
|
20572
20382
|
};
|
|
20573
20383
|
blurInputPath = () => {
|
|
20574
|
-
this.inputRef?.blur();
|
|
20384
|
+
this.inputRef.current?.blur();
|
|
20575
20385
|
};
|
|
20576
20386
|
getInputPaths = () => {
|
|
20577
20387
|
// The widget itself is an input, so we return a single empty list to
|
|
@@ -20579,152 +20389,57 @@ class NumericInput extends React__namespace.Component {
|
|
|
20579
20389
|
/* c8 ignore next */
|
|
20580
20390
|
return [[]];
|
|
20581
20391
|
};
|
|
20392
|
+
|
|
20393
|
+
/**
|
|
20394
|
+
* Sets the value of the input at the given path.
|
|
20395
|
+
*/
|
|
20582
20396
|
setInputValue = (path, newValue, cb) => {
|
|
20583
|
-
/* c8 ignore next */
|
|
20584
20397
|
this.props.onChange({
|
|
20585
20398
|
currentValue: newValue
|
|
20586
20399
|
}, cb);
|
|
20587
20400
|
};
|
|
20401
|
+
|
|
20402
|
+
/**
|
|
20403
|
+
* Returns the value the user has currently input for this widget.
|
|
20404
|
+
*/
|
|
20588
20405
|
getUserInput() {
|
|
20589
20406
|
return NumericInput.getUserInputFromProps(this.props);
|
|
20590
20407
|
}
|
|
20408
|
+
|
|
20409
|
+
/**
|
|
20410
|
+
* Returns the JSON representation of the prompt for this widget.
|
|
20411
|
+
* This is used by the AI to determine the prompt for the widget.
|
|
20412
|
+
*/
|
|
20591
20413
|
getPromptJSON() {
|
|
20592
20414
|
return getPromptJSON$r(this.props, this.getUserInput());
|
|
20593
20415
|
}
|
|
20594
|
-
handleChange = (newValue, cb) => {
|
|
20595
|
-
this.props.onChange({
|
|
20596
|
-
currentValue: newValue
|
|
20597
|
-
}, cb);
|
|
20598
|
-
this.props.trackInteraction();
|
|
20599
|
-
};
|
|
20600
|
-
_handleFocus = () => {
|
|
20601
|
-
this.props.onFocus([]);
|
|
20602
|
-
this.setState(currentState => {
|
|
20603
|
-
return {
|
|
20604
|
-
...currentState,
|
|
20605
|
-
isFocused: true
|
|
20606
|
-
};
|
|
20607
|
-
});
|
|
20608
|
-
};
|
|
20609
|
-
_handleBlur = () => {
|
|
20610
|
-
this.props.onBlur([]);
|
|
20611
|
-
this.setState(currentState => {
|
|
20612
|
-
return {
|
|
20613
|
-
...currentState,
|
|
20614
|
-
isFocused: false
|
|
20615
|
-
};
|
|
20616
|
-
});
|
|
20617
|
-
};
|
|
20618
20416
|
render() {
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
|
|
20622
|
-
}
|
|
20623
|
-
|
|
20624
|
-
// To right align a custom keypad we need to wrap it.
|
|
20625
|
-
const maybeRightAlignKeypadInput = keypadInput => {
|
|
20626
|
-
return this.props.rightAlign ? /*#__PURE__*/React__namespace.createElement("div", {
|
|
20627
|
-
className: "perseus-input-right-align"
|
|
20628
|
-
}, keypadInput) : keypadInput;
|
|
20629
|
-
};
|
|
20630
|
-
if (this.props.apiOptions.customKeypad) {
|
|
20631
|
-
// TODO(charlie): Support "Review Mode".
|
|
20632
|
-
return maybeRightAlignKeypadInput( /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, {
|
|
20633
|
-
ref: ref => this.inputRef = ref,
|
|
20634
|
-
value: this.props.currentValue,
|
|
20635
|
-
keypadElement: this.props.keypadElement,
|
|
20636
|
-
onChange: this.handleChange,
|
|
20637
|
-
onFocus: this._handleFocus,
|
|
20638
|
-
onBlur: this._handleBlur
|
|
20639
|
-
}));
|
|
20640
|
-
}
|
|
20641
|
-
|
|
20642
|
-
// Note: This is _very_ similar to what `input-number.jsx` does. If
|
|
20643
|
-
// you modify this, double-check if you also need to modify that
|
|
20644
|
-
// component.
|
|
20645
|
-
const styles = aphrodite.StyleSheet.create({
|
|
20646
|
-
input: {
|
|
20647
|
-
borderRadius: "3px",
|
|
20648
|
-
borderWidth: this.state.isFocused ? "2px" : "1px",
|
|
20649
|
-
display: "inline-block",
|
|
20650
|
-
fontFamily: `Symbola, "Times New Roman", serif`,
|
|
20651
|
-
fontSize: "18px",
|
|
20652
|
-
height: "32px",
|
|
20653
|
-
lineHeight: "18px",
|
|
20654
|
-
padding: this.state.isFocused ? "4px" : "4px 5px",
|
|
20655
|
-
// account for added focus border thickness
|
|
20656
|
-
textAlign: this.props.rightAlign ? "right" : "left",
|
|
20657
|
-
width: this.props.size === "small" ? 40 : 80
|
|
20658
|
-
}
|
|
20659
|
-
});
|
|
20660
|
-
return /*#__PURE__*/React__namespace.createElement(InputWithExamples, {
|
|
20661
|
-
ref: ref => this.inputRef = ref,
|
|
20662
|
-
value: this.props.currentValue,
|
|
20663
|
-
onChange: this.handleChange,
|
|
20664
|
-
labelText: labelText,
|
|
20665
|
-
examples: this.examples(),
|
|
20666
|
-
shouldShowExamples: this.shouldShowExamples(),
|
|
20667
|
-
onFocus: this._handleFocus,
|
|
20668
|
-
onBlur: this._handleBlur,
|
|
20669
|
-
id: this.props.widgetId,
|
|
20670
|
-
disabled: this.props.apiOptions.readOnly,
|
|
20671
|
-
style: styles.input
|
|
20672
|
-
});
|
|
20417
|
+
return /*#__PURE__*/React__namespace.createElement(NumericInputComponent, _extends__default["default"]({}, this.props, {
|
|
20418
|
+
ref: this.inputRef
|
|
20419
|
+
}));
|
|
20673
20420
|
}
|
|
20674
20421
|
}
|
|
20675
|
-
|
|
20676
|
-
// TODO(thomas): Currently we receive a list of lists of acceptable answer types
|
|
20677
|
-
// and union them down into a single set. It's worth considering whether it
|
|
20678
|
-
// wouldn't make more sense to have a single set of acceptable answer types for
|
|
20679
|
-
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
20680
|
-
// When should two answers to a problem take different answer types?
|
|
20681
|
-
// See D27790 for more discussion.
|
|
20682
|
-
const unionAnswerForms = function (answerFormsList) {
|
|
20683
|
-
// Takes a list of lists of answer forms, and returns a list of the forms
|
|
20684
|
-
// in each of these lists in the same order that they're listed in the
|
|
20685
|
-
// `formExamples` forms from above.
|
|
20686
|
-
|
|
20687
|
-
// uniqueBy takes a list of elements and a function which compares whether
|
|
20688
|
-
// two elements are equal, and returns a list of unique elements. This is
|
|
20689
|
-
// just a helper function here, but works generally.
|
|
20690
|
-
const uniqueBy = function (list, iteratee) {
|
|
20691
|
-
// @ts-expect-error - TS2347 - Untyped function calls may not accept type arguments.
|
|
20692
|
-
return list.reduce((uniqueList, element) => {
|
|
20693
|
-
// For each element, decide whether it's already in the list of
|
|
20694
|
-
// unique items.
|
|
20695
|
-
const inList = ___default["default"].find(uniqueList, iteratee.bind(null, element));
|
|
20696
|
-
if (inList) {
|
|
20697
|
-
return uniqueList;
|
|
20698
|
-
}
|
|
20699
|
-
return uniqueList.concat([element]);
|
|
20700
|
-
}, []);
|
|
20701
|
-
};
|
|
20702
|
-
|
|
20703
|
-
// Pull out all of the forms from the different lists.
|
|
20704
|
-
const allForms = answerFormsList.flat();
|
|
20705
|
-
// Pull out the unique forms using uniqueBy.
|
|
20706
|
-
const uniqueForms = uniqueBy(allForms, ___default["default"].isEqual);
|
|
20707
|
-
// Sort them by the order they appear in the `formExamples` list.
|
|
20708
|
-
const formExampleKeys = Object.keys(formExamples);
|
|
20709
|
-
return ___default["default"].sortBy(uniqueForms, form => {
|
|
20710
|
-
return formExampleKeys.indexOf(form.name);
|
|
20711
|
-
});
|
|
20712
|
-
};
|
|
20422
|
+
// Transforms the widget options to the props used to render the widget.
|
|
20713
20423
|
const propsTransform = function (widgetOptions) {
|
|
20714
|
-
|
|
20424
|
+
// Omit the answers from the widget options since they are
|
|
20425
|
+
// not needed for rendering the widget.
|
|
20426
|
+
const {
|
|
20427
|
+
answers: _,
|
|
20428
|
+
...rendererProps
|
|
20429
|
+
} = {
|
|
20430
|
+
...widgetOptions,
|
|
20715
20431
|
answerForms: unionAnswerForms(
|
|
20716
|
-
//
|
|
20717
|
-
//
|
|
20718
|
-
widgetOptions.answers.map(answer => {
|
|
20719
|
-
|
|
20720
|
-
return ___default["default"].map(answer.answerForms, form => {
|
|
20432
|
+
// Filter out the correct answers and map them to the answer forms
|
|
20433
|
+
// so that we can generate the examples for the widget.
|
|
20434
|
+
widgetOptions.answers.filter(answer => answer.status === "correct").map(answer => {
|
|
20435
|
+
return (answer.answerForms || []).map(form => {
|
|
20721
20436
|
return {
|
|
20722
20437
|
simplify: answer.simplify,
|
|
20723
20438
|
name: form
|
|
20724
20439
|
};
|
|
20725
20440
|
});
|
|
20726
20441
|
}))
|
|
20727
|
-
}
|
|
20442
|
+
};
|
|
20728
20443
|
return rendererProps;
|
|
20729
20444
|
};
|
|
20730
20445
|
var NumericInput$1 = {
|
|
@@ -20739,23 +20454,11 @@ var NumericInput$1 = {
|
|
|
20739
20454
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
20740
20455
|
const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
|
|
20741
20456
|
const answerStrings = correctAnswers.map(answer => {
|
|
20742
|
-
//
|
|
20743
|
-
|
|
20744
|
-
let format = "decimal";
|
|
20745
|
-
if (answer.answerForms && answer.answerForms[0]) {
|
|
20746
|
-
// NOTE(johnsullivan): This isn't exactly ideal, but
|
|
20747
|
-
// it does behave well for all the currently known
|
|
20748
|
-
// problems. See D14742 for some discussion on
|
|
20749
|
-
// alternate strategies.
|
|
20750
|
-
format = answer.answerForms[0];
|
|
20751
|
-
}
|
|
20752
|
-
|
|
20753
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
20457
|
+
// Either get the first answer form or default to decimal
|
|
20458
|
+
const format = answer.answerForms && answer.answerForms[0] ? answer.answerForms[0] : "decimal";
|
|
20754
20459
|
let answerString = kmath.KhanMath.toNumericString(answer.value, format);
|
|
20755
20460
|
if (answer.maxError) {
|
|
20756
|
-
answerString += " \u00B1 " +
|
|
20757
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
20758
|
-
kmath.KhanMath.toNumericString(answer.maxError, format);
|
|
20461
|
+
answerString += " \u00B1 " + kmath.KhanMath.toNumericString(answer.maxError, format);
|
|
20759
20462
|
}
|
|
20760
20463
|
return answerString;
|
|
20761
20464
|
});
|
|
@@ -23290,6 +22993,7 @@ const BASE_ICON_SIZE = 10;
|
|
|
23290
22993
|
// If you pass in an object you need to specify an SVG path to
|
|
23291
22994
|
// render along with the width and height of the path (to ensure
|
|
23292
22995
|
// that it gets scaled correctly).
|
|
22996
|
+
|
|
23293
22997
|
/**
|
|
23294
22998
|
* An SVG Icon
|
|
23295
22999
|
*
|
|
@@ -23547,7 +23251,7 @@ function ChoiceInner(props) {
|
|
|
23547
23251
|
return /*#__PURE__*/React__namespace.createElement("span", null, letter);
|
|
23548
23252
|
}
|
|
23549
23253
|
if (correct) {
|
|
23550
|
-
return /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
23254
|
+
return /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconCheck, {
|
|
23551
23255
|
style: {
|
|
23552
23256
|
position: "relative",
|
|
23553
23257
|
top: -1
|
|
@@ -24003,7 +23707,7 @@ const styles$p = aphrodite.StyleSheet.create({
|
|
|
24003
23707
|
}
|
|
24004
23708
|
}
|
|
24005
23709
|
});
|
|
24006
|
-
var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(Choice,
|
|
23710
|
+
var Choice$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(Choice, _extends__default["default"]({}, props, {
|
|
24007
23711
|
forwardedRef: ref
|
|
24008
23712
|
})));
|
|
24009
23713
|
|
|
@@ -24037,11 +23741,11 @@ const ChoiceNoneAbove = function (_ref) {
|
|
|
24037
23741
|
strings: strings
|
|
24038
23742
|
})
|
|
24039
23743
|
};
|
|
24040
|
-
return /*#__PURE__*/React__namespace.createElement(Choice$1,
|
|
23744
|
+
return /*#__PURE__*/React__namespace.createElement(Choice$1, _extends__default["default"]({}, choiceProps, {
|
|
24041
23745
|
ref: forwardedRef
|
|
24042
23746
|
}));
|
|
24043
23747
|
};
|
|
24044
|
-
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove,
|
|
23748
|
+
var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__*/React__namespace.createElement(ChoiceNoneAbove, _extends__default["default"]({}, props, {
|
|
24045
23749
|
forwardedRef: ref
|
|
24046
23750
|
})));
|
|
24047
23751
|
|
|
@@ -24291,7 +23995,7 @@ const BaseRadio = function (_ref) {
|
|
|
24291
23995
|
className: className,
|
|
24292
23996
|
onClick: clickHandler,
|
|
24293
23997
|
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
24294
|
-
}, /*#__PURE__*/React__namespace.createElement(Element,
|
|
23998
|
+
}, /*#__PURE__*/React__namespace.createElement(Element, _extends__default["default"]({}, elementProps, {
|
|
24295
23999
|
ref: ref
|
|
24296
24000
|
})))
|
|
24297
24001
|
);
|
|
@@ -24383,7 +24087,6 @@ const styles$o = aphrodite.StyleSheet.create({
|
|
|
24383
24087
|
paddingLeft: phoneMargin
|
|
24384
24088
|
// paddingRight is handled by responsiveFieldset
|
|
24385
24089
|
},
|
|
24386
|
-
|
|
24387
24090
|
responsiveFieldset: {
|
|
24388
24091
|
paddingRight: phoneMargin,
|
|
24389
24092
|
minWidth: "auto"
|
|
@@ -24627,7 +24330,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24627
24330
|
);
|
|
24628
24331
|
}
|
|
24629
24332
|
};
|
|
24630
|
-
|
|
24631
24333
|
render() {
|
|
24632
24334
|
const {
|
|
24633
24335
|
choices
|
|
@@ -24743,22 +24445,17 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24743
24445
|
}
|
|
24744
24446
|
}
|
|
24745
24447
|
|
|
24746
|
-
const {
|
|
24747
|
-
shuffle: shuffle$2,
|
|
24748
|
-
random
|
|
24749
|
-
} = Util;
|
|
24750
|
-
|
|
24751
24448
|
// Transforms the choices for display.
|
|
24752
24449
|
const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
24753
24450
|
const _maybeRandomize = function (array) {
|
|
24754
|
-
const randomSeed = problemNum === undefined ? random : problemNum;
|
|
24451
|
+
const randomSeed = problemNum === undefined ? perseusCore.random : problemNum;
|
|
24755
24452
|
// NOTE: `problemNum` will only be set when the radio widget is
|
|
24756
24453
|
// rendered at the root of an exercise question. It will be `undefined`
|
|
24757
24454
|
// if it's rendered embedded in another widget, such as `graded-group`,
|
|
24758
24455
|
// or if rendered within an article. This results in a predictable
|
|
24759
24456
|
// shuffle order. To avoid this we use a random seed when `problemNum`
|
|
24760
24457
|
// is `undefined`.
|
|
24761
|
-
return widgetOptions.randomize ? shuffle
|
|
24458
|
+
return widgetOptions.randomize ? perseusCore.shuffle(array, randomSeed ?? 0) : array;
|
|
24762
24459
|
};
|
|
24763
24460
|
const _addNoneOfAbove = function (choices) {
|
|
24764
24461
|
let noneOfTheAbove = null;
|
|
@@ -24809,7 +24506,7 @@ const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
|
24809
24506
|
// 1) we randomize the order first
|
|
24810
24507
|
_maybeRandomize(choices)));
|
|
24811
24508
|
};
|
|
24812
|
-
const transform = (widgetOptions, strings, problemNum) => {
|
|
24509
|
+
const transform$1 = (widgetOptions, strings, problemNum) => {
|
|
24813
24510
|
const choices = _choiceTransform(widgetOptions, strings, problemNum);
|
|
24814
24511
|
const numCorrect = ___default["default"].reduce(widgetOptions.choices, function (memo, choice) {
|
|
24815
24512
|
return choice.correct ? memo + 1 : memo;
|
|
@@ -24835,8 +24532,8 @@ var Radio = {
|
|
|
24835
24532
|
displayName: "Radio / Multiple choice",
|
|
24836
24533
|
accessible: true,
|
|
24837
24534
|
widget: Radio$1,
|
|
24838
|
-
transform: transform,
|
|
24839
|
-
staticTransform: transform,
|
|
24535
|
+
transform: transform$1,
|
|
24536
|
+
staticTransform: transform$1,
|
|
24840
24537
|
version: perseusCore.radioLogic.version,
|
|
24841
24538
|
propUpgrades: perseusCore.radioLogic.widgetOptionsUpgrades,
|
|
24842
24539
|
isLintable: true
|
|
@@ -24999,8 +24696,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
24999
24696
|
const isMobile = this.props.apiOptions.isMobile;
|
|
25000
24697
|
let indexedItems = this.props.items.map((item, n) => [item, n]);
|
|
25001
24698
|
if (this.props.randomizeItems) {
|
|
25002
|
-
|
|
25003
|
-
indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
|
|
24699
|
+
indexedItems = perseusCore.shuffle(indexedItems, this.props.problemNum);
|
|
25004
24700
|
}
|
|
25005
24701
|
const table = /*#__PURE__*/React__namespace.createElement("table", {
|
|
25006
24702
|
className: "categorizer-table " + aphrodite.css(styles$n.mobileTable)
|
|
@@ -25026,9 +24722,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
25026
24722
|
const uniqueId = self.state.uniqueId + "_" + itemNum;
|
|
25027
24723
|
return /*#__PURE__*/React__namespace.createElement("tr", {
|
|
25028
24724
|
key: itemNum
|
|
25029
|
-
}, /*#__PURE__*/React__namespace.createElement("td", null, /*#__PURE__*/React__namespace.createElement(Renderer
|
|
25030
|
-
// @ts-expect-error - TS2322 - Type 'string | number' is not assignable to type 'string | undefined'.
|
|
25031
|
-
, {
|
|
24725
|
+
}, /*#__PURE__*/React__namespace.createElement("td", null, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
25032
24726
|
content: item,
|
|
25033
24727
|
linterContext: this.props.linterContext,
|
|
25034
24728
|
strings: this.context.strings
|
|
@@ -25421,6 +25115,7 @@ var Definition$1 = {
|
|
|
25421
25115
|
|
|
25422
25116
|
// There are no required props, but this component can receive props from any
|
|
25423
25117
|
// deprecated widget
|
|
25118
|
+
|
|
25424
25119
|
class DeprecatedStandin extends React__default["default"].Component {
|
|
25425
25120
|
static contextType = PerseusI18nContext;
|
|
25426
25121
|
// this just helps with TS weak typing when a Widget
|
|
@@ -25541,20 +25236,20 @@ class Dropdown extends React__namespace.Component {
|
|
|
25541
25236
|
}, children)));
|
|
25542
25237
|
}
|
|
25543
25238
|
}
|
|
25544
|
-
|
|
25239
|
+
function transform(widgetOptions) {
|
|
25545
25240
|
return {
|
|
25546
25241
|
placeholder: widgetOptions.placeholder,
|
|
25547
25242
|
visibleLabel: widgetOptions.visibleLabel,
|
|
25548
25243
|
ariaLabel: widgetOptions.ariaLabel,
|
|
25549
25244
|
choices: widgetOptions.choices.map(choice => choice.content)
|
|
25550
25245
|
};
|
|
25551
|
-
}
|
|
25246
|
+
}
|
|
25552
25247
|
var Dropdown$1 = {
|
|
25553
25248
|
name: "dropdown",
|
|
25554
25249
|
displayName: "Drop down",
|
|
25555
25250
|
accessible: true,
|
|
25556
25251
|
widget: Dropdown,
|
|
25557
|
-
transform
|
|
25252
|
+
transform
|
|
25558
25253
|
};
|
|
25559
25254
|
|
|
25560
25255
|
const getPromptJSON$j = renderProps => {
|
|
@@ -25630,7 +25325,6 @@ class Explanation extends React__namespace.Component {
|
|
|
25630
25325
|
// adds space between the right border and any text that follows
|
|
25631
25326
|
paddingLeft: "2px" // adds space between the left border and the button text
|
|
25632
25327
|
};
|
|
25633
|
-
|
|
25634
25328
|
const labelStyle = {
|
|
25635
25329
|
fontSize: "18px",
|
|
25636
25330
|
lineHeight: "inherit",
|
|
@@ -25786,7 +25480,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
25786
25480
|
fontSize: 28,
|
|
25787
25481
|
color: wonderBlocksTokens.color.green
|
|
25788
25482
|
}
|
|
25789
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25483
|
+
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconStar, {
|
|
25790
25484
|
style: {
|
|
25791
25485
|
marginBottom: 5
|
|
25792
25486
|
}
|
|
@@ -25979,7 +25673,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25979
25673
|
if (this.state.status === GRADING_STATUSES.correct) {
|
|
25980
25674
|
// TODO(jeremy): update to a WB colour
|
|
25981
25675
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
25982
|
-
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25676
|
+
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconOk, {
|
|
25983
25677
|
style: {
|
|
25984
25678
|
color: "#526f03"
|
|
25985
25679
|
}
|
|
@@ -25988,7 +25682,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25988
25682
|
} else if (this.state.status === GRADING_STATUSES.incorrect) {
|
|
25989
25683
|
// TODO(jeremy): update to a WB colour
|
|
25990
25684
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
25991
|
-
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon,
|
|
25685
|
+
icon = /*#__PURE__*/React__namespace.createElement(InlineIcon, _extends__default["default"]({}, iconRemove, {
|
|
25992
25686
|
style: {
|
|
25993
25687
|
color: "#ff5454"
|
|
25994
25688
|
}
|
|
@@ -26015,7 +25709,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
26015
25709
|
className: classes
|
|
26016
25710
|
}, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
|
|
26017
25711
|
className: aphrodite.css(styles$i.title)
|
|
26018
|
-
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
25712
|
+
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, this.props, {
|
|
26019
25713
|
ref: this.rendererRef,
|
|
26020
25714
|
apiOptions: {
|
|
26021
25715
|
...apiOptions,
|
|
@@ -26058,7 +25752,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
26058
25752
|
showHint: false
|
|
26059
25753
|
});
|
|
26060
25754
|
}
|
|
26061
|
-
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
25755
|
+
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, this.props.hint, {
|
|
26062
25756
|
ref: this.hintRendererRef,
|
|
26063
25757
|
apiOptions: apiOptions,
|
|
26064
25758
|
linterContext: this.props.linterContext,
|
|
@@ -26283,7 +25977,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
26283
25977
|
// TODO(jeremy): Don't spread this.props, instead
|
|
26284
25978
|
// pass in all props GradedGroup needs explicilty
|
|
26285
25979
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
26286
|
-
React__namespace.createElement(GradedGroup,
|
|
25980
|
+
React__namespace.createElement(GradedGroup, _extends__default["default"]({
|
|
26287
25981
|
key: i
|
|
26288
25982
|
}, this.props, gradedGroup, {
|
|
26289
25983
|
inGradedGroupSet: false,
|
|
@@ -26312,7 +26006,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
26312
26006
|
onChangeCurrentGroup: currentGroup => this.setState({
|
|
26313
26007
|
currentGroup
|
|
26314
26008
|
})
|
|
26315
|
-
})), /*#__PURE__*/React__namespace.createElement(GradedGroup,
|
|
26009
|
+
})), /*#__PURE__*/React__namespace.createElement(GradedGroup, _extends__default["default"]({
|
|
26316
26010
|
key: this.state.currentGroup
|
|
26317
26011
|
// @ts-expect-error - TS2322 - Type 'GradedGroup | null' is not assignable to type 'GradedGroup'.
|
|
26318
26012
|
// Type 'null' is not assignable to type 'GradedGroup'.
|
|
@@ -26708,7 +26402,7 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26708
26402
|
}
|
|
26709
26403
|
const functionProps = model.getPropsForCoeffs(coeffs, xRange);
|
|
26710
26404
|
const Movable = movableTypeToComponent[model.movable];
|
|
26711
|
-
return /*#__PURE__*/React__namespace.createElement(Movable,
|
|
26405
|
+
return /*#__PURE__*/React__namespace.createElement(Movable, _extends__default["default"]({}, functionProps, {
|
|
26712
26406
|
key: this.props.model.url,
|
|
26713
26407
|
range: xRange,
|
|
26714
26408
|
style: style
|
|
@@ -26841,7 +26535,7 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26841
26535
|
width: box[0],
|
|
26842
26536
|
height: box[1]
|
|
26843
26537
|
}
|
|
26844
|
-
}, image, /*#__PURE__*/React__namespace.createElement(Graphie,
|
|
26538
|
+
}, image, /*#__PURE__*/React__namespace.createElement(Graphie, _extends__default["default"]({}, this.props.graph, {
|
|
26845
26539
|
setDrawingAreaAvailable: this.props.setDrawingAreaAvailable
|
|
26846
26540
|
}), this.props.model && this.renderPlot(), this.props.model && this.renderAsymptote(), this.props.model && points)));
|
|
26847
26541
|
}
|
|
@@ -27985,7 +27679,6 @@ class Interaction extends React__namespace.Component {
|
|
|
27985
27679
|
}
|
|
27986
27680
|
});
|
|
27987
27681
|
}
|
|
27988
|
-
|
|
27989
27682
|
if (element.type === "parametric") {
|
|
27990
27683
|
const fn = t => {
|
|
27991
27684
|
return [
|
|
@@ -28038,7 +27731,6 @@ class Interaction extends React__namespace.Component {
|
|
|
28038
27731
|
}
|
|
28039
27732
|
});
|
|
28040
27733
|
}
|
|
28041
|
-
|
|
28042
27734
|
if (element.type === "label") {
|
|
28043
27735
|
const coord = [
|
|
28044
27736
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
@@ -28370,7 +28062,6 @@ function scaleCommandBy(scaleFactor) {
|
|
|
28370
28062
|
command.args[6] * scaleFactor // end y
|
|
28371
28063
|
]
|
|
28372
28064
|
};
|
|
28373
|
-
|
|
28374
28065
|
default:
|
|
28375
28066
|
return {
|
|
28376
28067
|
...command,
|
|
@@ -29130,7 +28821,6 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
29130
28821
|
userSelect: "none",
|
|
29131
28822
|
borderWidth: 0 // <button> gives us a border by default
|
|
29132
28823
|
},
|
|
29133
|
-
|
|
29134
28824
|
// We want to render the element in-place in our fixtures, so allow us to
|
|
29135
28825
|
// render in the bottom corner in production and in-place in testing.
|
|
29136
28826
|
hudFixedPosition: {
|
|
@@ -29160,7 +28850,6 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
29160
28850
|
":hover": {
|
|
29161
28851
|
backgroundColor: "#a1a5a9" // in between those two grays
|
|
29162
28852
|
},
|
|
29163
|
-
|
|
29164
28853
|
":active": {
|
|
29165
28854
|
backgroundColor: gray68
|
|
29166
28855
|
}
|
|
@@ -29205,7 +28894,6 @@ class InfoTip extends React__namespace.Component {
|
|
|
29205
28894
|
});
|
|
29206
28895
|
/* eslint-enable react/no-did-mount-set-state */
|
|
29207
28896
|
}
|
|
29208
|
-
|
|
29209
28897
|
render() {
|
|
29210
28898
|
if (this.state.didMount) {
|
|
29211
28899
|
return /*#__PURE__*/React__namespace.createElement(InfoTipBase, this.props);
|
|
@@ -29471,7 +29159,6 @@ class NumberInput extends React__namespace.Component {
|
|
|
29471
29159
|
if (val !== Math.floor(val)) {
|
|
29472
29160
|
return; // bail if not an integer
|
|
29473
29161
|
}
|
|
29474
|
-
|
|
29475
29162
|
if (e.key === "ArrowUp") {
|
|
29476
29163
|
val = val + 1;
|
|
29477
29164
|
} else if (e.key === "ArrowDown") {
|
|
@@ -29504,7 +29191,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
29504
29191
|
useArrowKeys,
|
|
29505
29192
|
...restProps
|
|
29506
29193
|
} = this.props;
|
|
29507
|
-
return /*#__PURE__*/React__namespace.createElement("input",
|
|
29194
|
+
return /*#__PURE__*/React__namespace.createElement("input", _extends__default["default"]({}, restProps, {
|
|
29508
29195
|
className: classes,
|
|
29509
29196
|
type: "text",
|
|
29510
29197
|
ref: this.inputRef,
|
|
@@ -29549,7 +29236,7 @@ class RangeInput extends React__namespace.Component {
|
|
|
29549
29236
|
const checkValidity = this.props.checkValidity || truth;
|
|
29550
29237
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
29551
29238
|
className: "range-input"
|
|
29552
|
-
}, /*#__PURE__*/React__namespace.createElement(NumberInput,
|
|
29239
|
+
}, /*#__PURE__*/React__namespace.createElement(NumberInput, _extends__default["default"]({}, this.props, {
|
|
29553
29240
|
value: value[0],
|
|
29554
29241
|
checkValidity: val => checkValidity([val, value[1]])
|
|
29555
29242
|
// eslint-disable-next-line react/jsx-no-bind
|
|
@@ -29557,7 +29244,7 @@ class RangeInput extends React__namespace.Component {
|
|
|
29557
29244
|
onChange: this.onChange.bind(this, 0),
|
|
29558
29245
|
placeholder: this.props.placeholder[0],
|
|
29559
29246
|
allowPiTruncation: this.props.allowPiTruncation
|
|
29560
|
-
})), /*#__PURE__*/React__namespace.createElement(NumberInput,
|
|
29247
|
+
})), /*#__PURE__*/React__namespace.createElement(NumberInput, _extends__default["default"]({}, this.props, {
|
|
29561
29248
|
value: value[1],
|
|
29562
29249
|
checkValidity: val => checkValidity([value[0], val])
|
|
29563
29250
|
// eslint-disable-next-line react/jsx-no-bind
|
|
@@ -29570,20 +29257,20 @@ class RangeInput extends React__namespace.Component {
|
|
|
29570
29257
|
}
|
|
29571
29258
|
|
|
29572
29259
|
var components = /*#__PURE__*/Object.freeze({
|
|
29573
|
-
|
|
29574
|
-
|
|
29575
|
-
|
|
29576
|
-
|
|
29577
|
-
|
|
29578
|
-
|
|
29579
|
-
|
|
29580
|
-
|
|
29581
|
-
|
|
29582
|
-
|
|
29583
|
-
|
|
29584
|
-
|
|
29585
|
-
|
|
29586
|
-
|
|
29260
|
+
__proto__: null,
|
|
29261
|
+
ButtonGroup: ButtonGroup,
|
|
29262
|
+
Graphie: Graphie,
|
|
29263
|
+
HUD: HUD,
|
|
29264
|
+
Icon: Icon,
|
|
29265
|
+
InfoTip: InfoTip,
|
|
29266
|
+
InlineIcon: InlineIcon,
|
|
29267
|
+
MathInput: MathInput,
|
|
29268
|
+
MultiButtonGroup: MultiButtonGroup,
|
|
29269
|
+
NumberInput: NumberInput,
|
|
29270
|
+
RangeInput: RangeInput,
|
|
29271
|
+
SvgImage: SvgImage,
|
|
29272
|
+
TextInput: TextInput,
|
|
29273
|
+
TextListEditor: TextListEditor
|
|
29587
29274
|
});
|
|
29588
29275
|
|
|
29589
29276
|
/**
|
|
@@ -29659,17 +29346,17 @@ function GraphLockedLabelsLayer(props) {
|
|
|
29659
29346
|
} = props;
|
|
29660
29347
|
return lockedFigures.map((figure, i) => {
|
|
29661
29348
|
if (figure.type === "label") {
|
|
29662
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29349
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29663
29350
|
key: `label-${i}`
|
|
29664
29351
|
}, figure));
|
|
29665
29352
|
}
|
|
29666
29353
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, {
|
|
29667
29354
|
key: i
|
|
29668
|
-
}, figure.labels?.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29355
|
+
}, figure.labels?.map((label, j) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29669
29356
|
key: `${i}-label-${j}`
|
|
29670
|
-
}, label))), figure.type === "line" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, figure.points[0].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29357
|
+
}, label))), figure.type === "line" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, figure.points[0].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29671
29358
|
key: `locked-figure-${i}-point-1-label-${k}`
|
|
29672
|
-
}, label))), figure.points[1].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel,
|
|
29359
|
+
}, label))), figure.points[1].labels?.map((label, k) => /*#__PURE__*/React__namespace.createElement(LockedLabel, _extends__default["default"]({
|
|
29673
29360
|
key: `locked-figure-${i}-point-2-label-${k}`
|
|
29674
29361
|
}, label)))));
|
|
29675
29362
|
});
|
|
@@ -29715,9 +29402,9 @@ const LockedFunction = props => {
|
|
|
29715
29402
|
const {
|
|
29716
29403
|
color,
|
|
29717
29404
|
strokeStyle,
|
|
29718
|
-
directionalAxis
|
|
29405
|
+
directionalAxis,
|
|
29406
|
+
domain
|
|
29719
29407
|
} = props;
|
|
29720
|
-
const domain = props.domain ? [Number.isFinite(props.domain[0]) ? props.domain[0] : -Infinity, Number.isFinite(props.domain[1]) ? props.domain[1] : Infinity] : undefined;
|
|
29721
29408
|
const plotProps = {
|
|
29722
29409
|
color: perseusCore.lockedFigureColors[color],
|
|
29723
29410
|
style: strokeStyle,
|
|
@@ -29737,11 +29424,11 @@ const LockedFunction = props => {
|
|
|
29737
29424
|
"aria-label": hasAria ? props.ariaLabel : undefined,
|
|
29738
29425
|
"aria-hidden": !hasAria,
|
|
29739
29426
|
role: "img"
|
|
29740
|
-
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX,
|
|
29427
|
+
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, _extends__default["default"]({
|
|
29741
29428
|
y: x => equation.eval({
|
|
29742
29429
|
x
|
|
29743
29430
|
})
|
|
29744
|
-
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY,
|
|
29431
|
+
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY, _extends__default["default"]({
|
|
29745
29432
|
x: y => equation.eval({
|
|
29746
29433
|
y
|
|
29747
29434
|
})
|
|
@@ -30315,28 +30002,28 @@ const GraphLockedLayer = props => {
|
|
|
30315
30002
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lockedFigures.map((figure, index) => {
|
|
30316
30003
|
switch (figure.type) {
|
|
30317
30004
|
case "point":
|
|
30318
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPoint,
|
|
30005
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPoint, _extends__default["default"]({
|
|
30319
30006
|
key: `point-${index}`
|
|
30320
30007
|
}, figure));
|
|
30321
30008
|
case "line":
|
|
30322
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLine,
|
|
30009
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLine, _extends__default["default"]({
|
|
30323
30010
|
key: `line-${index}`,
|
|
30324
30011
|
range: props.range
|
|
30325
30012
|
}, figure));
|
|
30326
30013
|
case "vector":
|
|
30327
|
-
return /*#__PURE__*/React__namespace.createElement(LockedVector,
|
|
30014
|
+
return /*#__PURE__*/React__namespace.createElement(LockedVector, _extends__default["default"]({
|
|
30328
30015
|
key: `vector-${index}`
|
|
30329
30016
|
}, figure));
|
|
30330
30017
|
case "ellipse":
|
|
30331
|
-
return /*#__PURE__*/React__namespace.createElement(LockedEllipse,
|
|
30018
|
+
return /*#__PURE__*/React__namespace.createElement(LockedEllipse, _extends__default["default"]({
|
|
30332
30019
|
key: `ellipse-${index}`
|
|
30333
30020
|
}, figure));
|
|
30334
30021
|
case "polygon":
|
|
30335
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPolygon,
|
|
30022
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPolygon, _extends__default["default"]({
|
|
30336
30023
|
key: `polygon-${index}`
|
|
30337
30024
|
}, figure));
|
|
30338
30025
|
case "function":
|
|
30339
|
-
return /*#__PURE__*/React__namespace.createElement(LockedFunction,
|
|
30026
|
+
return /*#__PURE__*/React__namespace.createElement(LockedFunction, _extends__default["default"]({
|
|
30340
30027
|
key: `function-${index}`
|
|
30341
30028
|
}, figure));
|
|
30342
30029
|
case "label":
|
|
@@ -30567,7 +30254,7 @@ const TextLabel = _ref => {
|
|
|
30567
30254
|
children,
|
|
30568
30255
|
...rest
|
|
30569
30256
|
} = _ref;
|
|
30570
|
-
return /*#__PURE__*/React__default["default"].createElement(mafs.Text,
|
|
30257
|
+
return /*#__PURE__*/React__default["default"].createElement(mafs.Text, _extends__default["default"]({
|
|
30571
30258
|
size: 16,
|
|
30572
30259
|
svgTextProps: {
|
|
30573
30260
|
filter: "url(#background)",
|
|
@@ -31278,6 +30965,9 @@ const MovableLine = props => {
|
|
|
31278
30965
|
onMoveLine = () => {},
|
|
31279
30966
|
onMovePoint = () => {}
|
|
31280
30967
|
} = props;
|
|
30968
|
+
const {
|
|
30969
|
+
snapStep
|
|
30970
|
+
} = useGraphConfig();
|
|
31281
30971
|
|
|
31282
30972
|
// Aria live states for (0) point 1, (1) point 2, and (2) grab handle.
|
|
31283
30973
|
// When moving an element, set its aria live to "polite" and the others
|
|
@@ -31309,7 +30999,8 @@ const MovableLine = props => {
|
|
|
31309
30999
|
onMove: p => {
|
|
31310
31000
|
setAriaLives(["polite", "off", "off"]);
|
|
31311
31001
|
onMovePoint(0, p);
|
|
31312
|
-
}
|
|
31002
|
+
},
|
|
31003
|
+
constrain: getMovableLineKeyboardConstraint([start, end], snapStep, 0)
|
|
31313
31004
|
});
|
|
31314
31005
|
const {
|
|
31315
31006
|
visiblePoint: visiblePoint2,
|
|
@@ -31324,7 +31015,8 @@ const MovableLine = props => {
|
|
|
31324
31015
|
onMove: p => {
|
|
31325
31016
|
setAriaLives(["off", "polite", "off"]);
|
|
31326
31017
|
onMovePoint(1, p);
|
|
31327
|
-
}
|
|
31018
|
+
},
|
|
31019
|
+
constrain: getMovableLineKeyboardConstraint([start, end], snapStep, 1)
|
|
31328
31020
|
});
|
|
31329
31021
|
const line = /*#__PURE__*/React__namespace.createElement(Line$1, {
|
|
31330
31022
|
ariaLabel: ariaLabels?.grabHandleAriaLabel,
|
|
@@ -31430,6 +31122,34 @@ const Line$1 = props => {
|
|
|
31430
31122
|
color: stroke
|
|
31431
31123
|
}));
|
|
31432
31124
|
};
|
|
31125
|
+
const getMovableLineKeyboardConstraint = (line, snapStep, pointIndex) => {
|
|
31126
|
+
// Separate the two points into their own variables, and determine which point is being moved
|
|
31127
|
+
const coordToBeMoved = line[pointIndex];
|
|
31128
|
+
const otherPoint = line[1 - pointIndex];
|
|
31129
|
+
|
|
31130
|
+
// Create a helper function that moves the point and then checks
|
|
31131
|
+
// if it overlaps with the other point in the line after the move.
|
|
31132
|
+
const movePointWithConstraint = moveFunc => {
|
|
31133
|
+
// Move the point
|
|
31134
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
31135
|
+
// If the moved point overlaps with the other point in the line,
|
|
31136
|
+
// move the point again.
|
|
31137
|
+
if (mafs.vec.dist(movedCoord, otherPoint) === 0) {
|
|
31138
|
+
movedCoord = moveFunc(movedCoord);
|
|
31139
|
+
}
|
|
31140
|
+
return movedCoord;
|
|
31141
|
+
};
|
|
31142
|
+
|
|
31143
|
+
// Check if the new point will overlap the other point.
|
|
31144
|
+
// If it will, we need to snap the point to the left or right an additional
|
|
31145
|
+
// snapStep to avoid overlap.
|
|
31146
|
+
return {
|
|
31147
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
31148
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
31149
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
31150
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
31151
|
+
};
|
|
31152
|
+
};
|
|
31433
31153
|
function trimRange(range, graphDimensionsInPixels) {
|
|
31434
31154
|
const pixelsToTrim = 4;
|
|
31435
31155
|
const [xRange, yRange] = range;
|
|
@@ -31786,7 +31506,8 @@ function CircleGraph(props) {
|
|
|
31786
31506
|
} = props;
|
|
31787
31507
|
const {
|
|
31788
31508
|
center,
|
|
31789
|
-
radiusPoint
|
|
31509
|
+
radiusPoint,
|
|
31510
|
+
snapStep
|
|
31790
31511
|
} = graphState;
|
|
31791
31512
|
const {
|
|
31792
31513
|
strings,
|
|
@@ -31849,7 +31570,8 @@ function CircleGraph(props) {
|
|
|
31849
31570
|
onMove: newRadiusPoint => {
|
|
31850
31571
|
setRadiusPointAriaLive("polite");
|
|
31851
31572
|
dispatch(actions.circle.moveRadiusPoint(newRadiusPoint));
|
|
31852
|
-
}
|
|
31573
|
+
},
|
|
31574
|
+
constrain: getCircleKeyboardConstraint(center, radiusPoint, snapStep)
|
|
31853
31575
|
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
31854
31576
|
id: radiusId,
|
|
31855
31577
|
style: a11y.srOnly
|
|
@@ -31960,6 +31682,30 @@ function getCircleGraphDescription(state, i18n) {
|
|
|
31960
31682
|
const strings = describeCircleGraph(state, i18n);
|
|
31961
31683
|
return strings.srCircleInteractiveElement;
|
|
31962
31684
|
}
|
|
31685
|
+
const getCircleKeyboardConstraint = (center, radiusPoint, snapStep) => {
|
|
31686
|
+
// Create a helper function that moves the point and then checks
|
|
31687
|
+
// if it overlaps with the center point after the move.
|
|
31688
|
+
const movePointWithConstraint = moveFunc => {
|
|
31689
|
+
// Move the point
|
|
31690
|
+
let movedCoord = moveFunc(radiusPoint);
|
|
31691
|
+
// If the moved point overlaps with the center point,
|
|
31692
|
+
// move the point again.
|
|
31693
|
+
if (mafs.vec.dist(movedCoord, center) === 0) {
|
|
31694
|
+
movedCoord = moveFunc(movedCoord);
|
|
31695
|
+
}
|
|
31696
|
+
return movedCoord;
|
|
31697
|
+
};
|
|
31698
|
+
|
|
31699
|
+
// Check if the new point overlaps the center point.
|
|
31700
|
+
// If it does, we need to snap the point to the left
|
|
31701
|
+
// or right an additional snapStep to avoid the overlap.
|
|
31702
|
+
return {
|
|
31703
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
31704
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
31705
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
31706
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
31707
|
+
};
|
|
31708
|
+
};
|
|
31963
31709
|
|
|
31964
31710
|
// Exported for testing
|
|
31965
31711
|
function describeCircleGraph(state, i18n) {
|
|
@@ -31972,6 +31718,7 @@ function describeCircleGraph(state, i18n) {
|
|
|
31972
31718
|
radiusPoint
|
|
31973
31719
|
} = state;
|
|
31974
31720
|
const radius = getRadius(state);
|
|
31721
|
+
const isRadiusOnRight = radiusPoint[X] >= center[X];
|
|
31975
31722
|
|
|
31976
31723
|
// Aria label strings
|
|
31977
31724
|
const srCircleGraph = strings.srCircleGraph;
|
|
@@ -31979,7 +31726,10 @@ function describeCircleGraph(state, i18n) {
|
|
|
31979
31726
|
centerX: srFormatNumber(center[0], locale),
|
|
31980
31727
|
centerY: srFormatNumber(center[1], locale)
|
|
31981
31728
|
});
|
|
31982
|
-
const srCircleRadiusPoint = strings.
|
|
31729
|
+
const srCircleRadiusPoint = isRadiusOnRight ? strings.srCircleRadiusPointRight({
|
|
31730
|
+
radiusPointX: srFormatNumber(radiusPoint[0], locale),
|
|
31731
|
+
radiusPointY: srFormatNumber(radiusPoint[1], locale)
|
|
31732
|
+
}) : strings.srCircleRadiusPointLeft({
|
|
31983
31733
|
radiusPointX: srFormatNumber(radiusPoint[0], locale),
|
|
31984
31734
|
radiusPointY: srFormatNumber(radiusPoint[1], locale)
|
|
31985
31735
|
});
|
|
@@ -32145,6 +31895,12 @@ const LinearSystemGraph = props => {
|
|
|
32145
31895
|
locale
|
|
32146
31896
|
} = usePerseusI18n();
|
|
32147
31897
|
const id = React__namespace.useId();
|
|
31898
|
+
const intersectionId = `${id}-intersection`;
|
|
31899
|
+
const intersectionPoint = kmath.geometry.getLineIntersection(lines[0], lines[1]);
|
|
31900
|
+
const intersectionDescription = intersectionPoint ? strings.srLinearSystemIntersection({
|
|
31901
|
+
x: srFormatNumber(intersectionPoint[0], locale),
|
|
31902
|
+
y: srFormatNumber(intersectionPoint[1], locale)
|
|
31903
|
+
}) : strings.srLinearSystemParallel;
|
|
32148
31904
|
const linesAriaInfo = lines.map((line, i) => {
|
|
32149
31905
|
return {
|
|
32150
31906
|
pointsDescriptionId: `${id}-line${i + 1}-points`,
|
|
@@ -32161,16 +31917,17 @@ const LinearSystemGraph = props => {
|
|
|
32161
31917
|
slopeDescription: getSlopeStringForLine(line, strings)
|
|
32162
31918
|
};
|
|
32163
31919
|
});
|
|
31920
|
+
const individualLineDescriptions = linesAriaInfo.map(_ref => {
|
|
31921
|
+
let {
|
|
31922
|
+
pointsDescriptionId,
|
|
31923
|
+
interceptDescriptionId,
|
|
31924
|
+
slopeDescriptionId
|
|
31925
|
+
} = _ref;
|
|
31926
|
+
return `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`;
|
|
31927
|
+
}).join(" ");
|
|
32164
31928
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
32165
31929
|
"aria-label": strings.srLinearSystemGraph,
|
|
32166
|
-
"aria-describedby":
|
|
32167
|
-
let {
|
|
32168
|
-
pointsDescriptionId,
|
|
32169
|
-
interceptDescriptionId,
|
|
32170
|
-
slopeDescriptionId
|
|
32171
|
-
} = _ref;
|
|
32172
|
-
return `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`;
|
|
32173
|
-
}).join(" ")
|
|
31930
|
+
"aria-describedby": `${individualLineDescriptions} ${intersectionId}`
|
|
32174
31931
|
}, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
32175
31932
|
key: i,
|
|
32176
31933
|
points: line,
|
|
@@ -32187,9 +31944,15 @@ const LinearSystemGraph = props => {
|
|
|
32187
31944
|
x: srFormatNumber(line[1][0], locale),
|
|
32188
31945
|
y: srFormatNumber(line[1][1], locale)
|
|
32189
31946
|
}),
|
|
32190
|
-
grabHandleAriaLabel:
|
|
31947
|
+
grabHandleAriaLabel: strings.srLinearSystemGrabHandle({
|
|
31948
|
+
lineNumber: i + 1,
|
|
31949
|
+
point1X: srFormatNumber(line[0][0], locale),
|
|
31950
|
+
point1Y: srFormatNumber(line[0][1], locale),
|
|
31951
|
+
point2X: srFormatNumber(line[1][0], locale),
|
|
31952
|
+
point2Y: srFormatNumber(line[1][1], locale)
|
|
31953
|
+
})
|
|
32191
31954
|
},
|
|
32192
|
-
ariaDescribedBy: `${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId}`,
|
|
31955
|
+
ariaDescribedBy: `${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId} ${intersectionId}`,
|
|
32193
31956
|
onMoveLine: delta => {
|
|
32194
31957
|
dispatch(actions.linearSystem.moveLine(i, delta));
|
|
32195
31958
|
},
|
|
@@ -32221,7 +31984,10 @@ const LinearSystemGraph = props => {
|
|
|
32221
31984
|
id: slopeDescriptionId,
|
|
32222
31985
|
style: a11y.srOnly
|
|
32223
31986
|
}, slopeDescription));
|
|
32224
|
-
})
|
|
31987
|
+
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
31988
|
+
id: intersectionId,
|
|
31989
|
+
style: a11y.srOnly
|
|
31990
|
+
}, intersectionDescription));
|
|
32225
31991
|
};
|
|
32226
31992
|
|
|
32227
31993
|
// Exported for testing
|
|
@@ -32887,7 +32653,8 @@ function QuadraticGraph(props) {
|
|
|
32887
32653
|
graphState
|
|
32888
32654
|
} = props;
|
|
32889
32655
|
const {
|
|
32890
|
-
coords
|
|
32656
|
+
coords,
|
|
32657
|
+
snapStep
|
|
32891
32658
|
} = graphState;
|
|
32892
32659
|
const {
|
|
32893
32660
|
strings,
|
|
@@ -32940,6 +32707,7 @@ function QuadraticGraph(props) {
|
|
|
32940
32707
|
ariaLabel: `${srQuadraticPoint}${srVertex}`,
|
|
32941
32708
|
point: coord,
|
|
32942
32709
|
sequenceNumber: i + 1,
|
|
32710
|
+
constrain: getQuadraticKeyboardConstraint(coords, snapStep, i),
|
|
32943
32711
|
onMove: destination => dispatch(actions.quadratic.movePoint(i, destination))
|
|
32944
32712
|
});
|
|
32945
32713
|
}), srQuadraticDirection && /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -33028,6 +32796,60 @@ function describeQuadraticGraph(state, i18n) {
|
|
|
33028
32796
|
srQuadraticInteractiveElements
|
|
33029
32797
|
};
|
|
33030
32798
|
}
|
|
32799
|
+
const getQuadraticKeyboardConstraint = (coords, snapStep, pointMoved) => {
|
|
32800
|
+
// Make newCoords mutable
|
|
32801
|
+
const newCoords = [coords[0], coords[1], coords[2]];
|
|
32802
|
+
|
|
32803
|
+
// Get the point that is being moved
|
|
32804
|
+
const coordToBeMoved = newCoords[pointMoved];
|
|
32805
|
+
|
|
32806
|
+
// Create a function to validate and adjust the movement of the point
|
|
32807
|
+
const movePointWithConstraint = moveFunc => {
|
|
32808
|
+
// Move the point the desired direction
|
|
32809
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
32810
|
+
newCoords[pointMoved] = movedCoord;
|
|
32811
|
+
|
|
32812
|
+
// If these new coordinates are valid, return the moved coord
|
|
32813
|
+
if (areCoordsValid(newCoords)) {
|
|
32814
|
+
return movedCoord;
|
|
32815
|
+
}
|
|
32816
|
+
|
|
32817
|
+
// If the new coordinates are invalid, we need to move the point an additional
|
|
32818
|
+
// snapStep to avoid creating an invalid quadratic graph.
|
|
32819
|
+
movedCoord = moveFunc(movedCoord);
|
|
32820
|
+
newCoords[pointMoved] = movedCoord;
|
|
32821
|
+
|
|
32822
|
+
// If these updated coordinates are valid now, we can return the new coordinates.
|
|
32823
|
+
if (areCoordsValid(newCoords)) {
|
|
32824
|
+
return movedCoord;
|
|
32825
|
+
}
|
|
32826
|
+
|
|
32827
|
+
// Otherwise, if the new coordinates are still invalid, we need to move the point one final snapStep.
|
|
32828
|
+
// This is to support the edge case where all of the points are each exactly one snapStep away
|
|
32829
|
+
// from each other.
|
|
32830
|
+
// Eg. When coords = [[0, 0], [1, 0], [2, 0]], snapStep = [1, 1], and we're moving coords[0] to the right.
|
|
32831
|
+
return moveFunc(movedCoord);
|
|
32832
|
+
};
|
|
32833
|
+
return {
|
|
32834
|
+
up: mafs.vec.add(coordToBeMoved, [0, snapStep[1]]),
|
|
32835
|
+
down: mafs.vec.sub(coordToBeMoved, [0, snapStep[1]]),
|
|
32836
|
+
// For horizontal movement, we need to ensure that the points are not on the same vertical line.
|
|
32837
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
32838
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
32839
|
+
};
|
|
32840
|
+
};
|
|
32841
|
+
const areCoordsValid = coords => {
|
|
32842
|
+
const p1 = coords[0];
|
|
32843
|
+
const p2 = coords[1];
|
|
32844
|
+
const p3 = coords[2];
|
|
32845
|
+
|
|
32846
|
+
// If any of the points share the same x-coordinate,
|
|
32847
|
+
// we are unable to calculate the coefficients, and the graph is invalid.
|
|
32848
|
+
if (p1[0] === p2[0] || p2[0] === p3[0] || p1[0] === p3[0]) {
|
|
32849
|
+
return false;
|
|
32850
|
+
}
|
|
32851
|
+
return true;
|
|
32852
|
+
};
|
|
33031
32853
|
|
|
33032
32854
|
function renderRayGraph(state, dispatch, i18n) {
|
|
33033
32855
|
return {
|
|
@@ -33283,7 +33105,8 @@ function SinusoidGraph(props) {
|
|
|
33283
33105
|
// Note: The order of the coordinates is important:
|
|
33284
33106
|
// The coords[0] is the root and the coords[1] is the first peak
|
|
33285
33107
|
const {
|
|
33286
|
-
coords
|
|
33108
|
+
coords,
|
|
33109
|
+
snapStep
|
|
33287
33110
|
} = graphState;
|
|
33288
33111
|
|
|
33289
33112
|
// The coefficients are used to calculate the sinusoid equation, plot the graph, and to indicate
|
|
@@ -33322,11 +33145,37 @@ function SinusoidGraph(props) {
|
|
|
33322
33145
|
key: "point-" + i,
|
|
33323
33146
|
point: coord,
|
|
33324
33147
|
sequenceNumber: i + 1,
|
|
33148
|
+
constrain: getSinusoidKeyboardConstraint(coords, snapStep, i),
|
|
33325
33149
|
onMove: destination => dispatch(actions.sinusoid.movePoint(i, destination))
|
|
33326
33150
|
})), /*#__PURE__*/React__namespace.createElement("g", {
|
|
33327
33151
|
id: descriptionId
|
|
33328
33152
|
}, srSinusoidDescription));
|
|
33329
33153
|
}
|
|
33154
|
+
const getSinusoidKeyboardConstraint = (coords, snapStep, pointIndex) => {
|
|
33155
|
+
// Separate the two points into their own variables, and determine which point is being moved
|
|
33156
|
+
const coordToBeMoved = coords[pointIndex];
|
|
33157
|
+
const otherPoint = coords[1 - pointIndex];
|
|
33158
|
+
|
|
33159
|
+
// Create a helper function that checks if the new point is on the same
|
|
33160
|
+
// vertical line as the other point. If it is, we need to move the point
|
|
33161
|
+
// an additional snapStep.
|
|
33162
|
+
const movePointWithConstraint = moveFunc => {
|
|
33163
|
+
// Move the point
|
|
33164
|
+
let movedCoord = moveFunc(coordToBeMoved);
|
|
33165
|
+
// If the moved point overlaps with the other point in the line,
|
|
33166
|
+
// move the point again.
|
|
33167
|
+
if (movedCoord[X] === otherPoint[X]) {
|
|
33168
|
+
movedCoord = moveFunc(movedCoord);
|
|
33169
|
+
}
|
|
33170
|
+
return movedCoord;
|
|
33171
|
+
};
|
|
33172
|
+
return {
|
|
33173
|
+
up: movePointWithConstraint(coord => mafs.vec.add(coord, [0, snapStep[1]])),
|
|
33174
|
+
down: movePointWithConstraint(coord => mafs.vec.sub(coord, [0, snapStep[1]])),
|
|
33175
|
+
left: movePointWithConstraint(coord => mafs.vec.sub(coord, [snapStep[0], 0])),
|
|
33176
|
+
right: movePointWithConstraint(coord => mafs.vec.add(coord, [snapStep[0], 0]))
|
|
33177
|
+
};
|
|
33178
|
+
};
|
|
33330
33179
|
|
|
33331
33180
|
// Plot a sinusoid of the form: f(x) = a * sin(b * x - c) + d
|
|
33332
33181
|
const computeSine = function (x,
|
|
@@ -33378,6 +33227,14 @@ function describeSinusoidGraph(state, i18n) {
|
|
|
33378
33227
|
const [root, peak] = coords;
|
|
33379
33228
|
const diffX = Math.abs(peak[X] - root[X]);
|
|
33380
33229
|
const diffY = Math.abs(peak[Y] - root[Y]);
|
|
33230
|
+
const formattedRoot = {
|
|
33231
|
+
x: srFormatNumber(root[X], locale),
|
|
33232
|
+
y: srFormatNumber(root[Y], locale)
|
|
33233
|
+
};
|
|
33234
|
+
const formattedPeak = {
|
|
33235
|
+
x: srFormatNumber(peak[X], locale),
|
|
33236
|
+
y: srFormatNumber(peak[Y], locale)
|
|
33237
|
+
};
|
|
33381
33238
|
const srSinusoidGraph = strings.srSinusoidGraph;
|
|
33382
33239
|
const srSinusoidDescription = strings.srSinusoidDescription({
|
|
33383
33240
|
minValue: srFormatNumber(root[Y] - diffY, locale),
|
|
@@ -33385,14 +33242,8 @@ function describeSinusoidGraph(state, i18n) {
|
|
|
33385
33242
|
cycleStart: srFormatNumber(root[X] - 2 * diffX, locale),
|
|
33386
33243
|
cycleEnd: srFormatNumber(root[X] + 2 * diffX, locale)
|
|
33387
33244
|
});
|
|
33388
|
-
const srSinusoidRootPoint = strings.srSinusoidRootPoint(
|
|
33389
|
-
|
|
33390
|
-
y: srFormatNumber(root[Y], locale)
|
|
33391
|
-
});
|
|
33392
|
-
const srSinusoidPeakPoint = strings.srSinusoidPeakPoint({
|
|
33393
|
-
x: srFormatNumber(peak[X], locale),
|
|
33394
|
-
y: srFormatNumber(peak[Y], locale)
|
|
33395
|
-
});
|
|
33245
|
+
const srSinusoidRootPoint = strings.srSinusoidRootPoint(formattedRoot);
|
|
33246
|
+
const srSinusoidPeakPoint = peak[Y] === root[Y] ? strings.srSinusoidFlatPoint(formattedPeak) : peak[Y] > root[Y] ? strings.srSinusoidMaxPoint(formattedPeak) : strings.srSinusoidMinPoint(formattedPeak);
|
|
33396
33247
|
const srSinusoidInteractiveElements = strings.srInteractiveElements({
|
|
33397
33248
|
elements: strings.srSinusoidInteractiveElements({
|
|
33398
33249
|
point1X: srFormatNumber(root[X], locale),
|
|
@@ -33414,16 +33265,17 @@ const {
|
|
|
33414
33265
|
calculateAngleInDegrees,
|
|
33415
33266
|
convertDegreesToRadians
|
|
33416
33267
|
} = kmath.angles;
|
|
33417
|
-
const protractorImage = "https://
|
|
33268
|
+
const protractorImage = "https://cdn.kastatic.org/images/perseus/protractor.svg";
|
|
33418
33269
|
|
|
33419
33270
|
// The vector from the center of the protractor to the top left corner of the
|
|
33420
33271
|
// protractor image, in pixels. Used for positioning.
|
|
33421
|
-
const centerToTopLeft = [-
|
|
33272
|
+
const centerToTopLeft = [-195, -190];
|
|
33422
33273
|
|
|
33423
33274
|
// The vector from the center of the protractor to the center of the rotation
|
|
33424
33275
|
// handle.
|
|
33425
|
-
const centerToRotationHandle = [-
|
|
33276
|
+
const centerToRotationHandle = [-201, -15];
|
|
33426
33277
|
function Protractor() {
|
|
33278
|
+
const staticUrl = getDependencies().staticUrl;
|
|
33427
33279
|
const {
|
|
33428
33280
|
range,
|
|
33429
33281
|
snapStep
|
|
@@ -33435,7 +33287,9 @@ function Protractor() {
|
|
|
33435
33287
|
const [center, setCenter] = React.useState(initialCenter);
|
|
33436
33288
|
const [rotationHandleOffset, setRotationHandleOffset] = React.useState(centerToRotationHandle);
|
|
33437
33289
|
const draggableRef = React.useRef(null);
|
|
33438
|
-
|
|
33290
|
+
const {
|
|
33291
|
+
dragging
|
|
33292
|
+
} = useDraggable({
|
|
33439
33293
|
gestureTarget: draggableRef,
|
|
33440
33294
|
onMove: setCenter,
|
|
33441
33295
|
point: center,
|
|
@@ -33459,10 +33313,11 @@ function Protractor() {
|
|
|
33459
33313
|
ref: draggableRef,
|
|
33460
33314
|
transform: `translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,
|
|
33461
33315
|
style: {
|
|
33462
|
-
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px
|
|
33316
|
+
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`,
|
|
33317
|
+
cursor: dragging ? "grabbing" : "grab"
|
|
33463
33318
|
}
|
|
33464
33319
|
}, /*#__PURE__*/React__namespace.createElement("image", {
|
|
33465
|
-
href: protractorImage
|
|
33320
|
+
href: staticUrl(protractorImage)
|
|
33466
33321
|
}), /*#__PURE__*/React__namespace.createElement("g", {
|
|
33467
33322
|
transform: `translate(5, ${-centerToTopLeft[1]})`,
|
|
33468
33323
|
ref: rotationHandleRef
|
|
@@ -35394,8 +35249,8 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
35394
35249
|
|
|
35395
35250
|
// If the graph is static, it always displays the correct answer. This is
|
|
35396
35251
|
// standard behavior for Perseus widgets (e.g. compare the Radio widget).
|
|
35397
|
-
if (props.static) {
|
|
35398
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph,
|
|
35252
|
+
if (props.static && props.correct) {
|
|
35253
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends__default["default"]({}, props, {
|
|
35399
35254
|
state: initializeGraphState({
|
|
35400
35255
|
...props,
|
|
35401
35256
|
graph: props.correct
|
|
@@ -35403,7 +35258,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
35403
35258
|
dispatch: dispatch
|
|
35404
35259
|
}));
|
|
35405
35260
|
}
|
|
35406
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph,
|
|
35261
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends__default["default"]({}, props, {
|
|
35407
35262
|
state: state,
|
|
35408
35263
|
dispatch: dispatch
|
|
35409
35264
|
}));
|
|
@@ -35414,7 +35269,7 @@ const {
|
|
|
35414
35269
|
} = kmath.angles;
|
|
35415
35270
|
const {
|
|
35416
35271
|
getLineEquation,
|
|
35417
|
-
|
|
35272
|
+
getLineIntersectionString,
|
|
35418
35273
|
magnitude,
|
|
35419
35274
|
vector
|
|
35420
35275
|
} = kmath.geometry;
|
|
@@ -35496,7 +35351,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35496
35351
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
35497
35352
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
35498
35353
|
const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
|
|
35499
|
-
return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph,
|
|
35354
|
+
return /*#__PURE__*/React__namespace.createElement(StatefulMafsGraph, _extends__default["default"]({}, this.props, {
|
|
35500
35355
|
ref: this.mafsRef,
|
|
35501
35356
|
gridStep: gridStep,
|
|
35502
35357
|
snapStep: snapStep,
|
|
@@ -35779,7 +35634,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
35779
35634
|
}
|
|
35780
35635
|
static getLinearSystemEquationString(props) {
|
|
35781
35636
|
const coords = InteractiveGraph.getLinearSystemCoords(props.graph, props);
|
|
35782
|
-
return "\n" + getLineEquation(coords[0][0], coords[0][1]) + "\n" + getLineEquation(coords[1][0], coords[1][1]) + "\n" +
|
|
35637
|
+
return "\n" + getLineEquation(coords[0][0], coords[0][1]) + "\n" + getLineEquation(coords[1][0], coords[1][1]) + "\n" + getLineIntersectionString(coords[0], coords[1]);
|
|
35783
35638
|
}
|
|
35784
35639
|
static getPointEquationString(props) {
|
|
35785
35640
|
if (props.graph.type !== "point") {
|
|
@@ -35931,10 +35786,10 @@ const AnswerChoices = props => {
|
|
|
35931
35786
|
onToggle,
|
|
35932
35787
|
disabled
|
|
35933
35788
|
};
|
|
35934
|
-
return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect,
|
|
35789
|
+
return props.multipleSelect ? /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.MultiSelect, _extends__default["default"]({}, args, {
|
|
35935
35790
|
selectedValues: selectedValues,
|
|
35936
35791
|
onChange: selected => onAnswerChange(selected)
|
|
35937
|
-
})) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect,
|
|
35792
|
+
})) : /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, _extends__default["default"]({}, args, {
|
|
35938
35793
|
selectedValue: selectedValues[0],
|
|
35939
35794
|
onChange: selected => onAnswerChange([selected]),
|
|
35940
35795
|
placeholder: props.choices[0].content // not visible, but required
|
|
@@ -36220,7 +36075,6 @@ const styles$a = aphrodite.StyleSheet.create({
|
|
|
36220
36075
|
markerCorrect: {
|
|
36221
36076
|
background: "#00880b" // WB green darkened by 18%
|
|
36222
36077
|
},
|
|
36223
|
-
|
|
36224
36078
|
markerIncorrect: {
|
|
36225
36079
|
background: wonderBlocksTokens.color.offBlack64
|
|
36226
36080
|
}
|
|
@@ -36617,7 +36471,6 @@ class LabelImage extends React__namespace.Component {
|
|
|
36617
36471
|
const adjustPillDistance = {
|
|
36618
36472
|
[`margin${markerPosition.charAt(0).toUpperCase() + markerPosition.slice(1)}`]: 10 // move pill further from marker
|
|
36619
36473
|
};
|
|
36620
|
-
|
|
36621
36474
|
const answerChoicesActive = index === activeMarkerIndex;
|
|
36622
36475
|
const showAnswerChoice = marker.selected && !answerChoicesActive && !this.state.hideAnswers;
|
|
36623
36476
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
@@ -36666,7 +36519,7 @@ class LabelImage extends React__namespace.Component {
|
|
|
36666
36519
|
focused,
|
|
36667
36520
|
pressed
|
|
36668
36521
|
} = _ref2;
|
|
36669
|
-
return /*#__PURE__*/React__namespace.createElement(Marker,
|
|
36522
|
+
return /*#__PURE__*/React__namespace.createElement(Marker, _extends__default["default"]({}, marker, {
|
|
36670
36523
|
showCorrectness: showCorrectness,
|
|
36671
36524
|
showSelected: opened,
|
|
36672
36525
|
showPulsate: !markersInteracted,
|
|
@@ -36811,7 +36664,7 @@ const styles$9 = aphrodite.StyleSheet.create({
|
|
|
36811
36664
|
});
|
|
36812
36665
|
const LabelImageWithDependencies = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
36813
36666
|
const deps = useDependencies();
|
|
36814
|
-
return /*#__PURE__*/React__namespace.createElement(LabelImage,
|
|
36667
|
+
return /*#__PURE__*/React__namespace.createElement(LabelImage, _extends__default["default"]({
|
|
36815
36668
|
ref: ref,
|
|
36816
36669
|
analytics: deps.analytics
|
|
36817
36670
|
}, props));
|
|
@@ -37073,7 +36926,6 @@ class Draggable extends React__namespace.Component {
|
|
|
37073
36926
|
if (this.props.width) {
|
|
37074
36927
|
style.width = this.props.width + 1; // Fix for non-integer widths
|
|
37075
36928
|
}
|
|
37076
|
-
|
|
37077
36929
|
if (this.props.height) {
|
|
37078
36930
|
style.height = this.props.height;
|
|
37079
36931
|
}
|
|
@@ -37417,8 +37269,7 @@ class Sortable extends React__namespace.Component {
|
|
|
37417
37269
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
37418
37270
|
margin = "0 0 " + this.props.margin + "px 0"; // bottom
|
|
37419
37271
|
}
|
|
37420
|
-
|
|
37421
|
-
cards.push( /*#__PURE__*/React__namespace.createElement(Draggable, {
|
|
37272
|
+
cards.push(/*#__PURE__*/React__namespace.createElement(Draggable, {
|
|
37422
37273
|
content: item.option,
|
|
37423
37274
|
key: item.key,
|
|
37424
37275
|
state: item.state
|
|
@@ -37471,7 +37322,7 @@ class Sortable extends React__namespace.Component {
|
|
|
37471
37322
|
this, item.key)
|
|
37472
37323
|
}));
|
|
37473
37324
|
if (item.state === ItemState.DRAGGING || item.state === ItemState.ANIMATING) {
|
|
37474
|
-
cards.push(
|
|
37325
|
+
cards.push(/*#__PURE__*/React__namespace.createElement(Placeholder, {
|
|
37475
37326
|
key: "placeholder_" + item.key,
|
|
37476
37327
|
ref: "placeholder_" + item.key,
|
|
37477
37328
|
width: item.width,
|
|
@@ -37551,10 +37402,6 @@ const getPromptJSON$9 = (renderProps, userInput) => {
|
|
|
37551
37402
|
};
|
|
37552
37403
|
};
|
|
37553
37404
|
|
|
37554
|
-
const {
|
|
37555
|
-
shuffle: shuffle$1,
|
|
37556
|
-
seededRNG
|
|
37557
|
-
} = Util;
|
|
37558
37405
|
const HACKY_CSS_CLASSNAME = "perseus-widget-matcher";
|
|
37559
37406
|
class Matcher extends React__namespace.Component {
|
|
37560
37407
|
static contextType = PerseusI18nContext;
|
|
@@ -37656,16 +37503,16 @@ class Matcher extends React__namespace.Component {
|
|
|
37656
37503
|
}, "1")));
|
|
37657
37504
|
}
|
|
37658
37505
|
|
|
37659
|
-
|
|
37660
|
-
|
|
37661
|
-
|
|
37662
|
-
|
|
37663
|
-
|
|
37664
|
-
|
|
37665
|
-
|
|
37666
|
-
left
|
|
37667
|
-
|
|
37668
|
-
|
|
37506
|
+
/* TODO(LEMS-2841):
|
|
37507
|
+
Once the getMatcherPublicWidgetOptions function gets connected to the
|
|
37508
|
+
widget, we'll need to update this to the line below to only shuffle
|
|
37509
|
+
on the server.
|
|
37510
|
+
const {left, right} = this.props;
|
|
37511
|
+
*/
|
|
37512
|
+
const {
|
|
37513
|
+
left,
|
|
37514
|
+
right
|
|
37515
|
+
} = perseusCore.shuffleMatcher(this.props);
|
|
37669
37516
|
const showLabels = ___default["default"].any(this.props.labels);
|
|
37670
37517
|
const constraints = {
|
|
37671
37518
|
height: ___default["default"].max([this.state.leftHeight, this.state.rightHeight])
|
|
@@ -38089,7 +37936,7 @@ class Matrix extends React__namespace.Component {
|
|
|
38089
37936
|
boxSizing: "border-box",
|
|
38090
37937
|
backgroundColor: outside ? "#f3f3f3" : "#fff"
|
|
38091
37938
|
};
|
|
38092
|
-
MatrixInput = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput,
|
|
37939
|
+
MatrixInput = /*#__PURE__*/React__namespace.createElement(SimpleKeypadInput, _extends__default["default"]({}, inputProps, {
|
|
38093
37940
|
style: style,
|
|
38094
37941
|
scrollable: true,
|
|
38095
37942
|
keypadElement: this.props.keypadElement
|
|
@@ -39250,7 +39097,6 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
39250
39097
|
if (!___default["default"].isFinite(props.tickStep) || props.tickStep <= 0) {
|
|
39251
39098
|
return []; // this has screwed me for the last time!
|
|
39252
39099
|
}
|
|
39253
|
-
|
|
39254
39100
|
const results = [];
|
|
39255
39101
|
|
|
39256
39102
|
// For convenience, extract some props into separate variables
|
|
@@ -39321,6 +39167,7 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
39321
39167
|
|
|
39322
39168
|
// TODO: most widgets use some like Widget<Something, PerseusNumberLineWidgetOptions>
|
|
39323
39169
|
// should this one?
|
|
39170
|
+
|
|
39324
39171
|
class NumberLine extends React__namespace.Component {
|
|
39325
39172
|
static contextType = PerseusI18nContext;
|
|
39326
39173
|
static defaultProps = {
|
|
@@ -39465,7 +39312,7 @@ class NumberLine extends React__namespace.Component {
|
|
|
39465
39312
|
setup: this._setupGraphie,
|
|
39466
39313
|
setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable,
|
|
39467
39314
|
isMobile: this.props.apiOptions.isMobile
|
|
39468
|
-
}, /*#__PURE__*/React__namespace.createElement(TickMarks,
|
|
39315
|
+
}, /*#__PURE__*/React__namespace.createElement(TickMarks, _extends__default["default"]({}, ___default["default"].pick(props, ["range", "numDivisions", "labelTicks", "labelStyle", "labelRange", "tickStep"]), {
|
|
39469
39316
|
isMobile: this.props.apiOptions.isMobile
|
|
39470
39317
|
})), this._renderInequality(props), this._renderNumberLinePoint(props));
|
|
39471
39318
|
};
|
|
@@ -39692,7 +39539,6 @@ const numberLineTransform = editorProps => {
|
|
|
39692
39539
|
} else {
|
|
39693
39540
|
numDivisions = undefined; // send to getDefaultProps()
|
|
39694
39541
|
}
|
|
39695
|
-
|
|
39696
39542
|
___default["default"].extend(props, {
|
|
39697
39543
|
numLinePosition: numLinePosition,
|
|
39698
39544
|
numDivisions: numDivisions,
|
|
@@ -39717,7 +39563,6 @@ const staticTransform$1 = editorProps => {
|
|
|
39717
39563
|
} else {
|
|
39718
39564
|
numDivisions = undefined; // send to getDefaultProps()
|
|
39719
39565
|
}
|
|
39720
|
-
|
|
39721
39566
|
___default["default"].extend(props, {
|
|
39722
39567
|
numLinePosition: numLinePosition,
|
|
39723
39568
|
numDivisions: numDivisions,
|
|
@@ -39912,7 +39757,7 @@ class Card extends React__namespace.Component {
|
|
|
39912
39757
|
onTouchCancel: this.onMouseUp
|
|
39913
39758
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
39914
39759
|
className: className.join(" ")
|
|
39915
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
39760
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, rendererProps, {
|
|
39916
39761
|
linterContext: this.props.linterContext,
|
|
39917
39762
|
strings: this.context.strings
|
|
39918
39763
|
}))))
|
|
@@ -40737,7 +40582,6 @@ class Plotter extends React__namespace.Component {
|
|
|
40737
40582
|
const initialY = isMobile ? c.scaleY : 0;
|
|
40738
40583
|
for (let y = initialY; y <= c.dimY; y += c.scaleY) {
|
|
40739
40584
|
graphie.label([0, y], kmath.KhanMath.roundToApprox(y, 2), "left", /* isTeX */true /* for the \approx symbol */);
|
|
40740
|
-
|
|
40741
40585
|
graphie.style({
|
|
40742
40586
|
stroke: isMobile ? "#e9ebec" : "#000",
|
|
40743
40587
|
strokeWidth: 1,
|
|
@@ -41431,9 +41275,6 @@ const getPromptJSON$1 = userInput => {
|
|
|
41431
41275
|
};
|
|
41432
41276
|
};
|
|
41433
41277
|
|
|
41434
|
-
const {
|
|
41435
|
-
shuffle
|
|
41436
|
-
} = Util;
|
|
41437
41278
|
class Sorter extends React__namespace.Component {
|
|
41438
41279
|
_isMounted = false;
|
|
41439
41280
|
static defaultProps = {
|
|
@@ -41490,7 +41331,11 @@ class Sorter extends React__namespace.Component {
|
|
|
41490
41331
|
this.refs.sortable.moveOptionToIndex(option, index);
|
|
41491
41332
|
};
|
|
41492
41333
|
render() {
|
|
41493
|
-
|
|
41334
|
+
// TODO(LEMS-2841): Remove client-side shuffle once receiving public
|
|
41335
|
+
// options. The correct field will already be shuffled.
|
|
41336
|
+
// Probably easiest to replace "options" with "this.props.correct" when
|
|
41337
|
+
// setting up Sortable below. Or use the assignment to rename for clarity.
|
|
41338
|
+
const options = perseusCore.shuffle(this.props.correct, this.props.problemNum, /* ensurePermuted */true);
|
|
41494
41339
|
const {
|
|
41495
41340
|
apiOptions
|
|
41496
41341
|
} = this.props;
|
|
@@ -41698,7 +41543,7 @@ class Table extends React__namespace.Component {
|
|
|
41698
41543
|
}, ___default["default"](columns).times(c => {
|
|
41699
41544
|
return /*#__PURE__*/React__namespace.createElement("td", {
|
|
41700
41545
|
key: c
|
|
41701
|
-
}, /*#__PURE__*/React__namespace.createElement(InputComponent,
|
|
41546
|
+
}, /*#__PURE__*/React__namespace.createElement(InputComponent, _extends__default["default"]({
|
|
41702
41547
|
ref: getRefForPath(getInputPath(r, c)),
|
|
41703
41548
|
type: "text",
|
|
41704
41549
|
value: this.props.answers[r][c],
|
|
@@ -41909,10 +41754,51 @@ const init = function () {
|
|
|
41909
41754
|
replaceDeprecatedWidgets();
|
|
41910
41755
|
};
|
|
41911
41756
|
|
|
41757
|
+
/**
|
|
41758
|
+
* Adds the given perseus library version information to the __perseus_debug__
|
|
41759
|
+
* object and ensures that the object is attached to `globalThis` (`window` in
|
|
41760
|
+
* browser environments).
|
|
41761
|
+
*
|
|
41762
|
+
* This allows each library to provide runtime version information to assist in
|
|
41763
|
+
* debugging in production environments.
|
|
41764
|
+
*/
|
|
41765
|
+
const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
41766
|
+
// If the library version is the default value, then we don't want to
|
|
41767
|
+
// prefix it with a "v" to indicate that it is a version number.
|
|
41768
|
+
let prefix = "v";
|
|
41769
|
+
if (libraryVersion === "__lib_version__") {
|
|
41770
|
+
prefix = "";
|
|
41771
|
+
}
|
|
41772
|
+
const formattedVersion = `${prefix}${libraryVersion}`;
|
|
41773
|
+
if (typeof globalThis !== "undefined") {
|
|
41774
|
+
globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
|
|
41775
|
+
const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
|
|
41776
|
+
if (existingVersionEntry) {
|
|
41777
|
+
// If we already have an entry and it doesn't match the registered
|
|
41778
|
+
// version, we morph the entry into an array and log a warning.
|
|
41779
|
+
if (existingVersionEntry !== formattedVersion) {
|
|
41780
|
+
// Existing entry might be an array already (oops, at least 2
|
|
41781
|
+
// versions of the library already loaded!).
|
|
41782
|
+
const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
|
|
41783
|
+
allVersions.push(formattedVersion);
|
|
41784
|
+
globalThis.__perseus_debug__[libraryName] = allVersions;
|
|
41785
|
+
|
|
41786
|
+
// eslint-disable-next-line no-console
|
|
41787
|
+
console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
|
|
41788
|
+
}
|
|
41789
|
+
} else {
|
|
41790
|
+
globalThis.__perseus_debug__[libraryName] = formattedVersion;
|
|
41791
|
+
}
|
|
41792
|
+
} else {
|
|
41793
|
+
// eslint-disable-next-line no-console
|
|
41794
|
+
console.warn(`globalThis not found found (${formattedVersion})`);
|
|
41795
|
+
}
|
|
41796
|
+
};
|
|
41797
|
+
|
|
41912
41798
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
41913
41799
|
const libName = "@khanacademy/perseus";
|
|
41914
|
-
const libVersion = "
|
|
41915
|
-
|
|
41800
|
+
const libVersion = "55.0.0";
|
|
41801
|
+
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
41916
41802
|
|
|
41917
41803
|
const apiVersion = {
|
|
41918
41804
|
major: 12,
|
|
@@ -42068,7 +41954,7 @@ class ArticleRenderer extends React__namespace.Component {
|
|
|
42068
41954
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
42069
41955
|
key: sectionIndex,
|
|
42070
41956
|
className: "clearfix"
|
|
42071
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
41957
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({}, section, {
|
|
42072
41958
|
ref: elem => {
|
|
42073
41959
|
if (elem) {
|
|
42074
41960
|
this.sectionRenderers[sectionIndex] = elem;
|
|
@@ -42243,7 +42129,6 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
42243
42129
|
ReactDOM__default["default"].findDOMNode(this.refs["hintRenderer" + pos]).focus(); // eslint-disable-line react/no-string-refs
|
|
42244
42130
|
}
|
|
42245
42131
|
}
|
|
42246
|
-
|
|
42247
42132
|
_hintsVisible = () => {
|
|
42248
42133
|
if (this.props.hintsVisible == null || this.props.hintsVisible === -1) {
|
|
42249
42134
|
return this.props.hints.length;
|
|
@@ -42732,7 +42617,7 @@ class ServerItemRenderer extends React__namespace.Component {
|
|
|
42732
42617
|
};
|
|
42733
42618
|
const questionRenderer = /*#__PURE__*/React__namespace.createElement(context$1.Provider, {
|
|
42734
42619
|
value: contextValue
|
|
42735
|
-
}, /*#__PURE__*/React__namespace.createElement(Renderer,
|
|
42620
|
+
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends__default["default"]({
|
|
42736
42621
|
keypadElement: this.props.keypadElement,
|
|
42737
42622
|
problemNum: this.props.problemNum,
|
|
42738
42623
|
onInteractWithWidget: this.handleInteractWithWidget,
|
|
@@ -42781,7 +42666,7 @@ const ref = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__
|
|
|
42781
42666
|
let {
|
|
42782
42667
|
onRendered
|
|
42783
42668
|
} = _ref;
|
|
42784
|
-
return /*#__PURE__*/React__namespace.createElement(ServerItemRenderer,
|
|
42669
|
+
return /*#__PURE__*/React__namespace.createElement(ServerItemRenderer, _extends__default["default"]({}, props, {
|
|
42785
42670
|
onRendered: onRendered,
|
|
42786
42671
|
ref: ref
|
|
42787
42672
|
}));
|
|
@@ -44212,24 +44097,24 @@ const ScoringUtil = {
|
|
|
44212
44097
|
*/
|
|
44213
44098
|
|
|
44214
44099
|
Object.defineProperty(exports, 'isFailure', {
|
|
44215
|
-
|
|
44216
|
-
|
|
44100
|
+
enumerable: true,
|
|
44101
|
+
get: function () { return perseusCore.isFailure; }
|
|
44217
44102
|
});
|
|
44218
44103
|
Object.defineProperty(exports, 'isSuccess', {
|
|
44219
|
-
|
|
44220
|
-
|
|
44104
|
+
enumerable: true,
|
|
44105
|
+
get: function () { return perseusCore.isSuccess; }
|
|
44221
44106
|
});
|
|
44222
44107
|
Object.defineProperty(exports, 'parseAndMigratePerseusArticle', {
|
|
44223
|
-
|
|
44224
|
-
|
|
44108
|
+
enumerable: true,
|
|
44109
|
+
get: function () { return perseusCore.parseAndMigratePerseusArticle; }
|
|
44225
44110
|
});
|
|
44226
44111
|
Object.defineProperty(exports, 'parseAndMigratePerseusItem', {
|
|
44227
|
-
|
|
44228
|
-
|
|
44112
|
+
enumerable: true,
|
|
44113
|
+
get: function () { return perseusCore.parseAndMigratePerseusItem; }
|
|
44229
44114
|
});
|
|
44230
44115
|
Object.defineProperty(exports, 'parsePerseusItem', {
|
|
44231
|
-
|
|
44232
|
-
|
|
44116
|
+
enumerable: true,
|
|
44117
|
+
get: function () { return perseusCore.parsePerseusItem; }
|
|
44233
44118
|
});
|
|
44234
44119
|
exports.ApiOptions = ApiOptions;
|
|
44235
44120
|
exports.ArticleRenderer = ArticleRenderer;
|