@khanacademy/perseus 46.0.1 → 47.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +233 -1370
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +3 -13
- package/dist/index.js +218 -1364
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +33 -15
- package/dist/types.d.ts +0 -2
- package/dist/widget-type-utils.d.ts +0 -2
- package/package.json +1 -1
- package/dist/multi-items/item-types.d.ts +0 -33
- package/dist/multi-items/items.d.ts +0 -53
- package/dist/multi-items/multi-renderer.d.ts +0 -159
- package/dist/multi-items/prop-type-builders.d.ts +0 -14
- package/dist/multi-items/shape-types.d.ts +0 -47
- package/dist/multi-items/shapes.d.ts +0 -23
- package/dist/multi-items/tree-types.d.ts +0 -34
- package/dist/multi-items/trees.d.ts +0 -146
- package/dist/multi-items.d.ts +0 -73
package/dist/index.js
CHANGED
|
@@ -649,7 +649,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
649
649
|
className = className + " " + this.props.className;
|
|
650
650
|
}
|
|
651
651
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
652
|
-
style: [styles$
|
|
652
|
+
style: [styles$D.outerWrapper, this.state.focused && styles$D.wrapperFocused, this.props.hasError && styles$D.wrapperError]
|
|
653
653
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
654
654
|
style: {
|
|
655
655
|
display: "flex",
|
|
@@ -685,7 +685,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
685
685
|
style: a11y.srOnly
|
|
686
686
|
}, this.context.strings.mathInputDescription), /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
|
|
687
687
|
closeButtonVisible: true,
|
|
688
|
-
style: styles$
|
|
688
|
+
style: styles$D.popoverContent
|
|
689
689
|
}, /*#__PURE__*/React__namespace.createElement(mathInput.DesktopKeypad, _extends({
|
|
690
690
|
onAnalyticsEvent: this.props.onAnalyticsEvent,
|
|
691
691
|
extraKeys: this.props.extraKeys,
|
|
@@ -750,9 +750,9 @@ const MathInputIcon = _ref => {
|
|
|
750
750
|
fillColor = wonderBlocksTokens.color.offBlack;
|
|
751
751
|
break;
|
|
752
752
|
}
|
|
753
|
-
const dynamicClass = active || focused ? styles$
|
|
753
|
+
const dynamicClass = active || focused ? styles$D.iconActive : styles$D.iconInactive;
|
|
754
754
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
755
|
-
style: [styles$
|
|
755
|
+
style: [styles$D.iconContainer, dynamicClass]
|
|
756
756
|
}, /*#__PURE__*/React__namespace.createElement("svg", {
|
|
757
757
|
xmlns: "http://www.w3.org/2000/svg",
|
|
758
758
|
width: "16",
|
|
@@ -797,7 +797,7 @@ const inputFocused = {
|
|
|
797
797
|
borderColor: wonderBlocksTokens.color.blue,
|
|
798
798
|
margin: -1
|
|
799
799
|
};
|
|
800
|
-
const styles$
|
|
800
|
+
const styles$D = aphrodite.StyleSheet.create({
|
|
801
801
|
iconContainer: {
|
|
802
802
|
display: "flex",
|
|
803
803
|
justifyContent: "center",
|
|
@@ -2603,7 +2603,7 @@ class Expression extends React__namespace.Component {
|
|
|
2603
2603
|
render() {
|
|
2604
2604
|
if (this.props.apiOptions.customKeypad) {
|
|
2605
2605
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
2606
|
-
className: aphrodite.css(styles$
|
|
2606
|
+
className: aphrodite.css(styles$C.mobileLabelInputWrapper)
|
|
2607
2607
|
}, !!this.props.visibleLabel && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
|
|
2608
2608
|
htmlFor: this._textareaId,
|
|
2609
2609
|
tag: "label"
|
|
@@ -2637,7 +2637,7 @@ class Expression extends React__namespace.Component {
|
|
|
2637
2637
|
ERROR_TITLE
|
|
2638
2638
|
} = this.context.strings;
|
|
2639
2639
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
2640
|
-
className: aphrodite.css(styles$
|
|
2640
|
+
className: aphrodite.css(styles$C.desktopLabelInputWrapper)
|
|
2641
2641
|
}, !!this.props.visibleLabel && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
|
|
2642
2642
|
htmlFor: this._textareaId,
|
|
2643
2643
|
tag: "label"
|
|
@@ -2676,7 +2676,7 @@ class Expression extends React__namespace.Component {
|
|
|
2676
2676
|
}))));
|
|
2677
2677
|
}
|
|
2678
2678
|
}
|
|
2679
|
-
const styles$
|
|
2679
|
+
const styles$C = aphrodite.StyleSheet.create({
|
|
2680
2680
|
mobileLabelInputWrapper: {
|
|
2681
2681
|
padding: "15px 4px 0"
|
|
2682
2682
|
},
|
|
@@ -18124,33 +18124,33 @@ class Lint extends React__namespace.Component {
|
|
|
18124
18124
|
let warningText;
|
|
18125
18125
|
let warningTextStyle;
|
|
18126
18126
|
if (this.props.severity === Severity.Error) {
|
|
18127
|
-
severityStyle = styles$
|
|
18127
|
+
severityStyle = styles$B.indicatorError;
|
|
18128
18128
|
warningText = "Error";
|
|
18129
|
-
warningTextStyle = styles$
|
|
18129
|
+
warningTextStyle = styles$B.publishBlockingError;
|
|
18130
18130
|
} else if (this.props.severity === Severity.Warning) {
|
|
18131
|
-
severityStyle = styles$
|
|
18131
|
+
severityStyle = styles$B.indicatorWarning;
|
|
18132
18132
|
warningText = "Warning";
|
|
18133
|
-
warningTextStyle = styles$
|
|
18133
|
+
warningTextStyle = styles$B.warning;
|
|
18134
18134
|
} else {
|
|
18135
|
-
severityStyle = styles$
|
|
18135
|
+
severityStyle = styles$B.indicatorGuideline;
|
|
18136
18136
|
warningText = "Recommendation";
|
|
18137
|
-
warningTextStyle = styles$
|
|
18137
|
+
warningTextStyle = styles$B.warning;
|
|
18138
18138
|
}
|
|
18139
18139
|
return /*#__PURE__*/React__namespace.createElement("a", {
|
|
18140
18140
|
href: `https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,
|
|
18141
18141
|
target: "lint-help-window",
|
|
18142
18142
|
className: aphrodite.css(style)
|
|
18143
18143
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
18144
|
-
className: aphrodite.css(styles$
|
|
18144
|
+
className: aphrodite.css(styles$B.indicator, severityStyle)
|
|
18145
18145
|
}, this.props.severity === 1 && /*#__PURE__*/React__namespace.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React__namespace.createElement("div", {
|
|
18146
|
-
className: aphrodite.css(styles$
|
|
18146
|
+
className: aphrodite.css(styles$B.tooltip, tooltipAbove && styles$B.tooltipAbove)
|
|
18147
18147
|
}, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React__namespace.createElement("p", {
|
|
18148
18148
|
key: i,
|
|
18149
|
-
className: aphrodite.css(styles$
|
|
18149
|
+
className: aphrodite.css(styles$B.tooltipParagraph)
|
|
18150
18150
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
18151
18151
|
className: aphrodite.css(warningTextStyle)
|
|
18152
18152
|
}, warningText, ":", " "), m)), /*#__PURE__*/React__namespace.createElement("div", {
|
|
18153
|
-
className: aphrodite.css(styles$
|
|
18153
|
+
className: aphrodite.css(styles$B.tail, tooltipAbove && styles$B.tailAbove)
|
|
18154
18154
|
})));
|
|
18155
18155
|
};
|
|
18156
18156
|
|
|
@@ -18178,20 +18178,20 @@ class Lint extends React__namespace.Component {
|
|
|
18178
18178
|
}
|
|
18179
18179
|
if (blockHighlight) {
|
|
18180
18180
|
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
18181
|
-
className: aphrodite.css(styles$
|
|
18182
|
-
}, this.renderLink(styles$
|
|
18181
|
+
className: aphrodite.css(styles$B.lintContainer, styles$B.lintContainerBlock)
|
|
18182
|
+
}, this.renderLink(styles$B.radioWidgetHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
|
|
18183
18183
|
}
|
|
18184
18184
|
if (inline) {
|
|
18185
18185
|
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
18186
|
-
className: aphrodite.css(styles$
|
|
18187
|
-
}, this.renderLink(styles$
|
|
18186
|
+
className: aphrodite.css(styles$B.lintContainer)
|
|
18187
|
+
}, this.renderLink(styles$B.inlineHoverTarget), /*#__PURE__*/React__namespace.createElement("span", null, children));
|
|
18188
18188
|
}
|
|
18189
18189
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
18190
|
-
className: aphrodite.css(styles$
|
|
18191
|
-
}, this.renderLink(styles$
|
|
18190
|
+
className: aphrodite.css(styles$B.lintContainer)
|
|
18191
|
+
}, this.renderLink(styles$B.hoverTarget), /*#__PURE__*/React__namespace.createElement("div", null, children));
|
|
18192
18192
|
}
|
|
18193
18193
|
}
|
|
18194
|
-
const styles$
|
|
18194
|
+
const styles$B = aphrodite.StyleSheet.create({
|
|
18195
18195
|
// This is the class of the outermost element.
|
|
18196
18196
|
// We use relative positioning so that the lint indicator can be
|
|
18197
18197
|
// positioned absolutely relative to the position of the linty container.
|
|
@@ -19012,8 +19012,6 @@ function getWidgetFromWidgetMap(widgetId, widgetMap) {
|
|
|
19012
19012
|
|
|
19013
19013
|
/**
|
|
19014
19014
|
* Get select widgets from a widget map.
|
|
19015
|
-
* Useful for multi-items that needs to split
|
|
19016
|
-
* one PerseusItem into several
|
|
19017
19015
|
*
|
|
19018
19016
|
* @param {ReadonlyArray<string>} widgetIds to extract
|
|
19019
19017
|
* @param {PerseusWidgetsMap} widgetMap to extract from
|
|
@@ -20618,7 +20616,7 @@ class Renderer extends React__namespace.Component {
|
|
|
20618
20616
|
};
|
|
20619
20617
|
const mobileInnerStyle = {
|
|
20620
20618
|
...innerStyle,
|
|
20621
|
-
...styles$
|
|
20619
|
+
...styles$A.mobileZoomableParentFix
|
|
20622
20620
|
};
|
|
20623
20621
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
20624
20622
|
key: state.key,
|
|
@@ -20758,7 +20756,7 @@ class Renderer extends React__namespace.Component {
|
|
|
20758
20756
|
};
|
|
20759
20757
|
const mobileInnerStyle = {
|
|
20760
20758
|
...innerStyle,
|
|
20761
|
-
...styles$
|
|
20759
|
+
...styles$A.mobileZoomableParentFix
|
|
20762
20760
|
};
|
|
20763
20761
|
const wrappedOutput = /*#__PURE__*/React__namespace.createElement("div", {
|
|
20764
20762
|
style: {
|
|
@@ -21221,7 +21219,7 @@ class Renderer extends React__namespace.Component {
|
|
|
21221
21219
|
return this.lastRenderedMarkdown;
|
|
21222
21220
|
}
|
|
21223
21221
|
}
|
|
21224
|
-
const styles$
|
|
21222
|
+
const styles$A = {
|
|
21225
21223
|
mobileZoomableParentFix: {
|
|
21226
21224
|
// NOTE(abdul): There is an issue where transform animations will
|
|
21227
21225
|
// cause the Zoomable component to disappear when running on the
|
|
@@ -22187,10 +22185,10 @@ class InputNumber extends React__namespace.Component {
|
|
|
22187
22185
|
// Note: This is _very_ similar to what `numeric-input.jsx` does. If
|
|
22188
22186
|
// you modify this, double-check if you also need to modify that
|
|
22189
22187
|
// component.
|
|
22190
|
-
const inputStyles = [styles$
|
|
22188
|
+
const inputStyles = [styles$z.default, this.props.size === "small" ? styles$z.small : null, this.props.rightAlign ? styles$z.rightAlign : styles$z.leftAlign];
|
|
22191
22189
|
// Unanswered
|
|
22192
22190
|
if (this.props.reviewMode && !this.props.currentValue) {
|
|
22193
|
-
inputStyles.push(styles$
|
|
22191
|
+
inputStyles.push(styles$z.answerStateUnanswered);
|
|
22194
22192
|
}
|
|
22195
22193
|
return /*#__PURE__*/React__namespace.createElement(InputWithExamples
|
|
22196
22194
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -22209,7 +22207,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
22209
22207
|
});
|
|
22210
22208
|
}
|
|
22211
22209
|
}
|
|
22212
|
-
const styles$
|
|
22210
|
+
const styles$z = aphrodite.StyleSheet.create({
|
|
22213
22211
|
default: {
|
|
22214
22212
|
width: 80,
|
|
22215
22213
|
height: "auto"
|
|
@@ -23377,7 +23375,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
|
|
|
23377
23375
|
const rects = this.state.cachedHighlightRects;
|
|
23378
23376
|
return /*#__PURE__*/React__namespace.createElement("div", null, rects.map((rect, index) => /*#__PURE__*/React__namespace.createElement("div", {
|
|
23379
23377
|
key: index,
|
|
23380
|
-
className: aphrodite.css(styles$
|
|
23378
|
+
className: aphrodite.css(styles$y.highlightRect),
|
|
23381
23379
|
style: {
|
|
23382
23380
|
// NOTE(mdr): We apply `position: absolute` here
|
|
23383
23381
|
// rather than in Aphrodite styles, because
|
|
@@ -23396,7 +23394,7 @@ class HighlightRenderer extends React__namespace.PureComponent {
|
|
|
23396
23394
|
})));
|
|
23397
23395
|
}
|
|
23398
23396
|
}
|
|
23399
|
-
const styles$
|
|
23397
|
+
const styles$y = aphrodite.StyleSheet.create({
|
|
23400
23398
|
highlightRect: {
|
|
23401
23399
|
background: "#fffabe" // highlighter yellow :)
|
|
23402
23400
|
}
|
|
@@ -23477,7 +23475,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
|
|
|
23477
23475
|
// TooltipContent wouldn't let me overwrite
|
|
23478
23476
|
// user-select and onClick
|
|
23479
23477
|
const content = /*#__PURE__*/React__namespace.createElement("div", {
|
|
23480
|
-
className: aphrodite.css(styles$
|
|
23478
|
+
className: aphrodite.css(styles$x.tooltipLabel),
|
|
23481
23479
|
onClick: this.props.onClick
|
|
23482
23480
|
}, this.props.label);
|
|
23483
23481
|
const style = {
|
|
@@ -23497,7 +23495,7 @@ class HighlightTooltip extends React__namespace.PureComponent {
|
|
|
23497
23495
|
}, /*#__PURE__*/React__namespace.createElement("div", null)));
|
|
23498
23496
|
}
|
|
23499
23497
|
}
|
|
23500
|
-
const styles$
|
|
23498
|
+
const styles$x = aphrodite.StyleSheet.create({
|
|
23501
23499
|
tooltipLabel: {
|
|
23502
23500
|
// Unlike most tooltip contents, we don't want this label to be
|
|
23503
23501
|
// selectable. Selecting it is not only unhelpful, but dangerous: if
|
|
@@ -24055,7 +24053,7 @@ class HighlightableContent extends React__namespace.PureComponent {
|
|
|
24055
24053
|
// starting point: https://phabricator.khanacademy.org/D35623?id=170698
|
|
24056
24054
|
const buildHighlight = r => this._buildHighlight(r);
|
|
24057
24055
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
24058
|
-
className: aphrodite.css(styles$
|
|
24056
|
+
className: aphrodite.css(styles$w.container),
|
|
24059
24057
|
ref: container => this._container = container
|
|
24060
24058
|
}, /*#__PURE__*/React__namespace.createElement("div", null, this.props.enabled && this._container && this._content && /*#__PURE__*/React__namespace.createElement(HighlightingUI, {
|
|
24061
24059
|
buildHighlight: buildHighlight,
|
|
@@ -24076,14 +24074,14 @@ class HighlightableContent extends React__namespace.PureComponent {
|
|
|
24076
24074
|
onAddHighlight: this._handleAddHighlight,
|
|
24077
24075
|
onRemoveHighlight: this._handleRemoveHighlight
|
|
24078
24076
|
})), /*#__PURE__*/React__namespace.createElement("div", {
|
|
24079
|
-
className: aphrodite.css(styles$
|
|
24077
|
+
className: aphrodite.css(styles$w.content),
|
|
24080
24078
|
ref: content => this._content = content
|
|
24081
24079
|
}, /*#__PURE__*/React__namespace.createElement(WordIndexer, {
|
|
24082
24080
|
onWordsUpdate: this._handleWordsUpdate
|
|
24083
24081
|
}, this.props.children)));
|
|
24084
24082
|
}
|
|
24085
24083
|
}
|
|
24086
|
-
const styles$
|
|
24084
|
+
const styles$w = aphrodite.StyleSheet.create({
|
|
24087
24085
|
// We render content with z-index 1, and highlights with z-index 0, so that
|
|
24088
24086
|
// content will receive the browser's native pointer events. (Highlights
|
|
24089
24087
|
// have their own magic code to manage hover detection, despite being
|
|
@@ -24505,7 +24503,7 @@ class LineHeightMeasurer extends React__namespace.Component {
|
|
|
24505
24503
|
}
|
|
24506
24504
|
render() {
|
|
24507
24505
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
24508
|
-
className: aphrodite.css(styles$
|
|
24506
|
+
className: aphrodite.css(styles$v.measurer),
|
|
24509
24507
|
"aria-hidden": "true"
|
|
24510
24508
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
24511
24509
|
ref: ref => this._line = ref,
|
|
@@ -24513,7 +24511,7 @@ class LineHeightMeasurer extends React__namespace.Component {
|
|
|
24513
24511
|
}, "Line Height Measurement"));
|
|
24514
24512
|
}
|
|
24515
24513
|
}
|
|
24516
|
-
const styles$
|
|
24514
|
+
const styles$v = aphrodite.StyleSheet.create({
|
|
24517
24515
|
measurer: {
|
|
24518
24516
|
position: "absolute",
|
|
24519
24517
|
top: 0,
|
|
@@ -25494,11 +25492,11 @@ const FocusRing = function (_ref) {
|
|
|
25494
25492
|
};
|
|
25495
25493
|
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
25496
25494
|
"data-testid": "focus-ring",
|
|
25497
|
-
className: aphrodite.css(styles$
|
|
25495
|
+
className: aphrodite.css(styles$u.ring),
|
|
25498
25496
|
style: style
|
|
25499
25497
|
}, children);
|
|
25500
25498
|
};
|
|
25501
|
-
const styles$
|
|
25499
|
+
const styles$u = aphrodite.StyleSheet.create({
|
|
25502
25500
|
ring: {
|
|
25503
25501
|
margin: "auto",
|
|
25504
25502
|
display: "inline-block",
|
|
@@ -25525,7 +25523,7 @@ function getChoiceLetter(pos, strings) {
|
|
|
25525
25523
|
}
|
|
25526
25524
|
|
|
25527
25525
|
const CHOICE_ICON_SIZE = 24;
|
|
25528
|
-
const styles$
|
|
25526
|
+
const styles$t = aphrodite.StyleSheet.create({
|
|
25529
25527
|
iconWrapper: {
|
|
25530
25528
|
display: "inline-block",
|
|
25531
25529
|
position: "relative"
|
|
@@ -25548,7 +25546,7 @@ const CrossOutLine = function (props) {
|
|
|
25548
25546
|
width: CROSS_OUT_LINE_SIZE,
|
|
25549
25547
|
height: CROSS_OUT_LINE_SIZE,
|
|
25550
25548
|
viewBox: `0 0 ${CROSS_OUT_LINE_SIZE} ${CROSS_OUT_LINE_SIZE}`,
|
|
25551
|
-
className: aphrodite.css(styles$
|
|
25549
|
+
className: aphrodite.css(styles$s.crossOutLine),
|
|
25552
25550
|
"data-testid": "choice-icon__cross-out-line"
|
|
25553
25551
|
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
25554
25552
|
// The line stretches from the bottom-left to top-right.
|
|
@@ -25563,7 +25561,7 @@ const CrossOutLine = function (props) {
|
|
|
25563
25561
|
strokeLinecap: "round"
|
|
25564
25562
|
}));
|
|
25565
25563
|
};
|
|
25566
|
-
const styles$
|
|
25564
|
+
const styles$s = aphrodite.StyleSheet.create({
|
|
25567
25565
|
crossOutLine: {
|
|
25568
25566
|
// Center the icon within the container.
|
|
25569
25567
|
position: "absolute",
|
|
@@ -25647,7 +25645,7 @@ const ChoiceIcon = function (props) {
|
|
|
25647
25645
|
} = props;
|
|
25648
25646
|
const dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, correct);
|
|
25649
25647
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
25650
|
-
className: aphrodite.css(styles$
|
|
25648
|
+
className: aphrodite.css(styles$t.iconWrapper)
|
|
25651
25649
|
}, /*#__PURE__*/React__namespace.createElement(FocusRing, {
|
|
25652
25650
|
color: wonderBlocksTokens.color.blue,
|
|
25653
25651
|
visible: focused || hovered,
|
|
@@ -25655,13 +25653,13 @@ const ChoiceIcon = function (props) {
|
|
|
25655
25653
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
25656
25654
|
style: dynamicStyles,
|
|
25657
25655
|
"data-testid": "choice-icon__library-choice-icon",
|
|
25658
|
-
className: aphrodite.css(styles$
|
|
25656
|
+
className: aphrodite.css(styles$r.circle, showCorrectness && correct && styles$r.circleCorrect, showCorrectness && !correct && styles$r.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$r.circleIncorrectAnswered)
|
|
25659
25657
|
// used in BaseRadio editMode to check
|
|
25660
25658
|
// if we actually clicked on the radio icon
|
|
25661
25659
|
,
|
|
25662
25660
|
"data-is-radio-icon": true
|
|
25663
25661
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
25664
|
-
className: aphrodite.css(styles$
|
|
25662
|
+
className: aphrodite.css(styles$r.innerWrapper)
|
|
25665
25663
|
}, /*#__PURE__*/React__namespace.createElement(ChoiceInner, {
|
|
25666
25664
|
pos: pos,
|
|
25667
25665
|
showCorrectness: showCorrectness,
|
|
@@ -25670,7 +25668,7 @@ const ChoiceIcon = function (props) {
|
|
|
25670
25668
|
color: dynamicStyles.borderColor
|
|
25671
25669
|
}));
|
|
25672
25670
|
};
|
|
25673
|
-
const styles$
|
|
25671
|
+
const styles$r = aphrodite.StyleSheet.create({
|
|
25674
25672
|
innerWrapper: {
|
|
25675
25673
|
width: CHOICE_ICON_SIZE,
|
|
25676
25674
|
height: CHOICE_ICON_SIZE,
|
|
@@ -25765,19 +25763,19 @@ const OptionStatus = function (props) {
|
|
|
25765
25763
|
}
|
|
25766
25764
|
let textStyle;
|
|
25767
25765
|
if (correct) {
|
|
25768
|
-
textStyle = styles$
|
|
25766
|
+
textStyle = styles$q.correct;
|
|
25769
25767
|
} else {
|
|
25770
25768
|
if (checked || previouslyAnswered) {
|
|
25771
|
-
textStyle = styles$
|
|
25769
|
+
textStyle = styles$q.incorrectAnswered;
|
|
25772
25770
|
} else {
|
|
25773
|
-
textStyle = styles$
|
|
25771
|
+
textStyle = styles$q.incorrect;
|
|
25774
25772
|
}
|
|
25775
25773
|
}
|
|
25776
25774
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
25777
|
-
className: aphrodite.css(styles$
|
|
25775
|
+
className: aphrodite.css(styles$q.text, textStyle)
|
|
25778
25776
|
}, renderText(checked, correct, crossedOut, strings));
|
|
25779
25777
|
};
|
|
25780
|
-
const styles$
|
|
25778
|
+
const styles$q = aphrodite.StyleSheet.create({
|
|
25781
25779
|
text: {
|
|
25782
25780
|
alignItems: "center",
|
|
25783
25781
|
display: "flex",
|
|
@@ -25846,8 +25844,8 @@ const Choice = function (props) {
|
|
|
25846
25844
|
crossedOut: updatedCrossedOut
|
|
25847
25845
|
});
|
|
25848
25846
|
}
|
|
25849
|
-
const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$
|
|
25850
|
-
const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$
|
|
25847
|
+
const descriptionClassName = classNames__default["default"]("description", aphrodite.css(styles$p.description));
|
|
25848
|
+
const rationaleClassName = classNames__default["default"]("perseus-radio-rationale-content", aphrodite.css(styles$p.rationale));
|
|
25851
25849
|
|
|
25852
25850
|
// We want to show the choices as dimmed out when the choices are disabled.
|
|
25853
25851
|
// However, we don't want to do this when we're in review mode in the
|
|
@@ -26014,7 +26012,7 @@ const Choice = function (props) {
|
|
|
26014
26012
|
"data-testid": `perseus-radio-rationale-content-${pos}`
|
|
26015
26013
|
}, rationale));
|
|
26016
26014
|
};
|
|
26017
|
-
const styles$
|
|
26015
|
+
const styles$p = aphrodite.StyleSheet.create({
|
|
26018
26016
|
description: {
|
|
26019
26017
|
display: "inline-block",
|
|
26020
26018
|
width: "100%"
|
|
@@ -26205,10 +26203,10 @@ const BaseRadio = function (_ref) {
|
|
|
26205
26203
|
const isMobile = apiOptions.isMobile;
|
|
26206
26204
|
const firstChoiceHighlighted = choices[0].highlighted;
|
|
26207
26205
|
const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
26208
|
-
const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$
|
|
26209
|
-
const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$
|
|
26206
|
+
const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$o.radio, styles$o.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$o.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$o.radioContainerLastHighlighted));
|
|
26207
|
+
const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$o.instructions, isMobile && styles$o.instructionsMobile));
|
|
26210
26208
|
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
|
|
26211
|
-
const responsiveClassName = aphrodite.css(styles$
|
|
26209
|
+
const responsiveClassName = aphrodite.css(styles$o.responsiveFieldset);
|
|
26212
26210
|
const fieldset = /*#__PURE__*/React__namespace.createElement("fieldset", {
|
|
26213
26211
|
className: `perseus-widget-radio-fieldset ${responsiveClassName}`
|
|
26214
26212
|
}, /*#__PURE__*/React__namespace.createElement("legend", {
|
|
@@ -26259,7 +26257,7 @@ const BaseRadio = function (_ref) {
|
|
|
26259
26257
|
const aphroditeClassName = checked => {
|
|
26260
26258
|
// Whether or not to show correctness borders
|
|
26261
26259
|
// for this choice and the next choice.
|
|
26262
|
-
return aphrodite.css(sharedStyles.aboveScratchpad, styles$
|
|
26260
|
+
return aphrodite.css(sharedStyles.aboveScratchpad, styles$o.item, styles$o.responsiveItem, checked && styles$o.selectedItem, checked && choice.highlighted && styles$o.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$o.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$o.nextHighlighted);
|
|
26263
26261
|
};
|
|
26264
26262
|
|
|
26265
26263
|
// HACK(abdulrahman): Preloads the selection-state
|
|
@@ -26324,10 +26322,10 @@ const BaseRadio = function (_ref) {
|
|
|
26324
26322
|
// Allow for horizontal scrolling if content is too wide, which may be
|
|
26325
26323
|
// an issue especially on phones.
|
|
26326
26324
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
26327
|
-
className: aphrodite.css(styles$
|
|
26325
|
+
className: aphrodite.css(styles$o.responsiveContainer)
|
|
26328
26326
|
}, fieldset);
|
|
26329
26327
|
};
|
|
26330
|
-
const styles$
|
|
26328
|
+
const styles$o = aphrodite.StyleSheet.create({
|
|
26331
26329
|
instructions: {
|
|
26332
26330
|
display: "block",
|
|
26333
26331
|
color: gray17,
|
|
@@ -27059,9 +27057,9 @@ class Categorizer extends React__namespace.Component {
|
|
|
27059
27057
|
indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
|
|
27060
27058
|
}
|
|
27061
27059
|
const table = /*#__PURE__*/React__namespace.createElement("table", {
|
|
27062
|
-
className: "categorizer-table " + aphrodite.css(styles$
|
|
27060
|
+
className: "categorizer-table " + aphrodite.css(styles$n.mobileTable)
|
|
27063
27061
|
}, /*#__PURE__*/React__namespace.createElement("thead", null, /*#__PURE__*/React__namespace.createElement("tr", null, /*#__PURE__*/React__namespace.createElement("td", {
|
|
27064
|
-
className: aphrodite.css(styles$
|
|
27062
|
+
className: aphrodite.css(styles$n.emptyHeaderCell)
|
|
27065
27063
|
}), this.props.categories.map((category, i) => {
|
|
27066
27064
|
// Array index is the correct key here, as that's
|
|
27067
27065
|
// how category grading actually works -- no way
|
|
@@ -27069,7 +27067,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
27069
27067
|
// middle. (If we later add that, this should be
|
|
27070
27068
|
// fixed.)
|
|
27071
27069
|
return /*#__PURE__*/React__namespace.createElement("th", {
|
|
27072
|
-
className: aphrodite.css(styles$
|
|
27070
|
+
className: aphrodite.css(styles$n.header),
|
|
27073
27071
|
key: i
|
|
27074
27072
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27075
27073
|
content: category,
|
|
@@ -27091,7 +27089,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
27091
27089
|
})), self.props.categories.map((catName, catNum) => {
|
|
27092
27090
|
const selected = self.props.values[itemNum] === catNum;
|
|
27093
27091
|
return /*#__PURE__*/React__namespace.createElement("td", {
|
|
27094
|
-
className: "category " + aphrodite.css(styles$
|
|
27092
|
+
className: "category " + aphrodite.css(styles$n.cell),
|
|
27095
27093
|
key: catNum
|
|
27096
27094
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
27097
27095
|
className: ClassNames.INTERACTIVE,
|
|
@@ -27106,7 +27104,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
27106
27104
|
onChange: () => this.onChange(itemNum, catNum),
|
|
27107
27105
|
onClick: e => e.stopPropagation()
|
|
27108
27106
|
}), !isMobile && /*#__PURE__*/React__namespace.createElement("span", {
|
|
27109
|
-
className: aphrodite.css(styles$
|
|
27107
|
+
className: aphrodite.css(styles$n.radioSpan, selected && styles$n.checkedRadioSpan, this.props.static && selected && styles$n.staticCheckedRadioSpan)
|
|
27110
27108
|
}, selected ? /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircle) : /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleThin))));
|
|
27111
27109
|
}));
|
|
27112
27110
|
/* eslint-enable max-len */
|
|
@@ -27118,7 +27116,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
27118
27116
|
"categorizer-container": true,
|
|
27119
27117
|
"static-mode": this.props.static
|
|
27120
27118
|
});
|
|
27121
|
-
const inlineStyles = this.props.apiOptions.isMobile ? [styles$
|
|
27119
|
+
const inlineStyles = this.props.apiOptions.isMobile ? [styles$n.fullBleedContainer] : [];
|
|
27122
27120
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
27123
27121
|
className: extraClassNames + " " + aphrodite.css(...inlineStyles)
|
|
27124
27122
|
}, table);
|
|
@@ -27130,7 +27128,7 @@ const pageMargin = 16;
|
|
|
27130
27128
|
|
|
27131
27129
|
// Stylesheets aren't directly testable
|
|
27132
27130
|
/* c8 ignore next */
|
|
27133
|
-
const styles$
|
|
27131
|
+
const styles$n = aphrodite.StyleSheet.create({
|
|
27134
27132
|
mobileTable: {
|
|
27135
27133
|
[mediaQueries.smOrSmaller]: {
|
|
27136
27134
|
minWidth: "auto"
|
|
@@ -27399,7 +27397,7 @@ class CSProgram extends React__namespace.Component {
|
|
|
27399
27397
|
// creator "went wild".
|
|
27400
27398
|
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
27401
27399
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
27402
|
-
className: aphrodite.css(styles$
|
|
27400
|
+
className: aphrodite.css(styles$m.widthOverride, styleContainer && styles$m.container)
|
|
27403
27401
|
}, /*#__PURE__*/React__namespace.createElement("iframe", {
|
|
27404
27402
|
sandbox: sandboxOptions,
|
|
27405
27403
|
src: url,
|
|
@@ -27409,7 +27407,7 @@ class CSProgram extends React__namespace.Component {
|
|
|
27409
27407
|
}));
|
|
27410
27408
|
}
|
|
27411
27409
|
}
|
|
27412
|
-
const styles$
|
|
27410
|
+
const styles$m = aphrodite.StyleSheet.create({
|
|
27413
27411
|
// Override the inherited width from the perseus paragraph class
|
|
27414
27412
|
// 820 is minimum width for 420px editor and 400px canvas
|
|
27415
27413
|
widthOverride: {
|
|
@@ -27460,7 +27458,7 @@ class Definition extends React__namespace.Component {
|
|
|
27460
27458
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.Popover, {
|
|
27461
27459
|
content: /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContentCore, {
|
|
27462
27460
|
color: "white",
|
|
27463
|
-
style: styles$
|
|
27461
|
+
style: styles$l.tooltipBody,
|
|
27464
27462
|
closeButtonVisible: true
|
|
27465
27463
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27466
27464
|
apiOptions: this.props.apiOptions,
|
|
@@ -27492,7 +27490,7 @@ class Definition extends React__namespace.Component {
|
|
|
27492
27490
|
});
|
|
27493
27491
|
}
|
|
27494
27492
|
}
|
|
27495
|
-
const styles$
|
|
27493
|
+
const styles$l = {
|
|
27496
27494
|
tooltipBody: {
|
|
27497
27495
|
color: wonderBlocksTokens.color.offBlack,
|
|
27498
27496
|
fontSize: 20,
|
|
@@ -27618,7 +27616,7 @@ class Dropdown extends React__namespace.Component {
|
|
|
27618
27616
|
key: "placeholder",
|
|
27619
27617
|
value: "0",
|
|
27620
27618
|
disabled: true,
|
|
27621
|
-
label: this.props.placeholder
|
|
27619
|
+
label: this.props.placeholder || " "
|
|
27622
27620
|
}), ...this.props.choices.map((choice, i) => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
27623
27621
|
key: String(i + 1),
|
|
27624
27622
|
value: String(i + 1),
|
|
@@ -27639,15 +27637,14 @@ class Dropdown extends React__namespace.Component {
|
|
|
27639
27637
|
}
|
|
27640
27638
|
}, this.props.visibleLabel && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
27641
27639
|
tag: "label",
|
|
27642
|
-
|
|
27640
|
+
htmlFor: ids.get("dropdown")
|
|
27643
27641
|
}, this.props.visibleLabel), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
27644
27642
|
id: ids.get("dropdown"),
|
|
27645
27643
|
placeholder: "",
|
|
27646
27644
|
onChange: value => this._handleChange(parseInt(value)),
|
|
27647
27645
|
selectedValue: String(this.props.selected),
|
|
27648
27646
|
disabled: this.props.apiOptions.readOnly,
|
|
27649
|
-
"aria-label": this.props.ariaLabel || this.context.strings.selectAnAnswer
|
|
27650
|
-
"aria-labelledby": ids.get("dropdown-label")
|
|
27647
|
+
"aria-label": this.props.ariaLabel || this.props.visibleLabel || this.context.strings.selectAnAnswer
|
|
27651
27648
|
// This is currently necessary for SRs to read the labels properly.
|
|
27652
27649
|
// However, WB is working on a change to add the "combobox" role to
|
|
27653
27650
|
// all dropdowns.
|
|
@@ -27761,7 +27758,7 @@ class Explanation extends React__namespace.Component {
|
|
|
27761
27758
|
marginRight: "-6px",
|
|
27762
27759
|
"white-space": "normal"
|
|
27763
27760
|
};
|
|
27764
|
-
const contentStyling = [styles$
|
|
27761
|
+
const contentStyling = [styles$k.content, this.state.expanded ? styles$k.contentExpanded : styles$k.contentCollapsed, allowTransition && (this.state.expanded ? styles$k.transitionExpanded : styles$k.transitionCollapsed)];
|
|
27765
27762
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
|
|
27766
27763
|
mockOnFirstRender: true,
|
|
27767
27764
|
scope: "explanation-widget"
|
|
@@ -27780,7 +27777,7 @@ class Explanation extends React__namespace.Component {
|
|
|
27780
27777
|
"aria-hidden": !this.state.expanded,
|
|
27781
27778
|
testId: "content-container"
|
|
27782
27779
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
27783
|
-
style: styles$
|
|
27780
|
+
style: styles$k.contentWrapper
|
|
27784
27781
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27785
27782
|
apiOptions: this.props.apiOptions,
|
|
27786
27783
|
content: this.props.explanation,
|
|
@@ -27793,7 +27790,7 @@ class Explanation extends React__namespace.Component {
|
|
|
27793
27790
|
const leftBorderSpacing = 23;
|
|
27794
27791
|
const verticalContentPadding = 10;
|
|
27795
27792
|
const arrowHeight = 14;
|
|
27796
|
-
const styles$
|
|
27793
|
+
const styles$k = aphrodite.StyleSheet.create({
|
|
27797
27794
|
content: {
|
|
27798
27795
|
borderLeft: "0px solid #ccc",
|
|
27799
27796
|
display: "inline-grid",
|
|
@@ -27879,15 +27876,15 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
27879
27876
|
nextQuestion
|
|
27880
27877
|
} = this.context.strings;
|
|
27881
27878
|
const answerBarStyle = {
|
|
27882
|
-
...styles$
|
|
27879
|
+
...styles$j.answerBar,
|
|
27883
27880
|
backgroundColor: answerBarState === "CORRECT" ? wonderBlocksTokens.color.offWhite : "white",
|
|
27884
27881
|
// Center the "Correct!" message only when there's no next question
|
|
27885
27882
|
justifyContent: answerBarState === "CORRECT" && !onNextQuestion ? "center" : "space-between"
|
|
27886
27883
|
};
|
|
27887
27884
|
const message = answerBarState === "INCORRECT" ? /*#__PURE__*/React__namespace.createElement("span", {
|
|
27888
|
-
style: styles$
|
|
27885
|
+
style: styles$j.text
|
|
27889
27886
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
27890
|
-
style: styles$
|
|
27887
|
+
style: styles$j.tryAgainIcon
|
|
27891
27888
|
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconTryAgain)), /*#__PURE__*/React__namespace.createElement("span", {
|
|
27892
27889
|
style: {
|
|
27893
27890
|
marginLeft: 8
|
|
@@ -27906,7 +27903,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
27906
27903
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
27907
27904
|
style: answerBarStyle
|
|
27908
27905
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
27909
|
-
style: styles$
|
|
27906
|
+
style: styles$j.text
|
|
27910
27907
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
27911
27908
|
style: {
|
|
27912
27909
|
fontSize: 28,
|
|
@@ -27928,7 +27925,7 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
27928
27925
|
}
|
|
27929
27926
|
}
|
|
27930
27927
|
const fontSize = 17;
|
|
27931
|
-
const styles$
|
|
27928
|
+
const styles$j = {
|
|
27932
27929
|
answerBar: {
|
|
27933
27930
|
display: "flex",
|
|
27934
27931
|
alignItems: "center",
|
|
@@ -28121,7 +28118,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
28121
28118
|
}));
|
|
28122
28119
|
gradeStatus = this.context.strings.incorrect;
|
|
28123
28120
|
}
|
|
28124
|
-
const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$
|
|
28121
|
+
const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$i.gradedGroupInSet) : aphrodite.css(styles$i.gradedGroup);
|
|
28125
28122
|
const classes = classNames__default["default"]({
|
|
28126
28123
|
[mobileClass]: apiOptions.isMobile,
|
|
28127
28124
|
"perseus-graded-group": true,
|
|
@@ -28140,7 +28137,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
28140
28137
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
28141
28138
|
className: classes
|
|
28142
28139
|
}, !!this.props.title && /*#__PURE__*/React__namespace.createElement("div", {
|
|
28143
|
-
className: aphrodite.css(styles$
|
|
28140
|
+
className: aphrodite.css(styles$i.title)
|
|
28144
28141
|
}, this.props.title), /*#__PURE__*/React__namespace.createElement(Renderer, _extends({}, this.props, {
|
|
28145
28142
|
ref: this.rendererRef,
|
|
28146
28143
|
apiOptions: {
|
|
@@ -28173,7 +28170,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
28173
28170
|
}, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
|
|
28174
28171
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
|
|
28175
28172
|
tabIndex: "0",
|
|
28176
|
-
className: aphrodite.css(styles$
|
|
28173
|
+
className: aphrodite.css(styles$i.explanationTitle),
|
|
28177
28174
|
onClick: () => this.setState({
|
|
28178
28175
|
showHint: false
|
|
28179
28176
|
}),
|
|
@@ -28205,7 +28202,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
28205
28202
|
showHint: true
|
|
28206
28203
|
});
|
|
28207
28204
|
},
|
|
28208
|
-
className: aphrodite.css(styles$
|
|
28205
|
+
className: aphrodite.css(styles$i.showHintLink)
|
|
28209
28206
|
}, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React__namespace.createElement(GradedGroupAnswerBar, {
|
|
28210
28207
|
apiOptions: apiOptions,
|
|
28211
28208
|
answerBarState: answerBarState,
|
|
@@ -28217,7 +28214,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
28217
28214
|
const traverseChildWidgets$2 = function (props, traverseRenderer) {
|
|
28218
28215
|
return ___default["default"].extend({}, props, traverseRenderer(props));
|
|
28219
28216
|
};
|
|
28220
|
-
const styles$
|
|
28217
|
+
const styles$i = aphrodite.StyleSheet.create({
|
|
28221
28218
|
gradedGroupInSet: {
|
|
28222
28219
|
// Reset a few desktop-only styles that come from graded-group.less
|
|
28223
28220
|
marginLeft: 0,
|
|
@@ -28298,20 +28295,20 @@ class Indicators extends React__namespace.Component {
|
|
|
28298
28295
|
return /*#__PURE__*/React__namespace.createElement("ul", {
|
|
28299
28296
|
// reduntantly add class name for use in .less files--
|
|
28300
28297
|
// the styles object key gets hashed
|
|
28301
|
-
className: classNames__default["default"](aphrodite.css(styles$
|
|
28298
|
+
className: classNames__default["default"](aphrodite.css(styles$h.indicatorContainer), "indicatorContainer")
|
|
28302
28299
|
}, this.props.gradedGroups.map((_ref, i) => {
|
|
28303
28300
|
let {
|
|
28304
28301
|
title
|
|
28305
28302
|
} = _ref;
|
|
28306
28303
|
return /*#__PURE__*/React__namespace.createElement("li", {
|
|
28307
|
-
className: aphrodite.css(styles$
|
|
28304
|
+
className: aphrodite.css(styles$h.indicator),
|
|
28308
28305
|
key: title
|
|
28309
28306
|
}, /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
|
|
28310
28307
|
role: "button",
|
|
28311
28308
|
"aria-label": this.context.strings.skipToTitle({
|
|
28312
28309
|
title
|
|
28313
28310
|
}),
|
|
28314
|
-
style: styles$
|
|
28311
|
+
style: styles$h.indicatorButton,
|
|
28315
28312
|
onClick: () => this.props.onChangeCurrentGroup(i),
|
|
28316
28313
|
onKeyDown: e => this.handleKeyDown(e, i)
|
|
28317
28314
|
}, _ref2 => {
|
|
@@ -28321,9 +28318,9 @@ class Indicators extends React__namespace.Component {
|
|
|
28321
28318
|
pressed
|
|
28322
28319
|
} = _ref2;
|
|
28323
28320
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
28324
|
-
style: [styles$
|
|
28321
|
+
style: [styles$h.indicatorDot, (hovered || focused || pressed) && styles$h.indicatorDotFocused]
|
|
28325
28322
|
}, i === this.props.currentGroup && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
28326
|
-
style: styles$
|
|
28323
|
+
style: styles$h.indicatorDotActive
|
|
28327
28324
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
28328
28325
|
className: aphrodite.css(a11y.srOnly)
|
|
28329
28326
|
}, this.context.strings.current)));
|
|
@@ -28403,7 +28400,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
28403
28400
|
} = getDependencies();
|
|
28404
28401
|
if (JIPT.useJIPT && this.props.gradedGroups.length > 1) {
|
|
28405
28402
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
28406
|
-
className: aphrodite.css(styles$
|
|
28403
|
+
className: aphrodite.css(styles$h.container)
|
|
28407
28404
|
}, this.props.gradedGroups.map((gradedGroup, i) => {
|
|
28408
28405
|
return (
|
|
28409
28406
|
/*#__PURE__*/
|
|
@@ -28426,13 +28423,13 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
28426
28423
|
const numGroups = this.props.gradedGroups.length;
|
|
28427
28424
|
const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
|
|
28428
28425
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
28429
|
-
className: aphrodite.css(styles$
|
|
28426
|
+
className: aphrodite.css(styles$h.container)
|
|
28430
28427
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
28431
|
-
className: aphrodite.css(styles$
|
|
28428
|
+
className: aphrodite.css(styles$h.top)
|
|
28432
28429
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
28433
|
-
className: aphrodite.css(styles$
|
|
28430
|
+
className: aphrodite.css(styles$h.title)
|
|
28434
28431
|
}, currentGroup.title), /*#__PURE__*/React__namespace.createElement("div", {
|
|
28435
|
-
className: aphrodite.css(styles$
|
|
28432
|
+
className: aphrodite.css(styles$h.spacer)
|
|
28436
28433
|
}), /*#__PURE__*/React__namespace.createElement(Indicators, {
|
|
28437
28434
|
currentGroup: this.state.currentGroup,
|
|
28438
28435
|
gradedGroups: this.props.gradedGroups,
|
|
@@ -28470,7 +28467,7 @@ var GradedGroupSet$1 = {
|
|
|
28470
28467
|
tracking: "all",
|
|
28471
28468
|
isLintable: true
|
|
28472
28469
|
};
|
|
28473
|
-
const styles$
|
|
28470
|
+
const styles$h = aphrodite.StyleSheet.create({
|
|
28474
28471
|
top: {
|
|
28475
28472
|
display: "flex",
|
|
28476
28473
|
flexDirection: "row"
|
|
@@ -28576,7 +28573,7 @@ class ButtonGroup extends React__namespace.Component {
|
|
|
28576
28573
|
id: "" + i,
|
|
28577
28574
|
ref: "button" + i,
|
|
28578
28575
|
key: "" + i,
|
|
28579
|
-
className: aphrodite.css(styles$
|
|
28576
|
+
className: aphrodite.css(styles$g.buttonStyle, button.value === value && styles$g.selectedStyle),
|
|
28580
28577
|
onClick: () => this.toggleSelect(button.value)
|
|
28581
28578
|
}, button.content || "" + button.value);
|
|
28582
28579
|
});
|
|
@@ -28589,7 +28586,7 @@ class ButtonGroup extends React__namespace.Component {
|
|
|
28589
28586
|
}, buttons);
|
|
28590
28587
|
}
|
|
28591
28588
|
}
|
|
28592
|
-
const styles$
|
|
28589
|
+
const styles$g = aphrodite.StyleSheet.create({
|
|
28593
28590
|
buttonStyle: {
|
|
28594
28591
|
backgroundColor: "white",
|
|
28595
28592
|
border: "1px solid #ccc",
|
|
@@ -31967,7 +31964,7 @@ const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
|
|
|
31967
31964
|
width: "24",
|
|
31968
31965
|
height: "24",
|
|
31969
31966
|
viewBox: "0 0 24 24",
|
|
31970
|
-
className: aphrodite.css(styles$
|
|
31967
|
+
className: aphrodite.css(styles$f.icon)
|
|
31971
31968
|
}, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
|
|
31972
31969
|
id: "a",
|
|
31973
31970
|
d: "M7.401 10.035c-1.424.748-2.599 1.905-3.544 " + "3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 " + "12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 " + "1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-" + "3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 " + "0 0 0 0 6z"
|
|
@@ -31998,7 +31995,7 @@ const HiddenIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
|
|
|
31998
31995
|
width: "24",
|
|
31999
31996
|
height: "24",
|
|
32000
31997
|
viewBox: "0 0 24 24",
|
|
32001
|
-
className: aphrodite.css(styles$
|
|
31998
|
+
className: aphrodite.css(styles$f.icon)
|
|
32002
31999
|
}, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
|
|
32003
32000
|
id: "a",
|
|
32004
32001
|
d: "M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 " + "7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 " + "1.028c-.945-1.574-2.12-2.73-3.544-3.48.258." + "604.401 1.268.401 1.966 0 1.02-.305 " + "1.967-.828 2.757l2.535 2.536a1 1 0 0 " + "1-1.414 1.414l-12-12a1 1 0 0 1 " + "1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 " + "0-4.001-4.001l4 4.001zM6.072 8.486l2.976 " + "2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 " + "0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 " + "3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 " + "2.363-3.085 3.929-4z"
|
|
@@ -32037,20 +32034,20 @@ const HUD = _ref => {
|
|
|
32037
32034
|
let state;
|
|
32038
32035
|
let icon;
|
|
32039
32036
|
if (enabled) {
|
|
32040
|
-
state = styles$
|
|
32037
|
+
state = styles$f.enabled;
|
|
32041
32038
|
icon = /*#__PURE__*/React__namespace.createElement(VisibleIcon, null);
|
|
32042
32039
|
} else {
|
|
32043
|
-
state = styles$
|
|
32040
|
+
state = styles$f.disabled;
|
|
32044
32041
|
icon = /*#__PURE__*/React__namespace.createElement(HiddenIcon, null);
|
|
32045
32042
|
}
|
|
32046
32043
|
return /*#__PURE__*/React__namespace.createElement("button", {
|
|
32047
|
-
className: aphrodite.css(styles$
|
|
32044
|
+
className: aphrodite.css(styles$f.hud, fixedPosition && styles$f.hudFixedPosition, state),
|
|
32048
32045
|
onClick: e => {
|
|
32049
32046
|
onClick();
|
|
32050
32047
|
}
|
|
32051
32048
|
}, icon, message);
|
|
32052
32049
|
};
|
|
32053
|
-
const styles$
|
|
32050
|
+
const styles$f = aphrodite.StyleSheet.create({
|
|
32054
32051
|
hud: {
|
|
32055
32052
|
boxSizing: "border-box",
|
|
32056
32053
|
height: 36,
|
|
@@ -32103,16 +32100,16 @@ const styles$g = aphrodite.StyleSheet.create({
|
|
|
32103
32100
|
const InfoTipBase = props => {
|
|
32104
32101
|
return /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
32105
32102
|
content: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.Body, {
|
|
32106
|
-
style: styles$
|
|
32103
|
+
style: styles$e.body
|
|
32107
32104
|
}, props.children),
|
|
32108
32105
|
placement: "right"
|
|
32109
32106
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
|
|
32110
32107
|
size: "small",
|
|
32111
32108
|
icon: questionIcon__default["default"],
|
|
32112
|
-
style: styles$
|
|
32109
|
+
style: styles$e.spacingLeft
|
|
32113
32110
|
}));
|
|
32114
32111
|
};
|
|
32115
|
-
const styles$
|
|
32112
|
+
const styles$e = aphrodite.StyleSheet.create({
|
|
32116
32113
|
spacingLeft: {
|
|
32117
32114
|
marginInlineStart: wonderBlocksTokens.spacing.xxxSmall_4
|
|
32118
32115
|
},
|
|
@@ -32188,7 +32185,7 @@ class MultiButtonGroup extends React__namespace.Component {
|
|
|
32188
32185
|
id: "" + i,
|
|
32189
32186
|
key: "" + i,
|
|
32190
32187
|
ref: "button" + i,
|
|
32191
|
-
className: aphrodite.css(styles$
|
|
32188
|
+
className: aphrodite.css(styles$d.buttonStyle, selected && styles$d.selectedStyle),
|
|
32192
32189
|
onClick: () => this.toggleSelect(button.value)
|
|
32193
32190
|
}, button.content || "" + button.value);
|
|
32194
32191
|
});
|
|
@@ -32201,7 +32198,7 @@ class MultiButtonGroup extends React__namespace.Component {
|
|
|
32201
32198
|
}, buttons);
|
|
32202
32199
|
}
|
|
32203
32200
|
}
|
|
32204
|
-
const styles$
|
|
32201
|
+
const styles$d = aphrodite.StyleSheet.create({
|
|
32205
32202
|
buttonStyle: {
|
|
32206
32203
|
backgroundColor: "white",
|
|
32207
32204
|
border: "1px solid #ccc",
|
|
@@ -32534,11 +32531,39 @@ const LegacyGrid = _ref => {
|
|
|
32534
32531
|
return null;
|
|
32535
32532
|
};
|
|
32536
32533
|
|
|
32534
|
+
/**
|
|
32535
|
+
* The Perseus "data schema" file.
|
|
32536
|
+
*
|
|
32537
|
+
* This file, and the types in it, represents the "data schema" that Perseus
|
|
32538
|
+
* uses. The @khanacademy/perseus-editor package edits and produces objects
|
|
32539
|
+
* that conform to the types in this file. Similarly, the top-level renderers
|
|
32540
|
+
* in @khanacademy/perseus, consume objects that conform to these types.
|
|
32541
|
+
*
|
|
32542
|
+
* WARNING: This file should not import any types from elsewhere so that it is
|
|
32543
|
+
* easy to reason about changes that alter the Perseus schema. This helps
|
|
32544
|
+
* ensure that it is not changed accidentally when upgrading a dependant
|
|
32545
|
+
* package or other part of Perseus code. Note that TypeScript does type
|
|
32546
|
+
* checking via something called "structural typing". This means that as long
|
|
32547
|
+
* as the shape of a type matches, the name it goes by doesn't matter. As a
|
|
32548
|
+
* result, a `Coord` type that looks like this `[x: number, y: number]` is
|
|
32549
|
+
* _identical_, in TypeScript's eyes, to this `Vector2` type `[x: number, y:
|
|
32550
|
+
* number]`. Also, with tuples, the labels for each entry is ignored, so `[x:
|
|
32551
|
+
* number, y: number]` is compatible with `[min: number, max: number]`. The
|
|
32552
|
+
* labels are for humans, not TypeScript. :)
|
|
32553
|
+
*
|
|
32554
|
+
* If you make changes to types in this file, be very sure that:
|
|
32555
|
+
*
|
|
32556
|
+
* a) the changes are backwards compatible. If they are not, old data from
|
|
32557
|
+
* previous versions of the "schema" could become unrenderable, or worse,
|
|
32558
|
+
* introduce hard-to-diagnose bugs.
|
|
32559
|
+
* b) the parsing code (`util/parse-perseus-json/`) is updated to handle
|
|
32560
|
+
* the new format _as well as_ the old format.
|
|
32561
|
+
*/
|
|
32562
|
+
|
|
32537
32563
|
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
32538
|
-
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
32539
32564
|
|
|
32540
|
-
//
|
|
32541
|
-
|
|
32565
|
+
// Same name as Mafs
|
|
32566
|
+
|
|
32542
32567
|
/**
|
|
32543
32568
|
* Our core set of Perseus widgets.
|
|
32544
32569
|
*
|
|
@@ -32582,6 +32607,7 @@ const LegacyGrid = _ref => {
|
|
|
32582
32607
|
*
|
|
32583
32608
|
* @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
|
|
32584
32609
|
*/
|
|
32610
|
+
|
|
32585
32611
|
/**
|
|
32586
32612
|
* A map of widget IDs to widget options. This is most often used as the type
|
|
32587
32613
|
* for a set of widgets defined in a `PerseusItem` but can also be useful to
|
|
@@ -32594,6 +32620,7 @@ const LegacyGrid = _ref => {
|
|
|
32594
32620
|
* @see {@link PerseusWidgetTypes} additional widgets can be added to this map type
|
|
32595
32621
|
* by augmenting the PerseusWidgetTypes with new widget types!
|
|
32596
32622
|
*/
|
|
32623
|
+
|
|
32597
32624
|
/**
|
|
32598
32625
|
* A "PerseusItem" is a classic Perseus item. It is rendered by the
|
|
32599
32626
|
* `ServerItemRenderer` and the layout is pre-set.
|
|
@@ -32601,18 +32628,12 @@ const LegacyGrid = _ref => {
|
|
|
32601
32628
|
* To render more complex Perseus items, see the `Item` type in the multi item
|
|
32602
32629
|
* area.
|
|
32603
32630
|
*/
|
|
32631
|
+
|
|
32604
32632
|
/**
|
|
32605
32633
|
* A "PerseusArticle" is an item that is meant to be rendered as an article.
|
|
32606
32634
|
* This item is never scored and is rendered by the `ArticleRenderer`.
|
|
32607
32635
|
*/
|
|
32608
|
-
|
|
32609
|
-
* A "MultiItem" is an advanced Perseus item. It is rendered by the
|
|
32610
|
-
* `MultiRenderer` and you can control the layout of individual parts of the
|
|
32611
|
-
* item.
|
|
32612
|
-
*
|
|
32613
|
-
* @deprecated MultiItem support is slated for removal in a future Perseus
|
|
32614
|
-
* release.
|
|
32615
|
-
*/
|
|
32636
|
+
|
|
32616
32637
|
const ItemExtras = [
|
|
32617
32638
|
// The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
|
|
32618
32639
|
"calculator",
|
|
@@ -39071,7 +39092,7 @@ const HideAnswersToggle = props => {
|
|
|
39071
39092
|
strings
|
|
39072
39093
|
} = usePerseusI18n();
|
|
39073
39094
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
39074
|
-
style: styles$
|
|
39095
|
+
style: styles$c.switchWrapper
|
|
39075
39096
|
}, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
|
|
39076
39097
|
id: switchId,
|
|
39077
39098
|
checked: props.areAnswersHidden,
|
|
@@ -39083,7 +39104,7 @@ const HideAnswersToggle = props => {
|
|
|
39083
39104
|
tag: "label"
|
|
39084
39105
|
}, strings.hideAnswersToggleLabel));
|
|
39085
39106
|
};
|
|
39086
|
-
const styles$
|
|
39107
|
+
const styles$c = aphrodite.StyleSheet.create({
|
|
39087
39108
|
switchWrapper: {
|
|
39088
39109
|
display: "flex",
|
|
39089
39110
|
flexDirection: "row",
|
|
@@ -39141,7 +39162,7 @@ const AnswerPill = props => {
|
|
|
39141
39162
|
id: idFactory.get("perseus-label-image-widget-answer-pill"),
|
|
39142
39163
|
onClick: correct ? undefined : onClick,
|
|
39143
39164
|
ref: ref,
|
|
39144
|
-
style: [style, popperStyle, styles$
|
|
39165
|
+
style: [style, popperStyle, styles$b.pill, correct && styles$b.correct, incorrect && styles$b.incorrect, (focused || hovered) && BringToFront]
|
|
39145
39166
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
39146
39167
|
content: answerString,
|
|
39147
39168
|
strings: strings,
|
|
@@ -39149,7 +39170,7 @@ const AnswerPill = props => {
|
|
|
39149
39170
|
}));
|
|
39150
39171
|
});
|
|
39151
39172
|
};
|
|
39152
|
-
const styles$
|
|
39173
|
+
const styles$b = aphrodite.StyleSheet.create({
|
|
39153
39174
|
correct: {
|
|
39154
39175
|
// WB green darkened by 18%
|
|
39155
39176
|
backgroundColor: "#00880b"
|
|
@@ -39215,25 +39236,25 @@ class Marker extends React__namespace.Component {
|
|
|
39215
39236
|
icon: iconNull
|
|
39216
39237
|
};
|
|
39217
39238
|
if (showCorrectness) {
|
|
39218
|
-
iconStyles = [styles$
|
|
39239
|
+
iconStyles = [styles$a.markerGraded, showCorrectness === "correct" ? styles$a.markerCorrect : styles$a.markerIncorrect, isOpen && styles$a.markerSelected];
|
|
39219
39240
|
args = {
|
|
39220
39241
|
...args,
|
|
39221
39242
|
icon: showCorrectness === "correct" ? iconCheck : iconMinus
|
|
39222
39243
|
};
|
|
39223
39244
|
} else if (selectedAnswers && selectedAnswers.length > 0) {
|
|
39224
|
-
iconStyles = [styles$
|
|
39245
|
+
iconStyles = [styles$a.markerFilled, isOpen && styles$a.markerSelected];
|
|
39225
39246
|
} else if (isOpen) {
|
|
39226
|
-
iconStyles = [styles$
|
|
39247
|
+
iconStyles = [styles$a.markerSelected];
|
|
39227
39248
|
args = {
|
|
39228
39249
|
...args,
|
|
39229
39250
|
icon: iconChevronDown,
|
|
39230
39251
|
size: 8
|
|
39231
39252
|
};
|
|
39232
39253
|
} else if (showPulsate) {
|
|
39233
|
-
iconStyles = [styles$
|
|
39254
|
+
iconStyles = [styles$a.markerPulsateBase, this._mounted && shouldReduceMotion() ? showPulsate && styles$a.markerUnfilledPulsateOnce : showPulsate && styles$a.markerUnfilledPulsateInfinite];
|
|
39234
39255
|
}
|
|
39235
39256
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
39236
|
-
style: [styles$
|
|
39257
|
+
style: [styles$a.markerIcon, iconStyles],
|
|
39237
39258
|
ref: node => this._icon = node
|
|
39238
39259
|
}, /*#__PURE__*/React__namespace.createElement(Icon, args));
|
|
39239
39260
|
}
|
|
@@ -39254,7 +39275,7 @@ class Marker extends React__namespace.Component {
|
|
|
39254
39275
|
const markerDisabled = showCorrectness === "correct";
|
|
39255
39276
|
const active = hovered || focused;
|
|
39256
39277
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
39257
|
-
style: [styles$
|
|
39278
|
+
style: [styles$a.marker, active && !markerDisabled && styles$a.markerActive],
|
|
39258
39279
|
"aria-label": markerDisabled ? this.context.strings.correctExcited : label
|
|
39259
39280
|
}, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React__namespace.createElement(AnswerPill, {
|
|
39260
39281
|
selectedAnswers: selected,
|
|
@@ -39267,7 +39288,7 @@ class Marker extends React__namespace.Component {
|
|
|
39267
39288
|
}));
|
|
39268
39289
|
}
|
|
39269
39290
|
}
|
|
39270
|
-
const styles$
|
|
39291
|
+
const styles$a = aphrodite.StyleSheet.create({
|
|
39271
39292
|
marker: {
|
|
39272
39293
|
position: "absolute",
|
|
39273
39294
|
backgroundColor: wonderBlocksTokens.color.white,
|
|
@@ -39861,13 +39882,13 @@ class LabelImage extends React__namespace.Component {
|
|
|
39861
39882
|
const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
|
|
39862
39883
|
const choicesString = strings.choices;
|
|
39863
39884
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
39864
|
-
className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$
|
|
39885
|
+
className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$9.instructions))
|
|
39865
39886
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
39866
|
-
className: aphrodite.css(styles$
|
|
39887
|
+
className: aphrodite.css(styles$9.instructionsCaption)
|
|
39867
39888
|
}, promptString, " ", !hideChoices && choicesString), !hideChoices && /*#__PURE__*/React__namespace.createElement("div", {
|
|
39868
|
-
className: aphrodite.css(styles$
|
|
39889
|
+
className: aphrodite.css(styles$9.instructionsChoices)
|
|
39869
39890
|
}, choices.map((choice, index) => /*#__PURE__*/React__namespace.createElement("div", {
|
|
39870
|
-
className: aphrodite.css(styles$
|
|
39891
|
+
className: aphrodite.css(styles$9.instructionsChoice),
|
|
39871
39892
|
key: index
|
|
39872
39893
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
39873
39894
|
content: choice,
|
|
@@ -39885,20 +39906,20 @@ class LabelImage extends React__namespace.Component {
|
|
|
39885
39906
|
activeMarkerIndex
|
|
39886
39907
|
} = this.state;
|
|
39887
39908
|
return /*#__PURE__*/React__namespace.createElement("div", null, this.renderInstructions(), /*#__PURE__*/React__namespace.createElement("div", {
|
|
39888
|
-
className: aphrodite.css(styles$
|
|
39909
|
+
className: aphrodite.css(styles$9.markersCanvas),
|
|
39889
39910
|
style: {
|
|
39890
39911
|
maxWidth: imageWidth,
|
|
39891
39912
|
maxHeight: imageHeight
|
|
39892
39913
|
}
|
|
39893
39914
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
39894
|
-
className: aphrodite.css(styles$
|
|
39915
|
+
className: aphrodite.css(styles$9.imageContainer,
|
|
39895
39916
|
// Ensure image interaction is disabled while answer
|
|
39896
39917
|
// choices popup is visible. This addresses specific
|
|
39897
39918
|
// case where user may click on question image to
|
|
39898
39919
|
// dismiss the popup. If the image is larger in size
|
|
39899
39920
|
// than its rendered in the widget, this would
|
|
39900
39921
|
// result in a zoom of the image.
|
|
39901
|
-
activeMarkerIndex !== -1 && styles$
|
|
39922
|
+
activeMarkerIndex !== -1 && styles$9.imageInteractionDisabled)
|
|
39902
39923
|
}, /*#__PURE__*/React__namespace.createElement(context$1.Consumer, null, _ref3 => {
|
|
39903
39924
|
let {
|
|
39904
39925
|
setAssetStatus
|
|
@@ -39924,7 +39945,7 @@ class LabelImage extends React__namespace.Component {
|
|
|
39924
39945
|
}));
|
|
39925
39946
|
}
|
|
39926
39947
|
}
|
|
39927
|
-
const styles$
|
|
39948
|
+
const styles$9 = aphrodite.StyleSheet.create({
|
|
39928
39949
|
instructions: {
|
|
39929
39950
|
paddingBottom: 16
|
|
39930
39951
|
},
|
|
@@ -40012,7 +40033,7 @@ class Placeholder extends React__namespace.Component {
|
|
|
40012
40033
|
const {
|
|
40013
40034
|
layout
|
|
40014
40035
|
} = this.props;
|
|
40015
|
-
const className = aphrodite.css(styles$
|
|
40036
|
+
const className = aphrodite.css(styles$8.card, styles$8.placeholder, layout === "horizontal" && styles$8.horizontalCard);
|
|
40016
40037
|
const style = {
|
|
40017
40038
|
width: this.props.width,
|
|
40018
40039
|
height: this.props.height
|
|
@@ -40219,7 +40240,7 @@ class Draggable extends React__namespace.Component {
|
|
|
40219
40240
|
// We need to keep backwards compatbility with rules specified directly
|
|
40220
40241
|
// in CSS. Hence the hacky tacking on of manual classNames.
|
|
40221
40242
|
// See sortable.less for details.
|
|
40222
|
-
let className = aphrodite.css(styles$
|
|
40243
|
+
let className = aphrodite.css(styles$8.card, styles$8.draggable, layout === "horizontal" && styles$8.horizontalCard, layout === "vertical" && styles$8.verticalCard, type === ItemState.DRAGGING && styles$8.dragging, type === ItemState.DISABLED && styles$8.disabled, !includePadding && styles$8.unpaddedCard) + " " + ClassNames.INTERACTIVE + " perseus-sortable-draggable";
|
|
40223
40244
|
if (!includePadding) {
|
|
40224
40245
|
className += " perseus-sortable-draggable-unpadded";
|
|
40225
40246
|
}
|
|
@@ -40557,7 +40578,7 @@ class Sortable extends React__namespace.Component {
|
|
|
40557
40578
|
} = this.props;
|
|
40558
40579
|
// We need to keep backwards compatbility with rules specified directly
|
|
40559
40580
|
// in CSS. See sortable.less for details.
|
|
40560
|
-
const className = aphrodite.css(styles$
|
|
40581
|
+
const className = aphrodite.css(styles$8.sortable) + " perseus-sortable";
|
|
40561
40582
|
const syncWidth = this.props.constraints?.width || layout === "vertical";
|
|
40562
40583
|
const syncHeight = this.props.constraints?.height || layout === "horizontal";
|
|
40563
40584
|
___default["default"].each(this.state.items, function (item, i, items) {
|
|
@@ -40643,7 +40664,7 @@ class Sortable extends React__namespace.Component {
|
|
|
40643
40664
|
}, cards);
|
|
40644
40665
|
}
|
|
40645
40666
|
}
|
|
40646
|
-
const styles$
|
|
40667
|
+
const styles$8 = aphrodite.StyleSheet.create({
|
|
40647
40668
|
sortable: {
|
|
40648
40669
|
boxSizing: "border-box",
|
|
40649
40670
|
float: "left",
|
|
@@ -40839,25 +40860,25 @@ class Matcher extends React__namespace.Component {
|
|
|
40839
40860
|
};
|
|
40840
40861
|
const cellMarginPx = this.props.apiOptions.isMobile ? 8 : 5;
|
|
40841
40862
|
return /*#__PURE__*/React__namespace.createElement("table", {
|
|
40842
|
-
className: aphrodite.css(styles$
|
|
40863
|
+
className: aphrodite.css(styles$7.widget) + " " + HACKY_CSS_CLASSNAME
|
|
40843
40864
|
}, /*#__PURE__*/React__namespace.createElement("tbody", null, showLabels && /*#__PURE__*/React__namespace.createElement("tr", {
|
|
40844
|
-
className: aphrodite.css(styles$
|
|
40865
|
+
className: aphrodite.css(styles$7.row)
|
|
40845
40866
|
}, /*#__PURE__*/React__namespace.createElement("th", {
|
|
40846
|
-
className: aphrodite.css(styles$
|
|
40867
|
+
className: aphrodite.css(styles$7.column, styles$7.columnLabel)
|
|
40847
40868
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
40848
40869
|
content: this.props.labels[0] || "...",
|
|
40849
40870
|
linterContext: this.props.linterContext,
|
|
40850
40871
|
strings: this.context.strings
|
|
40851
40872
|
})), /*#__PURE__*/React__namespace.createElement("th", {
|
|
40852
|
-
className: aphrodite.css(styles$
|
|
40873
|
+
className: aphrodite.css(styles$7.column, styles$7.columnRight, styles$7.columnLabel)
|
|
40853
40874
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
40854
40875
|
content: this.props.labels[1] || "...",
|
|
40855
40876
|
linterContext: this.props.linterContext,
|
|
40856
40877
|
strings: this.context.strings
|
|
40857
40878
|
}))), /*#__PURE__*/React__namespace.createElement("tr", {
|
|
40858
|
-
className: aphrodite.css(styles$
|
|
40879
|
+
className: aphrodite.css(styles$7.row)
|
|
40859
40880
|
}, /*#__PURE__*/React__namespace.createElement("td", {
|
|
40860
|
-
className: aphrodite.css(styles$
|
|
40881
|
+
className: aphrodite.css(styles$7.column)
|
|
40861
40882
|
}, /*#__PURE__*/React__namespace.createElement(Sortable, {
|
|
40862
40883
|
options: left,
|
|
40863
40884
|
layout: "vertical",
|
|
@@ -40872,7 +40893,7 @@ class Matcher extends React__namespace.Component {
|
|
|
40872
40893
|
,
|
|
40873
40894
|
ref: "left"
|
|
40874
40895
|
})), /*#__PURE__*/React__namespace.createElement("td", {
|
|
40875
|
-
className: aphrodite.css(styles$
|
|
40896
|
+
className: aphrodite.css(styles$7.column, styles$7.columnRight)
|
|
40876
40897
|
}, /*#__PURE__*/React__namespace.createElement(Sortable, {
|
|
40877
40898
|
options: right,
|
|
40878
40899
|
layout: "vertical",
|
|
@@ -40890,7 +40911,7 @@ class Matcher extends React__namespace.Component {
|
|
|
40890
40911
|
}
|
|
40891
40912
|
const padding = 5;
|
|
40892
40913
|
const border = "1px solid #444";
|
|
40893
|
-
const styles$
|
|
40914
|
+
const styles$7 = aphrodite.StyleSheet.create({
|
|
40894
40915
|
widget: {
|
|
40895
40916
|
paddingTop: padding,
|
|
40896
40917
|
maxWidth: "100%",
|
|
@@ -41581,9 +41602,9 @@ function drawText(ctx, item) {
|
|
|
41581
41602
|
if (item.value === null) {
|
|
41582
41603
|
return;
|
|
41583
41604
|
}
|
|
41584
|
-
ctx.fillStyle = styles$
|
|
41585
|
-
ctx.font = styles$
|
|
41586
|
-
ctx.fillText(item.value, item.pos[0] - styles$
|
|
41605
|
+
ctx.fillStyle = styles$6.fgColor;
|
|
41606
|
+
ctx.font = styles$6.font;
|
|
41607
|
+
ctx.fillText(item.value, item.pos[0] - styles$6.fontSizePx / 2 + 1, item.pos[1] + styles$6.fontSizePx / 2);
|
|
41587
41608
|
}
|
|
41588
41609
|
|
|
41589
41610
|
/**
|
|
@@ -41604,16 +41625,16 @@ function drawText(ctx, item) {
|
|
|
41604
41625
|
function drawDoubleLine(ctx, item) {
|
|
41605
41626
|
// Outer line that forms both of the bond lines.
|
|
41606
41627
|
let path = new Path2D();
|
|
41607
|
-
ctx.lineWidth = 5 * styles$
|
|
41608
|
-
ctx.strokeStyle = styles$
|
|
41628
|
+
ctx.lineWidth = 5 * styles$6.lineWidth;
|
|
41629
|
+
ctx.strokeStyle = styles$6.fgColor;
|
|
41609
41630
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
41610
41631
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
41611
41632
|
ctx.stroke(path);
|
|
41612
41633
|
|
|
41613
41634
|
// Inner white line that separates the two bond lines.
|
|
41614
41635
|
path = new Path2D();
|
|
41615
|
-
ctx.lineWidth = 3 * styles$
|
|
41616
|
-
ctx.strokeStyle = styles$
|
|
41636
|
+
ctx.lineWidth = 3 * styles$6.lineWidth;
|
|
41637
|
+
ctx.strokeStyle = styles$6.bgColor;
|
|
41617
41638
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
41618
41639
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
41619
41640
|
ctx.stroke(path);
|
|
@@ -41640,16 +41661,16 @@ function drawTripleLine(ctx, item) {
|
|
|
41640
41661
|
|
|
41641
41662
|
// Outer line that will form the two outer bond lines.
|
|
41642
41663
|
let path = new Path2D();
|
|
41643
|
-
ctx.lineWidth = 7 * styles$
|
|
41644
|
-
ctx.strokeStyle = styles$
|
|
41664
|
+
ctx.lineWidth = 7 * styles$6.lineWidth;
|
|
41665
|
+
ctx.strokeStyle = styles$6.fgColor;
|
|
41645
41666
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
41646
41667
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
41647
41668
|
ctx.stroke(path);
|
|
41648
41669
|
|
|
41649
41670
|
// Middle white line that separates the bonds
|
|
41650
41671
|
path = new Path2D();
|
|
41651
|
-
ctx.lineWidth = 5 * styles$
|
|
41652
|
-
ctx.strokeStyle = styles$
|
|
41672
|
+
ctx.lineWidth = 5 * styles$6.lineWidth;
|
|
41673
|
+
ctx.strokeStyle = styles$6.bgColor;
|
|
41653
41674
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
41654
41675
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
41655
41676
|
ctx.stroke(path);
|
|
@@ -41671,8 +41692,8 @@ function drawTripleLine(ctx, item) {
|
|
|
41671
41692
|
*/
|
|
41672
41693
|
function drawLine(ctx, item) {
|
|
41673
41694
|
const path = new Path2D();
|
|
41674
|
-
ctx.lineWidth = styles$
|
|
41675
|
-
ctx.strokeStyle = styles$
|
|
41695
|
+
ctx.lineWidth = styles$6.lineWidth;
|
|
41696
|
+
ctx.strokeStyle = styles$6.fgColor;
|
|
41676
41697
|
path.moveTo(item.startPos[0], item.startPos[1]);
|
|
41677
41698
|
path.lineTo(item.endPos[0], item.endPos[1]);
|
|
41678
41699
|
ctx.stroke(path);
|
|
@@ -41724,7 +41745,7 @@ function compareElements(item0, item1) {
|
|
|
41724
41745
|
function draw(ctx, items) {
|
|
41725
41746
|
items.sort(compareElements).forEach(drawItem(ctx));
|
|
41726
41747
|
}
|
|
41727
|
-
const styles$
|
|
41748
|
+
const styles$6 = {
|
|
41728
41749
|
bgColor: "rgb(255, 255, 255)",
|
|
41729
41750
|
fgColor: "rgb(0, 0, 0)",
|
|
41730
41751
|
fontSizePx: 12,
|
|
@@ -43851,7 +43872,7 @@ class PhetSimulation extends React__namespace.Component {
|
|
|
43851
43872
|
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
43852
43873
|
const sandboxProperties = "allow-same-origin allow-scripts";
|
|
43853
43874
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
43854
|
-
style: styles$
|
|
43875
|
+
style: styles$5.widgetContainer
|
|
43855
43876
|
}, this.state.banner !== null &&
|
|
43856
43877
|
/*#__PURE__*/
|
|
43857
43878
|
// TODO(anna): Make this banner focusable
|
|
@@ -43864,12 +43885,12 @@ class PhetSimulation extends React__namespace.Component {
|
|
|
43864
43885
|
kind: this.state.banner.kind,
|
|
43865
43886
|
text: this.state.banner.message
|
|
43866
43887
|
})), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
43867
|
-
style: styles$
|
|
43888
|
+
style: styles$5.iframeContainer
|
|
43868
43889
|
}, /*#__PURE__*/React__namespace.createElement("iframe", {
|
|
43869
43890
|
ref: this.iframeRef,
|
|
43870
43891
|
title: this.props.description,
|
|
43871
43892
|
sandbox: sandboxProperties,
|
|
43872
|
-
className: aphrodite.css(styles$
|
|
43893
|
+
className: aphrodite.css(styles$5.iframeResponsive),
|
|
43873
43894
|
src: this.state.url?.toString(),
|
|
43874
43895
|
allow: "fullscreen"
|
|
43875
43896
|
})), this.state.url !== null && /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
@@ -43900,7 +43921,7 @@ const makeSafeUrl = (urlString, locale) => {
|
|
|
43900
43921
|
url.searchParams.set("locale", locale);
|
|
43901
43922
|
return url;
|
|
43902
43923
|
};
|
|
43903
|
-
const styles$
|
|
43924
|
+
const styles$5 = aphrodite.StyleSheet.create({
|
|
43904
43925
|
widgetContainer: {
|
|
43905
43926
|
borderRadius: 6,
|
|
43906
43927
|
borderWidth: 1,
|
|
@@ -44823,7 +44844,7 @@ class PythonProgram extends React__namespace.Component {
|
|
|
44823
44844
|
// creator "went wild".
|
|
44824
44845
|
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
44825
44846
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
44826
|
-
style: styles$
|
|
44847
|
+
style: styles$4.container
|
|
44827
44848
|
}, /*#__PURE__*/React__namespace.createElement("iframe", {
|
|
44828
44849
|
sandbox: sandboxOptions,
|
|
44829
44850
|
src: url,
|
|
@@ -44832,7 +44853,7 @@ class PythonProgram extends React__namespace.Component {
|
|
|
44832
44853
|
}));
|
|
44833
44854
|
}
|
|
44834
44855
|
}
|
|
44835
|
-
const styles$
|
|
44856
|
+
const styles$4 = aphrodite.StyleSheet.create({
|
|
44836
44857
|
container: {
|
|
44837
44858
|
margin: "auto",
|
|
44838
44859
|
width: "100%"
|
|
@@ -45318,7 +45339,7 @@ const VideoTranscriptLink = props => {
|
|
|
45318
45339
|
{
|
|
45319
45340
|
const video = result.data?.video;
|
|
45320
45341
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
45321
|
-
style: styles$
|
|
45342
|
+
style: styles$3.transcriptLink
|
|
45322
45343
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.Text, null, video?.title), /*#__PURE__*/React__namespace.createElement(wonderBlocksLayout.Strut, {
|
|
45323
45344
|
size: 10
|
|
45324
45345
|
}), /*#__PURE__*/React__namespace.createElement(Link__default["default"], {
|
|
@@ -45335,7 +45356,7 @@ const VideoTranscriptLink = props => {
|
|
|
45335
45356
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, strings.somethingWrong);
|
|
45336
45357
|
}
|
|
45337
45358
|
};
|
|
45338
|
-
const styles$
|
|
45359
|
+
const styles$3 = aphrodite.StyleSheet.create({
|
|
45339
45360
|
transcriptLink: {
|
|
45340
45361
|
flexDirection: "row",
|
|
45341
45362
|
width: "100%",
|
|
@@ -45456,7 +45477,7 @@ const init = function () {
|
|
|
45456
45477
|
|
|
45457
45478
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45458
45479
|
const libName = "@khanacademy/perseus";
|
|
45459
|
-
const libVersion = "
|
|
45480
|
+
const libVersion = "47.0.1";
|
|
45460
45481
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45461
45482
|
|
|
45462
45483
|
const apiVersion = {
|
|
@@ -45673,7 +45694,7 @@ class HintRenderer extends React__namespace.Component {
|
|
|
45673
45694
|
const {
|
|
45674
45695
|
isMobile
|
|
45675
45696
|
} = apiOptions;
|
|
45676
|
-
const classNames = classNames__default["default"]("hint", !isMobile && "perseus-hint-renderer", isMobile && aphrodite.css(styles$
|
|
45697
|
+
const classNames = classNames__default["default"]("hint", !isMobile && "perseus-hint-renderer", isMobile && aphrodite.css(styles$2.newHint), isMobile && lastRendered && aphrodite.css(styles$2.lastRenderedNewHint), lastHint && "last-hint", lastRendered && "last-rendered", className);
|
|
45677
45698
|
|
|
45678
45699
|
// TODO(charlie): Allowing `customKeypad` would require that we
|
|
45679
45700
|
// extend `ItemRenderer` to support nested inputs in the `HintsRenderer`.
|
|
@@ -45715,7 +45736,7 @@ class HintRenderer extends React__namespace.Component {
|
|
|
45715
45736
|
);
|
|
45716
45737
|
}
|
|
45717
45738
|
}
|
|
45718
|
-
const styles$
|
|
45739
|
+
const styles$2 = aphrodite.StyleSheet.create({
|
|
45719
45740
|
newHint: {
|
|
45720
45741
|
marginBottom: 1.5 * baseUnitPx,
|
|
45721
45742
|
borderLeftColor: gray97,
|
|
@@ -45892,14 +45913,14 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
45892
45913
|
} = apiOptions;
|
|
45893
45914
|
const showGetAnotherHint = getAnotherHint && hintsVisible > 0 && hintsVisible < this.props.hints.length;
|
|
45894
45915
|
const hintRatioCopy = `(${hintsVisible}/${this.props.hints.length})`;
|
|
45895
|
-
const classNames = classNames__default["default"](this.props.className, apiOptions.isMobile && hintsVisible > 0 && aphrodite.css(styles$
|
|
45916
|
+
const classNames = classNames__default["default"](this.props.className, apiOptions.isMobile && hintsVisible > 0 && aphrodite.css(styles$1.mobileHintStylesHintsRenderer));
|
|
45896
45917
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
45897
45918
|
className: classNames
|
|
45898
45919
|
}, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React__namespace.createElement("div", {
|
|
45899
|
-
className: aphrodite.css(styles$
|
|
45920
|
+
className: aphrodite.css(styles$1.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
|
|
45900
45921
|
}, this.context.strings.hints), hints, showGetAnotherHint && /*#__PURE__*/React__namespace.createElement("button", {
|
|
45901
45922
|
rel: "button",
|
|
45902
|
-
className: aphrodite.css(styles$
|
|
45923
|
+
className: aphrodite.css(styles$1.linkButton, styles$1.getAnotherHintButton, apiOptions.isMobile && styles$1.mobileHintStylesGetAnotherHintButton),
|
|
45903
45924
|
onClick: evt => {
|
|
45904
45925
|
evt.preventDefault();
|
|
45905
45926
|
evt.stopPropagation();
|
|
@@ -45908,14 +45929,14 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
45908
45929
|
}
|
|
45909
45930
|
}
|
|
45910
45931
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
45911
|
-
className: aphrodite.css(styles$
|
|
45932
|
+
className: aphrodite.css(styles$1.plusText, apiOptions.isMobile && styles$1.mobileHintStylesPlusText)
|
|
45912
45933
|
}, "+"), /*#__PURE__*/React__namespace.createElement("span", {
|
|
45913
|
-
className: aphrodite.css(styles$
|
|
45934
|
+
className: aphrodite.css(styles$1.getAnotherHintText)
|
|
45914
45935
|
}, this.context.strings.getAnotherHint, " ", hintRatioCopy)));
|
|
45915
45936
|
}
|
|
45916
45937
|
}
|
|
45917
45938
|
const hintIndentation = baseUnitPx + hintBorderWidth;
|
|
45918
|
-
const styles$
|
|
45939
|
+
const styles$1 = aphrodite.StyleSheet.create({
|
|
45919
45940
|
// eslint-disable-next-line react-native/no-unused-styles
|
|
45920
45941
|
rendererMargins: {
|
|
45921
45942
|
marginTop: baseUnitPx
|
|
@@ -46335,11 +46356,11 @@ class ServerItemRenderer extends React__namespace.Component {
|
|
|
46335
46356
|
// mobile hint styles, which are flush to the left.
|
|
46336
46357
|
// NOTE(charlie): We may still want to apply this
|
|
46337
46358
|
// padding for desktop exercises.
|
|
46338
|
-
apiOptions.isMobile ? undefined : aphrodite.css(styles
|
|
46359
|
+
apiOptions.isMobile ? undefined : aphrodite.css(styles.hintsContainer)
|
|
46339
46360
|
}, hintsRenderer)));
|
|
46340
46361
|
}
|
|
46341
46362
|
}
|
|
46342
|
-
const styles
|
|
46363
|
+
const styles = aphrodite.StyleSheet.create({
|
|
46343
46364
|
hintsContainer: {
|
|
46344
46365
|
marginLeft: 50
|
|
46345
46366
|
}
|
|
@@ -46446,1148 +46467,6 @@ const traverse = function (rendererOptions, contentCallback, widgetCallback, opt
|
|
|
46446
46467
|
return traverseRenderer$1(rendererOptions, contentCallback, deepCallbackFor(contentCallback, widgetCallback, optionsCallback), optionsCallback);
|
|
46447
46468
|
};
|
|
46448
46469
|
|
|
46449
|
-
/**
|
|
46450
|
-
* Utility functions for constructing and inferring multi-item shapes.
|
|
46451
|
-
*
|
|
46452
|
-
* A shape is an object that serves as a runtime type declaration: it specifies
|
|
46453
|
-
* a tree structure for a particular class of multi-item. See shape-types.js
|
|
46454
|
-
* for further discussion.
|
|
46455
|
-
*
|
|
46456
|
-
* This module allows you to construct arbitrary Shape trees, by combining
|
|
46457
|
-
* leaf node shapes like `content` and `hint` into composite shapes like
|
|
46458
|
-
* `arrayOf(shape({foo: content, bar: hint}))`.
|
|
46459
|
-
*/
|
|
46460
|
-
|
|
46461
|
-
/**
|
|
46462
|
-
* These tools allow you to construct arbirtary shapes, by combining simple
|
|
46463
|
-
* leaf shapes like `content` and `hint` into composite shapes like
|
|
46464
|
-
* `arrayOf(shape({question: content, hints: arrayOf(hint)}))`.
|
|
46465
|
-
*/
|
|
46466
|
-
const contentShape = {
|
|
46467
|
-
type: "content"
|
|
46468
|
-
};
|
|
46469
|
-
const hintShape = {
|
|
46470
|
-
type: "hint"
|
|
46471
|
-
};
|
|
46472
|
-
const tagsShape = {
|
|
46473
|
-
type: "tags"
|
|
46474
|
-
};
|
|
46475
|
-
const buildArrayShape = elementShape => ({
|
|
46476
|
-
type: "array",
|
|
46477
|
-
elementShape
|
|
46478
|
-
});
|
|
46479
|
-
const buildObjectShape = shape => ({
|
|
46480
|
-
type: "object",
|
|
46481
|
-
shape
|
|
46482
|
-
});
|
|
46483
|
-
const hintsShape = buildArrayShape(hintShape);
|
|
46484
|
-
var shapes = {
|
|
46485
|
-
content: contentShape,
|
|
46486
|
-
hint: hintShape,
|
|
46487
|
-
hints: hintsShape,
|
|
46488
|
-
tags: tagsShape,
|
|
46489
|
-
arrayOf: buildArrayShape,
|
|
46490
|
-
shape: buildObjectShape
|
|
46491
|
-
};
|
|
46492
|
-
|
|
46493
|
-
/**
|
|
46494
|
-
* Utility functions for manipulating multi-item-shaped trees.
|
|
46495
|
-
*
|
|
46496
|
-
* Multi-items are trees! But we also often have other trees that are shaped
|
|
46497
|
-
* like multi-items - for example, if we map a multi-item tree into a tree of
|
|
46498
|
-
* renderer info and state, and then map that again into a tree of just the
|
|
46499
|
-
* renderer nodes, like we do in MultiRenderer. See tree-types.js for further
|
|
46500
|
-
* discussion.
|
|
46501
|
-
*
|
|
46502
|
-
* These functions enable us to manipulate generic multi-item-shaped trees,
|
|
46503
|
-
* regardless of what type of data they contain at their leaves. You can use
|
|
46504
|
-
* the mapper functions to transform a tree into another tree of the same
|
|
46505
|
-
* shape, or to discover all the nodes of a particular type.
|
|
46506
|
-
*
|
|
46507
|
-
* We expose two simple mapper functions (mapContentNodes and mapHintNodes),
|
|
46508
|
-
* and also a more complex interface for creating a mapping over all of a
|
|
46509
|
-
* tree's node types simultaneously:
|
|
46510
|
-
*
|
|
46511
|
-
* `buildMapper()` returns a TreeMapper object that allows you to build your
|
|
46512
|
-
* mapper object one node type at a time. Then, you can execute your mapping by
|
|
46513
|
-
* calling the `mapTree` method.
|
|
46514
|
-
*
|
|
46515
|
-
* For example:
|
|
46516
|
-
* const renderers = buildMapper()
|
|
46517
|
-
* .setContentMapper(this.renderContentNode)
|
|
46518
|
-
* .setHintMapper(this.renderHintNode)
|
|
46519
|
-
* .setTagsMapper(this.renderTagsNode)
|
|
46520
|
-
* .setArrayMapper(this.hideSkippedQuestions)
|
|
46521
|
-
* .mapTree(tree, shape);
|
|
46522
|
-
*
|
|
46523
|
-
* This will copy the given tree, apply the given transformations to the
|
|
46524
|
-
* content, hint, and array nodes respectively, and return the resulting tree.
|
|
46525
|
-
*
|
|
46526
|
-
* For node types whose mappers aren't specified, we default to the identity
|
|
46527
|
-
* function. (This builder interface enables us to implement that default
|
|
46528
|
-
* behavior in a provably type-safe way, while not requiring the call site to
|
|
46529
|
-
* be aware of all the node types. Hooray!)
|
|
46530
|
-
*
|
|
46531
|
-
* The call to `setArrayMapper` must come last, because the array mapper's
|
|
46532
|
-
* argument types depend on the other mappers' types. See ArrayMapper for more
|
|
46533
|
-
* details.
|
|
46534
|
-
*
|
|
46535
|
-
* WARNING: These functions trust that the provided tree conforms to the
|
|
46536
|
-
* provided shape. If not, behavior is undefined and may not respect the type
|
|
46537
|
-
* signatures specified here.
|
|
46538
|
-
*/
|
|
46539
|
-
|
|
46540
|
-
/**
|
|
46541
|
-
* The sequence of edges that lead to a particular node in a Tree.
|
|
46542
|
-
* Elements can be `string` to correspond to an ObjectNode key, or `number` to
|
|
46543
|
-
* correspond to an ArrayNode index.
|
|
46544
|
-
*/
|
|
46545
|
-
|
|
46546
|
-
/**
|
|
46547
|
-
* These are function interfaces for mapping over various types of tree nodes.
|
|
46548
|
-
*
|
|
46549
|
-
* ArrayMapper is a bit more complicated than the leaf node mappers. It's
|
|
46550
|
-
* executed in the context of a `mapTree` call, after we've finished mapping
|
|
46551
|
-
* its child nodes, so the function has access to both the resulting array
|
|
46552
|
-
* (with mapped elements) and the original array (with the original untouched
|
|
46553
|
-
* elements).
|
|
46554
|
-
*
|
|
46555
|
-
* The ArrayMapper then has the opportunity to apply a final transformation to
|
|
46556
|
-
* the resulting array, like filtering certain elements or (in the hacky
|
|
46557
|
-
* MultiRenderer case) attaching a `renderHints` method to arrays of hint
|
|
46558
|
-
* renderers :)
|
|
46559
|
-
*
|
|
46560
|
-
* This is why `TreeMapper#setArrayMapper` must be called last: ArrayMapper's
|
|
46561
|
-
* types depend on the ContentMapper and HintMapper's types. And, since you can
|
|
46562
|
-
* only specify one mapper at a time in this builder interface (which is
|
|
46563
|
-
* necessary to provide default mappers in a type-safe way), you need your
|
|
46564
|
-
* dependencies to already be in place by the time you call `setArrayMapper`.
|
|
46565
|
-
* Otherwise, we'd have to set the ArrayMapper and *hope* that you *eventually*
|
|
46566
|
-
* provide a compatible ContentMapper and HintMapper, which is difficult to
|
|
46567
|
-
* prove at compile time.
|
|
46568
|
-
*
|
|
46569
|
-
* There's no ObjectMapper here, but not for any particular reason. We just
|
|
46570
|
-
* don't have a use case for it yet, so we haven't built it yet.
|
|
46571
|
-
*/
|
|
46572
|
-
|
|
46573
|
-
/**
|
|
46574
|
-
* A TreeMapper is a collection of node mappers, which, together, compose the
|
|
46575
|
-
* behavior for mapping over an entire tree.
|
|
46576
|
-
*
|
|
46577
|
-
* This serves as the interface for the two TreeMapper classes, including both
|
|
46578
|
-
* the internal mapper properties that we care about, and the `mapTree`
|
|
46579
|
-
* function that the call site will use.
|
|
46580
|
-
*/
|
|
46581
|
-
|
|
46582
|
-
/**
|
|
46583
|
-
* This is a TreeMapper that only has mappers specified for its leaf nodes; its
|
|
46584
|
-
* array mapper is the identity function.
|
|
46585
|
-
*
|
|
46586
|
-
* This is the TreeMapper initially returned by `buildMapper`. It allows you to
|
|
46587
|
-
* change the types of your ContentMapper and HintMapper, which is safe because
|
|
46588
|
-
* none of the other mappers that depend on those types (aka ArrayMapper) have
|
|
46589
|
-
* been specified yet. (Or, more specifically, the ArrayMapper is currently
|
|
46590
|
-
* `identity`, which can trivially vary with the ContentMapper and HintMapper's
|
|
46591
|
-
* types.)
|
|
46592
|
-
*
|
|
46593
|
-
* Once you call `setArrayMapper`, however, we move to the other class:
|
|
46594
|
-
* TreeMapperForLeavesAndCollections.
|
|
46595
|
-
*/
|
|
46596
|
-
class TreeMapperJustForLeaves {
|
|
46597
|
-
content;
|
|
46598
|
-
hint;
|
|
46599
|
-
tags;
|
|
46600
|
-
array;
|
|
46601
|
-
constructor(content, hint, tags) {
|
|
46602
|
-
this.content = content;
|
|
46603
|
-
this.hint = hint;
|
|
46604
|
-
this.tags = tags;
|
|
46605
|
-
this.array = identity;
|
|
46606
|
-
}
|
|
46607
|
-
setContentMapper(newContentMapper) {
|
|
46608
|
-
return new TreeMapperJustForLeaves(newContentMapper, this.hint, this.tags);
|
|
46609
|
-
}
|
|
46610
|
-
setHintMapper(newHintMapper) {
|
|
46611
|
-
return new TreeMapperJustForLeaves(this.content, newHintMapper, this.tags);
|
|
46612
|
-
}
|
|
46613
|
-
setTagsMapper(newTagsMapper) {
|
|
46614
|
-
return new TreeMapperJustForLeaves(this.content, this.hint, newTagsMapper);
|
|
46615
|
-
}
|
|
46616
|
-
setArrayMapper(newArrayMapper) {
|
|
46617
|
-
return new TreeMapperForLeavesAndCollections(this.content, this.hint, this.tags, newArrayMapper);
|
|
46618
|
-
}
|
|
46619
|
-
|
|
46620
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic. | TS2315 - Type 'Tree' is not generic.
|
|
46621
|
-
mapTree(tree, shape) {
|
|
46622
|
-
return mapTree(tree, shape, [], this);
|
|
46623
|
-
}
|
|
46624
|
-
}
|
|
46625
|
-
|
|
46626
|
-
/**
|
|
46627
|
-
* This is a TreeMapper that already has an ArrayMapper specified, so its
|
|
46628
|
-
* ContentMapper and HintMapper are now locked in.
|
|
46629
|
-
*/
|
|
46630
|
-
class TreeMapperForLeavesAndCollections {
|
|
46631
|
-
content;
|
|
46632
|
-
hint;
|
|
46633
|
-
tags;
|
|
46634
|
-
array;
|
|
46635
|
-
constructor(content, hint, tags, array) {
|
|
46636
|
-
this.content = content;
|
|
46637
|
-
this.hint = hint;
|
|
46638
|
-
this.tags = tags;
|
|
46639
|
-
this.array = array;
|
|
46640
|
-
}
|
|
46641
|
-
setArrayMapper(newArrayMapper) {
|
|
46642
|
-
return new TreeMapperForLeavesAndCollections(this.content, this.hint, this.tags, newArrayMapper);
|
|
46643
|
-
}
|
|
46644
|
-
|
|
46645
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic. | TS2315 - Type 'Tree' is not generic.
|
|
46646
|
-
mapTree(tree, shape) {
|
|
46647
|
-
return mapTree(tree, shape, [], this);
|
|
46648
|
-
}
|
|
46649
|
-
}
|
|
46650
|
-
function identity(x) {
|
|
46651
|
-
return x;
|
|
46652
|
-
}
|
|
46653
|
-
|
|
46654
|
-
/**
|
|
46655
|
-
* Return a new TreeMapper that will perform a no-op transformation on an input
|
|
46656
|
-
* tree. To make it useful, chain any combination of `setContentMapper`,
|
|
46657
|
-
* `setHintMapper`, `setTagMapper`, and `setArrayMapper` to specify
|
|
46658
|
-
* transformations for the individual node types.
|
|
46659
|
-
*/
|
|
46660
|
-
// @ts-expect-error - TS2300 - Duplicate identifier 'C'. | TS2300 - Duplicate identifier 'H'. | TS2300 - Duplicate identifier 'T'.
|
|
46661
|
-
function buildMapper() {
|
|
46662
|
-
return new TreeMapperJustForLeaves(identity, identity, identity);
|
|
46663
|
-
}
|
|
46664
|
-
|
|
46665
|
-
/**
|
|
46666
|
-
* Copy the given tree, apply the corresponding transformation specified in the
|
|
46667
|
-
* TreeMapper to each node, and return the resulting tree.
|
|
46668
|
-
*/
|
|
46669
|
-
function mapTree(
|
|
46670
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
46671
|
-
tree, shape, path, mappers
|
|
46672
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
46673
|
-
) {
|
|
46674
|
-
// We trust the shape of the multi-item to match the shape provided at
|
|
46675
|
-
// runtime. Therefore, in each shape branch, we cast the node to `any` and
|
|
46676
|
-
// reinterpret it as the expected node type.
|
|
46677
|
-
if (shape.type === "content") {
|
|
46678
|
-
const content = tree;
|
|
46679
|
-
return mappers.content(content, shape, path);
|
|
46680
|
-
}
|
|
46681
|
-
if (shape.type === "hint") {
|
|
46682
|
-
const hint = tree;
|
|
46683
|
-
return mappers.hint(hint, shape, path);
|
|
46684
|
-
}
|
|
46685
|
-
if (shape.type === "tags") {
|
|
46686
|
-
const tags = tree;
|
|
46687
|
-
return mappers.tags(tags, shape, path);
|
|
46688
|
-
}
|
|
46689
|
-
if (shape.type === "array") {
|
|
46690
|
-
// @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
|
|
46691
|
-
const array = tree;
|
|
46692
|
-
if (!Array.isArray(array)) {
|
|
46693
|
-
throw new perseusCore.PerseusError(`Invalid object of type "${typeof array}" found at path ` +
|
|
46694
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46695
|
-
`${["<root>"].concat(path).join(".")}. Expected array.`, perseusCore.Errors.Internal);
|
|
46696
|
-
}
|
|
46697
|
-
const elementShape = shape.elementShape;
|
|
46698
|
-
// @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
|
|
46699
|
-
const mappedElements = array.map((inner, i) => mapTree(inner, elementShape, path.concat(i), mappers));
|
|
46700
|
-
return mappers.array(mappedElements, array, shape, path);
|
|
46701
|
-
}
|
|
46702
|
-
if (shape.type === "object") {
|
|
46703
|
-
const object = tree;
|
|
46704
|
-
if (object && typeof object !== "object") {
|
|
46705
|
-
throw new perseusCore.PerseusError(`Invalid object of type "${typeof object}" found at ` +
|
|
46706
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46707
|
-
`path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, perseusCore.Errors.InvalidInput);
|
|
46708
|
-
}
|
|
46709
|
-
const valueShapes = shape.shape;
|
|
46710
|
-
if (!valueShapes) {
|
|
46711
|
-
throw new perseusCore.PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
|
|
46712
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46713
|
-
`${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
|
|
46714
|
-
}
|
|
46715
|
-
const newObject = {};
|
|
46716
|
-
Object.keys(valueShapes).forEach(key => {
|
|
46717
|
-
if (!(key in object)) {
|
|
46718
|
-
throw new perseusCore.PerseusError(`Key "${key}" is missing from shape at path ` +
|
|
46719
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46720
|
-
`${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
|
|
46721
|
-
}
|
|
46722
|
-
newObject[key] = mapTree(object[key], valueShapes[key], path.concat(key), mappers);
|
|
46723
|
-
});
|
|
46724
|
-
return newObject;
|
|
46725
|
-
}
|
|
46726
|
-
throw new perseusCore.PerseusError(
|
|
46727
|
-
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
46728
|
-
`unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
|
|
46729
|
-
}
|
|
46730
|
-
|
|
46731
|
-
/**
|
|
46732
|
-
* Utility functions for constructing and manipulating multi-items.
|
|
46733
|
-
*
|
|
46734
|
-
* These functions apply *specifically* to Items and ItemTrees - things that
|
|
46735
|
-
* actually semantically *are* multi-items. For more general functions for
|
|
46736
|
-
* traversing and manipulating *anything* shaped like a multi-item (like a
|
|
46737
|
-
* renderer tree or a score tree or, well, a multi-item), see trees.js.
|
|
46738
|
-
*/
|
|
46739
|
-
/**
|
|
46740
|
-
* Return a semantically empty ItemTree that conforms to the given shape.
|
|
46741
|
-
*
|
|
46742
|
-
* - An empty content node has an empty content string and no widgets/images.
|
|
46743
|
-
* - An empty hint node has an empty content string and no widgets/images.
|
|
46744
|
-
* - An empty array node has no elements.
|
|
46745
|
-
* - An empty object node has a semantically empty node for each of its keys.
|
|
46746
|
-
* (That is, we recursively call buildEmptyItemTreeForShape for each key.)
|
|
46747
|
-
*/
|
|
46748
|
-
function buildEmptyItemTreeForShape(shape) {
|
|
46749
|
-
if (shape.type === "content") {
|
|
46750
|
-
return {
|
|
46751
|
-
__type: "content",
|
|
46752
|
-
content: "",
|
|
46753
|
-
images: {},
|
|
46754
|
-
widgets: {}
|
|
46755
|
-
};
|
|
46756
|
-
}
|
|
46757
|
-
if (shape.type === "hint") {
|
|
46758
|
-
return {
|
|
46759
|
-
__type: "hint",
|
|
46760
|
-
replace: false,
|
|
46761
|
-
content: "",
|
|
46762
|
-
images: {},
|
|
46763
|
-
widgets: {}
|
|
46764
|
-
};
|
|
46765
|
-
}
|
|
46766
|
-
if (shape.type === "tags") {
|
|
46767
|
-
return [];
|
|
46768
|
-
}
|
|
46769
|
-
if (shape.type === "array") {
|
|
46770
|
-
return [];
|
|
46771
|
-
}
|
|
46772
|
-
if (shape.type === "object") {
|
|
46773
|
-
const valueShapes = shape.shape;
|
|
46774
|
-
const object = {};
|
|
46775
|
-
Object.keys(valueShapes).forEach(key => {
|
|
46776
|
-
object[key] = buildEmptyItemTreeForShape(valueShapes[key]);
|
|
46777
|
-
});
|
|
46778
|
-
return object;
|
|
46779
|
-
}
|
|
46780
|
-
throw new perseusCore.PerseusError(
|
|
46781
|
-
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
46782
|
-
`unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
|
|
46783
|
-
}
|
|
46784
|
-
|
|
46785
|
-
/**
|
|
46786
|
-
* Return a semantically empty Item that conforms to the given shape.
|
|
46787
|
-
*
|
|
46788
|
-
* - An empty content node has an empty content string and no widgets/images.
|
|
46789
|
-
* - An empty hint node has an empty content string and no widgets/images.
|
|
46790
|
-
* - An empty array node has no elements.
|
|
46791
|
-
* - An empty object node has a semantically empty node for each of its keys.
|
|
46792
|
-
* (That is, we recursively call buildEmptyItemTreeForShape for each key.)
|
|
46793
|
-
*/
|
|
46794
|
-
function buildEmptyItemForShape(shape) {
|
|
46795
|
-
return treeToItem(buildEmptyItemTreeForShape(shape));
|
|
46796
|
-
}
|
|
46797
|
-
|
|
46798
|
-
/**
|
|
46799
|
-
* Given an Item and its Shape, yield all of its content nodes to the callback.
|
|
46800
|
-
*/
|
|
46801
|
-
function findContentNodesInItem$2(item, shape, callback) {
|
|
46802
|
-
const itemTree = itemToTree(item);
|
|
46803
|
-
buildMapper().setContentMapper(callback).mapTree(itemTree, shape);
|
|
46804
|
-
}
|
|
46805
|
-
|
|
46806
|
-
/**
|
|
46807
|
-
* Given an Item and its Shape, yield all of its hint nodes to the callback.
|
|
46808
|
-
*/
|
|
46809
|
-
function findHintNodesInItem(item, shape, callback) {
|
|
46810
|
-
const itemTree = itemToTree(item);
|
|
46811
|
-
buildMapper().setHintMapper(callback).mapTree(itemTree, shape);
|
|
46812
|
-
}
|
|
46813
|
-
|
|
46814
|
-
/**
|
|
46815
|
-
* Given an ItemTree, return a Shape that it conforms to.
|
|
46816
|
-
*
|
|
46817
|
-
* The Shape might not be complete or correct Shape that this Item was designed
|
|
46818
|
-
* for. If you have access to the intended Shape, use that instead.
|
|
46819
|
-
*/
|
|
46820
|
-
function inferItemShape$2(item) {
|
|
46821
|
-
const itemTree = itemToTree(item);
|
|
46822
|
-
return inferItemTreeShape(itemTree);
|
|
46823
|
-
}
|
|
46824
|
-
function inferItemTreeShape(node) {
|
|
46825
|
-
if (Array.isArray(node)) {
|
|
46826
|
-
if (node.length) {
|
|
46827
|
-
if (typeof node[0] === "string") {
|
|
46828
|
-
// There's no ItemTree that can manifest as a string.
|
|
46829
|
-
// So, an array of strings must be a TagsNode, not ArrayNode.
|
|
46830
|
-
return shapes.tags;
|
|
46831
|
-
}
|
|
46832
|
-
// Otherwise, assume that this is a valid ArrayNode, and
|
|
46833
|
-
// therefore the shape of the first element applies to all
|
|
46834
|
-
// elements in the array.
|
|
46835
|
-
return shapes.arrayOf(inferItemTreeShape(node[0]));
|
|
46836
|
-
}
|
|
46837
|
-
// The array is empty, so we arbitrarily guess that it's a content
|
|
46838
|
-
// array. As discussed in the docstring, this might be incorrect,
|
|
46839
|
-
// and you shouldn't depend on it.
|
|
46840
|
-
return shapes.arrayOf(shapes.content);
|
|
46841
|
-
}
|
|
46842
|
-
if (
|
|
46843
|
-
// TODO(mdr): Remove #LegacyContentNode support.
|
|
46844
|
-
typeof node === "object" && (node.__type === "content" || node.__type === "item")) {
|
|
46845
|
-
return shapes.content;
|
|
46846
|
-
}
|
|
46847
|
-
if (typeof node === "object" && node.__type === "hint") {
|
|
46848
|
-
return shapes.hint;
|
|
46849
|
-
}
|
|
46850
|
-
if (typeof node === "object") {
|
|
46851
|
-
const valueShapes = {};
|
|
46852
|
-
Object.keys(node).forEach(key => {
|
|
46853
|
-
valueShapes[key] = inferItemTreeShape(node[key]);
|
|
46854
|
-
});
|
|
46855
|
-
return shapes.shape(valueShapes);
|
|
46856
|
-
}
|
|
46857
|
-
throw new perseusCore.PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, perseusCore.Errors.InvalidInput);
|
|
46858
|
-
}
|
|
46859
|
-
|
|
46860
|
-
/**
|
|
46861
|
-
* Convert the given Item to an ItemTree, by unwrapping the `_multi` key.
|
|
46862
|
-
*/
|
|
46863
|
-
function itemToTree(item) {
|
|
46864
|
-
return item._multi;
|
|
46865
|
-
}
|
|
46866
|
-
|
|
46867
|
-
/**
|
|
46868
|
-
* Convert the given ItemTree to an Item, by wrapping it in the `_multi` key.
|
|
46869
|
-
*/
|
|
46870
|
-
function treeToItem(node) {
|
|
46871
|
-
return {
|
|
46872
|
-
_multi: node
|
|
46873
|
-
};
|
|
46874
|
-
}
|
|
46875
|
-
|
|
46876
|
-
var isObject$1 = function (obj) {
|
|
46877
|
-
return obj === Object(obj);
|
|
46878
|
-
};
|
|
46879
|
-
var merge = function () {
|
|
46880
|
-
var obj = {};
|
|
46881
|
-
for (var i = 0; i < arguments.length; i++) {
|
|
46882
|
-
var source = arguments[i];
|
|
46883
|
-
if (source) {
|
|
46884
|
-
for (var prop in source) {
|
|
46885
|
-
obj[prop] = source[prop];
|
|
46886
|
-
}
|
|
46887
|
-
}
|
|
46888
|
-
}
|
|
46889
|
-
return obj;
|
|
46890
|
-
};
|
|
46891
|
-
var clone = function (obj) {
|
|
46892
|
-
if (!isObject$1(obj)) {
|
|
46893
|
-
return obj;
|
|
46894
|
-
}
|
|
46895
|
-
return Array.isArray(obj) ? obj.slice() : merge(obj);
|
|
46896
|
-
};
|
|
46897
|
-
|
|
46898
|
-
/* TODO batch *all* mutations
|
|
46899
|
-
* idea: freeze / thaw implementations for all types
|
|
46900
|
-
* lens constructor thaws, freeze delegates to type's freeze
|
|
46901
|
-
*/
|
|
46902
|
-
|
|
46903
|
-
// equivalents, without requiring it
|
|
46904
|
-
// find the implementation to use for a given object
|
|
46905
|
-
var dispatch = function (x) {
|
|
46906
|
-
if (Array.isArray(x)) {
|
|
46907
|
-
return arr;
|
|
46908
|
-
} else if (isObject$1(x)) {
|
|
46909
|
-
return obj;
|
|
46910
|
-
} else if (typeof x === "string") {
|
|
46911
|
-
return str;
|
|
46912
|
-
}
|
|
46913
|
-
};
|
|
46914
|
-
|
|
46915
|
-
// This is underscore with a different name
|
|
46916
|
-
var lens = function (obj) {
|
|
46917
|
-
if (obj instanceof lens) {
|
|
46918
|
-
return obj;
|
|
46919
|
-
}
|
|
46920
|
-
if (!(this instanceof lens)) {
|
|
46921
|
-
return new lens(obj);
|
|
46922
|
-
}
|
|
46923
|
-
var ops = dispatch(obj);
|
|
46924
|
-
this._wrapped = ops.thaw ? ops.thaw(obj) : obj;
|
|
46925
|
-
};
|
|
46926
|
-
lens.prototype.freeze = function () {
|
|
46927
|
-
var obj = this._wrapped;
|
|
46928
|
-
var ops = dispatch(obj);
|
|
46929
|
-
return ops.freeze ? ops.freeze(obj) : obj;
|
|
46930
|
-
};
|
|
46931
|
-
lens.prototype.zoom = function (lensArr) {
|
|
46932
|
-
if (this._zoomStack === undefined) {
|
|
46933
|
-
this._zoomStack = [];
|
|
46934
|
-
}
|
|
46935
|
-
this._zoomStack.push({
|
|
46936
|
-
zoom: lensArr,
|
|
46937
|
-
wrapped: this._wrapped
|
|
46938
|
-
});
|
|
46939
|
-
this._wrapped = lens(this._wrapped).get(lensArr);
|
|
46940
|
-
return this;
|
|
46941
|
-
};
|
|
46942
|
-
lens.prototype.deZoom = function () {
|
|
46943
|
-
var frame = this._zoomStack.pop();
|
|
46944
|
-
this._wrapped = lens(frame.wrapped).set(frame.zoom, this._wrapped).freeze();
|
|
46945
|
-
return this;
|
|
46946
|
-
};
|
|
46947
|
-
lens.prototype.get = function (lensArr) {
|
|
46948
|
-
var obj = this._wrapped;
|
|
46949
|
-
for (var i = 0; i < lensArr.length; i++) {
|
|
46950
|
-
obj = dispatch(obj).get(obj, lensArr[i]);
|
|
46951
|
-
}
|
|
46952
|
-
return obj;
|
|
46953
|
-
};
|
|
46954
|
-
lens.prototype.mod = function (lensArr, f) {
|
|
46955
|
-
var obj = this._wrapped;
|
|
46956
|
-
var newObj = clone(obj);
|
|
46957
|
-
var ops = dispatch(obj);
|
|
46958
|
-
if (lensArr.length === 0) {
|
|
46959
|
-
this._wrapped = f(this._wrapped);
|
|
46960
|
-
} else if (lensArr.length === 1) {
|
|
46961
|
-
this._wrapped = ops.mod(newObj, lensArr[0], f);
|
|
46962
|
-
} else {
|
|
46963
|
-
var monocle = lensArr[0];
|
|
46964
|
-
var shortLens = lensArr.slice(1);
|
|
46965
|
-
|
|
46966
|
-
// newObj = ops.mod(obj[monocle], shortLens, f);
|
|
46967
|
-
|
|
46968
|
-
newObj[monocle] = lens(obj[monocle]).mod(shortLens, f).freeze();
|
|
46969
|
-
this._wrapped = newObj;
|
|
46970
|
-
}
|
|
46971
|
-
return this;
|
|
46972
|
-
};
|
|
46973
|
-
|
|
46974
|
-
// TODO - move to individual files
|
|
46975
|
-
lens.prototype.merge = function (lensArr, props) {
|
|
46976
|
-
this._wrapped = lens(this._wrapped).mod(lensArr, function (oldProps) {
|
|
46977
|
-
return merge(oldProps, props);
|
|
46978
|
-
}).freeze();
|
|
46979
|
-
return this;
|
|
46980
|
-
};
|
|
46981
|
-
|
|
46982
|
-
// Lens must have length >= 1 or there would be nothing to return
|
|
46983
|
-
lens.prototype.del = function (lensArr) {
|
|
46984
|
-
var obj = this._wrapped;
|
|
46985
|
-
var ops = dispatch(obj);
|
|
46986
|
-
if (lensArr.length === 1) {
|
|
46987
|
-
this._wrapped = ops.del(obj, lensArr[0]);
|
|
46988
|
-
} else {
|
|
46989
|
-
var monocle = lensArr[0];
|
|
46990
|
-
var shortLens = lensArr.slice(1);
|
|
46991
|
-
var newObj = clone(obj);
|
|
46992
|
-
newObj[monocle] = lens(obj[monocle]).del(shortLens).freeze();
|
|
46993
|
-
this._wrapped = newObj;
|
|
46994
|
-
}
|
|
46995
|
-
return this;
|
|
46996
|
-
};
|
|
46997
|
-
lens.prototype.set = function (lensArr, set) {
|
|
46998
|
-
return this.mod(lensArr, function () {
|
|
46999
|
-
return set;
|
|
47000
|
-
});
|
|
47001
|
-
};
|
|
47002
|
-
|
|
47003
|
-
// ARRAY FUNCTIONS
|
|
47004
|
-
|
|
47005
|
-
const arr = {
|
|
47006
|
-
get: function (arr, monocle) {
|
|
47007
|
-
return arr[monocle];
|
|
47008
|
-
},
|
|
47009
|
-
set: function (arr, monocle, val) {
|
|
47010
|
-
var newArr = arr.splice();
|
|
47011
|
-
newArr[monocle] = val;
|
|
47012
|
-
return newArr;
|
|
47013
|
-
},
|
|
47014
|
-
mod: function (arr, monocle, f) {
|
|
47015
|
-
var newArr = arr.slice();
|
|
47016
|
-
newArr[monocle] = f(arr[monocle]);
|
|
47017
|
-
return newArr;
|
|
47018
|
-
},
|
|
47019
|
-
del: function (arr, monocle) {
|
|
47020
|
-
var newArr = arr.slice();
|
|
47021
|
-
newArr.splice(monocle, 1);
|
|
47022
|
-
return newArr;
|
|
47023
|
-
}
|
|
47024
|
-
};
|
|
47025
|
-
|
|
47026
|
-
/*
|
|
47027
|
-
// Lens must point to a member of an array. We'll insert into that array.
|
|
47028
|
-
lens.prototype.insertAt = function(lensArr, toInsert) {
|
|
47029
|
-
var obj = this._wrapped;
|
|
47030
|
-
|
|
47031
|
-
var arrLens = lensArr.slice(0, -1);
|
|
47032
|
-
var arr = lens(obj).get(arrLens).slice(); // slice to copy
|
|
47033
|
-
|
|
47034
|
-
var arrIdx = lensArr[lensArr.length-1];
|
|
47035
|
-
arr.splice(arrIdx, 0, toInsert);
|
|
47036
|
-
return lens(obj).set(arrLens, arr);
|
|
47037
|
-
};
|
|
47038
|
-
|
|
47039
|
-
lens.prototype.insertBefore = lens.prototype.insertAt;
|
|
47040
|
-
lens.prototype.insertAfter = function(lensArr, toInsert) {
|
|
47041
|
-
var newLens = lensArr.slice();
|
|
47042
|
-
newLens[newLens.length-1] += 1;
|
|
47043
|
-
return lens(this._wrapped).insertAt(newLens, toInsert);
|
|
47044
|
-
};
|
|
47045
|
-
*/
|
|
47046
|
-
|
|
47047
|
-
// OBJECT FUNCTIONS
|
|
47048
|
-
|
|
47049
|
-
const obj = {
|
|
47050
|
-
get: function (obj, monocle) {
|
|
47051
|
-
return obj[monocle];
|
|
47052
|
-
},
|
|
47053
|
-
set: function (obj, monocle, val) {
|
|
47054
|
-
var newObj = clone(obj);
|
|
47055
|
-
newObj[monocle] = val;
|
|
47056
|
-
return newObj;
|
|
47057
|
-
},
|
|
47058
|
-
mod: function (obj, monocle, f) {
|
|
47059
|
-
var newObj = clone(obj);
|
|
47060
|
-
newObj[monocle] = f(obj[monocle]);
|
|
47061
|
-
return newObj;
|
|
47062
|
-
},
|
|
47063
|
-
del: function (obj, monocle) {
|
|
47064
|
-
var newObj = clone(obj);
|
|
47065
|
-
delete newObj[monocle];
|
|
47066
|
-
return newObj;
|
|
47067
|
-
}
|
|
47068
|
-
};
|
|
47069
|
-
|
|
47070
|
-
// STRING FUNCTIONS
|
|
47071
|
-
|
|
47072
|
-
const str = {
|
|
47073
|
-
get: function (arr, monocle) {
|
|
47074
|
-
return arr[monocle];
|
|
47075
|
-
},
|
|
47076
|
-
set: function (arr, monocle, val) {
|
|
47077
|
-
var newArr = arr.splice();
|
|
47078
|
-
newArr[monocle] = val;
|
|
47079
|
-
return newArr;
|
|
47080
|
-
},
|
|
47081
|
-
mod: function (arr, monocle, f) {
|
|
47082
|
-
var newArr = arr.splice();
|
|
47083
|
-
newArr[monocle] = f(arr[monocle]);
|
|
47084
|
-
return newArr;
|
|
47085
|
-
},
|
|
47086
|
-
del: function (arr, monocle) {
|
|
47087
|
-
var newArr = arr.slice();
|
|
47088
|
-
newArr.splice(monocle);
|
|
47089
|
-
return newArr;
|
|
47090
|
-
}
|
|
47091
|
-
};
|
|
47092
|
-
|
|
47093
|
-
// TODO(mdr)
|
|
47094
|
-
// TODO(mdr)
|
|
47095
|
-
// TODO(mdr)
|
|
47096
|
-
|
|
47097
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
47098
|
-
|
|
47099
|
-
/**
|
|
47100
|
-
* TODO(somewhatabstract, JIRA-XXXX):
|
|
47101
|
-
* Some usage of this type somewhere is causing TypeScript to believe that these
|
|
47102
|
-
* elements should be components. Don't know where that is, to fix it up
|
|
47103
|
-
* properly. In reality, these types are just too hard to use and aren't
|
|
47104
|
-
* really helping us out as I now have to suppress this rather than
|
|
47105
|
-
* get value from the type. :(
|
|
47106
|
-
*/ // @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
47107
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
47108
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
47109
|
-
class MultiRenderer extends React__namespace.Component {
|
|
47110
|
-
static contextType = PerseusI18nContext;
|
|
47111
|
-
rendererDataTreeMapper;
|
|
47112
|
-
getRenderersMapper;
|
|
47113
|
-
constructor(props) {
|
|
47114
|
-
super(props);
|
|
47115
|
-
this.rendererDataTreeMapper = buildMapper()
|
|
47116
|
-
// @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ContentNode'.
|
|
47117
|
-
.setContentMapper((c, _, p) => this._makeContentRendererData(c, p))
|
|
47118
|
-
// @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'HintNode'.
|
|
47119
|
-
.setHintMapper(h => this._makeHintRendererData(h)).setTagsMapper(t => null);
|
|
47120
|
-
|
|
47121
|
-
// @ts-expect-error - TS2322 - Type 'TreeMapperForLeavesAndCollections<unknown, any, unknown, any, unknown, unknown>' is not assignable to type 'TreeMapper<ContentRendererData, ContentRendererElement, HintRendererData, HintRendererElement, null, null>'.
|
|
47122
|
-
this.getRenderersMapper = buildMapper()
|
|
47123
|
-
// @ts-expect-error - TS2571 - Object is of type 'unknown'.
|
|
47124
|
-
.setContentMapper(c => c.makeRenderer())
|
|
47125
|
-
// @ts-expect-error - TS2571 - Object is of type 'unknown'.
|
|
47126
|
-
.setHintMapper(h => h.makeRenderer()).setArrayMapper((renderers, data, shape) => this._annotateRendererArray(renderers, data, shape));
|
|
47127
|
-
|
|
47128
|
-
// Keep state in sync with props.
|
|
47129
|
-
this.state = this._tryMakeRendererState(this.props);
|
|
47130
|
-
}
|
|
47131
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
47132
|
-
// Keep state in sync with props.
|
|
47133
|
-
if (nextProps.item !== this.props.item) {
|
|
47134
|
-
this.setState(this._tryMakeRendererState(nextProps));
|
|
47135
|
-
}
|
|
47136
|
-
}
|
|
47137
|
-
|
|
47138
|
-
/**
|
|
47139
|
-
* Attempt to build a State that includes a renderer tree corresponding to
|
|
47140
|
-
* the item provided in props. On error, return a state with `renderError`
|
|
47141
|
-
* set instead.
|
|
47142
|
-
*/
|
|
47143
|
-
_tryMakeRendererState(props) {
|
|
47144
|
-
try {
|
|
47145
|
-
return {
|
|
47146
|
-
rendererDataTree: this._makeRendererDataTree(props.item, props.shape),
|
|
47147
|
-
renderError: null
|
|
47148
|
-
};
|
|
47149
|
-
} catch (e) {
|
|
47150
|
-
Log.error("Error building tree state", perseusCore.Errors.Internal, {
|
|
47151
|
-
cause: e
|
|
47152
|
-
});
|
|
47153
|
-
return {
|
|
47154
|
-
rendererDataTree: null,
|
|
47155
|
-
renderError: e
|
|
47156
|
-
};
|
|
47157
|
-
}
|
|
47158
|
-
}
|
|
47159
|
-
_handleSerializedStateUpdated = (path, newState) => {
|
|
47160
|
-
const {
|
|
47161
|
-
onSerializedStateUpdated
|
|
47162
|
-
} = this.props;
|
|
47163
|
-
if (onSerializedStateUpdated) {
|
|
47164
|
-
const oldState = this._getSerializedState(this.props.serializedState);
|
|
47165
|
-
onSerializedStateUpdated(lens(oldState).set(path, newState).freeze());
|
|
47166
|
-
}
|
|
47167
|
-
};
|
|
47168
|
-
|
|
47169
|
-
/**
|
|
47170
|
-
* Props that aren't directly used by the MultiRenderer are delegated to
|
|
47171
|
-
* the underlying Renderers.
|
|
47172
|
-
*/
|
|
47173
|
-
_getRendererProps() {
|
|
47174
|
-
// `item`, `children`, and others are unused. I'm
|
|
47175
|
-
// explicitly pulling them out of `this.props` so I don't pass them to
|
|
47176
|
-
// `<Renderer>`. I'm not sure how else to do this.
|
|
47177
|
-
const {
|
|
47178
|
-
item: _,
|
|
47179
|
-
children: __,
|
|
47180
|
-
shape: ___,
|
|
47181
|
-
serializedState: ____,
|
|
47182
|
-
onSerializedStateUpdated: _____,
|
|
47183
|
-
...otherProps
|
|
47184
|
-
} = this.props;
|
|
47185
|
-
return {
|
|
47186
|
-
...otherProps,
|
|
47187
|
-
strings: this.context.strings
|
|
47188
|
-
};
|
|
47189
|
-
}
|
|
47190
|
-
|
|
47191
|
-
/**
|
|
47192
|
-
* Construct a Renderer and a ref placeholder for the given ContentNode.
|
|
47193
|
-
*/
|
|
47194
|
-
_makeContentRendererData(content, path) {
|
|
47195
|
-
// NOTE(emily): The `findExternalWidgets` function here is computed
|
|
47196
|
-
// inline and thus changes each time we run this function. If it
|
|
47197
|
-
// were to change every render, it would cause the Renderer to
|
|
47198
|
-
// re-render a lot more than is necessary. Don't re-compute this
|
|
47199
|
-
// element unless it is necessary!
|
|
47200
|
-
// HACK(mdr): TypeScript can't prove that this is a ContentRendererData,
|
|
47201
|
-
// because of how we awkwardly construct it in order to obtain a
|
|
47202
|
-
// circular reference. But it is, I promise.
|
|
47203
|
-
const data = {
|
|
47204
|
-
ref: null,
|
|
47205
|
-
makeRenderer: null
|
|
47206
|
-
};
|
|
47207
|
-
const refFunc = e => data.ref = e;
|
|
47208
|
-
const findExternalWidgets = criterion => this._findWidgets(data, criterion);
|
|
47209
|
-
const handleSerializedState = state => this._handleSerializedStateUpdated(path, state);
|
|
47210
|
-
data.makeRenderer = () =>
|
|
47211
|
-
/*#__PURE__*/
|
|
47212
|
-
/**
|
|
47213
|
-
* TODO(somewhatabstract, JIRA-XXXX):
|
|
47214
|
-
* `content` contains props that Renderer doesn't have. However,
|
|
47215
|
-
* since the type for `content` is not exact, it's hard to know
|
|
47216
|
-
* if this spread is including undocumented props so mapping
|
|
47217
|
-
* one to one could introduce a bug. Need to work out the exact
|
|
47218
|
-
* type for ContentNode and then fix this.
|
|
47219
|
-
*/
|
|
47220
|
-
// @ts-expect-error - TS2322 - Type '{ ref: (e: any) => any; findExternalWidgets: (criterion: any) => readonly (Widget | null | undefined)[]; serializedState: any; onSerializedStateUpdated: (state: any) => void; __type: "content" | "item"; ... 9 more ...; reviewMode?: boolean | ... 1 more ... | undefined; }' is not assignable to type 'InexactPartial<Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "content" | "images" | "onRender" | "linterContext" | "widgets" | "alwaysUpdate" | ... 6 more ... | "serializedState">>'.
|
|
47221
|
-
React__namespace.createElement(Renderer, _extends({}, this._getRendererProps(), content, {
|
|
47222
|
-
ref: refFunc,
|
|
47223
|
-
findExternalWidgets: findExternalWidgets,
|
|
47224
|
-
serializedState: this.props.serializedState ? lens(this.props.serializedState).get(path) : null,
|
|
47225
|
-
onSerializedStateUpdated: handleSerializedState
|
|
47226
|
-
}));
|
|
47227
|
-
return data;
|
|
47228
|
-
}
|
|
47229
|
-
|
|
47230
|
-
/**
|
|
47231
|
-
* Construct a Renderer for the given HintNode, and keep track of the hint
|
|
47232
|
-
* itself for future use, too.
|
|
47233
|
-
*/
|
|
47234
|
-
_makeHintRendererData(hint) {
|
|
47235
|
-
// TODO(mdr): Once HintsRenderer supports inter-widget communication,
|
|
47236
|
-
// give it a ref. Until then, leave the ref null forever, to avoid
|
|
47237
|
-
// confusing the findWidgets functions.
|
|
47238
|
-
//
|
|
47239
|
-
// NOTE(davidflanagan): As a partial step toward inter-widget
|
|
47240
|
-
// communication we're going to pass a findExternalWidgets function
|
|
47241
|
-
// (using a dummy data object). This allows passage-ref widgets in
|
|
47242
|
-
// hints to use findWidget() to find the passage widgets they reference.
|
|
47243
|
-
// Note that this is one-way only, however. It does not allow
|
|
47244
|
-
// widgets in the question to find widgets in the hints, for example.
|
|
47245
|
-
const findExternalWidgets = criterion => this._findWidgets({}, criterion);
|
|
47246
|
-
return {
|
|
47247
|
-
hint,
|
|
47248
|
-
findExternalWidgets,
|
|
47249
|
-
// _annotateRendererArray() needs this
|
|
47250
|
-
ref: null,
|
|
47251
|
-
makeRenderer: () => /*#__PURE__*/React__namespace.createElement(HintsRenderer, _extends({}, this._getRendererProps(), {
|
|
47252
|
-
findExternalWidgets: findExternalWidgets
|
|
47253
|
-
// Note(Jeremy): The MultiRenderer codebase types are
|
|
47254
|
-
// slightly different from the rest of the codebase.
|
|
47255
|
-
// Ideally `HintNode` would spread the `Hint` type into it,
|
|
47256
|
-
// but there is a difference in optionality of `widgets`
|
|
47257
|
-
// and `images` and that causes a huge cascade of type
|
|
47258
|
-
// errors (they are truly optional, but most of our code
|
|
47259
|
-
// assumes they're provided/set). Ignoring this for now.
|
|
47260
|
-
// @ts-expect-error - TS2769 - Type 'HintNode' is not assignable to type 'Hint'.
|
|
47261
|
-
,
|
|
47262
|
-
hints: [hint]
|
|
47263
|
-
}))
|
|
47264
|
-
};
|
|
47265
|
-
}
|
|
47266
|
-
|
|
47267
|
-
/**
|
|
47268
|
-
* Construct a tree of interconnected RendererDatas, corresponding to the
|
|
47269
|
-
* given item. Called in `_tryMakeRendererState`, in order to store this
|
|
47270
|
-
* tree in the component state.
|
|
47271
|
-
*/
|
|
47272
|
-
_makeRendererDataTree(item, shape) {
|
|
47273
|
-
const itemTree = itemToTree(item);
|
|
47274
|
-
return this.rendererDataTreeMapper.mapTree(itemTree, shape);
|
|
47275
|
-
}
|
|
47276
|
-
|
|
47277
|
-
/**
|
|
47278
|
-
* Return all widgets that meet the given criterion, from all Renderers
|
|
47279
|
-
* except the Renderer that triggered this call.
|
|
47280
|
-
*
|
|
47281
|
-
* This function is provided to each Renderer's `findExternalWidgets` prop,
|
|
47282
|
-
* which enables widgets in different Renderers to discover each other and
|
|
47283
|
-
* communicate.
|
|
47284
|
-
*/
|
|
47285
|
-
_findWidgets(callingData, filterCriterion) {
|
|
47286
|
-
const results = [];
|
|
47287
|
-
this._mapRenderers(data => {
|
|
47288
|
-
if (callingData !== data && data.ref) {
|
|
47289
|
-
results.push(...data.ref.findInternalWidgets(filterCriterion));
|
|
47290
|
-
}
|
|
47291
|
-
});
|
|
47292
|
-
return results;
|
|
47293
|
-
}
|
|
47294
|
-
|
|
47295
|
-
/**
|
|
47296
|
-
* Copy the renderer tree, apply the given transformation to the leaf nodes
|
|
47297
|
-
* and the optional given transformation to the array nodes, and return the
|
|
47298
|
-
* result.
|
|
47299
|
-
*
|
|
47300
|
-
* Used to provide structured data to the call site (the Renderer tree on
|
|
47301
|
-
* `render`, the Score tree on `getScores`, etc.), and to traverse the
|
|
47302
|
-
* renderer tree even when we disregard the output (like in
|
|
47303
|
-
* `_findWidgets`).
|
|
47304
|
-
*/
|
|
47305
|
-
_mapRenderers(
|
|
47306
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
47307
|
-
leafMapper
|
|
47308
|
-
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
47309
|
-
) {
|
|
47310
|
-
const {
|
|
47311
|
-
rendererDataTree
|
|
47312
|
-
} = this.state;
|
|
47313
|
-
if (!rendererDataTree) {
|
|
47314
|
-
return null;
|
|
47315
|
-
}
|
|
47316
|
-
const mapper = buildMapper().setContentMapper(leafMapper).setHintMapper(leafMapper);
|
|
47317
|
-
return mapper.mapTree(rendererDataTree, this.props.shape);
|
|
47318
|
-
}
|
|
47319
|
-
_scoreFromRef(ref) {
|
|
47320
|
-
if (!ref) {
|
|
47321
|
-
return null;
|
|
47322
|
-
}
|
|
47323
|
-
const [guess, score] = ref.guessAndScore();
|
|
47324
|
-
let state;
|
|
47325
|
-
if (ref.getSerializedState) {
|
|
47326
|
-
state = ref.getSerializedState();
|
|
47327
|
-
}
|
|
47328
|
-
return keScoreFromPerseusScore(score, guess, state);
|
|
47329
|
-
}
|
|
47330
|
-
|
|
47331
|
-
/**
|
|
47332
|
-
* Return a tree in the shape of the multi-item, with scores at each of
|
|
47333
|
-
* the content nodes and `null` at the other leaf nodes.
|
|
47334
|
-
*/
|
|
47335
|
-
getScores() {
|
|
47336
|
-
return this._mapRenderers(data => this._scoreFromRef(data.ref));
|
|
47337
|
-
}
|
|
47338
|
-
|
|
47339
|
-
/**
|
|
47340
|
-
* Return a single composite score for all rendered content nodes.
|
|
47341
|
-
* The `guess` is a tree in the shape of the multi-item, with an individual
|
|
47342
|
-
* guess at each content node and `null` at the other leaf nodes.
|
|
47343
|
-
*/
|
|
47344
|
-
score() {
|
|
47345
|
-
const scores = [];
|
|
47346
|
-
const state = [];
|
|
47347
|
-
const guess = this._mapRenderers(data => {
|
|
47348
|
-
if (!data.ref) {
|
|
47349
|
-
return null;
|
|
47350
|
-
}
|
|
47351
|
-
if (data.ref.getSerializedState) {
|
|
47352
|
-
state.push(data.ref.getSerializedState());
|
|
47353
|
-
}
|
|
47354
|
-
scores.push(data.ref.score());
|
|
47355
|
-
return data.ref?.getUserInput();
|
|
47356
|
-
});
|
|
47357
|
-
const combinedScore = scores.reduce(combineScores);
|
|
47358
|
-
return keScoreFromPerseusScore(combinedScore, guess, state);
|
|
47359
|
-
}
|
|
47360
|
-
|
|
47361
|
-
/**
|
|
47362
|
-
* Return a tree in the shape of the multi-item, with serialized state at
|
|
47363
|
-
* each of the content nodes and `null` at the other leaf nodes.
|
|
47364
|
-
*
|
|
47365
|
-
* If the lastSerializedState argument is supplied, this function will fill
|
|
47366
|
-
* in the state of not-currently-rendered content and hint nodes with the
|
|
47367
|
-
* values from the previous serialized state. If no lastSerializedState is
|
|
47368
|
-
* supplied, `null` will be returned for not-currently-rendered content and
|
|
47369
|
-
* hint nodes.
|
|
47370
|
-
*/
|
|
47371
|
-
_getSerializedState(lastSerializedState) {
|
|
47372
|
-
return this._mapRenderers((data, _, path) => {
|
|
47373
|
-
if (data.ref) {
|
|
47374
|
-
return data.ref.getSerializedState();
|
|
47375
|
-
}
|
|
47376
|
-
if (lastSerializedState) {
|
|
47377
|
-
return lens(lastSerializedState).get(path);
|
|
47378
|
-
}
|
|
47379
|
-
return null;
|
|
47380
|
-
});
|
|
47381
|
-
}
|
|
47382
|
-
|
|
47383
|
-
/**
|
|
47384
|
-
* Given a tree in the shape of the multi-item, with serialized state at
|
|
47385
|
-
* each of the content nodes, restore each state to the corresponding
|
|
47386
|
-
* renderer if currently mounted.
|
|
47387
|
-
*/
|
|
47388
|
-
restoreSerializedState(serializedState, callback) {
|
|
47389
|
-
// We want to call our async callback only once all of the childrens'
|
|
47390
|
-
// callbacks have run. We add one to this counter before we call out to
|
|
47391
|
-
// each renderer and decrement it when it runs our callback.
|
|
47392
|
-
let numCallbacks = 0;
|
|
47393
|
-
const countCallback = () => {
|
|
47394
|
-
numCallbacks--;
|
|
47395
|
-
if (callback && numCallbacks === 0) {
|
|
47396
|
-
callback();
|
|
47397
|
-
}
|
|
47398
|
-
};
|
|
47399
|
-
this._mapRenderers((data, _, path) => {
|
|
47400
|
-
if (!data.ref) {
|
|
47401
|
-
return;
|
|
47402
|
-
}
|
|
47403
|
-
const state = lens(serializedState).get(path);
|
|
47404
|
-
if (!state) {
|
|
47405
|
-
return;
|
|
47406
|
-
}
|
|
47407
|
-
numCallbacks++;
|
|
47408
|
-
data.ref?.restoreSerializedState(state, countCallback);
|
|
47409
|
-
});
|
|
47410
|
-
}
|
|
47411
|
-
|
|
47412
|
-
/**
|
|
47413
|
-
* Given an array of renderers, if it happens to be an array of *hint*
|
|
47414
|
-
* renderers, then attach a `firstN` method to the array, which allows the
|
|
47415
|
-
* layout to render the hints together in one HintsRenderer.
|
|
47416
|
-
*/
|
|
47417
|
-
_annotateRendererArray(renderers, rendererDatas, shape) {
|
|
47418
|
-
if (shape.elementShape.type === "hint") {
|
|
47419
|
-
// The shape says that these are HintRendererDatas, even though
|
|
47420
|
-
// it's not provable at compile time, so perform a cast.
|
|
47421
|
-
const hintRendererDatas = rendererDatas;
|
|
47422
|
-
renderers = [...renderers];
|
|
47423
|
-
renderers.firstN = n => /*#__PURE__*/React__namespace.createElement(HintsRenderer, _extends({}, this._getRendererProps(), {
|
|
47424
|
-
findExternalWidgets: hintRendererDatas[0] ? hintRendererDatas[0].findExternalWidgets : undefined,
|
|
47425
|
-
hints: hintRendererDatas.map(d => d.hint),
|
|
47426
|
-
hintsVisible: n
|
|
47427
|
-
}));
|
|
47428
|
-
}
|
|
47429
|
-
return renderers;
|
|
47430
|
-
}
|
|
47431
|
-
|
|
47432
|
-
/**
|
|
47433
|
-
* Return a tree in the shape of the multi-item, with a Renderer at each
|
|
47434
|
-
* content node and a HintRenderer at each hint node.
|
|
47435
|
-
*
|
|
47436
|
-
* This is generated by running each of the `makeRenderer` functions at the
|
|
47437
|
-
* leaf nodes.
|
|
47438
|
-
*/
|
|
47439
|
-
_getRenderers() {
|
|
47440
|
-
return this.getRenderersMapper.mapTree(this.state.rendererDataTree, this.props.shape);
|
|
47441
|
-
}
|
|
47442
|
-
render() {
|
|
47443
|
-
if (this.state.renderError) {
|
|
47444
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
47445
|
-
className: aphrodite.css(styles.error)
|
|
47446
|
-
}, this.context.strings.errorRendering({
|
|
47447
|
-
error: String(this.state.renderError)
|
|
47448
|
-
}));
|
|
47449
|
-
}
|
|
47450
|
-
|
|
47451
|
-
// Pass the renderer tree to the `children` function, which will
|
|
47452
|
-
// determine the actual content of this component.
|
|
47453
|
-
return /*#__PURE__*/React__namespace.createElement(DependenciesContext.Provider, {
|
|
47454
|
-
value: this.props.dependencies
|
|
47455
|
-
}, this.props.children({
|
|
47456
|
-
renderers: this._getRenderers()
|
|
47457
|
-
}));
|
|
47458
|
-
}
|
|
47459
|
-
}
|
|
47460
|
-
const styles = aphrodite.StyleSheet.create({
|
|
47461
|
-
error: {
|
|
47462
|
-
color: "red"
|
|
47463
|
-
}
|
|
47464
|
-
});
|
|
47465
|
-
|
|
47466
|
-
/**
|
|
47467
|
-
* Utility functions to build React PropTypes for multi-items and shapes.
|
|
47468
|
-
*
|
|
47469
|
-
* If you're writing new components, though, consider using the Item and Shape
|
|
47470
|
-
* types instead.
|
|
47471
|
-
*/
|
|
47472
|
-
/**
|
|
47473
|
-
* Return a PropType that accepts Items of the given shape, and rejects other
|
|
47474
|
-
* objects.
|
|
47475
|
-
*
|
|
47476
|
-
* Usage: `propTypes: {item: buildPropTypeForShape(myShape)}`
|
|
47477
|
-
*/
|
|
47478
|
-
function buildPropTypeForShape(shape) {
|
|
47479
|
-
return PropTypes__default["default"].oneOfType([PropTypes__default["default"].shape({
|
|
47480
|
-
_multi: buildTreePropTypeForShape(shape)
|
|
47481
|
-
}), PropTypes__default["default"].oneOf([null, undefined])]);
|
|
47482
|
-
}
|
|
47483
|
-
|
|
47484
|
-
/**
|
|
47485
|
-
* Return a PropType that accepts ItemTrees of the given shape, and rejects
|
|
47486
|
-
* other objects.
|
|
47487
|
-
*/
|
|
47488
|
-
function buildTreePropTypeForShape(shape) {
|
|
47489
|
-
if (shape.type === "content") {
|
|
47490
|
-
return PropTypes__default["default"].shape({
|
|
47491
|
-
// TODO(mdr): Remove #LegacyContentNode support.
|
|
47492
|
-
__type: PropTypes__default["default"].oneOf(["content", "item"]).isRequired,
|
|
47493
|
-
content: PropTypes__default["default"].string,
|
|
47494
|
-
images: PropTypes__default["default"].objectOf(PropTypes__default["default"].any),
|
|
47495
|
-
widgets: PropTypes__default["default"].objectOf(PropTypes__default["default"].any)
|
|
47496
|
-
});
|
|
47497
|
-
}
|
|
47498
|
-
if (shape.type === "hint") {
|
|
47499
|
-
return PropTypes__default["default"].shape({
|
|
47500
|
-
__type: PropTypes__default["default"].oneOf(["hint"]).isRequired,
|
|
47501
|
-
content: PropTypes__default["default"].string,
|
|
47502
|
-
images: PropTypes__default["default"].objectOf(PropTypes__default["default"].any),
|
|
47503
|
-
widgets: PropTypes__default["default"].objectOf(PropTypes__default["default"].any),
|
|
47504
|
-
replace: PropTypes__default["default"].bool
|
|
47505
|
-
});
|
|
47506
|
-
}
|
|
47507
|
-
if (shape.type === "tags") {
|
|
47508
|
-
return PropTypes__default["default"].arrayOf(PropTypes__default["default"].string.isRequired);
|
|
47509
|
-
}
|
|
47510
|
-
if (shape.type === "array") {
|
|
47511
|
-
const elementPropType = buildTreePropTypeForShape(shape.elementShape);
|
|
47512
|
-
return PropTypes__default["default"].arrayOf(elementPropType.isRequired);
|
|
47513
|
-
}
|
|
47514
|
-
if (shape.type === "object") {
|
|
47515
|
-
const valueShapes = shape.shape;
|
|
47516
|
-
const propTypeShape = {};
|
|
47517
|
-
Object.keys(valueShapes).forEach(key => {
|
|
47518
|
-
propTypeShape[key] = buildTreePropTypeForShape(valueShapes[key]).isRequired;
|
|
47519
|
-
});
|
|
47520
|
-
return PropTypes__default["default"].shape(propTypeShape);
|
|
47521
|
-
}
|
|
47522
|
-
throw new perseusCore.PerseusError(
|
|
47523
|
-
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
47524
|
-
`unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
|
|
47525
|
-
}
|
|
47526
|
-
|
|
47527
|
-
/**
|
|
47528
|
-
* This library provides support for Perseus multi-items: structured Perseus
|
|
47529
|
-
* content that content creators can easily create, and that applications can
|
|
47530
|
-
* easily render into different parts of the layout.
|
|
47531
|
-
*
|
|
47532
|
-
* For more details about application and motivation, see:
|
|
47533
|
-
* https://sites.google.com/a/khanacademy.org/forge/for-developers/perseus-items-and-multi-items
|
|
47534
|
-
*
|
|
47535
|
-
* This file primarily exposes the `MultiRenderer` component, which performs
|
|
47536
|
-
* multi-rendering. To multi-render a question, pass in the content of the item
|
|
47537
|
-
* to the `MultiRenderer` component as a props. Then, pass in a function which
|
|
47538
|
-
* takes an object of renderers (in the same structure as the content), and
|
|
47539
|
-
* return a render tree. The `MultiRenderer` component will allow you to
|
|
47540
|
-
* combine scores, serialized state, etc. without having to manually call on
|
|
47541
|
-
* each of the functions. It also handles inter-widgets requests between the
|
|
47542
|
-
* different renderers.
|
|
47543
|
-
* For more details, see `multi-items/multi-renderer.jsx`.
|
|
47544
|
-
*
|
|
47545
|
-
* Example:
|
|
47546
|
-
*
|
|
47547
|
-
* item = {_multi: {
|
|
47548
|
-
* left: <content data>,
|
|
47549
|
-
* right: [<content data>, <content data>],
|
|
47550
|
-
* }}
|
|
47551
|
-
* shape = shapes.shape({
|
|
47552
|
-
* left: shapes.content,
|
|
47553
|
-
* right: shapes.arrayOf(shapes.content),
|
|
47554
|
-
* })
|
|
47555
|
-
*
|
|
47556
|
-
* <MultiRenderer item={item} shape={shape}>
|
|
47557
|
-
* {({renderers}) =>
|
|
47558
|
-
* <div>
|
|
47559
|
-
* <div id="left">{renderers.left}</div>
|
|
47560
|
-
* <ul id="right">
|
|
47561
|
-
* {renderers.right.map(r => <li>{r}</li>)}
|
|
47562
|
-
* </ul>
|
|
47563
|
-
* </div>
|
|
47564
|
-
* }
|
|
47565
|
-
* </MultiRenderer>
|
|
47566
|
-
*
|
|
47567
|
-
* This file also exposes `shapes`, which helps you construct a runtime type
|
|
47568
|
-
* declaration for your particular class of multi-item. This can then be used
|
|
47569
|
-
* to create a MultirendererEditor for your multi-item shape, and to validate
|
|
47570
|
-
* that a multi-item conforms to the shape via `buildPropTypeForShape`.
|
|
47571
|
-
* For more details, see `multi-items/shapes.js`.
|
|
47572
|
-
*
|
|
47573
|
-
* This file also exposes some utility functions for working with generic
|
|
47574
|
-
* multi-items, like `findContentNodesInItem`, `findHintNodesInItem`,
|
|
47575
|
-
* `inferItemShape`, and `buildEmptyItemForShape`.
|
|
47576
|
-
* For more details, see `multi-items/items.js`.
|
|
47577
|
-
*/
|
|
47578
|
-
var MultiItems = {
|
|
47579
|
-
// Tools for rendering your multi-items
|
|
47580
|
-
MultiRenderer,
|
|
47581
|
-
// Tools for declaring your multi-item shapes
|
|
47582
|
-
shapes,
|
|
47583
|
-
buildPropTypeForShape,
|
|
47584
|
-
// Tools for generically manipulating multi-items
|
|
47585
|
-
buildEmptyItemForShape,
|
|
47586
|
-
findContentNodesInItem: findContentNodesInItem$2,
|
|
47587
|
-
findHintNodesInItem,
|
|
47588
|
-
inferItemShape: inferItemShape$2
|
|
47589
|
-
};
|
|
47590
|
-
|
|
47591
46470
|
/**
|
|
47592
46471
|
* Calculates whether a perseus item is renderable by a specific
|
|
47593
46472
|
* perseus-item-data version.
|
|
@@ -47597,10 +46476,6 @@ var MultiItems = {
|
|
|
47597
46476
|
* This supports widgets that contain renderers, such as the
|
|
47598
46477
|
* group or sequence widgets.
|
|
47599
46478
|
*/
|
|
47600
|
-
const {
|
|
47601
|
-
findContentNodesInItem: findContentNodesInItem$1,
|
|
47602
|
-
inferItemShape: inferItemShape$1
|
|
47603
|
-
} = MultiItems;
|
|
47604
46479
|
const isUpgradedWidgetInfoRenderableBy = function (widgetInfo, widgetRendererVersion) {
|
|
47605
46480
|
if (widgetRendererVersion == null) {
|
|
47606
46481
|
// If the widget does not exist in this version, this will
|
|
@@ -47646,17 +46521,6 @@ const isItemRenderableByVersion = function (itemData, rendererContentVersion) {
|
|
|
47646
46521
|
if (itemData == null || rendererContentVersion == null) {
|
|
47647
46522
|
throw new perseusCore.PerseusError("missing parameter to Perseus.isRenderable.item", perseusCore.Errors.InvalidInput);
|
|
47648
46523
|
}
|
|
47649
|
-
if (itemData._multi) {
|
|
47650
|
-
const shape = inferItemShape$1(itemData);
|
|
47651
|
-
let isRenderable = true;
|
|
47652
|
-
findContentNodesInItem$1(itemData, shape, node => {
|
|
47653
|
-
const nodeIsRenderable = isRendererContentRenderableBy(node, rendererContentVersion);
|
|
47654
|
-
if (!nodeIsRenderable) {
|
|
47655
|
-
isRenderable = false;
|
|
47656
|
-
}
|
|
47657
|
-
});
|
|
47658
|
-
return isRenderable;
|
|
47659
|
-
}
|
|
47660
46524
|
return isRendererContentRenderableBy(itemData.question, rendererContentVersion);
|
|
47661
46525
|
};
|
|
47662
46526
|
|
|
@@ -47664,10 +46528,6 @@ const isItemRenderableByVersion = function (itemData, rendererContentVersion) {
|
|
|
47664
46528
|
* Identifies whether or not a given perseus item requires the use of a mouse
|
|
47665
46529
|
* or screen, based on the widgets it contains.
|
|
47666
46530
|
*/
|
|
47667
|
-
const {
|
|
47668
|
-
findContentNodesInItem,
|
|
47669
|
-
inferItemShape
|
|
47670
|
-
} = MultiItems;
|
|
47671
46531
|
|
|
47672
46532
|
// Iterate over a single Perseus renderer, mutating `widgets` by appending
|
|
47673
46533
|
// violating widget types discovered in this item.
|
|
@@ -47688,12 +46548,7 @@ function traverseRenderer(itemData, widgets) {
|
|
|
47688
46548
|
function violatingWidgets(itemData) {
|
|
47689
46549
|
// TODO(jordan): Hints as well
|
|
47690
46550
|
const widgets = [];
|
|
47691
|
-
|
|
47692
|
-
const shape = inferItemShape(itemData);
|
|
47693
|
-
findContentNodesInItem(itemData, shape, content => traverseRenderer(content, widgets));
|
|
47694
|
-
} else {
|
|
47695
|
-
traverseRenderer(itemData.question, widgets);
|
|
47696
|
-
}
|
|
46551
|
+
traverseRenderer(itemData.question, widgets);
|
|
47697
46552
|
|
|
47698
46553
|
// Uniquify the list of widgets (by type)
|
|
47699
46554
|
return ___default["default"].uniq(widgets);
|
|
@@ -50216,6 +49071,10 @@ const ScoringUtil = {
|
|
|
50216
49071
|
keScoreFromPerseusScore
|
|
50217
49072
|
};
|
|
50218
49073
|
|
|
49074
|
+
/**
|
|
49075
|
+
* Types
|
|
49076
|
+
*/
|
|
49077
|
+
|
|
50219
49078
|
exports.ApiOptions = ApiOptions;
|
|
50220
49079
|
exports.ArticleRenderer = ArticleRenderer;
|
|
50221
49080
|
exports.BaseRadio = BaseRadio;
|
|
@@ -50238,7 +49097,6 @@ exports.KhanMath = KhanMath;
|
|
|
50238
49097
|
exports.LoadingContext = context;
|
|
50239
49098
|
exports.Log = Log;
|
|
50240
49099
|
exports.MatrixWidget = Matrix$1;
|
|
50241
|
-
exports.MultiItems = MultiItems;
|
|
50242
49100
|
exports.NumericInput = NumericInput$1;
|
|
50243
49101
|
exports.PerseusExpressionAnswerFormConsidered = PerseusExpressionAnswerFormConsidered;
|
|
50244
49102
|
exports.PerseusI18nContext = PerseusI18nContext;
|
|
@@ -50257,8 +49115,6 @@ exports.Widgets = widgets$1;
|
|
|
50257
49115
|
exports.addWidget = addWidget;
|
|
50258
49116
|
exports.apiVersion = apiVersion;
|
|
50259
49117
|
exports.bodyXsmallBold = bodyXsmallBold;
|
|
50260
|
-
exports.buildEmptyItemTreeForShape = buildEmptyItemTreeForShape;
|
|
50261
|
-
exports.buildMapper = buildMapper;
|
|
50262
49118
|
exports.components = components;
|
|
50263
49119
|
exports.containerSizeClass = containerSizeClass;
|
|
50264
49120
|
exports.contentHasWidgetType = contentHasWidgetType;
|
|
@@ -50302,7 +49158,6 @@ exports.isItemRenderableByVersion = isItemRenderableByVersion;
|
|
|
50302
49158
|
exports.isWidgetIdInContent = isWidgetIdInContent;
|
|
50303
49159
|
exports.isWrongAnswerSupported = isWrongAnswerSupported;
|
|
50304
49160
|
exports.itemDataVersion = itemDataVersion;
|
|
50305
|
-
exports.itemToTree = itemToTree;
|
|
50306
49161
|
exports.itemVersion = ItemVersion;
|
|
50307
49162
|
exports.libVersion = libVersion;
|
|
50308
49163
|
exports.lockedFigureColors = lockedFigureColors;
|
|
@@ -50315,7 +49170,6 @@ exports.plotterPlotTypes = plotterPlotTypes;
|
|
|
50315
49170
|
exports.preprocessTex = preprocessTex;
|
|
50316
49171
|
exports.registerAllWidgetsForTesting = registerAllWidgetsForTesting;
|
|
50317
49172
|
exports.scorePerseusItem = scorePerseusItem;
|
|
50318
|
-
exports.shapes = shapes;
|
|
50319
49173
|
exports.shouldHaveIndividualAnswer = shouldHaveIndividualAnswer;
|
|
50320
49174
|
exports.traverse = traverse;
|
|
50321
49175
|
exports.usePerseusI18n = usePerseusI18n;
|