@khanacademy/perseus 20.7.0 → 20.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +376 -149
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +386 -141
- package/dist/index.js.map +1 -1
- package/dist/util/snowman-utils.d.ts +4 -5
- package/dist/widgets/interactive-graphs/graphs/components/angle.d.ts +13 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/use-transform.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/utils.d.ts +7 -0
- package/dist/widgets/interactive-graphs/legacy-grid.d.ts +6 -1
- package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +3 -0
- package/package.json +2 -6
package/dist/es/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as KAS from '@khanacademy/kas';
|
|
|
2
2
|
import { keyTranslator, CursorContext, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
|
|
3
3
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
4
4
|
import { linterContextDefault, Rule, linterContextProps } from '@khanacademy/perseus-linter';
|
|
5
|
-
import { View, RenderStateRoot, UniqueIDProvider, useUniqueIdWithMock, Text as Text$
|
|
5
|
+
import { View, RenderStateRoot, UniqueIDProvider, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
6
6
|
import * as i18n from '@khanacademy/wonder-blocks-i18n';
|
|
7
7
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
8
8
|
import classNames from 'classnames';
|
|
@@ -10,9 +10,8 @@ import * as React from 'react';
|
|
|
10
10
|
import React__default, { useState, useEffect, useRef } from 'react';
|
|
11
11
|
import _, { debounce as debounce$1 } from 'underscore';
|
|
12
12
|
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
13
|
-
import Color, { fade } from '@khanacademy/wonder-blocks-color';
|
|
14
13
|
import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
|
|
15
|
-
import
|
|
14
|
+
import { color, spacing } from '@khanacademy/wonder-blocks-tokens';
|
|
16
15
|
import { StyleSheet, css } from 'aphrodite';
|
|
17
16
|
import $ from 'jquery';
|
|
18
17
|
import PropTypes from 'prop-types';
|
|
@@ -31,8 +30,7 @@ import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-block
|
|
|
31
30
|
import caretDown from '@phosphor-icons/core/assets/regular/caret-down.svg';
|
|
32
31
|
import caretUp from '@phosphor-icons/core/assets/regular/caret-up.svg';
|
|
33
32
|
import debounce$2 from 'lodash.debounce';
|
|
34
|
-
import { Point as Point$2,
|
|
35
|
-
import { color } from '@khanacademy/wonder-blocks-tokens';
|
|
33
|
+
import { Point as Point$2, useTransformContext, vec, useMovable, Vector, Text as Text$1, Polygon, Coordinates, Mafs } from 'mafs';
|
|
36
34
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
37
35
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
38
36
|
import { LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
@@ -331,16 +329,16 @@ const MathInputIcon = ({
|
|
|
331
329
|
focused,
|
|
332
330
|
active
|
|
333
331
|
}) => {
|
|
334
|
-
let
|
|
332
|
+
let fillColor;
|
|
335
333
|
switch (true) {
|
|
336
334
|
case focused || active:
|
|
337
|
-
|
|
335
|
+
fillColor = color.white;
|
|
338
336
|
break;
|
|
339
337
|
case hovered:
|
|
340
|
-
|
|
338
|
+
fillColor = color.blue;
|
|
341
339
|
break;
|
|
342
340
|
default:
|
|
343
|
-
|
|
341
|
+
fillColor = color.offBlack;
|
|
344
342
|
break;
|
|
345
343
|
}
|
|
346
344
|
const dynamicClass = active || focused ? styles$D.iconActive : styles$D.iconInactive;
|
|
@@ -350,7 +348,7 @@ const MathInputIcon = ({
|
|
|
350
348
|
xmlns: "http://www.w3.org/2000/svg",
|
|
351
349
|
width: "16",
|
|
352
350
|
height: "16",
|
|
353
|
-
fill:
|
|
351
|
+
fill: fillColor,
|
|
354
352
|
viewBox: "0 0 256 256"
|
|
355
353
|
}, /*#__PURE__*/React.createElement("path", {
|
|
356
354
|
d: "M112,72a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16h64A8,8,0,0,1,112,72Zm-8,104H80V152a8,8,0,0,0-16,0v24H40a8,8,0,0,0,0,16H64v24a8,8,0,0,0,16,0V192h24a8,8,0,0,0,0-16Zm48,0h64a8,8,0,0,0,0-16H152a8,8,0,0,0,0,16Zm64,16H152a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16Zm-61.66-90.34a8,8,0,0,0,11.32,0L184,83.31l18.34,18.35a8,8,0,0,0,11.32-11.32L195.31,72l18.35-18.34a8,8,0,0,0-11.32-11.32L184,60.69,165.66,42.34a8,8,0,0,0-11.32,11.32L172.69,72,154.34,90.34A8,8,0,0,0,154.34,101.66Z"
|
|
@@ -387,7 +385,7 @@ const mapButtonSets = buttonSets => {
|
|
|
387
385
|
};
|
|
388
386
|
const inputFocused = {
|
|
389
387
|
borderWidth: 2,
|
|
390
|
-
borderColor:
|
|
388
|
+
borderColor: color.blue,
|
|
391
389
|
margin: -1
|
|
392
390
|
};
|
|
393
391
|
const styles$D = StyleSheet.create({
|
|
@@ -395,35 +393,35 @@ const styles$D = StyleSheet.create({
|
|
|
395
393
|
display: "flex",
|
|
396
394
|
justifyContent: "center",
|
|
397
395
|
height: "100%",
|
|
398
|
-
padding:
|
|
396
|
+
padding: spacing.xxxSmall_4,
|
|
399
397
|
borderRadius: 1
|
|
400
398
|
},
|
|
401
399
|
iconInactive: {
|
|
402
|
-
backgroundColor:
|
|
400
|
+
backgroundColor: color.offBlack8
|
|
403
401
|
},
|
|
404
402
|
iconActive: {
|
|
405
|
-
backgroundColor:
|
|
403
|
+
backgroundColor: color.offBlack64
|
|
406
404
|
},
|
|
407
405
|
outerWrapper: {
|
|
408
406
|
display: "inline-block",
|
|
409
407
|
borderStyle: "solid",
|
|
410
408
|
borderWidth: 1,
|
|
411
|
-
borderColor:
|
|
409
|
+
borderColor: color.offBlack50,
|
|
412
410
|
borderRadius: 3,
|
|
413
|
-
background:
|
|
411
|
+
background: color.white,
|
|
414
412
|
":hover": inputFocused
|
|
415
413
|
},
|
|
416
414
|
wrapperFocused: inputFocused,
|
|
417
415
|
wrapperError: {
|
|
418
|
-
borderColor:
|
|
419
|
-
background:
|
|
416
|
+
borderColor: color.red,
|
|
417
|
+
background: color.fadedRed8,
|
|
420
418
|
":hover": {
|
|
421
|
-
borderColor:
|
|
419
|
+
borderColor: color.red
|
|
422
420
|
}
|
|
423
421
|
},
|
|
424
422
|
popoverContent: {
|
|
425
423
|
padding: 0,
|
|
426
|
-
paddingBottom:
|
|
424
|
+
paddingBottom: spacing.xxSmall_6,
|
|
427
425
|
maxWidth: "initial"
|
|
428
426
|
}
|
|
429
427
|
});
|
|
@@ -21763,13 +21761,13 @@ const styles$A = StyleSheet.create({
|
|
|
21763
21761
|
width: 40
|
|
21764
21762
|
},
|
|
21765
21763
|
leftAlign: {
|
|
21766
|
-
paddingLeft:
|
|
21764
|
+
paddingLeft: spacing.xxxSmall_4,
|
|
21767
21765
|
paddingRight: 0
|
|
21768
21766
|
},
|
|
21769
21767
|
rightAlign: {
|
|
21770
21768
|
textAlign: "right",
|
|
21771
21769
|
paddingLeft: 0,
|
|
21772
|
-
paddingRight:
|
|
21770
|
+
paddingRight: spacing.xxxSmall_4
|
|
21773
21771
|
},
|
|
21774
21772
|
answerStateUnanswered: {
|
|
21775
21773
|
backgroundColor: "#eee",
|
|
@@ -22867,19 +22865,19 @@ function ChoiceInner(props) {
|
|
|
22867
22865
|
function getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct) {
|
|
22868
22866
|
let backgroundColor;
|
|
22869
22867
|
let borderColor;
|
|
22870
|
-
let color;
|
|
22868
|
+
let color$1;
|
|
22871
22869
|
if (!showCorrectness && pressed) {
|
|
22872
|
-
borderColor =
|
|
22873
|
-
color =
|
|
22870
|
+
borderColor = color.blue;
|
|
22871
|
+
color$1 = color.blue;
|
|
22874
22872
|
backgroundColor = "transparent";
|
|
22875
22873
|
} else if (checked) {
|
|
22876
|
-
const bg = showCorrectness && correct ?
|
|
22877
|
-
color = white$1;
|
|
22874
|
+
const bg = showCorrectness && correct ? color.green : color.blue;
|
|
22875
|
+
color$1 = white$1;
|
|
22878
22876
|
backgroundColor = bg;
|
|
22879
22877
|
borderColor = bg;
|
|
22880
22878
|
} else {
|
|
22881
|
-
borderColor =
|
|
22882
|
-
color =
|
|
22879
|
+
borderColor = color.offBlack64;
|
|
22880
|
+
color$1 = color.offBlack64;
|
|
22883
22881
|
}
|
|
22884
22882
|
|
|
22885
22883
|
// define shape
|
|
@@ -22892,7 +22890,7 @@ function getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, cor
|
|
|
22892
22890
|
return {
|
|
22893
22891
|
backgroundColor,
|
|
22894
22892
|
borderColor,
|
|
22895
|
-
color,
|
|
22893
|
+
color: color$1,
|
|
22896
22894
|
borderRadius
|
|
22897
22895
|
};
|
|
22898
22896
|
}
|
|
@@ -22913,7 +22911,7 @@ const ChoiceIcon = function ChoiceIcon(props) {
|
|
|
22913
22911
|
return /*#__PURE__*/React.createElement("div", {
|
|
22914
22912
|
className: css(styles$y.iconWrapper)
|
|
22915
22913
|
}, /*#__PURE__*/React.createElement(FocusRing, {
|
|
22916
|
-
color:
|
|
22914
|
+
color: color.blue,
|
|
22917
22915
|
visible: focused || hovered,
|
|
22918
22916
|
multipleSelect: multipleSelect
|
|
22919
22917
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -22978,9 +22976,9 @@ const styles$w = StyleSheet.create({
|
|
|
22978
22976
|
color: gray68
|
|
22979
22977
|
},
|
|
22980
22978
|
circleIncorrectAnswered: {
|
|
22981
|
-
backgroundColor:
|
|
22982
|
-
borderColor:
|
|
22983
|
-
color:
|
|
22979
|
+
backgroundColor: color.red,
|
|
22980
|
+
borderColor: color.red,
|
|
22981
|
+
color: color.white
|
|
22984
22982
|
}
|
|
22985
22983
|
});
|
|
22986
22984
|
|
|
@@ -23048,13 +23046,13 @@ const styles$v = StyleSheet.create({
|
|
|
23048
23046
|
textTransform: "uppercase"
|
|
23049
23047
|
},
|
|
23050
23048
|
correct: {
|
|
23051
|
-
color:
|
|
23049
|
+
color: color.green
|
|
23052
23050
|
},
|
|
23053
23051
|
incorrectAnswered: {
|
|
23054
|
-
color:
|
|
23052
|
+
color: color.red
|
|
23055
23053
|
},
|
|
23056
23054
|
incorrect: {
|
|
23057
|
-
color:
|
|
23055
|
+
color: color.offBlack64
|
|
23058
23056
|
}
|
|
23059
23057
|
});
|
|
23060
23058
|
|
|
@@ -23129,7 +23127,7 @@ const Choice = function Choice(props) {
|
|
|
23129
23127
|
// @ts-expect-error - TS2322 - Type '{ dispay: string; flexDirection: "column"; color: string; }' is not assignable to type 'Properties<string | number, string & {}>'.
|
|
23130
23128
|
dispay: "flex",
|
|
23131
23129
|
flexDirection: "column",
|
|
23132
|
-
color:
|
|
23130
|
+
color: color.offBlack
|
|
23133
23131
|
},
|
|
23134
23132
|
className: descriptionClassName
|
|
23135
23133
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -23172,7 +23170,7 @@ const Choice = function Choice(props) {
|
|
|
23172
23170
|
disabled: disabled || apiOptions.readOnly,
|
|
23173
23171
|
style: {
|
|
23174
23172
|
flex: 1,
|
|
23175
|
-
color:
|
|
23173
|
+
color: color.offBlack,
|
|
23176
23174
|
userSelect: "text"
|
|
23177
23175
|
},
|
|
23178
23176
|
ref: forwardedRef,
|
|
@@ -23187,9 +23185,9 @@ const Choice = function Choice(props) {
|
|
|
23187
23185
|
flexDirection: "row",
|
|
23188
23186
|
justifyContent: "center",
|
|
23189
23187
|
alignContent: "center",
|
|
23190
|
-
paddingTop:
|
|
23191
|
-
paddingBottom:
|
|
23192
|
-
paddingLeft:
|
|
23188
|
+
paddingTop: spacing.xSmall_8,
|
|
23189
|
+
paddingBottom: spacing.xSmall_8,
|
|
23190
|
+
paddingLeft: spacing.xSmall_8
|
|
23193
23191
|
}
|
|
23194
23192
|
}, /*#__PURE__*/React.createElement(ChoiceIcon, {
|
|
23195
23193
|
pos: pos,
|
|
@@ -23205,7 +23203,7 @@ const Choice = function Choice(props) {
|
|
|
23205
23203
|
previouslyAnswered: previouslyAnswered
|
|
23206
23204
|
}), /*#__PURE__*/React.createElement("span", {
|
|
23207
23205
|
style: {
|
|
23208
|
-
paddingLeft:
|
|
23206
|
+
paddingLeft: spacing.small_12,
|
|
23209
23207
|
textAlign: "left",
|
|
23210
23208
|
flex: 1,
|
|
23211
23209
|
paddingTop: 4
|
|
@@ -23225,7 +23223,7 @@ const Choice = function Choice(props) {
|
|
|
23225
23223
|
content: i18n._("Cross out option"),
|
|
23226
23224
|
closeButtonVisible: true,
|
|
23227
23225
|
actions: /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Strut, {
|
|
23228
|
-
size:
|
|
23226
|
+
size: spacing.medium_16
|
|
23229
23227
|
}), /*#__PURE__*/React.createElement(Button, {
|
|
23230
23228
|
kind: "primary",
|
|
23231
23229
|
"aria-label": i18n._("Cross out Choice %(letter)s", {
|
|
@@ -23273,7 +23271,7 @@ const Choice = function Choice(props) {
|
|
|
23273
23271
|
}) => /*#__PURE__*/React.createElement(Icon, {
|
|
23274
23272
|
icon: ellipsisHorizontalIcon,
|
|
23275
23273
|
size: 3,
|
|
23276
|
-
color:
|
|
23274
|
+
color: color.offBlack64
|
|
23277
23275
|
})))), showRationale && /*#__PURE__*/React.createElement("div", {
|
|
23278
23276
|
className: rationaleClassName,
|
|
23279
23277
|
"data-test-id": `perseus-radio-rationale-content-${pos}`
|
|
@@ -23289,7 +23287,7 @@ const styles$u = StyleSheet.create({
|
|
|
23289
23287
|
padding: intermediateCheckboxPadding,
|
|
23290
23288
|
paddingTop: 0,
|
|
23291
23289
|
marginLeft: 54,
|
|
23292
|
-
color:
|
|
23290
|
+
color: color.offBlack64,
|
|
23293
23291
|
[mediaQueries.smOrSmaller]: {
|
|
23294
23292
|
padding: intermediateCheckboxPaddingPhone,
|
|
23295
23293
|
paddingTop: 0
|
|
@@ -24687,8 +24685,8 @@ class Definition extends React.Component {
|
|
|
24687
24685
|
pressed
|
|
24688
24686
|
}) => /*#__PURE__*/React.createElement("span", {
|
|
24689
24687
|
style: {
|
|
24690
|
-
color:
|
|
24691
|
-
borderBottom: hovered || focused || pressed ? `2px solid ${
|
|
24688
|
+
color: color.blue,
|
|
24689
|
+
borderBottom: hovered || focused || pressed ? `2px solid ${color.blue}` : "none"
|
|
24692
24690
|
}
|
|
24693
24691
|
}, this.props.togglePrompt))));
|
|
24694
24692
|
}
|
|
@@ -24699,7 +24697,7 @@ Definition.defaultProps = {
|
|
|
24699
24697
|
};
|
|
24700
24698
|
const styles$q = {
|
|
24701
24699
|
tooltipBody: {
|
|
24702
|
-
color:
|
|
24700
|
+
color: color.offBlack,
|
|
24703
24701
|
fontSize: 20,
|
|
24704
24702
|
fontWeight: 500,
|
|
24705
24703
|
lineHeight: "30px"
|
|
@@ -24999,7 +24997,7 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
24999
24997
|
onNextQuestion
|
|
25000
24998
|
} = this.props;
|
|
25001
24999
|
const answerBarStyle = _extends({}, styles$o.answerBar, {
|
|
25002
|
-
backgroundColor: answerBarState === "CORRECT" ?
|
|
25000
|
+
backgroundColor: answerBarState === "CORRECT" ? color.offWhite : "white",
|
|
25003
25001
|
// Center the "Correct!" message only when there's no next question
|
|
25004
25002
|
justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
|
|
25005
25003
|
});
|
|
@@ -25029,7 +25027,7 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25029
25027
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25030
25028
|
style: {
|
|
25031
25029
|
fontSize: 28,
|
|
25032
|
-
color:
|
|
25030
|
+
color: color.green
|
|
25033
25031
|
}
|
|
25034
25032
|
}, /*#__PURE__*/React.createElement(InlineIcon, _extends({}, iconStar, {
|
|
25035
25033
|
style: {
|
|
@@ -25059,7 +25057,7 @@ const styles$o = {
|
|
|
25059
25057
|
marginTop: phoneMargin,
|
|
25060
25058
|
paddingLeft: phoneMargin,
|
|
25061
25059
|
paddingRight: 10,
|
|
25062
|
-
borderTop: `1px solid ${
|
|
25060
|
+
borderTop: `1px solid ${color.offBlack50}`
|
|
25063
25061
|
},
|
|
25064
25062
|
tryAgainIcon: {
|
|
25065
25063
|
fontSize: 28,
|
|
@@ -25361,7 +25359,7 @@ const styles$n = StyleSheet.create({
|
|
|
25361
25359
|
padding: 0,
|
|
25362
25360
|
border: "none",
|
|
25363
25361
|
marginTop: 20,
|
|
25364
|
-
color:
|
|
25362
|
+
color: color.blue,
|
|
25365
25363
|
cursor: "pointer",
|
|
25366
25364
|
display: "block",
|
|
25367
25365
|
clear: "both"
|
|
@@ -25369,7 +25367,7 @@ const styles$n = StyleSheet.create({
|
|
|
25369
25367
|
explanationTitle: {
|
|
25370
25368
|
backgroundColor: "unset",
|
|
25371
25369
|
marginTop: 20,
|
|
25372
|
-
color:
|
|
25370
|
+
color: color.blue,
|
|
25373
25371
|
marginBottom: 10,
|
|
25374
25372
|
cursor: "pointer",
|
|
25375
25373
|
fontSize: 14,
|
|
@@ -25578,7 +25576,7 @@ const styles$m = StyleSheet.create({
|
|
|
25578
25576
|
},
|
|
25579
25577
|
title: {
|
|
25580
25578
|
fontSize: 12,
|
|
25581
|
-
color:
|
|
25579
|
+
color: color.offBlack64,
|
|
25582
25580
|
textTransform: "uppercase",
|
|
25583
25581
|
marginBottom: 11,
|
|
25584
25582
|
letterSpacing: 0.8
|
|
@@ -25612,7 +25610,7 @@ const styles$m = StyleSheet.create({
|
|
|
25612
25610
|
height: 10,
|
|
25613
25611
|
borderRadius: "100%",
|
|
25614
25612
|
borderWidth: 2,
|
|
25615
|
-
borderColor:
|
|
25613
|
+
borderColor: color.blue,
|
|
25616
25614
|
borderStyle: "solid"
|
|
25617
25615
|
},
|
|
25618
25616
|
indicatorDotFocused: {
|
|
@@ -25620,7 +25618,7 @@ const styles$m = StyleSheet.create({
|
|
|
25620
25618
|
borderStyle: "double"
|
|
25621
25619
|
},
|
|
25622
25620
|
indicatorDotActive: {
|
|
25623
|
-
backgroundColor:
|
|
25621
|
+
backgroundColor: color.blue,
|
|
25624
25622
|
width: "100%",
|
|
25625
25623
|
height: "100%"
|
|
25626
25624
|
},
|
|
@@ -28216,6 +28214,54 @@ const normalizeCoords = (coordsList, ranges) => coordsList.map(coords => coords.
|
|
|
28216
28214
|
return (coord + ranges[i][1]) / extent;
|
|
28217
28215
|
}));
|
|
28218
28216
|
|
|
28217
|
+
const useTransform = (...points) => {
|
|
28218
|
+
const {
|
|
28219
|
+
viewTransform,
|
|
28220
|
+
userTransform
|
|
28221
|
+
} = useTransformContext();
|
|
28222
|
+
const transformToPx = vec.matrixMult(viewTransform, userTransform);
|
|
28223
|
+
const transformedPoints = points.map(point => vec.transform(point, transformToPx));
|
|
28224
|
+
return transformedPoints;
|
|
28225
|
+
};
|
|
28226
|
+
|
|
28227
|
+
/**
|
|
28228
|
+
* Given two points, find the tips that extends through the points to the edge of the range.
|
|
28229
|
+
* @param collinearPoint - The point that the line passes through. Needed to establish slope.
|
|
28230
|
+
* @param extendFrom - The point that the line extends from to the edge of the graph.
|
|
28231
|
+
*/
|
|
28232
|
+
const getRayIntersectionCoords = (collinearPoint, extendFrom, range) => {
|
|
28233
|
+
// edges of the graph
|
|
28234
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28235
|
+
const [aX, aY] = collinearPoint;
|
|
28236
|
+
const [bX, bY] = extendFrom;
|
|
28237
|
+
const yDiff = bY - aY;
|
|
28238
|
+
const xDiff = bX - aX;
|
|
28239
|
+
const slope = yDiff / xDiff;
|
|
28240
|
+
const yAtXMin = slope * (xMin - aX) + aY;
|
|
28241
|
+
const yAtXMax = slope * (xMax - aX) + aY;
|
|
28242
|
+
const xAtYMin = (yMin - aY) / slope + aX;
|
|
28243
|
+
const xAtYMax = (yMax - aY) / slope + aX;
|
|
28244
|
+
|
|
28245
|
+
// clock analogy to describe quadrants
|
|
28246
|
+
switch (true) {
|
|
28247
|
+
// 12 o'clock to 2:59
|
|
28248
|
+
case yDiff > 0 && xDiff >= 0:
|
|
28249
|
+
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
28250
|
+
// 3 o'clock to 5:59
|
|
28251
|
+
case yDiff <= 0 && xDiff > 0:
|
|
28252
|
+
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
28253
|
+
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
28254
|
+
// 9 o'clock to 11:59
|
|
28255
|
+
case yDiff >= 0 && xDiff < 0:
|
|
28256
|
+
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28257
|
+
// 6 o'clock to 8:59
|
|
28258
|
+
case yDiff < 0 && xDiff <= 0:
|
|
28259
|
+
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28260
|
+
default:
|
|
28261
|
+
return [xMax, yAtXMax];
|
|
28262
|
+
}
|
|
28263
|
+
};
|
|
28264
|
+
|
|
28219
28265
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
28220
28266
|
const MovableLine = props => {
|
|
28221
28267
|
const {
|
|
@@ -28226,18 +28272,12 @@ const MovableLine = props => {
|
|
|
28226
28272
|
stroke = defaultStroke
|
|
28227
28273
|
} = props;
|
|
28228
28274
|
const midpoint = vec.midpoint(start, end);
|
|
28229
|
-
const
|
|
28230
|
-
viewTransform,
|
|
28231
|
-
userTransform
|
|
28232
|
-
} = useTransformContext();
|
|
28233
|
-
const transformToPx = vec.matrixMult(viewTransform, userTransform);
|
|
28234
|
-
const startPtPx = vec.transform(start, transformToPx);
|
|
28235
|
-
const endPtPx = vec.transform(end, transformToPx);
|
|
28275
|
+
const [startPtPx, endPtPx] = useTransform(start, end);
|
|
28236
28276
|
let startExtend = undefined;
|
|
28237
28277
|
let endExtend = undefined;
|
|
28238
28278
|
if (extend) {
|
|
28239
|
-
startExtend = extend.start ?
|
|
28240
|
-
endExtend = extend.end ?
|
|
28279
|
+
startExtend = extend.start ? getRayIntersectionCoords(end, start, extend.range) : undefined;
|
|
28280
|
+
endExtend = extend.end ? getRayIntersectionCoords(start, end, extend.range) : undefined;
|
|
28241
28281
|
}
|
|
28242
28282
|
const line = useRef(null);
|
|
28243
28283
|
const {
|
|
@@ -28299,50 +28339,12 @@ function SVGLine(props) {
|
|
|
28299
28339
|
});
|
|
28300
28340
|
}
|
|
28301
28341
|
|
|
28302
|
-
/**
|
|
28303
|
-
* Given two points, find the tips that extends through the points to the edge of the range.
|
|
28304
|
-
* @param collinearPoint - The point that the line passes through. Needed to establish slope.
|
|
28305
|
-
* @param extendFrom - The point that the line extends from to the edge of the graph.
|
|
28306
|
-
*/
|
|
28307
|
-
const getExtensionCoords = (collinearPoint, extendFrom, range) => {
|
|
28308
|
-
// edges of the graph
|
|
28309
|
-
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28310
|
-
const [aX, aY] = collinearPoint;
|
|
28311
|
-
const [bX, bY] = extendFrom;
|
|
28312
|
-
const yDiff = bY - aY;
|
|
28313
|
-
const xDiff = bX - aX;
|
|
28314
|
-
const slope = yDiff / xDiff;
|
|
28315
|
-
const yAtXMin = slope * (xMin - aX) + aY;
|
|
28316
|
-
const yAtXMax = slope * (xMax - aX) + aY;
|
|
28317
|
-
const xAtYMin = (yMin - aY) / slope + aX;
|
|
28318
|
-
const xAtYMax = (yMax - aY) / slope + aX;
|
|
28319
|
-
|
|
28320
|
-
// clock analogy to describe quadrants
|
|
28321
|
-
switch (true) {
|
|
28322
|
-
// 12 o'clock to 2:59
|
|
28323
|
-
case yDiff > 0 && xDiff >= 0:
|
|
28324
|
-
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
28325
|
-
// 3 o'clock to 5:59
|
|
28326
|
-
case yDiff <= 0 && xDiff > 0:
|
|
28327
|
-
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
28328
|
-
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
28329
|
-
// 9 o'clock to 11:59
|
|
28330
|
-
case yDiff >= 0 && xDiff < 0:
|
|
28331
|
-
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28332
|
-
// 6 o'clock to 8:59
|
|
28333
|
-
case yDiff < 0 && xDiff <= 0:
|
|
28334
|
-
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28335
|
-
default:
|
|
28336
|
-
return [xMax, yAtXMax];
|
|
28337
|
-
}
|
|
28338
|
-
};
|
|
28339
|
-
|
|
28340
28342
|
const StyledMovablePoint = props => {
|
|
28341
28343
|
const hitboxRef = useRef(null);
|
|
28342
28344
|
const {
|
|
28343
28345
|
point,
|
|
28344
28346
|
onMove,
|
|
28345
|
-
color =
|
|
28347
|
+
color: color$1 = color.blue
|
|
28346
28348
|
} = props;
|
|
28347
28349
|
const {
|
|
28348
28350
|
dragging
|
|
@@ -28352,12 +28354,7 @@ const StyledMovablePoint = props => {
|
|
|
28352
28354
|
onMove,
|
|
28353
28355
|
constrain: p => p
|
|
28354
28356
|
});
|
|
28355
|
-
const
|
|
28356
|
-
viewTransform,
|
|
28357
|
-
userTransform
|
|
28358
|
-
} = useTransformContext();
|
|
28359
|
-
const transformToPx = vec.matrixMult(viewTransform, userTransform);
|
|
28360
|
-
const [x, y] = vec.transform(point, transformToPx);
|
|
28357
|
+
const [[x, y]] = useTransform(point);
|
|
28361
28358
|
return /*#__PURE__*/React.createElement("g", {
|
|
28362
28359
|
ref: hitboxRef,
|
|
28363
28360
|
className: "movable-point",
|
|
@@ -28366,7 +28363,7 @@ const StyledMovablePoint = props => {
|
|
|
28366
28363
|
cursor: dragging ? "grabbing" : "grab",
|
|
28367
28364
|
touchAction: "none",
|
|
28368
28365
|
outline: "none",
|
|
28369
|
-
"--movable-point-color": color
|
|
28366
|
+
"--movable-point-color": color$1
|
|
28370
28367
|
}
|
|
28371
28368
|
}, /*#__PURE__*/React.createElement("circle", {
|
|
28372
28369
|
className: "movable-point-hitbox",
|
|
@@ -28386,7 +28383,7 @@ const StyledMovablePoint = props => {
|
|
|
28386
28383
|
cx: x,
|
|
28387
28384
|
cy: y,
|
|
28388
28385
|
style: {
|
|
28389
|
-
fill: color
|
|
28386
|
+
fill: color$1
|
|
28390
28387
|
}
|
|
28391
28388
|
}));
|
|
28392
28389
|
};
|
|
@@ -28524,6 +28521,152 @@ const RayGraph = props => {
|
|
|
28524
28521
|
}));
|
|
28525
28522
|
};
|
|
28526
28523
|
|
|
28524
|
+
const Angle = ({
|
|
28525
|
+
centerPoint,
|
|
28526
|
+
endPoints,
|
|
28527
|
+
range,
|
|
28528
|
+
polygonPoints,
|
|
28529
|
+
showAngles
|
|
28530
|
+
}) => {
|
|
28531
|
+
const [centerX, centerY] = centerPoint;
|
|
28532
|
+
const areClockwise = clockwise$1([centerPoint, ...endPoints]);
|
|
28533
|
+
const [[startX, startY], [endX, endY]] = areClockwise ? endPoints : endPoints.reverse();
|
|
28534
|
+
const radius = 0.3;
|
|
28535
|
+
const a = vec.dist(centerPoint, endPoints[0]);
|
|
28536
|
+
const b = vec.dist(centerPoint, endPoints[1]);
|
|
28537
|
+
const c = vec.dist(endPoints[0], endPoints[1]);
|
|
28538
|
+
|
|
28539
|
+
// Law of cosines
|
|
28540
|
+
const angle = Math.acos((a ** 2 + b ** 2 - c ** 2) / (2 * a * b));
|
|
28541
|
+
const y1 = centerY + (startY - centerY) / a * radius;
|
|
28542
|
+
const x2 = centerX + (endX - centerX) / b * radius;
|
|
28543
|
+
const x1 = centerX + (startX - centerX) / a * radius;
|
|
28544
|
+
const y2 = centerY + (endY - centerY) / b * radius;
|
|
28545
|
+
|
|
28546
|
+
// Fourth point that would create a rhomboid
|
|
28547
|
+
// Used to calculate the inside of the angle and to create square
|
|
28548
|
+
const [x3, y3] = vec.add(centerPoint, vec.add(vec.sub([x1, y1], centerPoint), vec.sub([x2, y2], centerPoint)));
|
|
28549
|
+
if (!showAngles) {
|
|
28550
|
+
return isRightAngle(angle) ? /*#__PURE__*/React.createElement(RightAngleArc, {
|
|
28551
|
+
start: [x1, y1],
|
|
28552
|
+
vertex: [x2, y2],
|
|
28553
|
+
end: [x3, y3]
|
|
28554
|
+
}) : null;
|
|
28555
|
+
}
|
|
28556
|
+
|
|
28557
|
+
// Midpoint betwen ends of arc
|
|
28558
|
+
const isInside = shouldDrawArcInside([x3, y3], centerPoint, range, polygonPoints);
|
|
28559
|
+
const largeArcFlag = isInside ? 1 : 0;
|
|
28560
|
+
const sweepFlag = isInside ? 1 : 0;
|
|
28561
|
+
const arc = `M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} ${sweepFlag} ${x2} ${y2}`;
|
|
28562
|
+
let angleInDegrees = angle * (180 / Math.PI);
|
|
28563
|
+
// If we have triggered "largArcFlag", the angle should be greater than 180
|
|
28564
|
+
if (isInside) {
|
|
28565
|
+
angleInDegrees = 360 - angleInDegrees;
|
|
28566
|
+
}
|
|
28567
|
+
const angleLabelNumber = parseFloat(angleInDegrees.toFixed(1));
|
|
28568
|
+
const angleLabel = Number.isInteger(angleLabelNumber) ? angleLabelNumber : "≈ " + angleLabelNumber;
|
|
28569
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("filter", {
|
|
28570
|
+
id: "background",
|
|
28571
|
+
x: "-5%",
|
|
28572
|
+
width: "110%",
|
|
28573
|
+
y: "0%",
|
|
28574
|
+
height: "100%"
|
|
28575
|
+
}, /*#__PURE__*/React.createElement("feFlood", {
|
|
28576
|
+
floodColor: "#FFF",
|
|
28577
|
+
floodOpacity: "0.5"
|
|
28578
|
+
}), /*#__PURE__*/React.createElement("feComposite", {
|
|
28579
|
+
operator: "over",
|
|
28580
|
+
in: "SourceGraphic"
|
|
28581
|
+
}))), !isInside && isRightAngle(angle) ? /*#__PURE__*/React.createElement(RightAngleArc, {
|
|
28582
|
+
start: [x1, y1],
|
|
28583
|
+
vertex: [x2, y2],
|
|
28584
|
+
end: [x3, y3]
|
|
28585
|
+
}) : /*#__PURE__*/React.createElement("g", {
|
|
28586
|
+
style: {
|
|
28587
|
+
transform: `var(--mafs-view-transform) var(--mafs-user-transform)`
|
|
28588
|
+
}
|
|
28589
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
28590
|
+
d: arc,
|
|
28591
|
+
strokeWidth: 0.02,
|
|
28592
|
+
fill: "none"
|
|
28593
|
+
})), /*#__PURE__*/React.createElement(Text$1, {
|
|
28594
|
+
x: x3,
|
|
28595
|
+
y: y3,
|
|
28596
|
+
size: 15,
|
|
28597
|
+
svgTextProps: {
|
|
28598
|
+
filter: "url(#background)",
|
|
28599
|
+
fontWeight: "bold"
|
|
28600
|
+
}
|
|
28601
|
+
// Shift position if text is too close to movable point
|
|
28602
|
+
,
|
|
28603
|
+
attach: y3 - centerY > 0 ? "s" : "n",
|
|
28604
|
+
attachDistance: Math.abs(y3 - centerY) < 0.2 || vec.dist([x3, y3], centerPoint) < 0.3 ? 20 : 10
|
|
28605
|
+
}, angleLabel, "\xB0"));
|
|
28606
|
+
};
|
|
28607
|
+
const RightAngleArc = ({
|
|
28608
|
+
start: [x1, y1],
|
|
28609
|
+
vertex: [x2, y2],
|
|
28610
|
+
end: [x3, y3]
|
|
28611
|
+
}) => /*#__PURE__*/React.createElement("g", {
|
|
28612
|
+
style: {
|
|
28613
|
+
transform: `var(--mafs-view-transform) var(--mafs-user-transform)`
|
|
28614
|
+
}
|
|
28615
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
28616
|
+
d: `M ${x1} ${y1} L ${x3} ${y3} M ${x3} ${y3} L ${x2} ${y2}`,
|
|
28617
|
+
strokeWidth: 0.02,
|
|
28618
|
+
fill: "none"
|
|
28619
|
+
}));
|
|
28620
|
+
const isRightAngle = angle => Math.abs(angle - Math.PI / 2) < 0.01;
|
|
28621
|
+
const shouldDrawArcInside = (midPoint, vertex, range, polygonPoints) => {
|
|
28622
|
+
const rangeIntersectionPoint = getRayIntersectionCoords(vertex, midPoint, range);
|
|
28623
|
+
const lines = getLines(polygonPoints);
|
|
28624
|
+
let lineIntersections = 0;
|
|
28625
|
+
lines.forEach(line => linesIntersect([vertex, rangeIntersectionPoint], line) && lineIntersections++);
|
|
28626
|
+
|
|
28627
|
+
// The intersection check will sometimes return false if it intersects with
|
|
28628
|
+
// another vertex, so in the case we get 0 intersections, we check for points.
|
|
28629
|
+
if (lineIntersections === 0) {
|
|
28630
|
+
// find point in array
|
|
28631
|
+
const midpointIndex = polygonPoints.findIndex(([x, y]) => x === midPoint[0] && y === midPoint[1]);
|
|
28632
|
+
// get array sans point and adjacent points
|
|
28633
|
+
const [prev, next] = [(midpointIndex - 1 + polygonPoints.length) % polygonPoints.length, (midpointIndex + 1) % polygonPoints.length];
|
|
28634
|
+
const [[lineAx, lineAy], [lineBx, lineBy]] = [midPoint, rangeIntersectionPoint];
|
|
28635
|
+
for (let i = 0; i < polygonPoints.length; i++) {
|
|
28636
|
+
if ([prev, midpointIndex, next].includes(i)) {
|
|
28637
|
+
continue;
|
|
28638
|
+
}
|
|
28639
|
+
const [x, y] = polygonPoints[i];
|
|
28640
|
+
const intersectsPoint = (y - lineAy) * (lineBx - lineAx) === (lineBy - lineAy) * (x - lineAx);
|
|
28641
|
+
if (intersectsPoint) {
|
|
28642
|
+
return false;
|
|
28643
|
+
}
|
|
28644
|
+
}
|
|
28645
|
+
return true;
|
|
28646
|
+
}
|
|
28647
|
+
|
|
28648
|
+
// If the number of intersections is even, the angle is inside the polygon
|
|
28649
|
+
return isEven(lineIntersections);
|
|
28650
|
+
};
|
|
28651
|
+
const getLines = points => points.map((point, i) => {
|
|
28652
|
+
const next = points[(i + 1) % points.length];
|
|
28653
|
+
return [point, next];
|
|
28654
|
+
});
|
|
28655
|
+
|
|
28656
|
+
// https://stackoverflow.com/a/24392281/7347484
|
|
28657
|
+
// The "intersects" function in geometry doesn't seem to work for this use case
|
|
28658
|
+
const linesIntersect = ([[a, b], [c, d]], [[p, q], [r, s]]) => {
|
|
28659
|
+
const determinant = (c - a) * (s - q) - (r - p) * (d - b);
|
|
28660
|
+
if (determinant === 0) {
|
|
28661
|
+
return false;
|
|
28662
|
+
} else {
|
|
28663
|
+
const lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / determinant;
|
|
28664
|
+
const gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / determinant;
|
|
28665
|
+
return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1;
|
|
28666
|
+
}
|
|
28667
|
+
};
|
|
28668
|
+
const isEven = n => n % 2 === 0;
|
|
28669
|
+
|
|
28527
28670
|
const PolygonGraph = props => {
|
|
28528
28671
|
var _points$length;
|
|
28529
28672
|
const [focused, setFocused] = React.useState(false);
|
|
@@ -28533,7 +28676,9 @@ const PolygonGraph = props => {
|
|
|
28533
28676
|
} = props;
|
|
28534
28677
|
const {
|
|
28535
28678
|
coords,
|
|
28536
|
-
type
|
|
28679
|
+
type,
|
|
28680
|
+
showAngles,
|
|
28681
|
+
range
|
|
28537
28682
|
} = props.graphState;
|
|
28538
28683
|
const points = coords != null ? coords : [[0, 0]];
|
|
28539
28684
|
const pointsSum = points.reduce((acc, point) => vec.add(acc, point), [0, 0]);
|
|
@@ -28557,6 +28702,21 @@ const PolygonGraph = props => {
|
|
|
28557
28702
|
svgPolygonProps: {
|
|
28558
28703
|
strokeWidth: active ? "var(--movable-line-stroke-weight-active)" : "var(--movable-line-stroke-weight)"
|
|
28559
28704
|
}
|
|
28705
|
+
}), points.map((point, i) => {
|
|
28706
|
+
const pt1 = points.at(i - 1);
|
|
28707
|
+
const pt2 = points[(i + 1) % points.length];
|
|
28708
|
+
if (!pt1 || !pt2) {
|
|
28709
|
+
return null;
|
|
28710
|
+
}
|
|
28711
|
+
return /*#__PURE__*/React.createElement(Angle, {
|
|
28712
|
+
key: "angle-" + i,
|
|
28713
|
+
centerPoint: point,
|
|
28714
|
+
endPoints: [pt1, pt2],
|
|
28715
|
+
active: active,
|
|
28716
|
+
range: range,
|
|
28717
|
+
polygonPoints: points,
|
|
28718
|
+
showAngles: !!showAngles
|
|
28719
|
+
});
|
|
28560
28720
|
}), /*#__PURE__*/React.createElement(Polygon, {
|
|
28561
28721
|
points: [...points],
|
|
28562
28722
|
color: "transparent",
|
|
@@ -28574,7 +28734,7 @@ const PolygonGraph = props => {
|
|
|
28574
28734
|
className: "movable-polygon"
|
|
28575
28735
|
}
|
|
28576
28736
|
}), points.map((point, i) => /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
28577
|
-
key: i,
|
|
28737
|
+
key: "point-" + i,
|
|
28578
28738
|
point: point,
|
|
28579
28739
|
onMove: destination => dispatch(moveControlPoint(i, destination)),
|
|
28580
28740
|
"data-testid": type + i
|
|
@@ -29256,7 +29416,10 @@ var components = /*#__PURE__*/Object.freeze({
|
|
|
29256
29416
|
* If a graphie URL is provided in `backgroundImage`, will return the rendered graphie background.
|
|
29257
29417
|
* Otherwise, returns `null`.
|
|
29258
29418
|
*/
|
|
29259
|
-
const
|
|
29419
|
+
const LegacyGrid = ({
|
|
29420
|
+
box,
|
|
29421
|
+
backgroundImage
|
|
29422
|
+
}) => {
|
|
29260
29423
|
const {
|
|
29261
29424
|
url,
|
|
29262
29425
|
width,
|
|
@@ -29533,17 +29696,17 @@ function initializeGraphState(params) {
|
|
|
29533
29696
|
})
|
|
29534
29697
|
};
|
|
29535
29698
|
case "polygon":
|
|
29536
|
-
return {
|
|
29537
|
-
type: "polygon",
|
|
29699
|
+
return _extends({
|
|
29538
29700
|
hasBeenInteractedWith: false,
|
|
29539
29701
|
range,
|
|
29540
|
-
snapStep
|
|
29702
|
+
snapStep
|
|
29703
|
+
}, graph, {
|
|
29541
29704
|
coords: getPolygonCoords({
|
|
29542
29705
|
graph,
|
|
29543
29706
|
range,
|
|
29544
29707
|
step
|
|
29545
29708
|
})
|
|
29546
|
-
};
|
|
29709
|
+
});
|
|
29547
29710
|
case "angle":
|
|
29548
29711
|
case "point":
|
|
29549
29712
|
case "circle":
|
|
@@ -29604,9 +29767,10 @@ const getDefaultSegments = ({
|
|
|
29604
29767
|
return [5];
|
|
29605
29768
|
}
|
|
29606
29769
|
};
|
|
29770
|
+
const defaultRange = [[-10, 10], [-10, 10]];
|
|
29607
29771
|
return ys(graph.numSegments).map(y => {
|
|
29608
29772
|
let endpoints = [[-5, y], [5, y]];
|
|
29609
|
-
endpoints = normalizeCoords(endpoints,
|
|
29773
|
+
endpoints = normalizeCoords(endpoints, defaultRange);
|
|
29610
29774
|
endpoints = normalizePoints(range, step, endpoints);
|
|
29611
29775
|
return endpoints;
|
|
29612
29776
|
});
|
|
@@ -29688,7 +29852,6 @@ const renderGraph = props => {
|
|
|
29688
29852
|
};
|
|
29689
29853
|
const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
29690
29854
|
const [width, height] = props.box;
|
|
29691
|
-
const legacyGrid = getLegacyGrid([width, height], props.backgroundImage);
|
|
29692
29855
|
const [state, dispatch] = React.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
29693
29856
|
React.useImperativeHandle(ref, () => ({
|
|
29694
29857
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
@@ -29699,13 +29862,17 @@ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
29699
29862
|
height,
|
|
29700
29863
|
position: "relative"
|
|
29701
29864
|
}
|
|
29702
|
-
},
|
|
29865
|
+
}, /*#__PURE__*/React.createElement(LegacyGrid, {
|
|
29866
|
+
box: props.box,
|
|
29867
|
+
backgroundImage: props.backgroundImage
|
|
29868
|
+
}), /*#__PURE__*/React.createElement(View, {
|
|
29703
29869
|
style: {
|
|
29704
29870
|
position: "absolute",
|
|
29705
29871
|
bottom: 0,
|
|
29706
29872
|
left: 0
|
|
29707
29873
|
}
|
|
29708
29874
|
}, /*#__PURE__*/React.createElement(Mafs, {
|
|
29875
|
+
preserveAspectRatio: false,
|
|
29709
29876
|
viewBox: {
|
|
29710
29877
|
x: props.range[0],
|
|
29711
29878
|
y: props.range[1],
|
|
@@ -29715,7 +29882,7 @@ const MafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
29715
29882
|
zoom: false,
|
|
29716
29883
|
width: width,
|
|
29717
29884
|
height: height
|
|
29718
|
-
},
|
|
29885
|
+
}, /*#__PURE__*/React.createElement(Grid, props), props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
|
|
29719
29886
|
lockedFigures: props.lockedFigures
|
|
29720
29887
|
}), renderGraph({
|
|
29721
29888
|
state,
|
|
@@ -32650,7 +32817,7 @@ const styles$g = StyleSheet.create({
|
|
|
32650
32817
|
});
|
|
32651
32818
|
|
|
32652
32819
|
const BringToFront = {
|
|
32653
|
-
boxShadow: `0 8px 8px ${
|
|
32820
|
+
boxShadow: `0 8px 8px ${color.offBlack64}`,
|
|
32654
32821
|
zIndex: 1000
|
|
32655
32822
|
};
|
|
32656
32823
|
const AnswerPill = props => {
|
|
@@ -32703,7 +32870,7 @@ const styles$f = StyleSheet.create({
|
|
|
32703
32870
|
backgroundColor: "#00880b"
|
|
32704
32871
|
},
|
|
32705
32872
|
incorrect: {
|
|
32706
|
-
backgroundColor:
|
|
32873
|
+
backgroundColor: color.offBlack64
|
|
32707
32874
|
},
|
|
32708
32875
|
pill: {
|
|
32709
32876
|
// Reset the Pill's default height in order to account
|
|
@@ -32746,7 +32913,7 @@ class Marker extends React.Component {
|
|
|
32746
32913
|
// default dot
|
|
32747
32914
|
let args = {
|
|
32748
32915
|
size: MARKER_SIZE,
|
|
32749
|
-
color:
|
|
32916
|
+
color: color.white,
|
|
32750
32917
|
icon: iconNull
|
|
32751
32918
|
};
|
|
32752
32919
|
if (showCorrectness) {
|
|
@@ -32809,7 +32976,7 @@ Marker.defaultProps = {
|
|
|
32809
32976
|
const styles$e = StyleSheet.create({
|
|
32810
32977
|
marker: {
|
|
32811
32978
|
position: "absolute",
|
|
32812
|
-
backgroundColor:
|
|
32979
|
+
backgroundColor: color.white,
|
|
32813
32980
|
borderRadius: MARKER_SIZE,
|
|
32814
32981
|
// Center marker position based on its maximum size.
|
|
32815
32982
|
width: MARKER_SIZE,
|
|
@@ -32817,7 +32984,7 @@ const styles$e = StyleSheet.create({
|
|
|
32817
32984
|
marginLeft: MARKER_SIZE / -2,
|
|
32818
32985
|
marginTop: MARKER_SIZE / -2,
|
|
32819
32986
|
// Add a shadow to the marker to make it stand out from the image.
|
|
32820
|
-
boxShadow: `0 8px 8px ${
|
|
32987
|
+
boxShadow: `0 8px 8px ${color.offBlack8}`
|
|
32821
32988
|
},
|
|
32822
32989
|
// The base and unfilled marker style.
|
|
32823
32990
|
markerIcon: {
|
|
@@ -32827,7 +32994,7 @@ const styles$e = StyleSheet.create({
|
|
|
32827
32994
|
boxSizing: "border-box",
|
|
32828
32995
|
width: MARKER_SIZE,
|
|
32829
32996
|
height: MARKER_SIZE,
|
|
32830
|
-
border: `2px solid ${
|
|
32997
|
+
border: `2px solid ${color.offBlack64}`,
|
|
32831
32998
|
borderRadius: MARKER_SIZE
|
|
32832
32999
|
},
|
|
32833
33000
|
// The animation that presents the marker to the learner
|
|
@@ -32835,11 +33002,11 @@ const styles$e = StyleSheet.create({
|
|
|
32835
33002
|
animationName: {
|
|
32836
33003
|
"0%": {
|
|
32837
33004
|
transform: "scale(1)",
|
|
32838
|
-
backgroundColor:
|
|
33005
|
+
backgroundColor: color.blue
|
|
32839
33006
|
},
|
|
32840
33007
|
"100%": {
|
|
32841
33008
|
transform: "scale(1.3)",
|
|
32842
|
-
backgroundColor:
|
|
33009
|
+
backgroundColor: color.blue
|
|
32843
33010
|
}
|
|
32844
33011
|
},
|
|
32845
33012
|
animationDirection: "alternate",
|
|
@@ -32856,35 +33023,35 @@ const styles$e = StyleSheet.create({
|
|
|
32856
33023
|
animationIterationCount: "2"
|
|
32857
33024
|
},
|
|
32858
33025
|
markerActive: {
|
|
32859
|
-
outline: `2px solid ${
|
|
33026
|
+
outline: `2px solid ${color.blue}`,
|
|
32860
33027
|
outlineOffset: 2
|
|
32861
33028
|
},
|
|
32862
33029
|
// The learner is making an initial selection
|
|
32863
33030
|
markerSelected: {
|
|
32864
|
-
boxShadow: `0 8px 8px ${
|
|
32865
|
-
border: `solid 4px ${
|
|
32866
|
-
backgroundColor:
|
|
33031
|
+
boxShadow: `0 8px 8px ${color.offBlack8}`,
|
|
33032
|
+
border: `solid 4px ${color.white}`,
|
|
33033
|
+
backgroundColor: color.blue,
|
|
32867
33034
|
borderRadius: MARKER_SIZE,
|
|
32868
33035
|
transform: "rotate(180deg)"
|
|
32869
33036
|
},
|
|
32870
33037
|
// The learner has made a selection
|
|
32871
33038
|
markerFilled: {
|
|
32872
33039
|
backgroundColor: "#ECF3FE",
|
|
32873
|
-
border: `4px solid ${
|
|
33040
|
+
border: `4px solid ${color.blue}`
|
|
32874
33041
|
},
|
|
32875
33042
|
markerGraded: {
|
|
32876
33043
|
width: MARKER_SIZE,
|
|
32877
33044
|
height: MARKER_SIZE,
|
|
32878
33045
|
justifyContent: "center",
|
|
32879
33046
|
alignItems: "center",
|
|
32880
|
-
border: `2px solid ${
|
|
33047
|
+
border: `2px solid ${color.white}`
|
|
32881
33048
|
},
|
|
32882
33049
|
markerCorrect: {
|
|
32883
33050
|
background: "#00880b" // WB green darkened by 18%
|
|
32884
33051
|
},
|
|
32885
33052
|
|
|
32886
33053
|
markerIncorrect: {
|
|
32887
|
-
background:
|
|
33054
|
+
background: color.offBlack64
|
|
32888
33055
|
}
|
|
32889
33056
|
});
|
|
32890
33057
|
|
|
@@ -33313,6 +33480,7 @@ class LabelImage extends React.Component {
|
|
|
33313
33480
|
const answerChoicesActive = index === activeMarkerIndex;
|
|
33314
33481
|
const showAnswerChoice = marker.selected && !answerChoicesActive && !this.state.hideAnswers;
|
|
33315
33482
|
return /*#__PURE__*/React.createElement(View, {
|
|
33483
|
+
key: index,
|
|
33316
33484
|
style: {
|
|
33317
33485
|
position: "absolute",
|
|
33318
33486
|
left: `${marker.x}%`,
|
|
@@ -37911,7 +38079,7 @@ const styles$8 = StyleSheet.create({
|
|
|
37911
38079
|
// and the "Add highlight" action fails.
|
|
37912
38080
|
userSelect: "none",
|
|
37913
38081
|
fontFamily: `"Lato", sans-serif`,
|
|
37914
|
-
padding: `10px ${
|
|
38082
|
+
padding: `10px ${spacing.medium_16}px`,
|
|
37915
38083
|
cursor: "pointer"
|
|
37916
38084
|
}
|
|
37917
38085
|
});
|
|
@@ -41594,7 +41762,7 @@ const VideoTranscriptLink = props => {
|
|
|
41594
41762
|
const video = (_result$data = result.data) == null ? void 0 : _result$data.video;
|
|
41595
41763
|
return /*#__PURE__*/React.createElement(View, {
|
|
41596
41764
|
style: styles$4.transcriptLink
|
|
41597
|
-
}, /*#__PURE__*/React.createElement(Text$
|
|
41765
|
+
}, /*#__PURE__*/React.createElement(Text$2, null, video == null ? void 0 : video.title), /*#__PURE__*/React.createElement(Strut, {
|
|
41598
41766
|
size: 10
|
|
41599
41767
|
}), /*#__PURE__*/React.createElement(Link, {
|
|
41600
41768
|
href: "/transcript/" + ((video == null ? void 0 : video.contentId) || "videoNotFound"),
|
|
@@ -41763,7 +41931,7 @@ const init = function init(options) {
|
|
|
41763
41931
|
|
|
41764
41932
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
41765
41933
|
const libName = "@khanacademy/perseus";
|
|
41766
|
-
const libVersion = "20.
|
|
41934
|
+
const libVersion = "20.8.1";
|
|
41767
41935
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
41768
41936
|
|
|
41769
41937
|
const apiVersion = {
|
|
@@ -44420,6 +44588,66 @@ function injectWidgets(content, widgets) {
|
|
|
44420
44588
|
return context;
|
|
44421
44589
|
}
|
|
44422
44590
|
|
|
44591
|
+
/* Widgets that have individual answers */
|
|
44592
|
+
const INDIVIDUAL_ANSWER_WIDGETS = ["interactive-graph", "categorizer", "grapher"];
|
|
44593
|
+
|
|
44594
|
+
/* Widgets that are supported for automatic scoring */
|
|
44595
|
+
const SUPPORTED_WIDGETS = ["radio", "numeric-input", "input-number", "expression", ...INDIVIDUAL_ANSWER_WIDGETS];
|
|
44596
|
+
const getWidgetTypeFromWidgetKey = widgetKey => {
|
|
44597
|
+
return widgetKey.split(" ")[0];
|
|
44598
|
+
};
|
|
44599
|
+
|
|
44600
|
+
/* Verify if the perseus item has supported widgets for automatic scoring */
|
|
44601
|
+
const isWrongAnswerSupported = widgetKeys => {
|
|
44602
|
+
return widgetKeys.length !== 0 && widgetKeys.every(widgetKey => SUPPORTED_WIDGETS.includes(getWidgetTypeFromWidgetKey(widgetKey)));
|
|
44603
|
+
};
|
|
44604
|
+
|
|
44605
|
+
/* Verify if the widget key has an individual answer for the coach report view */
|
|
44606
|
+
const shouldHaveIndividualAnswer = widgetKey => {
|
|
44607
|
+
return INDIVIDUAL_ANSWER_WIDGETS.includes(getWidgetTypeFromWidgetKey(widgetKey));
|
|
44608
|
+
};
|
|
44609
|
+
|
|
44610
|
+
/* Returns the answer userInput submission for currently supported widgets */
|
|
44611
|
+
// TODO (LEMS-1834): Fix userInput any types to be specific
|
|
44612
|
+
const getAnswerFromUserInput = (widgetType, userInput) => {
|
|
44613
|
+
switch (widgetType) {
|
|
44614
|
+
case "categorizer":
|
|
44615
|
+
return userInput.values;
|
|
44616
|
+
case "input-number":
|
|
44617
|
+
return userInput.currentValue;
|
|
44618
|
+
case "numeric-input":
|
|
44619
|
+
return userInput.currentValue;
|
|
44620
|
+
case "radio":
|
|
44621
|
+
return userInput.choicesSelected;
|
|
44622
|
+
}
|
|
44623
|
+
return userInput;
|
|
44624
|
+
};
|
|
44625
|
+
|
|
44626
|
+
/* Returns the correct answer for a given widget key and Perseus Item */
|
|
44627
|
+
// TODO (LEMS-1835): We should fix the resonse type from getWidget to be specific.
|
|
44628
|
+
// TODO (LEMS-1836): We should also consider adding the getOneCorrectAnswerFromRubric method to all widgets.
|
|
44629
|
+
const getCorrectAnswerForWidgetKey = (widgetKey, itemData) => {
|
|
44630
|
+
const rubric = itemData.question.widgets[widgetKey].options;
|
|
44631
|
+
const widgetType = getWidgetTypeFromWidgetKey(widgetKey);
|
|
44632
|
+
const widget = getWidget(widgetType);
|
|
44633
|
+
|
|
44634
|
+
// @ts-expect-error - TS2339 - Property 'getOneCorrectAnswerFromRubric' does not exist on type 'ComponentType<any>'.
|
|
44635
|
+
return widget == null || widget.getOneCorrectAnswerFromRubric == null ? void 0 : widget.getOneCorrectAnswerFromRubric(rubric);
|
|
44636
|
+
};
|
|
44637
|
+
|
|
44638
|
+
/* Verify if the widget key exists in the content string of the Perseus Item */
|
|
44639
|
+
const isWidgetKeyInContent = (perseusItem, widgetKey) => {
|
|
44640
|
+
return perseusItem.question.content.indexOf(widgetKey) !== -1;
|
|
44641
|
+
};
|
|
44642
|
+
|
|
44643
|
+
/* Return an array of all the widget keys that exist in the content string of a Perseus Item */
|
|
44644
|
+
const getValidWidgetKeys = perseusItem => {
|
|
44645
|
+
const {
|
|
44646
|
+
widgets
|
|
44647
|
+
} = perseusItem.question;
|
|
44648
|
+
return keys(widgets).filter(key => isWidgetKeyInContent(perseusItem, key));
|
|
44649
|
+
};
|
|
44650
|
+
|
|
44423
44651
|
/**
|
|
44424
44652
|
* Helper to parse PerseusItem JSON
|
|
44425
44653
|
* Why not just use JSON.parse? We want:
|
|
@@ -44591,15 +44819,14 @@ function getWidgetRegex() {
|
|
|
44591
44819
|
}
|
|
44592
44820
|
|
|
44593
44821
|
/**
|
|
44594
|
-
* Add a widget placeholder using the
|
|
44595
|
-
* ex. addWidget(
|
|
44822
|
+
* Add a widget placeholder using the widget ID.
|
|
44823
|
+
* ex. addWidget("radio 1") => "[[☃ radio 1]]"
|
|
44596
44824
|
*
|
|
44597
|
-
* @param {
|
|
44598
|
-
* @param {number} instance
|
|
44825
|
+
* @param {string} id
|
|
44599
44826
|
* @returns {string}
|
|
44600
44827
|
*/
|
|
44601
|
-
function addWidget(
|
|
44602
|
-
return `[[☃ ${
|
|
44828
|
+
function addWidget(id) {
|
|
44829
|
+
return `[[☃ ${id}]]`;
|
|
44603
44830
|
}
|
|
44604
44831
|
|
|
44605
44832
|
/**
|
|
@@ -44691,5 +44918,5 @@ const EditorJsonify = {
|
|
|
44691
44918
|
}
|
|
44692
44919
|
};
|
|
44693
44920
|
|
|
44694
|
-
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, WidgetType, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, convertWidgetNameToEnum, displaySigFigs, generateTestPerseusItem, genericPerseusItemData, getAllWidgetIds, getAllWidgetTypes, getAnswersFromWidgets, getQuestionWidgetIds, getWidgetTypeFromWidgetId, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, traverse, violatingWidgets, allWidgets as widgets };
|
|
44921
|
+
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, WidgetType, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, convertWidgetNameToEnum, displaySigFigs, generateTestPerseusItem, genericPerseusItemData, getAllWidgetIds, getAllWidgetTypes, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetKey, getQuestionWidgetIds, getValidWidgetKeys, getWidgetTypeFromWidgetId, getWidgetTypeFromWidgetKey, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetKeyInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, violatingWidgets, allWidgets as widgets };
|
|
44695
44922
|
//# sourceMappingURL=index.js.map
|