@khanacademy/perseus-editor 14.1.2 → 14.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/util.d.ts +0 -14
- package/dist/es/index.js +1399 -1373
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +1457 -1427
- package/dist/index.js.map +1 -1
- package/dist/{components → widgets/interactive-graph-editor/components}/graph-points-count-selector.d.ts +1 -1
- package/dist/{components → widgets/interactive-graph-editor/components}/graph-type-selector.d.ts +1 -0
- package/dist/{components → widgets/interactive-graph-editor/components}/interactive-graph-description.d.ts +1 -1
- package/dist/widgets/interactive-graph-editor/interactive-graph-editor.d.ts +220 -128
- package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figures-section.d.ts +1 -1
- package/dist/widgets/interactive-graph-editor/locked-figures/util.d.ts +9 -0
- package/dist/widgets/interactive-graph-editor/start-coords/start-coords-angle.d.ts +9 -0
- package/dist/widgets/interactive-graph-editor/start-coords/start-coords-circle.d.ts +12 -0
- package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-line.d.ts +2 -2
- package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-multiline.d.ts +2 -2
- package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-point.d.ts +2 -2
- package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-quadratic.d.ts +2 -2
- package/dist/{components → widgets/interactive-graph-editor/start-coords}/start-coords-settings.d.ts +2 -1
- package/dist/widgets/interactive-graph-editor/start-coords/start-coords-sinusoid.d.ts +9 -0
- package/dist/widgets/interactive-graph-editor/start-coords/types.d.ts +24 -0
- package/dist/widgets/interactive-graph-editor/start-coords/util.d.ts +8 -0
- package/package.json +2 -2
- package/dist/components/start-coords-angle.d.ts +0 -8
- package/dist/components/start-coords-circle.d.ts +0 -11
- package/dist/components/start-coords-sinusoid.d.ts +0 -8
- /package/dist/{components → widgets/interactive-graph-editor/components}/interactive-graph-correct-answer.d.ts +0 -0
- /package/dist/{components → widgets/interactive-graph-editor/components}/interactive-graph-settings.d.ts +0 -0
- /package/dist/{components → widgets/interactive-graph-editor/components}/segment-count-selector.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/color-select.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/color-swatch.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/defining-point-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/ellipse-swatch.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/labeled-row.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/labeled-switch.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/line-stroke-select.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/line-swatch.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-ellipse-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-select.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-settings-actions.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-function-examples.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-function-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-label-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-line-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-point-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-polygon-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-vector-settings.d.ts +0 -0
- /package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/polygon-swatch.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ var wonderStuffCore = require('@khanacademy/wonder-stuff-core');
|
|
|
26
26
|
var mathInput = require('@khanacademy/math-input');
|
|
27
27
|
var kmath = require('@khanacademy/kmath');
|
|
28
28
|
var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
|
|
29
|
+
var Banner = require('@khanacademy/wonder-blocks-banner');
|
|
29
30
|
var wonderBlocksAccordion = require('@khanacademy/wonder-blocks-accordion');
|
|
30
31
|
var IconButton = require('@khanacademy/wonder-blocks-icon-button');
|
|
31
32
|
var caretDoubleDownIcon = require('@phosphor-icons/core/bold/caret-double-down-bold.svg');
|
|
@@ -41,7 +42,6 @@ var arrowFatRight = require('@phosphor-icons/core/regular/arrow-fat-right.svg');
|
|
|
41
42
|
var arrowFatUp = require('@phosphor-icons/core/regular/arrow-fat-up.svg');
|
|
42
43
|
var minusCircle = require('@phosphor-icons/core/regular/minus-circle.svg');
|
|
43
44
|
var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
|
|
44
|
-
var Banner = require('@khanacademy/wonder-blocks-banner');
|
|
45
45
|
var arrowCounterClockwise = require('@phosphor-icons/core/bold/arrow-counter-clockwise-bold.svg');
|
|
46
46
|
|
|
47
47
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -76,6 +76,7 @@ var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
|
|
|
76
76
|
var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
|
|
77
77
|
var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
|
|
78
78
|
var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
|
|
79
|
+
var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
|
|
79
80
|
var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
80
81
|
var caretDoubleDownIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleDownIcon);
|
|
81
82
|
var caretDoubleUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDoubleUpIcon);
|
|
@@ -90,12 +91,11 @@ var arrowFatRight__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatRight);
|
|
|
90
91
|
var arrowFatUp__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatUp);
|
|
91
92
|
var minusCircle__default = /*#__PURE__*/_interopDefaultLegacy(minusCircle);
|
|
92
93
|
var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
|
|
93
|
-
var Banner__default = /*#__PURE__*/_interopDefaultLegacy(Banner);
|
|
94
94
|
var arrowCounterClockwise__default = /*#__PURE__*/_interopDefaultLegacy(arrowCounterClockwise);
|
|
95
95
|
|
|
96
96
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
97
97
|
const libName = "@khanacademy/perseus-editor";
|
|
98
|
-
const libVersion = "14.
|
|
98
|
+
const libVersion = "14.2.0";
|
|
99
99
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
100
100
|
|
|
101
101
|
function _extends() {
|
|
@@ -29585,39 +29585,96 @@ function invariant(condition, message) {
|
|
|
29585
29585
|
throw new Error(value);
|
|
29586
29586
|
}
|
|
29587
29587
|
|
|
29588
|
-
|
|
29589
|
-
|
|
29590
|
-
|
|
29591
|
-
|
|
29592
|
-
|
|
29593
|
-
|
|
29594
|
-
|
|
29595
|
-
|
|
29596
|
-
|
|
29597
|
-
|
|
29598
|
-
|
|
29599
|
-
|
|
29600
|
-
|
|
29601
|
-
|
|
29602
|
-
|
|
29603
|
-
|
|
29604
|
-
}
|
|
29588
|
+
const UNLIMITED = "unlimited";
|
|
29589
|
+
// Parses a string (ostensibly from some UI element that only supports string
|
|
29590
|
+
// types, such as a <select />) into a numeric point count or the special sigil
|
|
29591
|
+
// "unlimited". Note that 0 is a special case, and means "unlimited".
|
|
29592
|
+
const parsePointCount = points => {
|
|
29593
|
+
const parsed = parseInt(points, 10);
|
|
29594
|
+
if (isNaN(parsed)) {
|
|
29595
|
+
return UNLIMITED;
|
|
29596
|
+
}
|
|
29597
|
+
return parsed === 0 ? UNLIMITED : parsed;
|
|
29598
|
+
};
|
|
29599
|
+
|
|
29600
|
+
const GraphPointsCountSelector = _ref => {
|
|
29601
|
+
let {
|
|
29602
|
+
numPoints = 1,
|
|
29603
|
+
onChange
|
|
29604
|
+
} = _ref;
|
|
29605
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
29606
|
+
selectedValue: `${numPoints}`,
|
|
29607
|
+
onChange: newValue => {
|
|
29608
|
+
onChange(parsePointCount(newValue));
|
|
29609
|
+
}
|
|
29610
|
+
// Never uses placeholder, always has value
|
|
29611
|
+
,
|
|
29612
|
+
placeholder: "",
|
|
29613
|
+
style: styles$J.singleSelectShort
|
|
29614
|
+
}, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29615
|
+
key: n,
|
|
29616
|
+
value: `${n}`,
|
|
29617
|
+
label: `${n} point${n > 1 ? "s" : ""}`
|
|
29618
|
+
})), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29619
|
+
key: "unlimited",
|
|
29620
|
+
value: UNLIMITED,
|
|
29621
|
+
label: "unlimited"
|
|
29622
|
+
})]);
|
|
29605
29623
|
};
|
|
29606
29624
|
const styles$J = aphrodite.StyleSheet.create({
|
|
29607
|
-
|
|
29608
|
-
|
|
29609
|
-
|
|
29610
|
-
|
|
29611
|
-
|
|
29612
|
-
|
|
29613
|
-
|
|
29614
|
-
|
|
29615
|
-
|
|
29616
|
-
|
|
29617
|
-
|
|
29618
|
-
|
|
29619
|
-
|
|
29620
|
-
|
|
29625
|
+
singleSelectShort: {
|
|
29626
|
+
// Non-standard spacing, but it's the smallest we can go
|
|
29627
|
+
// without running into styling issues with the dropdown.
|
|
29628
|
+
height: 26
|
|
29629
|
+
}
|
|
29630
|
+
});
|
|
29631
|
+
|
|
29632
|
+
const GraphTypeSelector = props => {
|
|
29633
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
29634
|
+
selectedValue: props.graphType,
|
|
29635
|
+
onChange: props.onChange,
|
|
29636
|
+
placeholder: "Select an answer type",
|
|
29637
|
+
style: styles$I.singleSelectShort
|
|
29638
|
+
}, props.showNoneOption && /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29639
|
+
value: "none",
|
|
29640
|
+
label: "None"
|
|
29641
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29642
|
+
value: "linear",
|
|
29643
|
+
label: "Linear function"
|
|
29644
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29645
|
+
value: "quadratic",
|
|
29646
|
+
label: "Quadratic function"
|
|
29647
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29648
|
+
value: "sinusoid",
|
|
29649
|
+
label: "Sinusoid function"
|
|
29650
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29651
|
+
value: "circle",
|
|
29652
|
+
label: "Circle"
|
|
29653
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29654
|
+
value: "point",
|
|
29655
|
+
label: "Point(s)"
|
|
29656
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29657
|
+
value: "linear-system",
|
|
29658
|
+
label: "Linear System"
|
|
29659
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29660
|
+
value: "polygon",
|
|
29661
|
+
label: "Polygon"
|
|
29662
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29663
|
+
value: "segment",
|
|
29664
|
+
label: "Line Segment(s)"
|
|
29665
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29666
|
+
value: "ray",
|
|
29667
|
+
label: "Ray"
|
|
29668
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
29669
|
+
value: "angle",
|
|
29670
|
+
label: "Angle"
|
|
29671
|
+
}));
|
|
29672
|
+
};
|
|
29673
|
+
const styles$I = aphrodite.StyleSheet.create({
|
|
29674
|
+
singleSelectShort: {
|
|
29675
|
+
// Non-standard spacing, but it's the smallest we can go
|
|
29676
|
+
// without running into styling issues with the dropdown.
|
|
29677
|
+
height: 26
|
|
29621
29678
|
}
|
|
29622
29679
|
});
|
|
29623
29680
|
|
|
@@ -29629,11 +29686,11 @@ function Heading(_ref) {
|
|
|
29629
29686
|
onToggle
|
|
29630
29687
|
} = _ref;
|
|
29631
29688
|
return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
|
|
29632
|
-
style: [styles$
|
|
29689
|
+
style: [styles$H.container, !isCollapsible && styles$H.notClickable],
|
|
29633
29690
|
disabled: !isCollapsible,
|
|
29634
29691
|
onClick: () => isCollapsible && onToggle?.(!isOpen)
|
|
29635
29692
|
}, () => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
29636
|
-
style: styles$
|
|
29693
|
+
style: styles$H.heading
|
|
29637
29694
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
29638
29695
|
style: {
|
|
29639
29696
|
fontSize: 14,
|
|
@@ -29643,7 +29700,7 @@ function Heading(_ref) {
|
|
|
29643
29700
|
isExpanded: isOpen
|
|
29644
29701
|
})));
|
|
29645
29702
|
}
|
|
29646
|
-
const styles$
|
|
29703
|
+
const styles$H = aphrodite.StyleSheet.create({
|
|
29647
29704
|
container: {
|
|
29648
29705
|
marginTop: wonderBlocksTokens.spacing.small_12,
|
|
29649
29706
|
// NOTE(jeremy): This is the inverse of the @editorPadding CSS
|
|
@@ -29667,348 +29724,765 @@ const styles$I = aphrodite.StyleSheet.create({
|
|
|
29667
29724
|
}
|
|
29668
29725
|
});
|
|
29669
29726
|
|
|
29670
|
-
function
|
|
29671
|
-
|
|
29672
|
-
|
|
29673
|
-
|
|
29674
|
-
|
|
29675
|
-
|
|
29676
|
-
|
|
29677
|
-
|
|
29678
|
-
|
|
29679
|
-
|
|
29680
|
-
|
|
29681
|
-
|
|
29682
|
-
|
|
29683
|
-
|
|
29684
|
-
|
|
29685
|
-
|
|
29686
|
-
|
|
29687
|
-
|
|
29688
|
-
|
|
29689
|
-
|
|
29690
|
-
|
|
29691
|
-
// `preventScroll` option otherwise.
|
|
29692
|
-
//
|
|
29693
|
-
// focusOptions documentation:
|
|
29694
|
-
//
|
|
29695
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
|
|
29696
|
-
//
|
|
29697
|
-
// Note that there could be cases where we want default focus() behavior.
|
|
29698
|
-
// One that comes to mind is a dropdown with a long list of options that
|
|
29699
|
-
// might be rendered off screen when opened. With this workaround the
|
|
29700
|
-
// selected option would not be scrolled into view if the option is near
|
|
29701
|
-
// the end of the list. We're not aware of any uses of the dropdown where
|
|
29702
|
-
// this is an issue, however, so there isn't currently a way to out of the
|
|
29703
|
-
// `preventScroll` behavior.
|
|
29704
|
-
|
|
29705
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
|
|
29706
|
-
element.focus({
|
|
29707
|
-
preventScroll: true
|
|
29708
|
-
});
|
|
29709
|
-
}
|
|
29710
|
-
const DEFAULT_COLOR = "grayH";
|
|
29711
|
-
function getDefaultFigureForType(type) {
|
|
29712
|
-
switch (type) {
|
|
29713
|
-
case "point":
|
|
29714
|
-
return {
|
|
29715
|
-
type: "point",
|
|
29716
|
-
coord: [0, 0],
|
|
29717
|
-
color: DEFAULT_COLOR,
|
|
29718
|
-
filled: true
|
|
29719
|
-
};
|
|
29720
|
-
case "line":
|
|
29721
|
-
return {
|
|
29722
|
-
type: "line",
|
|
29723
|
-
kind: "line",
|
|
29724
|
-
points: [getDefaultFigureForType("point"), {
|
|
29725
|
-
...getDefaultFigureForType("point"),
|
|
29726
|
-
coord: [2, 2]
|
|
29727
|
-
}],
|
|
29728
|
-
color: DEFAULT_COLOR,
|
|
29729
|
-
lineStyle: "solid",
|
|
29730
|
-
showPoint1: false,
|
|
29731
|
-
showPoint2: false
|
|
29732
|
-
};
|
|
29733
|
-
case "vector":
|
|
29734
|
-
return {
|
|
29735
|
-
type: "vector",
|
|
29736
|
-
points: [[0, 0], [2, 2]],
|
|
29737
|
-
color: DEFAULT_COLOR
|
|
29738
|
-
};
|
|
29739
|
-
case "ellipse":
|
|
29740
|
-
return {
|
|
29741
|
-
type: "ellipse",
|
|
29742
|
-
center: [0, 0],
|
|
29743
|
-
radius: [1, 1],
|
|
29744
|
-
angle: 0,
|
|
29745
|
-
color: DEFAULT_COLOR,
|
|
29746
|
-
fillStyle: "none",
|
|
29747
|
-
strokeStyle: "solid"
|
|
29748
|
-
};
|
|
29749
|
-
case "polygon":
|
|
29750
|
-
return {
|
|
29751
|
-
type: "polygon",
|
|
29752
|
-
points: [[0, 2], [-1, 0], [1, 0]],
|
|
29753
|
-
color: DEFAULT_COLOR,
|
|
29754
|
-
showVertices: false,
|
|
29755
|
-
fillStyle: "none",
|
|
29756
|
-
strokeStyle: "solid"
|
|
29757
|
-
};
|
|
29758
|
-
case "function":
|
|
29759
|
-
return {
|
|
29760
|
-
type: "function",
|
|
29761
|
-
color: DEFAULT_COLOR,
|
|
29762
|
-
strokeStyle: "solid",
|
|
29763
|
-
equation: "x^2",
|
|
29764
|
-
directionalAxis: "x"
|
|
29765
|
-
};
|
|
29766
|
-
case "label":
|
|
29767
|
-
return {
|
|
29768
|
-
type: "label",
|
|
29769
|
-
coord: [0, 0],
|
|
29770
|
-
text: "",
|
|
29771
|
-
color: DEFAULT_COLOR,
|
|
29772
|
-
size: "medium"
|
|
29773
|
-
};
|
|
29774
|
-
default:
|
|
29775
|
-
throw new wonderStuffCore.UnreachableCaseError(type);
|
|
29776
|
-
}
|
|
29777
|
-
}
|
|
29778
|
-
function degreeToRadian(degrees) {
|
|
29779
|
-
return degrees / 180 * Math.PI;
|
|
29780
|
-
}
|
|
29781
|
-
function radianToDegree(radians) {
|
|
29782
|
-
return radians / Math.PI * 180;
|
|
29783
|
-
}
|
|
29784
|
-
function getDefaultGraphStartCoords(graph, range, step) {
|
|
29785
|
-
switch (graph.type) {
|
|
29786
|
-
case "linear":
|
|
29787
|
-
case "ray":
|
|
29788
|
-
return perseus.getLineCoords({
|
|
29789
|
-
...graph,
|
|
29790
|
-
startCoords: undefined
|
|
29791
|
-
}, range, step);
|
|
29792
|
-
case "segment":
|
|
29793
|
-
return perseus.getSegmentCoords({
|
|
29794
|
-
...graph,
|
|
29795
|
-
startCoords: undefined
|
|
29796
|
-
}, range, step);
|
|
29797
|
-
case "linear-system":
|
|
29798
|
-
return perseus.getLinearSystemCoords({
|
|
29799
|
-
...graph,
|
|
29800
|
-
startCoords: undefined
|
|
29801
|
-
}, range, step);
|
|
29802
|
-
case "circle":
|
|
29803
|
-
const startCoords = perseus.getCircleCoords({
|
|
29804
|
-
...graph,
|
|
29805
|
-
startCoords: undefined
|
|
29806
|
-
});
|
|
29807
|
-
const radius = kmath.vector.length(kmath.vector.subtract(startCoords.radiusPoint, startCoords.center));
|
|
29808
|
-
return {
|
|
29809
|
-
center: startCoords.center,
|
|
29810
|
-
radius
|
|
29811
|
-
};
|
|
29812
|
-
case "sinusoid":
|
|
29813
|
-
return perseus.getSinusoidCoords({
|
|
29814
|
-
...graph,
|
|
29815
|
-
startCoords: undefined
|
|
29816
|
-
}, range, step);
|
|
29817
|
-
case "quadratic":
|
|
29818
|
-
return perseus.getQuadraticCoords({
|
|
29819
|
-
...graph,
|
|
29820
|
-
startCoords: undefined
|
|
29821
|
-
}, range, step);
|
|
29822
|
-
case "point":
|
|
29823
|
-
return perseus.getPointCoords({
|
|
29824
|
-
...graph,
|
|
29825
|
-
startCoords: undefined
|
|
29826
|
-
}, range, step);
|
|
29827
|
-
case "polygon":
|
|
29828
|
-
return perseus.getPolygonCoords({
|
|
29829
|
-
...graph,
|
|
29830
|
-
startCoords: undefined
|
|
29831
|
-
}, range, step);
|
|
29832
|
-
case "angle":
|
|
29833
|
-
return perseus.getAngleCoords({
|
|
29834
|
-
graph: {
|
|
29835
|
-
...graph,
|
|
29836
|
-
startCoords: undefined
|
|
29837
|
-
},
|
|
29838
|
-
range,
|
|
29839
|
-
step
|
|
29840
|
-
});
|
|
29841
|
-
default:
|
|
29842
|
-
return undefined;
|
|
29843
|
-
}
|
|
29727
|
+
function InteractiveGraphCorrectAnswer(props) {
|
|
29728
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
|
|
29729
|
+
title: "Correct Answer",
|
|
29730
|
+
isOpen: true,
|
|
29731
|
+
isCollapsible: false
|
|
29732
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
|
|
29733
|
+
style: {
|
|
29734
|
+
paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
|
|
29735
|
+
paddingBottom: wonderBlocksTokens.spacing.xxSmall_6,
|
|
29736
|
+
color: wonderBlocksTokens.color.offBlack64
|
|
29737
|
+
}
|
|
29738
|
+
}, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.BodyMonospace, {
|
|
29739
|
+
style: {
|
|
29740
|
+
fontSize: 12,
|
|
29741
|
+
backgroundColor: "#eee",
|
|
29742
|
+
paddingInline: wonderBlocksTokens.spacing.xxSmall_6,
|
|
29743
|
+
borderColor: "#ccc",
|
|
29744
|
+
borderStyle: "solid",
|
|
29745
|
+
borderWidth: 1
|
|
29746
|
+
}
|
|
29747
|
+
}, props.equationString)), props.children));
|
|
29844
29748
|
}
|
|
29845
|
-
const getSinusoidEquation = startCoords => {
|
|
29846
|
-
// Get coefficients
|
|
29847
|
-
// It's assumed that p1 is the root and p2 is the first peak
|
|
29848
|
-
const p1 = startCoords[0];
|
|
29849
|
-
const p2 = startCoords[1];
|
|
29850
|
-
|
|
29851
|
-
// Resulting coefficients are canonical for this sine curve
|
|
29852
|
-
const amplitude = p2[1] - p1[1];
|
|
29853
|
-
const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
|
|
29854
|
-
const phase = p1[0] * angularFrequency;
|
|
29855
|
-
const verticalOffset = p1[1];
|
|
29856
|
-
return "y = " + amplitude.toFixed(3) + "sin(" + angularFrequency.toFixed(3) + "x - " + phase.toFixed(3) + ") + " + verticalOffset.toFixed(3);
|
|
29857
|
-
};
|
|
29858
|
-
const getQuadraticEquation = startCoords => {
|
|
29859
|
-
const p1 = startCoords[0];
|
|
29860
|
-
const p2 = startCoords[1];
|
|
29861
|
-
const p3 = startCoords[2];
|
|
29862
|
-
const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
|
|
29863
|
-
if (denom === 0) {
|
|
29864
|
-
// Many of the callers assume that the return value is always defined.
|
|
29865
|
-
return "Division by zero error";
|
|
29866
|
-
}
|
|
29867
|
-
const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
|
|
29868
|
-
const b = (p3[0] * p3[0] * (p1[1] - p2[1]) + p2[0] * p2[0] * (p3[1] - p1[1]) + p1[0] * p1[0] * (p2[1] - p3[1])) / denom;
|
|
29869
|
-
const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
|
|
29870
|
-
return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
|
|
29871
|
-
};
|
|
29872
|
-
const findAngle = (point1, point2) => {
|
|
29873
|
-
const x = point1[0] - point2[0];
|
|
29874
|
-
const y = point1[1] - point2[1];
|
|
29875
|
-
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
29876
|
-
};
|
|
29877
|
-
const getAngleEquation = startCoords => {
|
|
29878
|
-
const [point1, vertex, point2] = startCoords;
|
|
29879
|
-
const angle = findAngle(point2, vertex) - findAngle(point1, vertex);
|
|
29880
|
-
const roundedAngle = angle.toFixed(0);
|
|
29881
|
-
return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`;
|
|
29882
|
-
};
|
|
29883
|
-
const shouldShowStartCoordsUI = (graph, isStatic) => {
|
|
29884
|
-
// We don't show the start coords UI for static graphs, since
|
|
29885
|
-
// the coords shown for this are determined by the coords on the
|
|
29886
|
-
// "correct" graph. The start coords would not be used here.
|
|
29887
|
-
if (isStatic) {
|
|
29888
|
-
return false;
|
|
29889
|
-
}
|
|
29890
|
-
if (graph.type === "point" && graph.numPoints === "unlimited") {
|
|
29891
|
-
return false;
|
|
29892
|
-
}
|
|
29893
|
-
if (graph.type === "polygon" && (graph.numSides === "unlimited" || graph.snapTo === "angles" || graph.snapTo === "sides")) {
|
|
29894
|
-
return false;
|
|
29895
|
-
}
|
|
29896
|
-
return true;
|
|
29897
|
-
};
|
|
29898
29749
|
|
|
29899
|
-
|
|
29900
|
-
* Dropdown for selecting a locked figure to add to an interactive graph.
|
|
29901
|
-
* Locked figures are elements (points, segmeents, etc.) that are not
|
|
29902
|
-
* interactive, just present in the graph's background.
|
|
29903
|
-
*
|
|
29904
|
-
* Used in the interactive graph editor's locked figures section.
|
|
29905
|
-
*/
|
|
29906
|
-
const LockedFigureSelect = props => {
|
|
29750
|
+
function InteractiveGraphDescription(props) {
|
|
29907
29751
|
const {
|
|
29908
|
-
|
|
29752
|
+
ariaLabelValue,
|
|
29753
|
+
ariaDescriptionValue,
|
|
29909
29754
|
onChange
|
|
29910
29755
|
} = props;
|
|
29911
|
-
const
|
|
29912
|
-
|
|
29913
|
-
|
|
29914
|
-
|
|
29915
|
-
|
|
29916
|
-
|
|
29917
|
-
}, /*#__PURE__*/React__namespace.createElement(
|
|
29918
|
-
|
|
29919
|
-
|
|
29920
|
-
|
|
29921
|
-
|
|
29922
|
-
|
|
29923
|
-
|
|
29756
|
+
const [isOpen, setIsOpen] = React__namespace.useState(true);
|
|
29757
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
|
|
29758
|
+
title: "Description",
|
|
29759
|
+
isCollapsible: true,
|
|
29760
|
+
isOpen: isOpen,
|
|
29761
|
+
onToggle: setIsOpen
|
|
29762
|
+
}), isOpen && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
|
|
29763
|
+
style: styles$G.caption
|
|
29764
|
+
}, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who are visually impaired."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
29765
|
+
tag: "label"
|
|
29766
|
+
}, "Title", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
29767
|
+
value: ariaLabelValue,
|
|
29768
|
+
onChange: newValue => onChange({
|
|
29769
|
+
fullGraphAriaLabel: newValue
|
|
29770
|
+
}),
|
|
29771
|
+
style: styles$G.spaceAbove
|
|
29772
|
+
})), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
29773
|
+
size: wonderBlocksTokens.spacing.small_12
|
|
29774
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
29775
|
+
tag: "label"
|
|
29776
|
+
}, "Description", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextArea, {
|
|
29777
|
+
rows: 8,
|
|
29778
|
+
resizeType: "vertical",
|
|
29779
|
+
value: ariaDescriptionValue,
|
|
29780
|
+
onChange: newValue => onChange({
|
|
29781
|
+
fullGraphAriaDescription: newValue
|
|
29782
|
+
}),
|
|
29783
|
+
style: styles$G.spaceAbove
|
|
29924
29784
|
}))));
|
|
29925
|
-
}
|
|
29926
|
-
const styles$
|
|
29927
|
-
|
|
29928
|
-
|
|
29785
|
+
}
|
|
29786
|
+
const styles$G = aphrodite.StyleSheet.create({
|
|
29787
|
+
caption: {
|
|
29788
|
+
color: wonderBlocksTokens.color.offBlack64,
|
|
29789
|
+
paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
|
|
29790
|
+
paddingBottom: wonderBlocksTokens.spacing.xxSmall_6
|
|
29929
29791
|
},
|
|
29930
|
-
|
|
29931
|
-
|
|
29932
|
-
borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
|
|
29792
|
+
spaceAbove: {
|
|
29793
|
+
marginTop: wonderBlocksTokens.spacing.xxxSmall_4
|
|
29933
29794
|
}
|
|
29934
29795
|
});
|
|
29935
29796
|
|
|
29936
|
-
|
|
29937
|
-
|
|
29938
|
-
*
|
|
29939
|
-
* This makes it so that the text field's input number updates on scroll
|
|
29940
|
-
* without scrolling the page.
|
|
29941
|
-
*
|
|
29942
|
-
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
|
|
29943
|
-
* they only scroll the page. Inputs in React do NOT work this way (explanation
|
|
29944
|
-
* here: https://stackoverflow.com/a/68266494). By default, scrolling on a
|
|
29945
|
-
* focused number input in React causes BOTH the input value to change AND
|
|
29946
|
-
* the page to scroll. The behavior in this component is an improvement on
|
|
29947
|
-
* the React behavior, but it's the opposite of the native HTML behavior.
|
|
29948
|
-
*
|
|
29949
|
-
* NOTE 2: Firefox seems to have a custom override for this. Even with this
|
|
29950
|
-
* stopPropogation, Firefox matches the native HTML behavior.
|
|
29951
|
-
*/
|
|
29952
|
-
const ScrolllessNumberTextField = props => {
|
|
29953
|
-
const inputRef = React__namespace.useRef(null);
|
|
29954
|
-
React__namespace.useEffect(() => {
|
|
29955
|
-
const ref = inputRef.current;
|
|
29956
|
-
|
|
29957
|
-
// stopPropogation makes it so that the page scroll event is not
|
|
29958
|
-
// triggered when the input is focused and the user scrolls.
|
|
29959
|
-
// The input value will still change on scroll.
|
|
29960
|
-
const ignoreScroll = e => {
|
|
29961
|
-
e.stopPropagation();
|
|
29962
|
-
};
|
|
29963
|
-
ref?.addEventListener("wheel", ignoreScroll);
|
|
29964
|
-
return () => {
|
|
29965
|
-
ref?.removeEventListener("wheel", ignoreScroll);
|
|
29966
|
-
};
|
|
29967
|
-
}, [inputRef]);
|
|
29968
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, _extends({
|
|
29969
|
-
type: "number"
|
|
29970
|
-
}, props, {
|
|
29971
|
-
ref: inputRef
|
|
29972
|
-
}));
|
|
29973
|
-
};
|
|
29974
|
-
|
|
29975
|
-
const AngleInput = props => {
|
|
29797
|
+
// Renders the given children in a View laid out horizontally.
|
|
29798
|
+
const LabeledRow = props => {
|
|
29976
29799
|
const {
|
|
29977
|
-
|
|
29978
|
-
|
|
29800
|
+
children,
|
|
29801
|
+
label,
|
|
29802
|
+
labelSide = "left",
|
|
29803
|
+
style
|
|
29979
29804
|
} = props;
|
|
29980
|
-
|
|
29981
|
-
|
|
29982
|
-
|
|
29983
|
-
|
|
29984
|
-
|
|
29985
|
-
|
|
29986
|
-
|
|
29987
|
-
|
|
29988
|
-
|
|
29989
|
-
}
|
|
29990
|
-
|
|
29991
|
-
// Update the graph.
|
|
29992
|
-
onChange(degreeToRadian(newValue));
|
|
29993
|
-
}
|
|
29994
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
29995
|
-
tag: "label",
|
|
29996
|
-
style: styles$G.row
|
|
29997
|
-
}, "angle (degrees)", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
29998
|
-
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
29999
|
-
}), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
|
|
30000
|
-
value: angleInput,
|
|
30001
|
-
onChange: handleAngleChange,
|
|
30002
|
-
style: styles$G.textField
|
|
30003
|
-
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30004
|
-
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30005
|
-
}));
|
|
29805
|
+
return /*#__PURE__*/React__namespace.createElement("label", {
|
|
29806
|
+
className: aphrodite.css(styles$F.label)
|
|
29807
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
29808
|
+
style: [styles$F.row, style]
|
|
29809
|
+
}, labelSide === "start" || /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
|
|
29810
|
+
style: styles$F.spaceEnd
|
|
29811
|
+
}, label), children, labelSide === "end" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
|
|
29812
|
+
style: styles$F.spaceStart
|
|
29813
|
+
}, label)));
|
|
30006
29814
|
};
|
|
30007
|
-
const styles$
|
|
29815
|
+
const styles$F = aphrodite.StyleSheet.create({
|
|
29816
|
+
label: {
|
|
29817
|
+
width: "fit-content"
|
|
29818
|
+
},
|
|
30008
29819
|
row: {
|
|
30009
|
-
display: "flex",
|
|
30010
29820
|
flexDirection: "row",
|
|
30011
|
-
|
|
29821
|
+
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
29822
|
+
alignItems: "center",
|
|
29823
|
+
width: "fit-content"
|
|
29824
|
+
},
|
|
29825
|
+
spaceStart: {
|
|
29826
|
+
marginInlineStart: wonderBlocksTokens.spacing.xSmall_8
|
|
29827
|
+
},
|
|
29828
|
+
spaceEnd: {
|
|
29829
|
+
marginInlineEnd: wonderBlocksTokens.spacing.xSmall_8
|
|
29830
|
+
}
|
|
29831
|
+
});
|
|
29832
|
+
|
|
29833
|
+
/* eslint-disable react/forbid-prop-types, react/no-unsafe */
|
|
29834
|
+
const {
|
|
29835
|
+
ButtonGroup: ButtonGroup$2,
|
|
29836
|
+
InfoTip: InfoTip$d,
|
|
29837
|
+
RangeInput: RangeInput$4
|
|
29838
|
+
} = perseus.components;
|
|
29839
|
+
const defaultBackgroundImage$1 = {
|
|
29840
|
+
url: null,
|
|
29841
|
+
width: 0,
|
|
29842
|
+
height: 0
|
|
29843
|
+
};
|
|
29844
|
+
function numSteps(range, step) {
|
|
29845
|
+
return Math.floor((range[1] - range[0]) / step);
|
|
29846
|
+
}
|
|
29847
|
+
class InteractiveGraphSettings extends React__namespace.Component {
|
|
29848
|
+
_isMounted = false;
|
|
29849
|
+
bgUrlRef = /*#__PURE__*/React__namespace.createRef();
|
|
29850
|
+
labelXRef = /*#__PURE__*/React__namespace.createRef();
|
|
29851
|
+
labelYRef = /*#__PURE__*/React__namespace.createRef();
|
|
29852
|
+
static stateFromProps(props) {
|
|
29853
|
+
return {
|
|
29854
|
+
labelsTextbox: props.labels,
|
|
29855
|
+
gridStepTextbox: props.gridStep,
|
|
29856
|
+
snapStepTextbox: props.snapStep,
|
|
29857
|
+
stepTextbox: props.step,
|
|
29858
|
+
rangeTextbox: props.range,
|
|
29859
|
+
// Shallow-copied clone
|
|
29860
|
+
backgroundImage: {
|
|
29861
|
+
...props.backgroundImage
|
|
29862
|
+
}
|
|
29863
|
+
};
|
|
29864
|
+
}
|
|
29865
|
+
constructor(props) {
|
|
29866
|
+
super(props);
|
|
29867
|
+
this.state = {
|
|
29868
|
+
isExpanded: true,
|
|
29869
|
+
...InteractiveGraphSettings.stateFromProps(props)
|
|
29870
|
+
};
|
|
29871
|
+
}
|
|
29872
|
+
static defaultProps = {
|
|
29873
|
+
box: [perseus.interactiveSizes.defaultBoxSizeSmall, perseus.interactiveSizes.defaultBoxSizeSmall],
|
|
29874
|
+
labels: ["x", "y"],
|
|
29875
|
+
range: [[-10, 10], [-10, 10]],
|
|
29876
|
+
step: [1, 1],
|
|
29877
|
+
gridStep: [1, 1],
|
|
29878
|
+
snapStep: [1, 1],
|
|
29879
|
+
valid: true,
|
|
29880
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
29881
|
+
markings: "graph",
|
|
29882
|
+
showProtractor: false,
|
|
29883
|
+
showTooltips: false
|
|
29884
|
+
};
|
|
29885
|
+
componentDidMount() {
|
|
29886
|
+
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
29887
|
+
// this.isMounted() but is still considered an anti-pattern.
|
|
29888
|
+
this._isMounted = true;
|
|
29889
|
+
this.changeGraph = ___default["default"].debounce(this.changeGraph, 300);
|
|
29890
|
+
}
|
|
29891
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
29892
|
+
// Make sure that state updates when switching
|
|
29893
|
+
// between different items in a multi-item editor.
|
|
29894
|
+
if (!___default["default"].isEqual(this.props.labels, nextProps.labels) || !___default["default"].isEqual(this.props.gridStep, nextProps.gridStep) || !___default["default"].isEqual(this.props.snapStep, nextProps.snapStep) || !___default["default"].isEqual(this.props.step, nextProps.step) || !___default["default"].isEqual(this.props.range, nextProps.range) || !___default["default"].isEqual(this.props.backgroundImage, nextProps.backgroundImage)) {
|
|
29895
|
+
this.setState(InteractiveGraphSettings.stateFromProps(nextProps));
|
|
29896
|
+
}
|
|
29897
|
+
}
|
|
29898
|
+
componentWillUnmount() {
|
|
29899
|
+
this._isMounted = false;
|
|
29900
|
+
}
|
|
29901
|
+
change = (() => {
|
|
29902
|
+
var _this = this;
|
|
29903
|
+
return function () {
|
|
29904
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
29905
|
+
args[_key] = arguments[_key];
|
|
29906
|
+
}
|
|
29907
|
+
return perseus.Changeable.change.apply(_this, args);
|
|
29908
|
+
};
|
|
29909
|
+
})();
|
|
29910
|
+
changeBackgroundUrl = e => {
|
|
29911
|
+
// Only continue on blur or "enter"
|
|
29912
|
+
if (e.type === "keypress" && e.key !== "Enter") {
|
|
29913
|
+
return;
|
|
29914
|
+
}
|
|
29915
|
+
const setUrl = (url, width, height) => {
|
|
29916
|
+
// Shallow-copied clone
|
|
29917
|
+
const image = {
|
|
29918
|
+
...this.props.backgroundImage
|
|
29919
|
+
};
|
|
29920
|
+
image.url = url;
|
|
29921
|
+
image.width = width;
|
|
29922
|
+
image.height = height;
|
|
29923
|
+
this.setState({
|
|
29924
|
+
backgroundImage: image
|
|
29925
|
+
}, this.changeGraph);
|
|
29926
|
+
};
|
|
29927
|
+
const url = this.bgUrlRef.current?.value;
|
|
29928
|
+
if (url) {
|
|
29929
|
+
perseus.Util.getImageSize(url, (width, height) => {
|
|
29930
|
+
if (this._isMounted) {
|
|
29931
|
+
setUrl(url, width, height);
|
|
29932
|
+
}
|
|
29933
|
+
});
|
|
29934
|
+
} else {
|
|
29935
|
+
setUrl(null, 0, 0);
|
|
29936
|
+
}
|
|
29937
|
+
};
|
|
29938
|
+
renderLabelChoices = choices => {
|
|
29939
|
+
return choices.map(nameAndValue => /*#__PURE__*/React__namespace.createElement("option", {
|
|
29940
|
+
key: nameAndValue[1],
|
|
29941
|
+
value: nameAndValue[1]
|
|
29942
|
+
}, nameAndValue[0]));
|
|
29943
|
+
};
|
|
29944
|
+
validRange = range => {
|
|
29945
|
+
const numbers = ___default["default"].every(range, function (num) {
|
|
29946
|
+
return ___default["default"].isFinite(num);
|
|
29947
|
+
});
|
|
29948
|
+
if (!numbers) {
|
|
29949
|
+
return "Range must be a valid number";
|
|
29950
|
+
}
|
|
29951
|
+
if (range[0] >= range[1]) {
|
|
29952
|
+
return "Range must have a higher number on the right";
|
|
29953
|
+
}
|
|
29954
|
+
return true;
|
|
29955
|
+
};
|
|
29956
|
+
validateStepValue = settings => {
|
|
29957
|
+
const {
|
|
29958
|
+
step,
|
|
29959
|
+
range,
|
|
29960
|
+
name,
|
|
29961
|
+
minTicks,
|
|
29962
|
+
maxTicks
|
|
29963
|
+
} = settings;
|
|
29964
|
+
const nSteps = numSteps(range, step);
|
|
29965
|
+
if (nSteps < minTicks) {
|
|
29966
|
+
return name + " is too large, there must be at least " + minTicks + " ticks.";
|
|
29967
|
+
}
|
|
29968
|
+
if (nSteps > maxTicks) {
|
|
29969
|
+
return name + " is too small, there can be at most " + maxTicks + " ticks.";
|
|
29970
|
+
}
|
|
29971
|
+
return true;
|
|
29972
|
+
};
|
|
29973
|
+
validSnapStep = (step, range) => {
|
|
29974
|
+
return this.validateStepValue({
|
|
29975
|
+
step: step,
|
|
29976
|
+
range: range,
|
|
29977
|
+
name: "Snap step",
|
|
29978
|
+
minTicks: 5,
|
|
29979
|
+
maxTicks: 60
|
|
29980
|
+
});
|
|
29981
|
+
};
|
|
29982
|
+
validGridStep = (step, range) => {
|
|
29983
|
+
return this.validateStepValue({
|
|
29984
|
+
step: step,
|
|
29985
|
+
range: range,
|
|
29986
|
+
name: "Grid step",
|
|
29987
|
+
minTicks: 3,
|
|
29988
|
+
maxTicks: 60
|
|
29989
|
+
});
|
|
29990
|
+
};
|
|
29991
|
+
validStep = (step, range) => {
|
|
29992
|
+
return this.validateStepValue({
|
|
29993
|
+
step: step,
|
|
29994
|
+
range: range,
|
|
29995
|
+
name: "Step",
|
|
29996
|
+
minTicks: 3,
|
|
29997
|
+
maxTicks: 20
|
|
29998
|
+
});
|
|
29999
|
+
};
|
|
30000
|
+
validBackgroundImageSize = image => {
|
|
30001
|
+
// Ignore empty images
|
|
30002
|
+
if (!image.url) {
|
|
30003
|
+
return true;
|
|
30004
|
+
}
|
|
30005
|
+
const validSize = image.width <= 450 && image.height <= 450;
|
|
30006
|
+
if (!validSize) {
|
|
30007
|
+
return "Image must be smaller than 450px x 450px.";
|
|
30008
|
+
}
|
|
30009
|
+
return true;
|
|
30010
|
+
};
|
|
30011
|
+
validateGraphSettings = (range, step, gridStep, snapStep, image) => {
|
|
30012
|
+
const self = this;
|
|
30013
|
+
let msg;
|
|
30014
|
+
const goodRange = ___default["default"].every(range, function (range) {
|
|
30015
|
+
msg = self.validRange(range);
|
|
30016
|
+
return msg === true;
|
|
30017
|
+
});
|
|
30018
|
+
if (!goodRange) {
|
|
30019
|
+
return msg;
|
|
30020
|
+
}
|
|
30021
|
+
const goodStep = ___default["default"].every(step, function (step, i) {
|
|
30022
|
+
msg = self.validStep(step, range[i]);
|
|
30023
|
+
return msg === true;
|
|
30024
|
+
});
|
|
30025
|
+
if (!goodStep) {
|
|
30026
|
+
return msg;
|
|
30027
|
+
}
|
|
30028
|
+
const goodGridStep = ___default["default"].every(gridStep, function (gridStep, i) {
|
|
30029
|
+
msg = self.validGridStep(gridStep, range[i]);
|
|
30030
|
+
return msg === true;
|
|
30031
|
+
});
|
|
30032
|
+
if (!goodGridStep) {
|
|
30033
|
+
return msg;
|
|
30034
|
+
}
|
|
30035
|
+
const goodSnapStep = ___default["default"].every(snapStep, function (snapStep, i) {
|
|
30036
|
+
msg = self.validSnapStep(snapStep, range[i]);
|
|
30037
|
+
return msg === true;
|
|
30038
|
+
});
|
|
30039
|
+
if (!goodSnapStep) {
|
|
30040
|
+
return msg;
|
|
30041
|
+
}
|
|
30042
|
+
const goodImageSize = this.validBackgroundImageSize(image);
|
|
30043
|
+
if (goodImageSize !== true) {
|
|
30044
|
+
msg = goodImageSize;
|
|
30045
|
+
return msg;
|
|
30046
|
+
}
|
|
30047
|
+
return true;
|
|
30048
|
+
};
|
|
30049
|
+
changeLabel = (i, e) => {
|
|
30050
|
+
const val = e.target.value;
|
|
30051
|
+
const labels = this.state.labelsTextbox.slice();
|
|
30052
|
+
labels[i] = val;
|
|
30053
|
+
this.setState({
|
|
30054
|
+
labelsTextbox: labels
|
|
30055
|
+
}, this.changeGraph);
|
|
30056
|
+
};
|
|
30057
|
+
changeRange = (i, values) => {
|
|
30058
|
+
const ranges = this.state.rangeTextbox.slice();
|
|
30059
|
+
ranges[i] = values;
|
|
30060
|
+
const step = this.state.stepTextbox.slice();
|
|
30061
|
+
const gridStep = this.state.gridStepTextbox.slice();
|
|
30062
|
+
const snapStep = this.state.snapStepTextbox.slice();
|
|
30063
|
+
const scale = perseus.Util.scaleFromExtent(ranges[i], this.props.box[i]);
|
|
30064
|
+
if (this.validRange(ranges[i]) === true) {
|
|
30065
|
+
step[i] = perseus.Util.tickStepFromExtent(ranges[i], this.props.box[i]);
|
|
30066
|
+
const gridStepValue = perseus.Util.gridStepFromTickStep(step[i], scale);
|
|
30067
|
+
if (gridStepValue) {
|
|
30068
|
+
gridStep[i] = gridStepValue;
|
|
30069
|
+
}
|
|
30070
|
+
snapStep[i] = gridStep[i] / 2;
|
|
30071
|
+
}
|
|
30072
|
+
this.setState({
|
|
30073
|
+
stepTextbox: step,
|
|
30074
|
+
gridStepTextbox: gridStep,
|
|
30075
|
+
snapStepTextbox: snapStep,
|
|
30076
|
+
rangeTextbox: ranges
|
|
30077
|
+
}, this.changeGraph);
|
|
30078
|
+
};
|
|
30079
|
+
changeStep = step => {
|
|
30080
|
+
this.setState({
|
|
30081
|
+
stepTextbox: step
|
|
30082
|
+
}, this.changeGraph);
|
|
30083
|
+
};
|
|
30084
|
+
changeSnapStep = snapStep => {
|
|
30085
|
+
this.setState({
|
|
30086
|
+
snapStepTextbox: snapStep
|
|
30087
|
+
}, this.changeGraph);
|
|
30088
|
+
};
|
|
30089
|
+
changeGridStep = gridStep => {
|
|
30090
|
+
this.setState({
|
|
30091
|
+
gridStepTextbox: gridStep,
|
|
30092
|
+
snapStepTextbox: ___default["default"].map(gridStep, function (step) {
|
|
30093
|
+
return step / 2;
|
|
30094
|
+
})
|
|
30095
|
+
}, this.changeGraph);
|
|
30096
|
+
};
|
|
30097
|
+
changeGraph = () => {
|
|
30098
|
+
const labels = this.state.labelsTextbox;
|
|
30099
|
+
const range = ___default["default"].map(this.state.rangeTextbox, function (range) {
|
|
30100
|
+
return ___default["default"].map(range, Number);
|
|
30101
|
+
});
|
|
30102
|
+
const step = ___default["default"].map(this.state.stepTextbox, Number);
|
|
30103
|
+
const gridStep = this.state.gridStepTextbox;
|
|
30104
|
+
const snapStep = this.state.snapStepTextbox;
|
|
30105
|
+
const image = this.state.backgroundImage;
|
|
30106
|
+
|
|
30107
|
+
// validationResult is either:
|
|
30108
|
+
// true -> the settings are valid
|
|
30109
|
+
// a string -> the settings are invalid, and the explanation
|
|
30110
|
+
// is contained in the string
|
|
30111
|
+
// TODO(aria): Refactor this to not be confusing
|
|
30112
|
+
const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
|
|
30113
|
+
if (validationResult === true) {
|
|
30114
|
+
// either true or a string
|
|
30115
|
+
this.change({
|
|
30116
|
+
valid: true,
|
|
30117
|
+
labels: labels,
|
|
30118
|
+
range: range,
|
|
30119
|
+
step: step,
|
|
30120
|
+
gridStep: gridStep,
|
|
30121
|
+
snapStep: snapStep,
|
|
30122
|
+
backgroundImage: image
|
|
30123
|
+
});
|
|
30124
|
+
} else {
|
|
30125
|
+
this.change({
|
|
30126
|
+
valid: validationResult // a string message, not false
|
|
30127
|
+
});
|
|
30128
|
+
}
|
|
30129
|
+
};
|
|
30130
|
+
|
|
30131
|
+
render() {
|
|
30132
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
|
|
30133
|
+
title: "Common Graph Settings",
|
|
30134
|
+
isOpen: this.state.isExpanded,
|
|
30135
|
+
isCollapsible: true,
|
|
30136
|
+
onToggle: () => this.setState({
|
|
30137
|
+
isExpanded: !this.state.isExpanded
|
|
30138
|
+
})
|
|
30139
|
+
}), this.state.isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement("div", {
|
|
30140
|
+
className: "graph-settings"
|
|
30141
|
+
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
30142
|
+
className: "perseus-widget-row"
|
|
30143
|
+
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
30144
|
+
className: "perseus-widget-left-col"
|
|
30145
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30146
|
+
label: "x Label"
|
|
30147
|
+
}, /*#__PURE__*/React__namespace.createElement("input", {
|
|
30148
|
+
type: "text",
|
|
30149
|
+
className: "graph-settings-axis-label",
|
|
30150
|
+
ref: this.labelXRef,
|
|
30151
|
+
onChange: e => this.changeLabel(0, e),
|
|
30152
|
+
value: this.state.labelsTextbox[0] || ""
|
|
30153
|
+
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30154
|
+
className: "perseus-widget-right-col"
|
|
30155
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30156
|
+
label: "y Label"
|
|
30157
|
+
}, /*#__PURE__*/React__namespace.createElement("input", {
|
|
30158
|
+
type: "text",
|
|
30159
|
+
className: "graph-settings-axis-label",
|
|
30160
|
+
ref: this.labelYRef,
|
|
30161
|
+
onChange: e => this.changeLabel(1, e),
|
|
30162
|
+
value: this.state.labelsTextbox[1] || ""
|
|
30163
|
+
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30164
|
+
className: "perseus-widget-row"
|
|
30165
|
+
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
30166
|
+
className: "perseus-widget-left-col"
|
|
30167
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30168
|
+
label: "x Range"
|
|
30169
|
+
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
30170
|
+
value: this.state.rangeTextbox[0],
|
|
30171
|
+
onChange: vals => this.changeRange(0, vals)
|
|
30172
|
+
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30173
|
+
className: "perseus-widget-right-col"
|
|
30174
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30175
|
+
label: "y Range"
|
|
30176
|
+
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
30177
|
+
value: this.state.rangeTextbox[1],
|
|
30178
|
+
onChange: vals => this.changeRange(1, vals)
|
|
30179
|
+
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30180
|
+
className: "perseus-widget-row"
|
|
30181
|
+
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
30182
|
+
className: "perseus-widget-left-col"
|
|
30183
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30184
|
+
label: "Tick Step"
|
|
30185
|
+
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
30186
|
+
value: this.state.stepTextbox,
|
|
30187
|
+
onChange: this.changeStep
|
|
30188
|
+
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30189
|
+
className: "perseus-widget-right-col"
|
|
30190
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30191
|
+
label: "Grid Step"
|
|
30192
|
+
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
30193
|
+
value: this.state.gridStepTextbox,
|
|
30194
|
+
onChange: this.changeGridStep
|
|
30195
|
+
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30196
|
+
className: "perseus-widget-row"
|
|
30197
|
+
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
30198
|
+
className: "perseus-widget-left-col"
|
|
30199
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30200
|
+
label: "Snap Step"
|
|
30201
|
+
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
30202
|
+
value: this.state.snapStepTextbox,
|
|
30203
|
+
onChange: this.changeSnapStep
|
|
30204
|
+
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30205
|
+
className: "perseus-widget-row"
|
|
30206
|
+
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30207
|
+
label: "Markings:"
|
|
30208
|
+
}, /*#__PURE__*/React__namespace.createElement(ButtonGroup$2, {
|
|
30209
|
+
value: this.props.markings,
|
|
30210
|
+
allowEmpty: false,
|
|
30211
|
+
buttons: [{
|
|
30212
|
+
value: "graph",
|
|
30213
|
+
content: "Graph"
|
|
30214
|
+
}, {
|
|
30215
|
+
value: "grid",
|
|
30216
|
+
content: "Grid"
|
|
30217
|
+
}, {
|
|
30218
|
+
value: "none",
|
|
30219
|
+
content: "None"
|
|
30220
|
+
}],
|
|
30221
|
+
onChange: this.change("markings")
|
|
30222
|
+
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
30223
|
+
className: "perseus-widget-left-col"
|
|
30224
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
|
|
30225
|
+
label: "Show tooltips",
|
|
30226
|
+
checked: this.props.showTooltips,
|
|
30227
|
+
onChange: value => {
|
|
30228
|
+
this.change({
|
|
30229
|
+
showTooltips: value
|
|
30230
|
+
});
|
|
30231
|
+
}
|
|
30232
|
+
}))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
30233
|
+
label: "Background image URL:",
|
|
30234
|
+
style: styles$E.resetSpaceTop
|
|
30235
|
+
}, /*#__PURE__*/React__namespace.createElement("input", {
|
|
30236
|
+
type: "text",
|
|
30237
|
+
className: aphrodite.css(styles$E.backgroundUrlInput),
|
|
30238
|
+
ref: this.bgUrlRef,
|
|
30239
|
+
value: this.state.backgroundImage.url || "",
|
|
30240
|
+
onChange: e => {
|
|
30241
|
+
// Shallow-copied clone
|
|
30242
|
+
const image = {
|
|
30243
|
+
...this.props.backgroundImage
|
|
30244
|
+
};
|
|
30245
|
+
image.url = e.target.value;
|
|
30246
|
+
this.setState({
|
|
30247
|
+
backgroundImage: image
|
|
30248
|
+
});
|
|
30249
|
+
},
|
|
30250
|
+
onKeyPress: this.changeBackgroundUrl,
|
|
30251
|
+
onBlur: this.changeBackgroundUrl
|
|
30252
|
+
}), /*#__PURE__*/React__namespace.createElement(InfoTip$d, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30253
|
+
style: styles$E.protractorSection
|
|
30254
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30255
|
+
style: styles$E.checkboxRow
|
|
30256
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
|
|
30257
|
+
label: "Show protractor",
|
|
30258
|
+
checked: this.props.showProtractor,
|
|
30259
|
+
onChange: value => {
|
|
30260
|
+
this.change({
|
|
30261
|
+
showProtractor: value
|
|
30262
|
+
});
|
|
30263
|
+
},
|
|
30264
|
+
style: styles$E.resetSpaceTop
|
|
30265
|
+
})), this.props.showProtractor && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
|
|
30266
|
+
layout: "floating",
|
|
30267
|
+
text: "The protractor is not accessible. Please consider an alternate approach.",
|
|
30268
|
+
kind: "warning"
|
|
30269
|
+
}))));
|
|
30270
|
+
}
|
|
30271
|
+
}
|
|
30272
|
+
const styles$E = aphrodite.StyleSheet.create({
|
|
30273
|
+
resetSpaceTop: {
|
|
30274
|
+
marginTop: 0
|
|
30275
|
+
},
|
|
30276
|
+
backgroundUrlInput: {
|
|
30277
|
+
border: `1px solid ${wonderBlocksTokens.color.offBlack32}`,
|
|
30278
|
+
borderRadius: wonderBlocksTokens.spacing.xxxSmall_4,
|
|
30279
|
+
padding: wonderBlocksTokens.spacing.xxxSmall_4
|
|
30280
|
+
},
|
|
30281
|
+
checkboxRow: {
|
|
30282
|
+
flexDirection: "row",
|
|
30283
|
+
alignItems: "center",
|
|
30284
|
+
justifyContent: "space-between",
|
|
30285
|
+
marginBottom: wonderBlocksTokens.spacing.xSmall_8
|
|
30286
|
+
},
|
|
30287
|
+
protractorSection: {
|
|
30288
|
+
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
30289
|
+
borderTop: `1px solid ${wonderBlocksTokens.color.offBlack16}`,
|
|
30290
|
+
paddingTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
30291
|
+
paddingBottom: wonderBlocksTokens.spacing.xSmall_8,
|
|
30292
|
+
borderBottom: `1px solid ${wonderBlocksTokens.color.offBlack16}`
|
|
30293
|
+
}
|
|
30294
|
+
});
|
|
30295
|
+
|
|
30296
|
+
const SegmentCountSelector = _ref => {
|
|
30297
|
+
let {
|
|
30298
|
+
numSegments = 1,
|
|
30299
|
+
onChange
|
|
30300
|
+
} = _ref;
|
|
30301
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
30302
|
+
key: "segment-select",
|
|
30303
|
+
selectedValue: `${numSegments}`
|
|
30304
|
+
// Never uses placeholder, always has value
|
|
30305
|
+
,
|
|
30306
|
+
placeholder: "",
|
|
30307
|
+
onChange: newValue => {
|
|
30308
|
+
const num = +newValue;
|
|
30309
|
+
onChange(num);
|
|
30310
|
+
},
|
|
30311
|
+
style: styles$D.singleSelectShort
|
|
30312
|
+
}, ___default["default"].range(1, 7).map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
30313
|
+
key: n,
|
|
30314
|
+
value: `${n}`,
|
|
30315
|
+
label: `${n} segment${n > 1 ? "s" : ""}`
|
|
30316
|
+
})));
|
|
30317
|
+
};
|
|
30318
|
+
const styles$D = aphrodite.StyleSheet.create({
|
|
30319
|
+
singleSelectShort: {
|
|
30320
|
+
// Non-standard spacing, but it's the smallest we can go
|
|
30321
|
+
// without running into styling issues with the dropdown.
|
|
30322
|
+
height: 26
|
|
30323
|
+
}
|
|
30324
|
+
});
|
|
30325
|
+
|
|
30326
|
+
/**
|
|
30327
|
+
* Dropdown for selecting a locked figure to add to an interactive graph.
|
|
30328
|
+
* Locked figures are elements (points, segmeents, etc.) that are not
|
|
30329
|
+
* interactive, just present in the graph's background.
|
|
30330
|
+
*
|
|
30331
|
+
* Used in the interactive graph editor's locked figures section.
|
|
30332
|
+
*/
|
|
30333
|
+
const LockedFigureSelect = props => {
|
|
30334
|
+
const {
|
|
30335
|
+
id,
|
|
30336
|
+
onChange
|
|
30337
|
+
} = props;
|
|
30338
|
+
const figureTypes = ["point", "line", "vector", "ellipse", "polygon", "function"];
|
|
30339
|
+
if (props.showLabelsFlag) {
|
|
30340
|
+
figureTypes.push("label");
|
|
30341
|
+
}
|
|
30342
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30343
|
+
style: styles$C.container
|
|
30344
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionMenu, {
|
|
30345
|
+
menuText: "Add locked figure",
|
|
30346
|
+
style: styles$C.addElementSelect
|
|
30347
|
+
}, figureTypes.map(figureType => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.ActionItem, {
|
|
30348
|
+
key: `${id}-${figureType}`,
|
|
30349
|
+
label: figureType,
|
|
30350
|
+
onClick: () => onChange(figureType)
|
|
30351
|
+
}))));
|
|
30352
|
+
};
|
|
30353
|
+
const styles$C = aphrodite.StyleSheet.create({
|
|
30354
|
+
container: {
|
|
30355
|
+
marginTop: wonderBlocksTokens.spacing.xSmall_8
|
|
30356
|
+
},
|
|
30357
|
+
addElementSelect: {
|
|
30358
|
+
backgroundColor: wonderBlocksTokens.color.fadedBlue8,
|
|
30359
|
+
borderRadius: wonderBlocksTokens.spacing.xxxSmall_4
|
|
30360
|
+
}
|
|
30361
|
+
});
|
|
30362
|
+
|
|
30363
|
+
/**
|
|
30364
|
+
* This is a custom text field of type="number" for use in Perseus Editors.
|
|
30365
|
+
*
|
|
30366
|
+
* This makes it so that the text field's input number updates on scroll
|
|
30367
|
+
* without scrolling the page.
|
|
30368
|
+
*
|
|
30369
|
+
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
|
|
30370
|
+
* they only scroll the page. Inputs in React do NOT work this way (explanation
|
|
30371
|
+
* here: https://stackoverflow.com/a/68266494). By default, scrolling on a
|
|
30372
|
+
* focused number input in React causes BOTH the input value to change AND
|
|
30373
|
+
* the page to scroll. The behavior in this component is an improvement on
|
|
30374
|
+
* the React behavior, but it's the opposite of the native HTML behavior.
|
|
30375
|
+
*
|
|
30376
|
+
* NOTE 2: Firefox seems to have a custom override for this. Even with this
|
|
30377
|
+
* stopPropogation, Firefox matches the native HTML behavior.
|
|
30378
|
+
*/
|
|
30379
|
+
const ScrolllessNumberTextField = props => {
|
|
30380
|
+
const inputRef = React__namespace.useRef(null);
|
|
30381
|
+
React__namespace.useEffect(() => {
|
|
30382
|
+
const ref = inputRef.current;
|
|
30383
|
+
|
|
30384
|
+
// stopPropogation makes it so that the page scroll event is not
|
|
30385
|
+
// triggered when the input is focused and the user scrolls.
|
|
30386
|
+
// The input value will still change on scroll.
|
|
30387
|
+
const ignoreScroll = e => {
|
|
30388
|
+
e.stopPropagation();
|
|
30389
|
+
};
|
|
30390
|
+
ref?.addEventListener("wheel", ignoreScroll);
|
|
30391
|
+
return () => {
|
|
30392
|
+
ref?.removeEventListener("wheel", ignoreScroll);
|
|
30393
|
+
};
|
|
30394
|
+
}, [inputRef]);
|
|
30395
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, _extends({
|
|
30396
|
+
type: "number"
|
|
30397
|
+
}, props, {
|
|
30398
|
+
ref: inputRef
|
|
30399
|
+
}));
|
|
30400
|
+
};
|
|
30401
|
+
|
|
30402
|
+
function focusWithChromeStickyFocusBugWorkaround(element) {
|
|
30403
|
+
// NOTE(marksandstrom) Chrome sticky focus bug.
|
|
30404
|
+
//
|
|
30405
|
+
// There is a bug in Chrome related to sticky positioning and
|
|
30406
|
+
// focus: When a child of an element with sticky positioning is
|
|
30407
|
+
// focused with the focus() method, the scrollable area
|
|
30408
|
+
// containing that element will scroll to the top (even though
|
|
30409
|
+
// the element is already visble on the page). For a dropdown
|
|
30410
|
+
// this means that the area will be scrolled to the top when
|
|
30411
|
+
// the user interacts with the dropdown (since we actively
|
|
30412
|
+
// manage dropdown header and option focus for keyboard users).
|
|
30413
|
+
//
|
|
30414
|
+
// To work around this bug the `preventScroll` focus option is
|
|
30415
|
+
// used.
|
|
30416
|
+
//
|
|
30417
|
+
// Using `focusOptions` is an experimental browser feature
|
|
30418
|
+
// "that should not be used in production code". However, since
|
|
30419
|
+
// Chrome is the only browser we support that exhibits this
|
|
30420
|
+
// buggy behavior and using `focusOptions` works around the
|
|
30421
|
+
// bug, it is perfectly reasonable to use the feature in this
|
|
30422
|
+
// case. We are not relying on the effect of the
|
|
30423
|
+
// `preventScroll` option otherwise.
|
|
30424
|
+
//
|
|
30425
|
+
// focusOptions documentation:
|
|
30426
|
+
//
|
|
30427
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
|
|
30428
|
+
//
|
|
30429
|
+
// Note that there could be cases where we want default focus() behavior.
|
|
30430
|
+
// One that comes to mind is a dropdown with a long list of options that
|
|
30431
|
+
// might be rendered off screen when opened. With this workaround the
|
|
30432
|
+
// selected option would not be scrolled into view if the option is near
|
|
30433
|
+
// the end of the list. We're not aware of any uses of the dropdown where
|
|
30434
|
+
// this is an issue, however, so there isn't currently a way to out of the
|
|
30435
|
+
// `preventScroll` behavior.
|
|
30436
|
+
|
|
30437
|
+
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
|
|
30438
|
+
element.focus({
|
|
30439
|
+
preventScroll: true
|
|
30440
|
+
});
|
|
30441
|
+
}
|
|
30442
|
+
function degreeToRadian(degrees) {
|
|
30443
|
+
return degrees / 180 * Math.PI;
|
|
30444
|
+
}
|
|
30445
|
+
function radianToDegree(radians) {
|
|
30446
|
+
return radians / Math.PI * 180;
|
|
30447
|
+
}
|
|
30448
|
+
|
|
30449
|
+
const AngleInput = props => {
|
|
30450
|
+
const {
|
|
30451
|
+
angle,
|
|
30452
|
+
onChange
|
|
30453
|
+
} = props;
|
|
30454
|
+
const [angleInput, setAngleInput] = React__namespace.useState(radianToDegree(angle).toString());
|
|
30455
|
+
function handleAngleChange(newValue) {
|
|
30456
|
+
// Update the local state (update the input field value).
|
|
30457
|
+
setAngleInput(newValue);
|
|
30458
|
+
|
|
30459
|
+
// If the new value is not a number, don't update the props.
|
|
30460
|
+
// If it's empty, keep the props the same value instead of setting to 0.
|
|
30461
|
+
if (isNaN(+newValue) || newValue === "") {
|
|
30462
|
+
return;
|
|
30463
|
+
}
|
|
30464
|
+
|
|
30465
|
+
// Update the graph.
|
|
30466
|
+
onChange(degreeToRadian(newValue));
|
|
30467
|
+
}
|
|
30468
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30469
|
+
tag: "label",
|
|
30470
|
+
style: styles$B.row
|
|
30471
|
+
}, "angle (degrees)", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30472
|
+
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30473
|
+
}), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
|
|
30474
|
+
value: angleInput,
|
|
30475
|
+
onChange: handleAngleChange,
|
|
30476
|
+
style: styles$B.textField
|
|
30477
|
+
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30478
|
+
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30479
|
+
}));
|
|
30480
|
+
};
|
|
30481
|
+
const styles$B = aphrodite.StyleSheet.create({
|
|
30482
|
+
row: {
|
|
30483
|
+
display: "flex",
|
|
30484
|
+
flexDirection: "row",
|
|
30485
|
+
alignItems: "center"
|
|
30012
30486
|
},
|
|
30013
30487
|
textField: {
|
|
30014
30488
|
width: wonderBlocksTokens.spacing.xxxLarge_64
|
|
@@ -30053,30 +30527,30 @@ const CoordinatePairInput = props => {
|
|
|
30053
30527
|
onChange(newCoords);
|
|
30054
30528
|
}
|
|
30055
30529
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30056
|
-
style: [styles$
|
|
30530
|
+
style: [styles$A.row, style]
|
|
30057
30531
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30058
30532
|
tag: "label",
|
|
30059
|
-
style: styles$
|
|
30533
|
+
style: styles$A.row
|
|
30060
30534
|
}, labels ? labels[0] : "x coord", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30061
30535
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30062
30536
|
}), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
|
|
30063
30537
|
value: coordState[0],
|
|
30064
30538
|
onChange: newValue => handleCoordChange(newValue, 0),
|
|
30065
|
-
style: [styles$
|
|
30539
|
+
style: [styles$A.textField, error ? styles$A.errorField : undefined]
|
|
30066
30540
|
})), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30067
30541
|
size: wonderBlocksTokens.spacing.medium_16
|
|
30068
30542
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30069
30543
|
tag: "label",
|
|
30070
|
-
style: styles$
|
|
30544
|
+
style: styles$A.row
|
|
30071
30545
|
}, labels ? labels[1] : "y coord", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30072
30546
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30073
30547
|
}), /*#__PURE__*/React__namespace.createElement(ScrolllessNumberTextField, {
|
|
30074
30548
|
value: coordState[1],
|
|
30075
30549
|
onChange: newValue => handleCoordChange(newValue, 1),
|
|
30076
|
-
style: [styles$
|
|
30550
|
+
style: [styles$A.textField, error ? styles$A.errorField : undefined]
|
|
30077
30551
|
})));
|
|
30078
30552
|
};
|
|
30079
|
-
const styles$
|
|
30553
|
+
const styles$A = aphrodite.StyleSheet.create({
|
|
30080
30554
|
row: {
|
|
30081
30555
|
display: "flex",
|
|
30082
30556
|
flexDirection: "row",
|
|
@@ -30109,14 +30583,14 @@ const PerseusEditorAccordion = props => {
|
|
|
30109
30583
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksAccordion.AccordionSection, {
|
|
30110
30584
|
expanded: expanded,
|
|
30111
30585
|
onToggle: onToggle,
|
|
30112
|
-
style: [styles$
|
|
30113
|
-
headerStyle: styles$
|
|
30586
|
+
style: [styles$z.container, containerStyle],
|
|
30587
|
+
headerStyle: styles$z.accordionHeader,
|
|
30114
30588
|
header: header
|
|
30115
30589
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30116
|
-
style: [styles$
|
|
30590
|
+
style: [styles$z.accordionPanel, panelStyle]
|
|
30117
30591
|
}, children)));
|
|
30118
30592
|
};
|
|
30119
|
-
const styles$
|
|
30593
|
+
const styles$z = aphrodite.StyleSheet.create({
|
|
30120
30594
|
container: {
|
|
30121
30595
|
backgroundColor: wonderBlocksTokens.color.fadedBlue8,
|
|
30122
30596
|
marginTop: wonderBlocksTokens.spacing.xSmall_8
|
|
@@ -30147,13 +30621,13 @@ const ColorSwatch = props => {
|
|
|
30147
30621
|
"aria-label":
|
|
30148
30622
|
// Don't include an aria label for decorative circles.
|
|
30149
30623
|
!decorative ? `${color}, ${filled ? "filled" : "open"}` : undefined,
|
|
30150
|
-
style: [styles$
|
|
30624
|
+
style: [styles$y.colorSwatch, {
|
|
30151
30625
|
border: `4px solid ${perseus.lockedFigureColors[color]}`,
|
|
30152
30626
|
backgroundColor: filled ? perseus.lockedFigureColors[color] : wonderBlocksTokens.color.white
|
|
30153
30627
|
}]
|
|
30154
30628
|
});
|
|
30155
30629
|
};
|
|
30156
|
-
const styles$
|
|
30630
|
+
const styles$y = aphrodite.StyleSheet.create({
|
|
30157
30631
|
colorSwatch: {
|
|
30158
30632
|
// Add a white outline so that the color swatch is visible when
|
|
30159
30633
|
// the dropdown option is highlighted with its blue background.
|
|
@@ -30172,10 +30646,10 @@ const ColorSelect = props => {
|
|
|
30172
30646
|
onChange
|
|
30173
30647
|
} = props;
|
|
30174
30648
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30175
|
-
style: [styles$
|
|
30649
|
+
style: [styles$x.row, style]
|
|
30176
30650
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30177
30651
|
tag: "label",
|
|
30178
|
-
style: styles$
|
|
30652
|
+
style: styles$x.row
|
|
30179
30653
|
}, "color", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30180
30654
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30181
30655
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -30194,7 +30668,7 @@ const ColorSelect = props => {
|
|
|
30194
30668
|
})
|
|
30195
30669
|
})))));
|
|
30196
30670
|
};
|
|
30197
|
-
const styles$
|
|
30671
|
+
const styles$x = aphrodite.StyleSheet.create({
|
|
30198
30672
|
row: {
|
|
30199
30673
|
display: "flex",
|
|
30200
30674
|
flexDirection: "row",
|
|
@@ -30213,17 +30687,17 @@ const EllipseSwatch = props => {
|
|
|
30213
30687
|
} = props;
|
|
30214
30688
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30215
30689
|
"aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
|
|
30216
|
-
style: [styles$
|
|
30690
|
+
style: [styles$w.container, {
|
|
30217
30691
|
border: `4px ${strokeStyle} ${perseus.lockedFigureColors[color]}`
|
|
30218
30692
|
}]
|
|
30219
30693
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30220
|
-
style: [styles$
|
|
30694
|
+
style: [styles$w.innerCircle, {
|
|
30221
30695
|
backgroundColor: perseus.lockedFigureColors[color],
|
|
30222
30696
|
opacity: fillStyle === "white" ? 0 : perseus.lockedFigureFillStyles[fillStyle]
|
|
30223
30697
|
}]
|
|
30224
30698
|
}));
|
|
30225
30699
|
};
|
|
30226
|
-
const styles$
|
|
30700
|
+
const styles$w = aphrodite.StyleSheet.create({
|
|
30227
30701
|
container: {
|
|
30228
30702
|
// Add a white outline so that the color swatch is visible when
|
|
30229
30703
|
// the dropdown option is highlighted with its blue background.
|
|
@@ -30249,7 +30723,7 @@ const LineStrokeSelect = props => {
|
|
|
30249
30723
|
} = props;
|
|
30250
30724
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30251
30725
|
tag: "label",
|
|
30252
|
-
style: styles$
|
|
30726
|
+
style: styles$v.lineStrokeSelect
|
|
30253
30727
|
}, "stroke", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30254
30728
|
size: wonderBlocksTokens.spacing.xxxSmall_4
|
|
30255
30729
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -30266,7 +30740,7 @@ const LineStrokeSelect = props => {
|
|
|
30266
30740
|
label: "dashed"
|
|
30267
30741
|
})));
|
|
30268
30742
|
};
|
|
30269
|
-
const styles$
|
|
30743
|
+
const styles$v = aphrodite.StyleSheet.create({
|
|
30270
30744
|
lineStrokeSelect: {
|
|
30271
30745
|
display: "flex",
|
|
30272
30746
|
flexDirection: "row",
|
|
@@ -30288,40 +30762,40 @@ const LockedFigureSettingsActions = props => {
|
|
|
30288
30762
|
onRemove
|
|
30289
30763
|
} = props;
|
|
30290
30764
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30291
|
-
style: styles$
|
|
30765
|
+
style: styles$u.container
|
|
30292
30766
|
}, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
30293
30767
|
startIcon: trashIcon__default["default"],
|
|
30294
30768
|
"aria-label": `Delete locked ${figureType}`,
|
|
30295
30769
|
onClick: onRemove,
|
|
30296
30770
|
kind: "tertiary",
|
|
30297
|
-
style: styles$
|
|
30771
|
+
style: styles$u.deleteButton
|
|
30298
30772
|
}, "Delete"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
30299
30773
|
icon: caretDoubleUpIcon__default["default"],
|
|
30300
30774
|
size: "small",
|
|
30301
30775
|
"aria-label": `Move locked ${figureType} to the back`,
|
|
30302
30776
|
onClick: () => onMove("back"),
|
|
30303
|
-
style: styles$
|
|
30777
|
+
style: styles$u.iconButton
|
|
30304
30778
|
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
30305
30779
|
icon: caretUpIcon__default["default"],
|
|
30306
30780
|
size: "small",
|
|
30307
30781
|
"aria-label": `Move locked ${figureType} backward`,
|
|
30308
30782
|
onClick: () => onMove("backward"),
|
|
30309
|
-
style: styles$
|
|
30783
|
+
style: styles$u.iconButton
|
|
30310
30784
|
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
30311
30785
|
icon: caretDownIcon__default["default"],
|
|
30312
30786
|
size: "small",
|
|
30313
30787
|
"aria-label": `Move locked ${figureType} forward`,
|
|
30314
30788
|
onClick: () => onMove("forward"),
|
|
30315
|
-
style: styles$
|
|
30789
|
+
style: styles$u.iconButton
|
|
30316
30790
|
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
30317
30791
|
icon: caretDoubleDownIcon__default["default"],
|
|
30318
30792
|
size: "small",
|
|
30319
30793
|
"aria-label": `Move locked ${figureType} to the front`,
|
|
30320
30794
|
onClick: () => onMove("front"),
|
|
30321
|
-
style: styles$
|
|
30795
|
+
style: styles$u.iconButton
|
|
30322
30796
|
}));
|
|
30323
30797
|
};
|
|
30324
|
-
const styles$
|
|
30798
|
+
const styles$u = aphrodite.StyleSheet.create({
|
|
30325
30799
|
container: {
|
|
30326
30800
|
width: "100%",
|
|
30327
30801
|
flexDirection: "row",
|
|
@@ -30340,7 +30814,7 @@ const styles$z = aphrodite.StyleSheet.create({
|
|
|
30340
30814
|
});
|
|
30341
30815
|
|
|
30342
30816
|
const {
|
|
30343
|
-
InfoTip: InfoTip$
|
|
30817
|
+
InfoTip: InfoTip$c
|
|
30344
30818
|
} = perseus.components;
|
|
30345
30819
|
const LockedEllipseSettings = props => {
|
|
30346
30820
|
const {
|
|
@@ -30368,7 +30842,7 @@ const LockedEllipseSettings = props => {
|
|
|
30368
30842
|
/*#__PURE__*/
|
|
30369
30843
|
// Summary: Ellipse, center, radius, color (opacity, dashed)
|
|
30370
30844
|
React__namespace.createElement(wonderBlocksCore.View, {
|
|
30371
|
-
style: styles$
|
|
30845
|
+
style: styles$t.row
|
|
30372
30846
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30373
30847
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30374
30848
|
}), /*#__PURE__*/React__namespace.createElement(EllipseSwatch, {
|
|
@@ -30377,19 +30851,19 @@ const LockedEllipseSettings = props => {
|
|
|
30377
30851
|
strokeStyle: strokeStyle
|
|
30378
30852
|
}))
|
|
30379
30853
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30380
|
-
style: styles$
|
|
30854
|
+
style: styles$t.row
|
|
30381
30855
|
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
30382
30856
|
coord: center,
|
|
30383
|
-
style: styles$
|
|
30857
|
+
style: styles$t.spaceUnder,
|
|
30384
30858
|
onChange: newCoords => onChangeProps({
|
|
30385
30859
|
center: newCoords
|
|
30386
30860
|
})
|
|
30387
30861
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30388
|
-
style: styles$
|
|
30389
|
-
}, /*#__PURE__*/React__namespace.createElement(InfoTip$
|
|
30862
|
+
style: styles$t.spaceUnder
|
|
30863
|
+
}, /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
30390
30864
|
coord: radius,
|
|
30391
30865
|
labels: ["x radius", "y radius"],
|
|
30392
|
-
style: styles$
|
|
30866
|
+
style: styles$t.spaceUnder,
|
|
30393
30867
|
onChange: newCoords => onChangeProps({
|
|
30394
30868
|
radius: newCoords
|
|
30395
30869
|
})
|
|
@@ -30401,7 +30875,7 @@ const LockedEllipseSettings = props => {
|
|
|
30401
30875
|
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30402
30876
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30403
30877
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30404
|
-
style: [styles$
|
|
30878
|
+
style: [styles$t.row, styles$t.spaceUnder]
|
|
30405
30879
|
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
30406
30880
|
selectedValue: color,
|
|
30407
30881
|
onChange: handleColorChange
|
|
@@ -30409,7 +30883,7 @@ const LockedEllipseSettings = props => {
|
|
|
30409
30883
|
size: wonderBlocksTokens.spacing.medium_16
|
|
30410
30884
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30411
30885
|
tag: "label",
|
|
30412
|
-
style: [styles$
|
|
30886
|
+
style: [styles$t.row, styles$t.truncatedWidth]
|
|
30413
30887
|
}, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30414
30888
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30415
30889
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -30435,7 +30909,7 @@ const LockedEllipseSettings = props => {
|
|
|
30435
30909
|
onRemove: onRemove
|
|
30436
30910
|
}));
|
|
30437
30911
|
};
|
|
30438
|
-
const styles$
|
|
30912
|
+
const styles$t = aphrodite.StyleSheet.create({
|
|
30439
30913
|
row: {
|
|
30440
30914
|
display: "flex",
|
|
30441
30915
|
flexDirection: "row",
|
|
@@ -30456,15 +30930,15 @@ const LineSwatch = props => {
|
|
|
30456
30930
|
lineStyle
|
|
30457
30931
|
} = props;
|
|
30458
30932
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30459
|
-
style: styles$
|
|
30933
|
+
style: styles$s.container
|
|
30460
30934
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30461
30935
|
"aria-label": `${color}, ${lineStyle}`,
|
|
30462
|
-
style: [styles$
|
|
30936
|
+
style: [styles$s.lineSwatch, {
|
|
30463
30937
|
border: `5px ${lineStyle} ${perseus.lockedFigureColors[color]}`
|
|
30464
30938
|
}]
|
|
30465
30939
|
}));
|
|
30466
30940
|
};
|
|
30467
|
-
const styles$
|
|
30941
|
+
const styles$s = aphrodite.StyleSheet.create({
|
|
30468
30942
|
container: {
|
|
30469
30943
|
backgroundColor: wonderBlocksTokens.color.white,
|
|
30470
30944
|
justifyContent: "center",
|
|
@@ -30549,9 +31023,9 @@ const LockedFunctionSettings = props => {
|
|
|
30549
31023
|
expanded: props.expanded,
|
|
30550
31024
|
onToggle: props.onToggle,
|
|
30551
31025
|
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30552
|
-
style: styles$
|
|
31026
|
+
style: styles$r.row
|
|
30553
31027
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
30554
|
-
style: styles$
|
|
31028
|
+
style: styles$r.accordionHeader
|
|
30555
31029
|
}, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30556
31030
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30557
31031
|
}), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
|
|
@@ -30559,7 +31033,7 @@ const LockedFunctionSettings = props => {
|
|
|
30559
31033
|
lineStyle: strokeStyle
|
|
30560
31034
|
}))
|
|
30561
31035
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30562
|
-
style: [styles$
|
|
31036
|
+
style: [styles$r.row, styles$r.spaceUnder]
|
|
30563
31037
|
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
30564
31038
|
selectedValue: lineColor,
|
|
30565
31039
|
onChange: newValue => {
|
|
@@ -30573,14 +31047,14 @@ const LockedFunctionSettings = props => {
|
|
|
30573
31047
|
handlePropChange("strokeStyle", newValue);
|
|
30574
31048
|
}
|
|
30575
31049
|
})), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30576
|
-
style: [styles$
|
|
31050
|
+
style: [styles$r.row, styles$r.rowSpace]
|
|
30577
31051
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
30578
31052
|
selectedValue: directionalAxis,
|
|
30579
31053
|
onChange: newValue => {
|
|
30580
31054
|
handlePropChange("directionalAxis", newValue);
|
|
30581
31055
|
},
|
|
30582
31056
|
"aria-label": "equation prefix",
|
|
30583
|
-
style: [styles$
|
|
31057
|
+
style: [styles$r.dropdownLabel, styles$r.axisMenu]
|
|
30584
31058
|
// Placeholder is required, but never gets used.
|
|
30585
31059
|
,
|
|
30586
31060
|
placeholder: ""
|
|
@@ -30599,17 +31073,17 @@ const LockedFunctionSettings = props => {
|
|
|
30599
31073
|
onChange: newValue => {
|
|
30600
31074
|
handlePropChange("equation", newValue);
|
|
30601
31075
|
},
|
|
30602
|
-
style: [styles$
|
|
31076
|
+
style: [styles$r.textField]
|
|
30603
31077
|
})), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30604
|
-
style: [styles$
|
|
31078
|
+
style: [styles$r.row, styles$r.rowSpace]
|
|
30605
31079
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30606
31080
|
tag: "label",
|
|
30607
|
-
style: [styles$
|
|
31081
|
+
style: [styles$r.dropdownLabel, styles$r.domainMin]
|
|
30608
31082
|
}, `${domainRangeText} min`, /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30609
31083
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30610
31084
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
30611
31085
|
type: "number",
|
|
30612
|
-
style: styles$
|
|
31086
|
+
style: styles$r.domainMinField,
|
|
30613
31087
|
value: domainEntries[0],
|
|
30614
31088
|
onChange: newValue => {
|
|
30615
31089
|
handleDomainChange(0, newValue);
|
|
@@ -30619,12 +31093,12 @@ const LockedFunctionSettings = props => {
|
|
|
30619
31093
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30620
31094
|
tag: "label",
|
|
30621
31095
|
"aria-label": `${domainRangeText} max`,
|
|
30622
|
-
style: [styles$
|
|
31096
|
+
style: [styles$r.dropdownLabel, styles$r.domainMax]
|
|
30623
31097
|
}, "max", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30624
31098
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30625
31099
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
30626
31100
|
type: "number",
|
|
30627
|
-
style: styles$
|
|
31101
|
+
style: styles$r.domainMaxField,
|
|
30628
31102
|
value: domainEntries[1],
|
|
30629
31103
|
onChange: newValue => {
|
|
30630
31104
|
handleDomainChange(1, newValue);
|
|
@@ -30632,11 +31106,11 @@ const LockedFunctionSettings = props => {
|
|
|
30632
31106
|
}))), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
30633
31107
|
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Example Functions"),
|
|
30634
31108
|
expanded: false,
|
|
30635
|
-
containerStyle: styles$
|
|
30636
|
-
panelStyle: styles$
|
|
31109
|
+
containerStyle: styles$r.exampleWorkspace,
|
|
31110
|
+
panelStyle: styles$r.exampleAccordionPanel
|
|
30637
31111
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30638
31112
|
tag: "label",
|
|
30639
|
-
style: styles$
|
|
31113
|
+
style: styles$r.dropdownLabel
|
|
30640
31114
|
}, "Choose a category", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30641
31115
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
30642
31116
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -30650,7 +31124,7 @@ const LockedFunctionSettings = props => {
|
|
|
30650
31124
|
label: category
|
|
30651
31125
|
});
|
|
30652
31126
|
}))), exampleCategorySelected && /*#__PURE__*/React__namespace.createElement("ul", {
|
|
30653
|
-
className: aphrodite.css(styles$
|
|
31127
|
+
className: aphrodite.css(styles$r.exampleContainer)
|
|
30654
31128
|
}, exampleContent.map((example, index) => /*#__PURE__*/React__namespace.createElement(ExampleItem, {
|
|
30655
31129
|
category: exampleCategory,
|
|
30656
31130
|
example: example,
|
|
@@ -30672,29 +31146,29 @@ const ExampleItem = props => {
|
|
|
30672
31146
|
const exampleId = React.useId();
|
|
30673
31147
|
return /*#__PURE__*/React__namespace.createElement("li", {
|
|
30674
31148
|
key: `${category}-${index}`,
|
|
30675
|
-
className: aphrodite.css(styles$
|
|
31149
|
+
className: aphrodite.css(styles$r.exampleRow)
|
|
30676
31150
|
}, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
30677
31151
|
icon: autoPasteIcon__default["default"],
|
|
30678
31152
|
"aria-label": "paste example",
|
|
30679
31153
|
"aria-describedby": exampleId,
|
|
30680
31154
|
onClick: () => pasteEquationFn("equation", example),
|
|
30681
31155
|
size: "medium",
|
|
30682
|
-
style: styles$
|
|
31156
|
+
style: styles$r.copyPasteButton
|
|
30683
31157
|
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
30684
31158
|
icon: copyIcon__default["default"],
|
|
30685
31159
|
"aria-label": "copy example",
|
|
30686
31160
|
"aria-describedby": exampleId,
|
|
30687
31161
|
onClick: () => navigator.clipboard.writeText(example),
|
|
30688
31162
|
size: "medium",
|
|
30689
|
-
style: styles$
|
|
31163
|
+
style: styles$r.copyPasteButton
|
|
30690
31164
|
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30691
31165
|
size: wonderBlocksTokens.spacing.xxxSmall_4
|
|
30692
31166
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30693
|
-
style: styles$
|
|
31167
|
+
style: styles$r.exampleContent,
|
|
30694
31168
|
id: exampleId
|
|
30695
31169
|
}, example));
|
|
30696
31170
|
};
|
|
30697
|
-
const styles$
|
|
31171
|
+
const styles$r = aphrodite.StyleSheet.create({
|
|
30698
31172
|
accordionHeader: {
|
|
30699
31173
|
textOverflow: "ellipsis",
|
|
30700
31174
|
// A maximum width needs to be specified in order for the ellipsis to work.
|
|
@@ -30812,14 +31286,14 @@ function LockedLabelSettings(props) {
|
|
|
30812
31286
|
expanded: expanded,
|
|
30813
31287
|
onToggle: onToggle,
|
|
30814
31288
|
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30815
|
-
style: [styles$
|
|
31289
|
+
style: [styles$q.row, styles$q.accordionHeaderContainer]
|
|
30816
31290
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30817
31291
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30818
31292
|
}), text !== "" && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
30819
31293
|
style: [{
|
|
30820
31294
|
backgroundColor: wonderBlocksTokens.color.white,
|
|
30821
31295
|
color: perseus.lockedFigureColors[color]
|
|
30822
|
-
}, styles$
|
|
31296
|
+
}, styles$q.accordionHeader]
|
|
30823
31297
|
}, text))
|
|
30824
31298
|
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
30825
31299
|
coord: coord,
|
|
@@ -30828,10 +31302,10 @@ function LockedLabelSettings(props) {
|
|
|
30828
31302
|
coord: newCoords
|
|
30829
31303
|
});
|
|
30830
31304
|
},
|
|
30831
|
-
style: styles$
|
|
31305
|
+
style: styles$q.spaceUnder
|
|
30832
31306
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30833
31307
|
tag: "label",
|
|
30834
|
-
style: [styles$
|
|
31308
|
+
style: [styles$q.row, styles$q.spaceUnder]
|
|
30835
31309
|
}, "TeX", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30836
31310
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30837
31311
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
@@ -30841,7 +31315,7 @@ function LockedLabelSettings(props) {
|
|
|
30841
31315
|
text: newValue
|
|
30842
31316
|
})
|
|
30843
31317
|
})), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30844
|
-
style: styles$
|
|
31318
|
+
style: styles$q.row
|
|
30845
31319
|
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
30846
31320
|
selectedValue: color,
|
|
30847
31321
|
onChange: newColor => {
|
|
@@ -30849,12 +31323,12 @@ function LockedLabelSettings(props) {
|
|
|
30849
31323
|
color: newColor
|
|
30850
31324
|
});
|
|
30851
31325
|
},
|
|
30852
|
-
style: styles$
|
|
31326
|
+
style: styles$q.spaceUnder
|
|
30853
31327
|
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30854
31328
|
size: wonderBlocksTokens.spacing.medium_16
|
|
30855
31329
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
30856
31330
|
tag: "label",
|
|
30857
|
-
style: styles$
|
|
31331
|
+
style: styles$q.row
|
|
30858
31332
|
}, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30859
31333
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30860
31334
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -30881,7 +31355,7 @@ function LockedLabelSettings(props) {
|
|
|
30881
31355
|
onRemove: onRemove
|
|
30882
31356
|
}));
|
|
30883
31357
|
}
|
|
30884
|
-
const styles$
|
|
31358
|
+
const styles$q = aphrodite.StyleSheet.create({
|
|
30885
31359
|
accordionHeaderContainer: {
|
|
30886
31360
|
// Stop the label summary from wrapping.
|
|
30887
31361
|
whiteSpace: "nowrap"
|
|
@@ -30915,7 +31389,7 @@ const LabeledSwitch = props => {
|
|
|
30915
31389
|
const ids = wonderBlocksCore.useUniqueIdWithMock();
|
|
30916
31390
|
const switchId = ids.get("switch");
|
|
30917
31391
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30918
|
-
style: [styles$
|
|
31392
|
+
style: [styles$p.row, style]
|
|
30919
31393
|
}, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
|
|
30920
31394
|
id: switchId,
|
|
30921
31395
|
checked: checked,
|
|
@@ -30927,7 +31401,7 @@ const LabeledSwitch = props => {
|
|
|
30927
31401
|
htmlFor: switchId
|
|
30928
31402
|
}, label));
|
|
30929
31403
|
};
|
|
30930
|
-
const styles$
|
|
31404
|
+
const styles$p = aphrodite.StyleSheet.create({
|
|
30931
31405
|
row: {
|
|
30932
31406
|
flexDirection: "row",
|
|
30933
31407
|
alignItems: "center"
|
|
@@ -30961,13 +31435,13 @@ const DefiningPointSettings = props => {
|
|
|
30961
31435
|
return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
30962
31436
|
expanded: expanded,
|
|
30963
31437
|
onToggle: onToggle,
|
|
30964
|
-
containerStyle: styles$
|
|
30965
|
-
panelStyle: styles$
|
|
31438
|
+
containerStyle: styles$o.container,
|
|
31439
|
+
panelStyle: styles$o.accordionPanel,
|
|
30966
31440
|
header:
|
|
30967
31441
|
/*#__PURE__*/
|
|
30968
31442
|
// Summary: Point, coords, color (filled/open)
|
|
30969
31443
|
React__namespace.createElement(wonderBlocksCore.View, {
|
|
30970
|
-
style: styles$
|
|
31444
|
+
style: styles$o.row
|
|
30971
31445
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
30972
31446
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
30973
31447
|
}), showPoint && /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
|
|
@@ -30977,7 +31451,7 @@ const DefiningPointSettings = props => {
|
|
|
30977
31451
|
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
30978
31452
|
coord: coord,
|
|
30979
31453
|
error: !!error,
|
|
30980
|
-
style: styles$
|
|
31454
|
+
style: styles$o.spaceUnder,
|
|
30981
31455
|
onChange: newCoords => {
|
|
30982
31456
|
onChangeProps({
|
|
30983
31457
|
coord: newCoords
|
|
@@ -30986,12 +31460,12 @@ const DefiningPointSettings = props => {
|
|
|
30986
31460
|
}), onTogglePoint && /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
|
|
30987
31461
|
label: "show point on graph",
|
|
30988
31462
|
checked: !!showPoint,
|
|
30989
|
-
style: showPoint && styles$
|
|
31463
|
+
style: showPoint && styles$o.spaceUnder,
|
|
30990
31464
|
onChange: onTogglePoint
|
|
30991
31465
|
}), showPoint && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
30992
31466
|
selectedValue: pointColor,
|
|
30993
31467
|
onChange: handleColorChange,
|
|
30994
|
-
style: styles$
|
|
31468
|
+
style: styles$o.spaceUnder
|
|
30995
31469
|
}), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
|
|
30996
31470
|
label: "open point",
|
|
30997
31471
|
checked: !filled,
|
|
@@ -31002,7 +31476,7 @@ const DefiningPointSettings = props => {
|
|
|
31002
31476
|
}
|
|
31003
31477
|
})));
|
|
31004
31478
|
};
|
|
31005
|
-
const styles$
|
|
31479
|
+
const styles$o = aphrodite.StyleSheet.create({
|
|
31006
31480
|
container: {
|
|
31007
31481
|
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
31008
31482
|
marginBottom: 0,
|
|
@@ -31070,7 +31544,7 @@ const LockedLineSettings = props => {
|
|
|
31070
31544
|
expanded: props.expanded,
|
|
31071
31545
|
onToggle: props.onToggle,
|
|
31072
31546
|
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31073
|
-
style: styles$
|
|
31547
|
+
style: styles$n.row
|
|
31074
31548
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31075
31549
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
31076
31550
|
}), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
|
|
@@ -31079,7 +31553,7 @@ const LockedLineSettings = props => {
|
|
|
31079
31553
|
}))
|
|
31080
31554
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
31081
31555
|
tag: "label",
|
|
31082
|
-
style: [styles$
|
|
31556
|
+
style: [styles$n.row, styles$n.spaceUnder]
|
|
31083
31557
|
}, "kind", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31084
31558
|
size: wonderBlocksTokens.spacing.xxxSmall_4
|
|
31085
31559
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -31100,7 +31574,7 @@ const LockedLineSettings = props => {
|
|
|
31100
31574
|
value: "segment",
|
|
31101
31575
|
label: "segment"
|
|
31102
31576
|
}))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31103
|
-
style: styles$
|
|
31577
|
+
style: styles$n.row
|
|
31104
31578
|
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
31105
31579
|
selectedValue: lineColor,
|
|
31106
31580
|
onChange: handleColorChange
|
|
@@ -31112,7 +31586,7 @@ const LockedLineSettings = props => {
|
|
|
31112
31586
|
lineStyle: value
|
|
31113
31587
|
})
|
|
31114
31588
|
})), isInvalid && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
31115
|
-
style: styles$
|
|
31589
|
+
style: styles$n.errorText
|
|
31116
31590
|
}, lengthZeroStr), /*#__PURE__*/React__namespace.createElement(DefiningPointSettings, _extends({
|
|
31117
31591
|
label: "Point 1",
|
|
31118
31592
|
showPoint: showPoint1,
|
|
@@ -31137,7 +31611,7 @@ const LockedLineSettings = props => {
|
|
|
31137
31611
|
onRemove: onRemove
|
|
31138
31612
|
}));
|
|
31139
31613
|
};
|
|
31140
|
-
const styles$
|
|
31614
|
+
const styles$n = aphrodite.StyleSheet.create({
|
|
31141
31615
|
row: {
|
|
31142
31616
|
display: "flex",
|
|
31143
31617
|
flexDirection: "row",
|
|
@@ -31178,7 +31652,7 @@ const LockedPointSettings = props => {
|
|
|
31178
31652
|
/*#__PURE__*/
|
|
31179
31653
|
// Summary: Point, coords, color (filled/open)
|
|
31180
31654
|
React__namespace.createElement(wonderBlocksCore.View, {
|
|
31181
|
-
style: styles$
|
|
31655
|
+
style: styles$m.row
|
|
31182
31656
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Point (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31183
31657
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
31184
31658
|
}), /*#__PURE__*/React__namespace.createElement(ColorSwatch, {
|
|
@@ -31187,7 +31661,7 @@ const LockedPointSettings = props => {
|
|
|
31187
31661
|
}))
|
|
31188
31662
|
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
31189
31663
|
coord: coord,
|
|
31190
|
-
style: styles$
|
|
31664
|
+
style: styles$m.spaceUnder,
|
|
31191
31665
|
onChange: newCoord => {
|
|
31192
31666
|
onChangeProps({
|
|
31193
31667
|
coord: newCoord
|
|
@@ -31196,7 +31670,7 @@ const LockedPointSettings = props => {
|
|
|
31196
31670
|
}), /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
31197
31671
|
selectedValue: pointColor,
|
|
31198
31672
|
onChange: handleColorChange,
|
|
31199
|
-
style: styles$
|
|
31673
|
+
style: styles$m.spaceUnder
|
|
31200
31674
|
}), /*#__PURE__*/React__namespace.createElement(LabeledSwitch, {
|
|
31201
31675
|
label: "open point",
|
|
31202
31676
|
checked: !filled,
|
|
@@ -31211,7 +31685,7 @@ const LockedPointSettings = props => {
|
|
|
31211
31685
|
onRemove: onRemove
|
|
31212
31686
|
}));
|
|
31213
31687
|
};
|
|
31214
|
-
const styles$
|
|
31688
|
+
const styles$m = aphrodite.StyleSheet.create({
|
|
31215
31689
|
row: {
|
|
31216
31690
|
flexDirection: "row",
|
|
31217
31691
|
alignItems: "center"
|
|
@@ -31229,17 +31703,17 @@ const PolygonSwatch = props => {
|
|
|
31229
31703
|
} = props;
|
|
31230
31704
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31231
31705
|
"aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
|
|
31232
|
-
style: [styles$
|
|
31706
|
+
style: [styles$l.container, {
|
|
31233
31707
|
border: `4px ${strokeStyle} ${perseus.lockedFigureColors[color]}`
|
|
31234
31708
|
}]
|
|
31235
31709
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31236
|
-
style: [styles$
|
|
31710
|
+
style: [styles$l.innerSquare, {
|
|
31237
31711
|
backgroundColor: perseus.lockedFigureColors[color],
|
|
31238
31712
|
opacity: fillStyle === "white" ? 0 : perseus.lockedFigureFillStyles[fillStyle]
|
|
31239
31713
|
}]
|
|
31240
31714
|
}));
|
|
31241
31715
|
};
|
|
31242
|
-
const styles$
|
|
31716
|
+
const styles$l = aphrodite.StyleSheet.create({
|
|
31243
31717
|
container: {
|
|
31244
31718
|
// Add a white outline so that the color swatch is visible when
|
|
31245
31719
|
// the dropdown option is highlighted with its blue background.
|
|
@@ -31317,7 +31791,7 @@ const LockedPolygonSettings = props => {
|
|
|
31317
31791
|
/*#__PURE__*/
|
|
31318
31792
|
// Summary: Polygon, number of sides, style swatch
|
|
31319
31793
|
React__namespace.createElement(wonderBlocksCore.View, {
|
|
31320
|
-
style: styles$
|
|
31794
|
+
style: styles$k.row
|
|
31321
31795
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Polygon, ${points.length} sides`), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31322
31796
|
size: wonderBlocksTokens.spacing.xSmall_8
|
|
31323
31797
|
}), /*#__PURE__*/React__namespace.createElement(PolygonSwatch, {
|
|
@@ -31326,7 +31800,7 @@ const LockedPolygonSettings = props => {
|
|
|
31326
31800
|
strokeStyle: strokeStyle
|
|
31327
31801
|
}))
|
|
31328
31802
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31329
|
-
style: [styles$
|
|
31803
|
+
style: [styles$k.row, styles$k.spaceUnder]
|
|
31330
31804
|
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
31331
31805
|
selectedValue: color,
|
|
31332
31806
|
onChange: handleColorChange
|
|
@@ -31334,7 +31808,7 @@ const LockedPolygonSettings = props => {
|
|
|
31334
31808
|
size: wonderBlocksTokens.spacing.medium_16
|
|
31335
31809
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
31336
31810
|
tag: "label",
|
|
31337
|
-
style: [styles$
|
|
31811
|
+
style: [styles$k.row, styles$k.truncatedWidth]
|
|
31338
31812
|
}, "fill", /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31339
31813
|
size: wonderBlocksTokens.spacing.xxSmall_6
|
|
31340
31814
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
@@ -31360,17 +31834,17 @@ const LockedPolygonSettings = props => {
|
|
|
31360
31834
|
onChange: newValue => onChangeProps({
|
|
31361
31835
|
showVertices: newValue
|
|
31362
31836
|
}),
|
|
31363
|
-
style: styles$
|
|
31837
|
+
style: styles$k.spaceUnder
|
|
31364
31838
|
}), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
31365
31839
|
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, "Points"),
|
|
31366
31840
|
expanded: true,
|
|
31367
|
-
containerStyle: styles$
|
|
31368
|
-
panelStyle: styles$
|
|
31841
|
+
containerStyle: styles$k.pointAccordionContainer,
|
|
31842
|
+
panelStyle: styles$k.pointAccordionPanel
|
|
31369
31843
|
}, points.map((point, index) => {
|
|
31370
31844
|
const pointLabel = String.fromCharCode(65 + index);
|
|
31371
31845
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31372
31846
|
key: `locked-polygon-point-index-${index}`,
|
|
31373
|
-
style: [styles$
|
|
31847
|
+
style: [styles$k.row, styles$k.spaceUnder]
|
|
31374
31848
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `${pointLabel}:`), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31375
31849
|
size: wonderBlocksTokens.spacing.medium_16
|
|
31376
31850
|
}), /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
@@ -31398,10 +31872,10 @@ const LockedPolygonSettings = props => {
|
|
|
31398
31872
|
points: newPoints
|
|
31399
31873
|
});
|
|
31400
31874
|
},
|
|
31401
|
-
style: styles$
|
|
31875
|
+
style: styles$k.icon
|
|
31402
31876
|
}));
|
|
31403
31877
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31404
|
-
style: [styles$
|
|
31878
|
+
style: [styles$k.row, styles$k.polygonActionsContainer]
|
|
31405
31879
|
}, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
31406
31880
|
kind: "tertiary",
|
|
31407
31881
|
startIcon: plusCircle__default["default"],
|
|
@@ -31411,1006 +31885,555 @@ const LockedPolygonSettings = props => {
|
|
|
31411
31885
|
});
|
|
31412
31886
|
}
|
|
31413
31887
|
}, "Add point"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31414
|
-
style: styles$
|
|
31888
|
+
style: styles$k.movementButtonsContainer
|
|
31415
31889
|
}, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
31416
31890
|
"aria-label": "Move polygon up",
|
|
31417
|
-
style: styles$
|
|
31891
|
+
style: styles$k.iconButton,
|
|
31418
31892
|
size: "small",
|
|
31419
31893
|
icon: arrowFatUp__default["default"],
|
|
31420
31894
|
onClick: () => handlePolygonMove("up")
|
|
31421
31895
|
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31422
|
-
style: styles$
|
|
31896
|
+
style: styles$k.row
|
|
31423
31897
|
}, /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
31424
31898
|
"aria-label": "Move polygon left",
|
|
31425
|
-
style: styles$
|
|
31426
|
-
size: "small",
|
|
31427
|
-
icon: arrowFatLeft__default["default"],
|
|
31428
|
-
onClick: () => handlePolygonMove("left")
|
|
31429
|
-
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
31430
|
-
"aria-label": "Move polygon down",
|
|
31431
|
-
style: styles$p.iconButton,
|
|
31899
|
+
style: styles$k.iconButton,
|
|
31432
31900
|
size: "small",
|
|
31433
|
-
icon:
|
|
31434
|
-
onClick: () => handlePolygonMove("
|
|
31435
|
-
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
31436
|
-
"aria-label": "Move polygon
|
|
31437
|
-
style: styles$
|
|
31438
|
-
size: "small",
|
|
31439
|
-
icon:
|
|
31440
|
-
onClick: () => handlePolygonMove("
|
|
31441
|
-
})
|
|
31442
|
-
|
|
31443
|
-
|
|
31444
|
-
|
|
31445
|
-
|
|
31446
|
-
|
|
31447
|
-
|
|
31448
|
-
|
|
31449
|
-
|
|
31450
|
-
|
|
31451
|
-
alignItems: "center"
|
|
31452
|
-
},
|
|
31453
|
-
pointAccordionContainer: {
|
|
31454
|
-
backgroundColor: wonderBlocksTokens.color.white
|
|
31455
|
-
},
|
|
31456
|
-
pointAccordionPanel: {
|
|
31457
|
-
alignItems: "start"
|
|
31458
|
-
},
|
|
31459
|
-
icon: {
|
|
31460
|
-
marginInlineStart: wonderBlocksTokens.spacing.xxxSmall_4
|
|
31461
|
-
},
|
|
31462
|
-
polygonActionsContainer: {
|
|
31463
|
-
width: "100%"
|
|
31464
|
-
},
|
|
31465
|
-
iconButton: {
|
|
31466
|
-
margin: 0
|
|
31467
|
-
},
|
|
31468
|
-
movementButtonsContainer: {
|
|
31469
|
-
display: "flex",
|
|
31470
|
-
flexDirection: "column",
|
|
31471
|
-
alignItems: "center",
|
|
31472
|
-
minWidth: "fit-content"
|
|
31473
|
-
},
|
|
31474
|
-
spaceUnder: {
|
|
31475
|
-
marginBottom: wonderBlocksTokens.spacing.xSmall_8
|
|
31476
|
-
},
|
|
31477
|
-
truncatedWidth: {
|
|
31478
|
-
// Allow truncation, stop bleeding over the edge.
|
|
31479
|
-
minWidth: 0
|
|
31480
|
-
}
|
|
31481
|
-
});
|
|
31482
|
-
|
|
31483
|
-
/**
|
|
31484
|
-
* LockedVectorSettings is a component that allows the user to edit the
|
|
31485
|
-
* settings of specifically a locked vector on the graph.
|
|
31486
|
-
*
|
|
31487
|
-
* Used in the interactive graph editor's locked figures section.
|
|
31488
|
-
*/
|
|
31489
|
-
const lengthErrorMessage = "The vector cannot have length 0.";
|
|
31490
|
-
const LockedVectorSettings = props => {
|
|
31491
|
-
const {
|
|
31492
|
-
points,
|
|
31493
|
-
color: lineColor,
|
|
31494
|
-
onChangeProps,
|
|
31495
|
-
onMove,
|
|
31496
|
-
onRemove
|
|
31497
|
-
} = props;
|
|
31498
|
-
const [tail, tip] = points;
|
|
31499
|
-
const lineLabel = `Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;
|
|
31500
|
-
|
|
31501
|
-
// Check if the line has length 0.
|
|
31502
|
-
const isInvalid = kmath.vector.equal(tail, tip);
|
|
31503
|
-
function handleChangePoint(newCoord, index) {
|
|
31504
|
-
if (typeof newCoord !== "undefined") {
|
|
31505
|
-
const newPoints = [...points];
|
|
31506
|
-
newPoints[index] = [...newCoord];
|
|
31507
|
-
onChangeProps({
|
|
31508
|
-
points: newPoints
|
|
31509
|
-
});
|
|
31510
|
-
}
|
|
31511
|
-
}
|
|
31512
|
-
function handleColorChange(newColor) {
|
|
31513
|
-
onChangeProps({
|
|
31514
|
-
color: newColor
|
|
31515
|
-
});
|
|
31516
|
-
}
|
|
31517
|
-
return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
31518
|
-
expanded: props.expanded,
|
|
31519
|
-
onToggle: props.onToggle,
|
|
31520
|
-
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31521
|
-
style: styles$o.row
|
|
31522
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31523
|
-
size: wonderBlocksTokens.spacing.xSmall_8
|
|
31524
|
-
}), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
|
|
31525
|
-
color: lineColor,
|
|
31526
|
-
lineStyle: "solid"
|
|
31527
|
-
}))
|
|
31528
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31529
|
-
style: [styles$o.row, styles$o.spaceUnder]
|
|
31530
|
-
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
31531
|
-
selectedValue: lineColor,
|
|
31532
|
-
onChange: handleColorChange
|
|
31533
|
-
})), isInvalid && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
31534
|
-
style: styles$o.errorText
|
|
31535
|
-
}, lengthErrorMessage), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
31536
|
-
expanded: true // Initial state is expanded
|
|
31537
|
-
,
|
|
31538
|
-
containerStyle: styles$o.container,
|
|
31539
|
-
panelStyle: styles$o.accordionPanel,
|
|
31540
|
-
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31541
|
-
style: styles$o.row
|
|
31542
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Tail (${tail[0]}, ${tail[1]})`))
|
|
31543
|
-
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
31544
|
-
coord: tail,
|
|
31545
|
-
error: isInvalid,
|
|
31546
|
-
onChange: newProps => {
|
|
31547
|
-
handleChangePoint(newProps, 0);
|
|
31548
|
-
}
|
|
31549
|
-
})), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
31550
|
-
expanded: true // Initial state is expanded
|
|
31551
|
-
,
|
|
31552
|
-
containerStyle: styles$o.container,
|
|
31553
|
-
panelStyle: styles$o.accordionPanel,
|
|
31554
|
-
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31555
|
-
style: styles$o.row
|
|
31556
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Tip (${tip[0]}, ${tip[1]})`))
|
|
31557
|
-
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
31558
|
-
coord: tip,
|
|
31559
|
-
error: isInvalid,
|
|
31560
|
-
onChange: newProps => {
|
|
31561
|
-
handleChangePoint(newProps, 1);
|
|
31562
|
-
}
|
|
31563
|
-
})), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
|
|
31564
|
-
figureType: props.type,
|
|
31565
|
-
onMove: onMove,
|
|
31566
|
-
onRemove: onRemove
|
|
31567
|
-
}));
|
|
31568
|
-
};
|
|
31569
|
-
const styles$o = aphrodite.StyleSheet.create({
|
|
31570
|
-
accordionPanel: {
|
|
31571
|
-
paddingBottom: wonderBlocksTokens.spacing.medium_16
|
|
31572
|
-
},
|
|
31573
|
-
container: {
|
|
31574
|
-
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
31575
|
-
marginBottom: 0,
|
|
31576
|
-
marginLeft: -wonderBlocksTokens.spacing.xxxSmall_4,
|
|
31577
|
-
marginRight: -wonderBlocksTokens.spacing.xxxSmall_4,
|
|
31578
|
-
backgroundColor: wonderBlocksTokens.color.white
|
|
31579
|
-
},
|
|
31580
|
-
errorText: {
|
|
31581
|
-
color: wonderBlocksTokens.color.red,
|
|
31582
|
-
marginTop: wonderBlocksTokens.spacing.xSmall_8
|
|
31583
|
-
},
|
|
31584
|
-
row: {
|
|
31585
|
-
flexDirection: "row",
|
|
31586
|
-
alignItems: "center"
|
|
31587
|
-
}
|
|
31588
|
-
});
|
|
31589
|
-
|
|
31590
|
-
/**
|
|
31591
|
-
* LockedFigureSettings takes in a figure and renders the
|
|
31592
|
-
* respective settings for that figure type.
|
|
31593
|
-
*
|
|
31594
|
-
* Used in the interactive graph editor's locked figures section.
|
|
31595
|
-
*/
|
|
31596
|
-
|
|
31597
|
-
// Union this type with other locked figure types when they are added.
|
|
31598
|
-
|
|
31599
|
-
const LockedFigureSettings = props => {
|
|
31600
|
-
switch (props.type) {
|
|
31601
|
-
case "point":
|
|
31602
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPointSettings, props);
|
|
31603
|
-
case "line":
|
|
31604
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLineSettings, props);
|
|
31605
|
-
case "vector":
|
|
31606
|
-
return /*#__PURE__*/React__namespace.createElement(LockedVectorSettings, props);
|
|
31607
|
-
case "ellipse":
|
|
31608
|
-
return /*#__PURE__*/React__namespace.createElement(LockedEllipseSettings, props);
|
|
31609
|
-
case "polygon":
|
|
31610
|
-
return /*#__PURE__*/React__namespace.createElement(LockedPolygonSettings, props);
|
|
31611
|
-
case "function":
|
|
31612
|
-
return /*#__PURE__*/React__namespace.createElement(LockedFunctionSettings, props);
|
|
31613
|
-
case "label":
|
|
31614
|
-
if (props.showLabelsFlag) {
|
|
31615
|
-
return /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, props);
|
|
31616
|
-
}
|
|
31617
|
-
break;
|
|
31618
|
-
}
|
|
31619
|
-
return null;
|
|
31620
|
-
};
|
|
31621
|
-
|
|
31622
|
-
const LockedFiguresSection = props => {
|
|
31623
|
-
// Keep track of all figures' accordions' expanded states for the
|
|
31624
|
-
// expand/collapse all button. Set the whole array to false initially.
|
|
31625
|
-
const collapsedStateArray = Array((props.figures ?? []).length).fill(false);
|
|
31626
|
-
const [expandedStates, setExpandedStates] = React__namespace.useState(collapsedStateArray);
|
|
31627
|
-
const [isExpanded, setIsExpanded] = React__namespace.useState(true);
|
|
31628
|
-
const uniqueId = wonderBlocksCore.useUniqueIdWithMock().get("locked-figures-section");
|
|
31629
|
-
const {
|
|
31630
|
-
figures,
|
|
31631
|
-
onChange
|
|
31632
|
-
} = props;
|
|
31633
|
-
function addLockedFigure(newFigure) {
|
|
31634
|
-
const lockedFigures = figures || [];
|
|
31635
|
-
const newProps = {
|
|
31636
|
-
lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
|
|
31637
|
-
};
|
|
31638
|
-
onChange(newProps);
|
|
31639
|
-
setExpandedStates([...expandedStates, true]);
|
|
31640
|
-
}
|
|
31641
|
-
function moveLockedFigure(index, movement) {
|
|
31642
|
-
// Don't allow moving the first figure up or the last figure down.
|
|
31643
|
-
if (index === 0 && (movement === "back" || movement === "backward")) {
|
|
31644
|
-
return;
|
|
31645
|
-
}
|
|
31646
|
-
if (figures && index === figures.length - 1 && (movement === "front" || movement === "forward")) {
|
|
31647
|
-
return;
|
|
31648
|
-
}
|
|
31649
|
-
const lockedFigures = figures || [];
|
|
31650
|
-
const newFigures = [...lockedFigures];
|
|
31651
|
-
const newExpandedStates = [...expandedStates];
|
|
31652
|
-
|
|
31653
|
-
// First, remove the figure from its current position
|
|
31654
|
-
// in the figures array and the expanded states array.
|
|
31655
|
-
const [removedFigure] = newFigures.splice(index, 1);
|
|
31656
|
-
newExpandedStates.splice(index, 1);
|
|
31657
|
-
|
|
31658
|
-
// Then, add it back in the new position. Add "true" to the
|
|
31659
|
-
// expanded states array for the new position (it must already
|
|
31660
|
-
// be open since the button to move it is being pressed from there).
|
|
31661
|
-
switch (movement) {
|
|
31662
|
-
case "back":
|
|
31663
|
-
newFigures.unshift(removedFigure);
|
|
31664
|
-
newExpandedStates.unshift(true);
|
|
31665
|
-
break;
|
|
31666
|
-
case "backward":
|
|
31667
|
-
newFigures.splice(index - 1, 0, removedFigure);
|
|
31668
|
-
newExpandedStates.splice(index - 1, 0, true);
|
|
31669
|
-
break;
|
|
31670
|
-
case "forward":
|
|
31671
|
-
newFigures.splice(index + 1, 0, removedFigure);
|
|
31672
|
-
newExpandedStates.splice(index + 1, 0, true);
|
|
31673
|
-
break;
|
|
31674
|
-
case "front":
|
|
31675
|
-
newFigures.push(removedFigure);
|
|
31676
|
-
newExpandedStates.push(true);
|
|
31677
|
-
break;
|
|
31678
|
-
}
|
|
31679
|
-
onChange({
|
|
31680
|
-
lockedFigures: newFigures
|
|
31681
|
-
});
|
|
31682
|
-
setExpandedStates(newExpandedStates);
|
|
31683
|
-
}
|
|
31684
|
-
function removeLockedFigure(index) {
|
|
31685
|
-
// eslint-disable-next-line no-alert
|
|
31686
|
-
if (window.confirm("Are you sure you want to delete this figure?")) {
|
|
31687
|
-
const lockedFigures = figures || [];
|
|
31688
|
-
onChange({
|
|
31689
|
-
lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
|
|
31690
|
-
});
|
|
31691
|
-
|
|
31692
|
-
// Update expanded states
|
|
31693
|
-
const newExpandedStates = [...expandedStates];
|
|
31694
|
-
newExpandedStates.splice(index, 1);
|
|
31695
|
-
setExpandedStates(newExpandedStates);
|
|
31696
|
-
}
|
|
31697
|
-
}
|
|
31698
|
-
function changeProps(index,
|
|
31699
|
-
// Omit the type from the figure props so it doesn't think
|
|
31700
|
-
// we're trying to pass in the props for the wrong type.
|
|
31701
|
-
figureProps) {
|
|
31702
|
-
const lockedFigures = figures || [];
|
|
31703
|
-
const newFigures = {
|
|
31704
|
-
lockedFigures: [...lockedFigures.slice(0, index), {
|
|
31705
|
-
...lockedFigures[index],
|
|
31706
|
-
...figureProps
|
|
31707
|
-
}, ...lockedFigures.slice(index + 1)]
|
|
31708
|
-
};
|
|
31709
|
-
onChange(newFigures);
|
|
31710
|
-
}
|
|
31711
|
-
function toggleExpanded(newValue) {
|
|
31712
|
-
setExpandedStates(Array(figures?.length).fill(newValue));
|
|
31713
|
-
}
|
|
31714
|
-
const allCollapsed = expandedStates.every(value => !value);
|
|
31715
|
-
const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
|
|
31716
|
-
const showExpandButton = !!figures?.length;
|
|
31717
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
|
|
31718
|
-
title: "Locked Figures",
|
|
31719
|
-
isOpen: isExpanded,
|
|
31720
|
-
onToggle: () => setIsExpanded(!isExpanded),
|
|
31721
|
-
isCollapsible: true
|
|
31722
|
-
}), isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, figures?.map((figure, index) => {
|
|
31723
|
-
return /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
|
|
31724
|
-
key: `${uniqueId}-locked-${figure}-${index}`,
|
|
31725
|
-
showLabelsFlag: props.showLabelsFlag,
|
|
31726
|
-
expanded: expandedStates[index],
|
|
31727
|
-
onToggle: newValue => {
|
|
31728
|
-
const newExpanded = [...expandedStates];
|
|
31729
|
-
newExpanded[index] = newValue;
|
|
31730
|
-
setExpandedStates(newExpanded);
|
|
31731
|
-
}
|
|
31732
|
-
}, figure, {
|
|
31733
|
-
onChangeProps: newProps => changeProps(index, newProps),
|
|
31734
|
-
onMove: movement => moveLockedFigure(index, movement),
|
|
31735
|
-
onRemove: () => removeLockedFigure(index)
|
|
31736
|
-
}));
|
|
31737
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31738
|
-
style: styles$n.buttonContainer
|
|
31739
|
-
}, /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
|
|
31740
|
-
showLabelsFlag: props.showLabelsFlag,
|
|
31741
|
-
id: `${uniqueId}-select`,
|
|
31742
|
-
onChange: addLockedFigure
|
|
31743
|
-
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31744
|
-
size: wonderBlocksTokens.spacing.small_12
|
|
31745
|
-
}), showExpandButton && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
31746
|
-
kind: "secondary",
|
|
31747
|
-
onClick: () => toggleExpanded(allCollapsed),
|
|
31748
|
-
style: styles$n.button
|
|
31749
|
-
}, buttonLabel))));
|
|
31750
|
-
};
|
|
31751
|
-
const styles$n = aphrodite.StyleSheet.create({
|
|
31752
|
-
buttonContainer: {
|
|
31753
|
-
flexDirection: "row",
|
|
31754
|
-
alignItems: "center"
|
|
31755
|
-
},
|
|
31756
|
-
button: {
|
|
31757
|
-
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
31758
|
-
flexGrow: 1
|
|
31759
|
-
}
|
|
31760
|
-
});
|
|
31761
|
-
|
|
31762
|
-
const UNLIMITED = "unlimited";
|
|
31763
|
-
// Parses a string (ostensibly from some UI element that only supports string
|
|
31764
|
-
// types, such as a <select />) into a numeric point count or the special sigil
|
|
31765
|
-
// "unlimited". Note that 0 is a special case, and means "unlimited".
|
|
31766
|
-
const parsePointCount = points => {
|
|
31767
|
-
const parsed = parseInt(points, 10);
|
|
31768
|
-
if (isNaN(parsed)) {
|
|
31769
|
-
return UNLIMITED;
|
|
31770
|
-
}
|
|
31771
|
-
return parsed === 0 ? UNLIMITED : parsed;
|
|
31772
|
-
};
|
|
31773
|
-
|
|
31774
|
-
const GraphPointsCountSelector = _ref => {
|
|
31775
|
-
let {
|
|
31776
|
-
numPoints = 1,
|
|
31777
|
-
onChange
|
|
31778
|
-
} = _ref;
|
|
31779
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
31780
|
-
selectedValue: `${numPoints}`,
|
|
31781
|
-
onChange: newValue => {
|
|
31782
|
-
onChange(parsePointCount(newValue));
|
|
31783
|
-
}
|
|
31784
|
-
// Never uses placeholder, always has value
|
|
31785
|
-
,
|
|
31786
|
-
placeholder: "",
|
|
31787
|
-
style: styles$m.singleSelectShort
|
|
31788
|
-
}, [...[...Array(7).keys()].map(n => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31789
|
-
key: n,
|
|
31790
|
-
value: `${n}`,
|
|
31791
|
-
label: `${n} point${n > 1 ? "s" : ""}`
|
|
31792
|
-
})), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31793
|
-
key: "unlimited",
|
|
31794
|
-
value: UNLIMITED,
|
|
31795
|
-
label: "unlimited"
|
|
31796
|
-
})]);
|
|
31797
|
-
};
|
|
31798
|
-
const styles$m = aphrodite.StyleSheet.create({
|
|
31799
|
-
singleSelectShort: {
|
|
31800
|
-
// Non-standard spacing, but it's the smallest we can go
|
|
31801
|
-
// without running into styling issues with the dropdown.
|
|
31802
|
-
height: 26
|
|
31803
|
-
}
|
|
31804
|
-
});
|
|
31805
|
-
|
|
31806
|
-
const GraphTypeSelector = props => {
|
|
31807
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.SingleSelect, {
|
|
31808
|
-
selectedValue: props.graphType,
|
|
31809
|
-
onChange: props.onChange,
|
|
31810
|
-
placeholder: "Select a graph type",
|
|
31811
|
-
style: styles$l.singleSelectShort
|
|
31812
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31813
|
-
value: "linear",
|
|
31814
|
-
label: "Linear function"
|
|
31815
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31816
|
-
value: "quadratic",
|
|
31817
|
-
label: "Quadratic function"
|
|
31818
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31819
|
-
value: "sinusoid",
|
|
31820
|
-
label: "Sinusoid function"
|
|
31821
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31822
|
-
value: "circle",
|
|
31823
|
-
label: "Circle"
|
|
31824
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31825
|
-
value: "point",
|
|
31826
|
-
label: "Point(s)"
|
|
31827
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31828
|
-
value: "linear-system",
|
|
31829
|
-
label: "Linear System"
|
|
31830
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31831
|
-
value: "polygon",
|
|
31832
|
-
label: "Polygon"
|
|
31833
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31834
|
-
value: "segment",
|
|
31835
|
-
label: "Line Segment(s)"
|
|
31836
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31837
|
-
value: "ray",
|
|
31838
|
-
label: "Ray"
|
|
31839
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
31840
|
-
value: "angle",
|
|
31841
|
-
label: "Angle"
|
|
31901
|
+
icon: arrowFatLeft__default["default"],
|
|
31902
|
+
onClick: () => handlePolygonMove("left")
|
|
31903
|
+
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
31904
|
+
"aria-label": "Move polygon down",
|
|
31905
|
+
style: styles$k.iconButton,
|
|
31906
|
+
size: "small",
|
|
31907
|
+
icon: arrowFatDown__default["default"],
|
|
31908
|
+
onClick: () => handlePolygonMove("down")
|
|
31909
|
+
}), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
|
|
31910
|
+
"aria-label": "Move polygon right",
|
|
31911
|
+
style: styles$k.iconButton,
|
|
31912
|
+
size: "small",
|
|
31913
|
+
icon: arrowFatRight__default["default"],
|
|
31914
|
+
onClick: () => handlePolygonMove("right")
|
|
31915
|
+
}))))), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
|
|
31916
|
+
figureType: props.type,
|
|
31917
|
+
onMove: onMove,
|
|
31918
|
+
onRemove: onRemove
|
|
31842
31919
|
}));
|
|
31843
31920
|
};
|
|
31844
|
-
const styles$
|
|
31845
|
-
|
|
31846
|
-
|
|
31847
|
-
|
|
31848
|
-
|
|
31921
|
+
const styles$k = aphrodite.StyleSheet.create({
|
|
31922
|
+
row: {
|
|
31923
|
+
display: "flex",
|
|
31924
|
+
flexDirection: "row",
|
|
31925
|
+
alignItems: "center"
|
|
31926
|
+
},
|
|
31927
|
+
pointAccordionContainer: {
|
|
31928
|
+
backgroundColor: wonderBlocksTokens.color.white
|
|
31929
|
+
},
|
|
31930
|
+
pointAccordionPanel: {
|
|
31931
|
+
alignItems: "start"
|
|
31932
|
+
},
|
|
31933
|
+
icon: {
|
|
31934
|
+
marginInlineStart: wonderBlocksTokens.spacing.xxxSmall_4
|
|
31935
|
+
},
|
|
31936
|
+
polygonActionsContainer: {
|
|
31937
|
+
width: "100%"
|
|
31938
|
+
},
|
|
31939
|
+
iconButton: {
|
|
31940
|
+
margin: 0
|
|
31941
|
+
},
|
|
31942
|
+
movementButtonsContainer: {
|
|
31943
|
+
display: "flex",
|
|
31944
|
+
flexDirection: "column",
|
|
31945
|
+
alignItems: "center",
|
|
31946
|
+
minWidth: "fit-content"
|
|
31947
|
+
},
|
|
31948
|
+
spaceUnder: {
|
|
31949
|
+
marginBottom: wonderBlocksTokens.spacing.xSmall_8
|
|
31950
|
+
},
|
|
31951
|
+
truncatedWidth: {
|
|
31952
|
+
// Allow truncation, stop bleeding over the edge.
|
|
31953
|
+
minWidth: 0
|
|
31849
31954
|
}
|
|
31850
31955
|
});
|
|
31851
31956
|
|
|
31852
|
-
|
|
31853
|
-
|
|
31854
|
-
|
|
31855
|
-
|
|
31856
|
-
|
|
31857
|
-
|
|
31858
|
-
|
|
31859
|
-
|
|
31860
|
-
paddingBottom: wonderBlocksTokens.spacing.xxSmall_6,
|
|
31861
|
-
color: wonderBlocksTokens.color.offBlack64
|
|
31862
|
-
}
|
|
31863
|
-
}, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.BodyMonospace, {
|
|
31864
|
-
style: {
|
|
31865
|
-
fontSize: 12,
|
|
31866
|
-
backgroundColor: "#eee",
|
|
31867
|
-
paddingInline: wonderBlocksTokens.spacing.xxSmall_6,
|
|
31868
|
-
borderColor: "#ccc",
|
|
31869
|
-
borderStyle: "solid",
|
|
31870
|
-
borderWidth: 1
|
|
31871
|
-
}
|
|
31872
|
-
}, props.equationString)), props.children));
|
|
31873
|
-
}
|
|
31874
|
-
|
|
31875
|
-
function InteractiveGraphDescription(props) {
|
|
31957
|
+
/**
|
|
31958
|
+
* LockedVectorSettings is a component that allows the user to edit the
|
|
31959
|
+
* settings of specifically a locked vector on the graph.
|
|
31960
|
+
*
|
|
31961
|
+
* Used in the interactive graph editor's locked figures section.
|
|
31962
|
+
*/
|
|
31963
|
+
const lengthErrorMessage = "The vector cannot have length 0.";
|
|
31964
|
+
const LockedVectorSettings = props => {
|
|
31876
31965
|
const {
|
|
31877
|
-
|
|
31878
|
-
|
|
31879
|
-
|
|
31966
|
+
points,
|
|
31967
|
+
color: lineColor,
|
|
31968
|
+
onChangeProps,
|
|
31969
|
+
onMove,
|
|
31970
|
+
onRemove
|
|
31880
31971
|
} = props;
|
|
31881
|
-
const [
|
|
31882
|
-
|
|
31883
|
-
title: "Description",
|
|
31884
|
-
isCollapsible: true,
|
|
31885
|
-
isOpen: isOpen,
|
|
31886
|
-
onToggle: setIsOpen
|
|
31887
|
-
}), isOpen && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelXSmall, {
|
|
31888
|
-
style: styles$k.caption
|
|
31889
|
-
}, "Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who are visually impaired."), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
31890
|
-
tag: "label"
|
|
31891
|
-
}, "Title", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextField, {
|
|
31892
|
-
value: ariaLabelValue,
|
|
31893
|
-
onChange: newValue => onChange({
|
|
31894
|
-
fullGraphAriaLabel: newValue
|
|
31895
|
-
}),
|
|
31896
|
-
style: styles$k.spaceAbove
|
|
31897
|
-
})), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31898
|
-
size: wonderBlocksTokens.spacing.small_12
|
|
31899
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, {
|
|
31900
|
-
tag: "label"
|
|
31901
|
-
}, "Description", /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.TextArea, {
|
|
31902
|
-
rows: 8,
|
|
31903
|
-
resizeType: "vertical",
|
|
31904
|
-
value: ariaDescriptionValue,
|
|
31905
|
-
onChange: newValue => onChange({
|
|
31906
|
-
fullGraphAriaDescription: newValue
|
|
31907
|
-
}),
|
|
31908
|
-
style: styles$k.spaceAbove
|
|
31909
|
-
}))));
|
|
31910
|
-
}
|
|
31911
|
-
const styles$k = aphrodite.StyleSheet.create({
|
|
31912
|
-
caption: {
|
|
31913
|
-
color: wonderBlocksTokens.color.offBlack64,
|
|
31914
|
-
paddingTop: wonderBlocksTokens.spacing.xxSmall_6,
|
|
31915
|
-
paddingBottom: wonderBlocksTokens.spacing.xxSmall_6
|
|
31916
|
-
},
|
|
31917
|
-
spaceAbove: {
|
|
31918
|
-
marginTop: wonderBlocksTokens.spacing.xxxSmall_4
|
|
31919
|
-
}
|
|
31920
|
-
});
|
|
31972
|
+
const [tail, tip] = points;
|
|
31973
|
+
const lineLabel = `Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;
|
|
31921
31974
|
|
|
31922
|
-
|
|
31923
|
-
const
|
|
31924
|
-
|
|
31925
|
-
|
|
31926
|
-
|
|
31927
|
-
|
|
31928
|
-
|
|
31929
|
-
|
|
31930
|
-
|
|
31931
|
-
|
|
31932
|
-
};
|
|
31933
|
-
function numSteps(range, step) {
|
|
31934
|
-
return Math.floor((range[1] - range[0]) / step);
|
|
31935
|
-
}
|
|
31936
|
-
class InteractiveGraphSettings extends React__namespace.Component {
|
|
31937
|
-
_isMounted = false;
|
|
31938
|
-
bgUrlRef = /*#__PURE__*/React__namespace.createRef();
|
|
31939
|
-
labelXRef = /*#__PURE__*/React__namespace.createRef();
|
|
31940
|
-
labelYRef = /*#__PURE__*/React__namespace.createRef();
|
|
31941
|
-
static stateFromProps(props) {
|
|
31942
|
-
return {
|
|
31943
|
-
labelsTextbox: props.labels,
|
|
31944
|
-
gridStepTextbox: props.gridStep,
|
|
31945
|
-
snapStepTextbox: props.snapStep,
|
|
31946
|
-
stepTextbox: props.step,
|
|
31947
|
-
rangeTextbox: props.range,
|
|
31948
|
-
// Shallow-copied clone
|
|
31949
|
-
backgroundImage: {
|
|
31950
|
-
...props.backgroundImage
|
|
31951
|
-
}
|
|
31952
|
-
};
|
|
31953
|
-
}
|
|
31954
|
-
constructor(props) {
|
|
31955
|
-
super(props);
|
|
31956
|
-
this.state = {
|
|
31957
|
-
isExpanded: true,
|
|
31958
|
-
...InteractiveGraphSettings.stateFromProps(props)
|
|
31959
|
-
};
|
|
31975
|
+
// Check if the line has length 0.
|
|
31976
|
+
const isInvalid = kmath.vector.equal(tail, tip);
|
|
31977
|
+
function handleChangePoint(newCoord, index) {
|
|
31978
|
+
if (typeof newCoord !== "undefined") {
|
|
31979
|
+
const newPoints = [...points];
|
|
31980
|
+
newPoints[index] = [...newCoord];
|
|
31981
|
+
onChangeProps({
|
|
31982
|
+
points: newPoints
|
|
31983
|
+
});
|
|
31984
|
+
}
|
|
31960
31985
|
}
|
|
31961
|
-
|
|
31962
|
-
|
|
31963
|
-
|
|
31964
|
-
|
|
31965
|
-
step: [1, 1],
|
|
31966
|
-
gridStep: [1, 1],
|
|
31967
|
-
snapStep: [1, 1],
|
|
31968
|
-
valid: true,
|
|
31969
|
-
backgroundImage: defaultBackgroundImage$1,
|
|
31970
|
-
markings: "graph",
|
|
31971
|
-
showProtractor: false,
|
|
31972
|
-
showTooltips: false
|
|
31973
|
-
};
|
|
31974
|
-
componentDidMount() {
|
|
31975
|
-
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
31976
|
-
// this.isMounted() but is still considered an anti-pattern.
|
|
31977
|
-
this._isMounted = true;
|
|
31978
|
-
this.changeGraph = ___default["default"].debounce(this.changeGraph, 300);
|
|
31986
|
+
function handleColorChange(newColor) {
|
|
31987
|
+
onChangeProps({
|
|
31988
|
+
color: newColor
|
|
31989
|
+
});
|
|
31979
31990
|
}
|
|
31980
|
-
|
|
31981
|
-
|
|
31982
|
-
|
|
31983
|
-
|
|
31984
|
-
|
|
31991
|
+
return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
31992
|
+
expanded: props.expanded,
|
|
31993
|
+
onToggle: props.onToggle,
|
|
31994
|
+
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31995
|
+
style: styles$j.row
|
|
31996
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, lineLabel), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
31997
|
+
size: wonderBlocksTokens.spacing.xSmall_8
|
|
31998
|
+
}), /*#__PURE__*/React__namespace.createElement(LineSwatch, {
|
|
31999
|
+
color: lineColor,
|
|
32000
|
+
lineStyle: "solid"
|
|
32001
|
+
}))
|
|
32002
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32003
|
+
style: [styles$j.row, styles$j.spaceUnder]
|
|
32004
|
+
}, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
|
|
32005
|
+
selectedValue: lineColor,
|
|
32006
|
+
onChange: handleColorChange
|
|
32007
|
+
})), isInvalid && /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
32008
|
+
style: styles$j.errorText
|
|
32009
|
+
}, lengthErrorMessage), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
32010
|
+
expanded: true // Initial state is expanded
|
|
32011
|
+
,
|
|
32012
|
+
containerStyle: styles$j.container,
|
|
32013
|
+
panelStyle: styles$j.accordionPanel,
|
|
32014
|
+
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32015
|
+
style: styles$j.row
|
|
32016
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Tail (${tail[0]}, ${tail[1]})`))
|
|
32017
|
+
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
32018
|
+
coord: tail,
|
|
32019
|
+
error: isInvalid,
|
|
32020
|
+
onChange: newProps => {
|
|
32021
|
+
handleChangePoint(newProps, 0);
|
|
31985
32022
|
}
|
|
32023
|
+
})), /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
|
|
32024
|
+
expanded: true // Initial state is expanded
|
|
32025
|
+
,
|
|
32026
|
+
containerStyle: styles$j.container,
|
|
32027
|
+
panelStyle: styles$j.accordionPanel,
|
|
32028
|
+
header: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32029
|
+
style: styles$j.row
|
|
32030
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelLarge, null, `Tip (${tip[0]}, ${tip[1]})`))
|
|
32031
|
+
}, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
|
|
32032
|
+
coord: tip,
|
|
32033
|
+
error: isInvalid,
|
|
32034
|
+
onChange: newProps => {
|
|
32035
|
+
handleChangePoint(newProps, 1);
|
|
32036
|
+
}
|
|
32037
|
+
})), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
|
|
32038
|
+
figureType: props.type,
|
|
32039
|
+
onMove: onMove,
|
|
32040
|
+
onRemove: onRemove
|
|
32041
|
+
}));
|
|
32042
|
+
};
|
|
32043
|
+
const styles$j = aphrodite.StyleSheet.create({
|
|
32044
|
+
accordionPanel: {
|
|
32045
|
+
paddingBottom: wonderBlocksTokens.spacing.medium_16
|
|
32046
|
+
},
|
|
32047
|
+
container: {
|
|
32048
|
+
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
32049
|
+
marginBottom: 0,
|
|
32050
|
+
marginLeft: -wonderBlocksTokens.spacing.xxxSmall_4,
|
|
32051
|
+
marginRight: -wonderBlocksTokens.spacing.xxxSmall_4,
|
|
32052
|
+
backgroundColor: wonderBlocksTokens.color.white
|
|
32053
|
+
},
|
|
32054
|
+
errorText: {
|
|
32055
|
+
color: wonderBlocksTokens.color.red,
|
|
32056
|
+
marginTop: wonderBlocksTokens.spacing.xSmall_8
|
|
32057
|
+
},
|
|
32058
|
+
row: {
|
|
32059
|
+
flexDirection: "row",
|
|
32060
|
+
alignItems: "center"
|
|
31986
32061
|
}
|
|
31987
|
-
|
|
31988
|
-
|
|
31989
|
-
|
|
31990
|
-
|
|
31991
|
-
|
|
31992
|
-
|
|
31993
|
-
|
|
31994
|
-
|
|
32062
|
+
});
|
|
32063
|
+
|
|
32064
|
+
/**
|
|
32065
|
+
* LockedFigureSettings takes in a figure and renders the
|
|
32066
|
+
* respective settings for that figure type.
|
|
32067
|
+
*
|
|
32068
|
+
* Used in the interactive graph editor's locked figures section.
|
|
32069
|
+
*/
|
|
32070
|
+
|
|
32071
|
+
// Union this type with other locked figure types when they are added.
|
|
32072
|
+
|
|
32073
|
+
const LockedFigureSettings = props => {
|
|
32074
|
+
switch (props.type) {
|
|
32075
|
+
case "point":
|
|
32076
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPointSettings, props);
|
|
32077
|
+
case "line":
|
|
32078
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLineSettings, props);
|
|
32079
|
+
case "vector":
|
|
32080
|
+
return /*#__PURE__*/React__namespace.createElement(LockedVectorSettings, props);
|
|
32081
|
+
case "ellipse":
|
|
32082
|
+
return /*#__PURE__*/React__namespace.createElement(LockedEllipseSettings, props);
|
|
32083
|
+
case "polygon":
|
|
32084
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPolygonSettings, props);
|
|
32085
|
+
case "function":
|
|
32086
|
+
return /*#__PURE__*/React__namespace.createElement(LockedFunctionSettings, props);
|
|
32087
|
+
case "label":
|
|
32088
|
+
if (props.showLabelsFlag) {
|
|
32089
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, props);
|
|
31995
32090
|
}
|
|
31996
|
-
|
|
31997
|
-
|
|
31998
|
-
|
|
31999
|
-
|
|
32000
|
-
|
|
32001
|
-
|
|
32002
|
-
|
|
32003
|
-
|
|
32004
|
-
|
|
32005
|
-
|
|
32006
|
-
|
|
32007
|
-
|
|
32091
|
+
break;
|
|
32092
|
+
}
|
|
32093
|
+
return null;
|
|
32094
|
+
};
|
|
32095
|
+
|
|
32096
|
+
const DEFAULT_COLOR = "grayH";
|
|
32097
|
+
function getDefaultFigureForType(type) {
|
|
32098
|
+
switch (type) {
|
|
32099
|
+
case "point":
|
|
32100
|
+
return {
|
|
32101
|
+
type: "point",
|
|
32102
|
+
coord: [0, 0],
|
|
32103
|
+
color: DEFAULT_COLOR,
|
|
32104
|
+
filled: true
|
|
32008
32105
|
};
|
|
32009
|
-
|
|
32010
|
-
|
|
32011
|
-
|
|
32012
|
-
|
|
32013
|
-
|
|
32014
|
-
|
|
32015
|
-
|
|
32016
|
-
|
|
32017
|
-
|
|
32018
|
-
|
|
32019
|
-
|
|
32020
|
-
|
|
32021
|
-
|
|
32022
|
-
|
|
32023
|
-
|
|
32024
|
-
|
|
32025
|
-
|
|
32026
|
-
|
|
32027
|
-
|
|
32028
|
-
|
|
32029
|
-
|
|
32030
|
-
|
|
32031
|
-
|
|
32032
|
-
|
|
32033
|
-
|
|
32034
|
-
|
|
32035
|
-
|
|
32036
|
-
|
|
32037
|
-
|
|
32038
|
-
|
|
32039
|
-
|
|
32040
|
-
|
|
32041
|
-
|
|
32042
|
-
|
|
32043
|
-
|
|
32044
|
-
|
|
32045
|
-
|
|
32046
|
-
|
|
32047
|
-
|
|
32048
|
-
|
|
32049
|
-
|
|
32050
|
-
|
|
32051
|
-
|
|
32052
|
-
|
|
32053
|
-
|
|
32054
|
-
|
|
32055
|
-
|
|
32056
|
-
|
|
32057
|
-
|
|
32058
|
-
|
|
32059
|
-
|
|
32060
|
-
|
|
32061
|
-
|
|
32062
|
-
|
|
32063
|
-
|
|
32064
|
-
|
|
32065
|
-
|
|
32066
|
-
|
|
32067
|
-
|
|
32068
|
-
|
|
32069
|
-
|
|
32070
|
-
|
|
32071
|
-
|
|
32072
|
-
|
|
32073
|
-
|
|
32074
|
-
|
|
32075
|
-
|
|
32076
|
-
|
|
32077
|
-
|
|
32078
|
-
|
|
32079
|
-
|
|
32080
|
-
|
|
32081
|
-
|
|
32082
|
-
|
|
32083
|
-
|
|
32084
|
-
|
|
32085
|
-
|
|
32086
|
-
|
|
32087
|
-
|
|
32088
|
-
|
|
32089
|
-
|
|
32090
|
-
|
|
32091
|
-
if (!image.url) {
|
|
32092
|
-
return true;
|
|
32093
|
-
}
|
|
32094
|
-
const validSize = image.width <= 450 && image.height <= 450;
|
|
32095
|
-
if (!validSize) {
|
|
32096
|
-
return "Image must be smaller than 450px x 450px.";
|
|
32097
|
-
}
|
|
32098
|
-
return true;
|
|
32099
|
-
};
|
|
32100
|
-
validateGraphSettings = (range, step, gridStep, snapStep, image) => {
|
|
32101
|
-
const self = this;
|
|
32102
|
-
let msg;
|
|
32103
|
-
const goodRange = ___default["default"].every(range, function (range) {
|
|
32104
|
-
msg = self.validRange(range);
|
|
32105
|
-
return msg === true;
|
|
32106
|
-
});
|
|
32107
|
-
if (!goodRange) {
|
|
32108
|
-
return msg;
|
|
32109
|
-
}
|
|
32110
|
-
const goodStep = ___default["default"].every(step, function (step, i) {
|
|
32111
|
-
msg = self.validStep(step, range[i]);
|
|
32112
|
-
return msg === true;
|
|
32113
|
-
});
|
|
32114
|
-
if (!goodStep) {
|
|
32115
|
-
return msg;
|
|
32116
|
-
}
|
|
32117
|
-
const goodGridStep = ___default["default"].every(gridStep, function (gridStep, i) {
|
|
32118
|
-
msg = self.validGridStep(gridStep, range[i]);
|
|
32119
|
-
return msg === true;
|
|
32120
|
-
});
|
|
32121
|
-
if (!goodGridStep) {
|
|
32122
|
-
return msg;
|
|
32123
|
-
}
|
|
32124
|
-
const goodSnapStep = ___default["default"].every(snapStep, function (snapStep, i) {
|
|
32125
|
-
msg = self.validSnapStep(snapStep, range[i]);
|
|
32126
|
-
return msg === true;
|
|
32127
|
-
});
|
|
32128
|
-
if (!goodSnapStep) {
|
|
32129
|
-
return msg;
|
|
32106
|
+
case "line":
|
|
32107
|
+
return {
|
|
32108
|
+
type: "line",
|
|
32109
|
+
kind: "line",
|
|
32110
|
+
points: [getDefaultFigureForType("point"), {
|
|
32111
|
+
...getDefaultFigureForType("point"),
|
|
32112
|
+
coord: [2, 2]
|
|
32113
|
+
}],
|
|
32114
|
+
color: DEFAULT_COLOR,
|
|
32115
|
+
lineStyle: "solid",
|
|
32116
|
+
showPoint1: false,
|
|
32117
|
+
showPoint2: false
|
|
32118
|
+
};
|
|
32119
|
+
case "vector":
|
|
32120
|
+
return {
|
|
32121
|
+
type: "vector",
|
|
32122
|
+
points: [[0, 0], [2, 2]],
|
|
32123
|
+
color: DEFAULT_COLOR
|
|
32124
|
+
};
|
|
32125
|
+
case "ellipse":
|
|
32126
|
+
return {
|
|
32127
|
+
type: "ellipse",
|
|
32128
|
+
center: [0, 0],
|
|
32129
|
+
radius: [1, 1],
|
|
32130
|
+
angle: 0,
|
|
32131
|
+
color: DEFAULT_COLOR,
|
|
32132
|
+
fillStyle: "none",
|
|
32133
|
+
strokeStyle: "solid"
|
|
32134
|
+
};
|
|
32135
|
+
case "polygon":
|
|
32136
|
+
return {
|
|
32137
|
+
type: "polygon",
|
|
32138
|
+
points: [[0, 2], [-1, 0], [1, 0]],
|
|
32139
|
+
color: DEFAULT_COLOR,
|
|
32140
|
+
showVertices: false,
|
|
32141
|
+
fillStyle: "none",
|
|
32142
|
+
strokeStyle: "solid"
|
|
32143
|
+
};
|
|
32144
|
+
case "function":
|
|
32145
|
+
return {
|
|
32146
|
+
type: "function",
|
|
32147
|
+
color: DEFAULT_COLOR,
|
|
32148
|
+
strokeStyle: "solid",
|
|
32149
|
+
equation: "x^2",
|
|
32150
|
+
directionalAxis: "x"
|
|
32151
|
+
};
|
|
32152
|
+
case "label":
|
|
32153
|
+
return {
|
|
32154
|
+
type: "label",
|
|
32155
|
+
coord: [0, 0],
|
|
32156
|
+
text: "",
|
|
32157
|
+
color: DEFAULT_COLOR,
|
|
32158
|
+
size: "medium"
|
|
32159
|
+
};
|
|
32160
|
+
default:
|
|
32161
|
+
throw new wonderStuffCore.UnreachableCaseError(type);
|
|
32162
|
+
}
|
|
32163
|
+
}
|
|
32164
|
+
|
|
32165
|
+
const LockedFiguresSection = props => {
|
|
32166
|
+
// Keep track of all figures' accordions' expanded states for the
|
|
32167
|
+
// expand/collapse all button. Set the whole array to false initially.
|
|
32168
|
+
const collapsedStateArray = Array((props.figures ?? []).length).fill(false);
|
|
32169
|
+
const [expandedStates, setExpandedStates] = React__namespace.useState(collapsedStateArray);
|
|
32170
|
+
const [isExpanded, setIsExpanded] = React__namespace.useState(true);
|
|
32171
|
+
const uniqueId = wonderBlocksCore.useUniqueIdWithMock().get("locked-figures-section");
|
|
32172
|
+
const {
|
|
32173
|
+
figures,
|
|
32174
|
+
onChange
|
|
32175
|
+
} = props;
|
|
32176
|
+
function addLockedFigure(newFigure) {
|
|
32177
|
+
const lockedFigures = figures || [];
|
|
32178
|
+
const newProps = {
|
|
32179
|
+
lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
|
|
32180
|
+
};
|
|
32181
|
+
onChange(newProps);
|
|
32182
|
+
setExpandedStates([...expandedStates, true]);
|
|
32183
|
+
}
|
|
32184
|
+
function moveLockedFigure(index, movement) {
|
|
32185
|
+
// Don't allow moving the first figure up or the last figure down.
|
|
32186
|
+
if (index === 0 && (movement === "back" || movement === "backward")) {
|
|
32187
|
+
return;
|
|
32130
32188
|
}
|
|
32131
|
-
|
|
32132
|
-
|
|
32133
|
-
msg = goodImageSize;
|
|
32134
|
-
return msg;
|
|
32189
|
+
if (figures && index === figures.length - 1 && (movement === "front" || movement === "forward")) {
|
|
32190
|
+
return;
|
|
32135
32191
|
}
|
|
32136
|
-
|
|
32137
|
-
|
|
32138
|
-
|
|
32139
|
-
|
|
32140
|
-
|
|
32141
|
-
|
|
32142
|
-
|
|
32143
|
-
|
|
32144
|
-
|
|
32145
|
-
|
|
32146
|
-
|
|
32147
|
-
|
|
32148
|
-
|
|
32149
|
-
|
|
32150
|
-
|
|
32151
|
-
|
|
32152
|
-
|
|
32153
|
-
|
|
32154
|
-
|
|
32155
|
-
|
|
32156
|
-
|
|
32157
|
-
|
|
32158
|
-
|
|
32159
|
-
|
|
32192
|
+
const lockedFigures = figures || [];
|
|
32193
|
+
const newFigures = [...lockedFigures];
|
|
32194
|
+
const newExpandedStates = [...expandedStates];
|
|
32195
|
+
|
|
32196
|
+
// First, remove the figure from its current position
|
|
32197
|
+
// in the figures array and the expanded states array.
|
|
32198
|
+
const [removedFigure] = newFigures.splice(index, 1);
|
|
32199
|
+
newExpandedStates.splice(index, 1);
|
|
32200
|
+
|
|
32201
|
+
// Then, add it back in the new position. Add "true" to the
|
|
32202
|
+
// expanded states array for the new position (it must already
|
|
32203
|
+
// be open since the button to move it is being pressed from there).
|
|
32204
|
+
switch (movement) {
|
|
32205
|
+
case "back":
|
|
32206
|
+
newFigures.unshift(removedFigure);
|
|
32207
|
+
newExpandedStates.unshift(true);
|
|
32208
|
+
break;
|
|
32209
|
+
case "backward":
|
|
32210
|
+
newFigures.splice(index - 1, 0, removedFigure);
|
|
32211
|
+
newExpandedStates.splice(index - 1, 0, true);
|
|
32212
|
+
break;
|
|
32213
|
+
case "forward":
|
|
32214
|
+
newFigures.splice(index + 1, 0, removedFigure);
|
|
32215
|
+
newExpandedStates.splice(index + 1, 0, true);
|
|
32216
|
+
break;
|
|
32217
|
+
case "front":
|
|
32218
|
+
newFigures.push(removedFigure);
|
|
32219
|
+
newExpandedStates.push(true);
|
|
32220
|
+
break;
|
|
32160
32221
|
}
|
|
32161
|
-
|
|
32162
|
-
|
|
32163
|
-
gridStepTextbox: gridStep,
|
|
32164
|
-
snapStepTextbox: snapStep,
|
|
32165
|
-
rangeTextbox: ranges
|
|
32166
|
-
}, this.changeGraph);
|
|
32167
|
-
};
|
|
32168
|
-
changeStep = step => {
|
|
32169
|
-
this.setState({
|
|
32170
|
-
stepTextbox: step
|
|
32171
|
-
}, this.changeGraph);
|
|
32172
|
-
};
|
|
32173
|
-
changeSnapStep = snapStep => {
|
|
32174
|
-
this.setState({
|
|
32175
|
-
snapStepTextbox: snapStep
|
|
32176
|
-
}, this.changeGraph);
|
|
32177
|
-
};
|
|
32178
|
-
changeGridStep = gridStep => {
|
|
32179
|
-
this.setState({
|
|
32180
|
-
gridStepTextbox: gridStep,
|
|
32181
|
-
snapStepTextbox: ___default["default"].map(gridStep, function (step) {
|
|
32182
|
-
return step / 2;
|
|
32183
|
-
})
|
|
32184
|
-
}, this.changeGraph);
|
|
32185
|
-
};
|
|
32186
|
-
changeGraph = () => {
|
|
32187
|
-
const labels = this.state.labelsTextbox;
|
|
32188
|
-
const range = ___default["default"].map(this.state.rangeTextbox, function (range) {
|
|
32189
|
-
return ___default["default"].map(range, Number);
|
|
32222
|
+
onChange({
|
|
32223
|
+
lockedFigures: newFigures
|
|
32190
32224
|
});
|
|
32191
|
-
|
|
32192
|
-
|
|
32193
|
-
|
|
32194
|
-
|
|
32195
|
-
|
|
32196
|
-
|
|
32197
|
-
|
|
32198
|
-
|
|
32199
|
-
// is contained in the string
|
|
32200
|
-
// TODO(aria): Refactor this to not be confusing
|
|
32201
|
-
const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
|
|
32202
|
-
if (validationResult === true) {
|
|
32203
|
-
// either true or a string
|
|
32204
|
-
this.change({
|
|
32205
|
-
valid: true,
|
|
32206
|
-
labels: labels,
|
|
32207
|
-
range: range,
|
|
32208
|
-
step: step,
|
|
32209
|
-
gridStep: gridStep,
|
|
32210
|
-
snapStep: snapStep,
|
|
32211
|
-
backgroundImage: image
|
|
32212
|
-
});
|
|
32213
|
-
} else {
|
|
32214
|
-
this.change({
|
|
32215
|
-
valid: validationResult // a string message, not false
|
|
32225
|
+
setExpandedStates(newExpandedStates);
|
|
32226
|
+
}
|
|
32227
|
+
function removeLockedFigure(index) {
|
|
32228
|
+
// eslint-disable-next-line no-alert
|
|
32229
|
+
if (window.confirm("Are you sure you want to delete this figure?")) {
|
|
32230
|
+
const lockedFigures = figures || [];
|
|
32231
|
+
onChange({
|
|
32232
|
+
lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
|
|
32216
32233
|
});
|
|
32217
|
-
}
|
|
32218
|
-
};
|
|
32219
32234
|
|
|
32220
|
-
|
|
32221
|
-
|
|
32222
|
-
|
|
32223
|
-
|
|
32224
|
-
|
|
32225
|
-
onToggle: () => this.setState({
|
|
32226
|
-
isExpanded: !this.state.isExpanded
|
|
32227
|
-
})
|
|
32228
|
-
}), this.state.isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement("div", {
|
|
32229
|
-
className: "graph-settings"
|
|
32230
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
32231
|
-
className: "perseus-widget-row"
|
|
32232
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
32233
|
-
className: "perseus-widget-left-col"
|
|
32234
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32235
|
-
label: "x Label"
|
|
32236
|
-
}, /*#__PURE__*/React__namespace.createElement("input", {
|
|
32237
|
-
type: "text",
|
|
32238
|
-
className: "graph-settings-axis-label",
|
|
32239
|
-
ref: this.labelXRef,
|
|
32240
|
-
onChange: e => this.changeLabel(0, e),
|
|
32241
|
-
value: this.state.labelsTextbox[0] || ""
|
|
32242
|
-
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32243
|
-
className: "perseus-widget-right-col"
|
|
32244
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32245
|
-
label: "y Label"
|
|
32246
|
-
}, /*#__PURE__*/React__namespace.createElement("input", {
|
|
32247
|
-
type: "text",
|
|
32248
|
-
className: "graph-settings-axis-label",
|
|
32249
|
-
ref: this.labelYRef,
|
|
32250
|
-
onChange: e => this.changeLabel(1, e),
|
|
32251
|
-
value: this.state.labelsTextbox[1] || ""
|
|
32252
|
-
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32253
|
-
className: "perseus-widget-row"
|
|
32254
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
32255
|
-
className: "perseus-widget-left-col"
|
|
32256
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32257
|
-
label: "x Range"
|
|
32258
|
-
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
32259
|
-
value: this.state.rangeTextbox[0],
|
|
32260
|
-
onChange: vals => this.changeRange(0, vals)
|
|
32261
|
-
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32262
|
-
className: "perseus-widget-right-col"
|
|
32263
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32264
|
-
label: "y Range"
|
|
32265
|
-
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
32266
|
-
value: this.state.rangeTextbox[1],
|
|
32267
|
-
onChange: vals => this.changeRange(1, vals)
|
|
32268
|
-
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32269
|
-
className: "perseus-widget-row"
|
|
32270
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
32271
|
-
className: "perseus-widget-left-col"
|
|
32272
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32273
|
-
label: "Tick Step"
|
|
32274
|
-
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
32275
|
-
value: this.state.stepTextbox,
|
|
32276
|
-
onChange: this.changeStep
|
|
32277
|
-
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32278
|
-
className: "perseus-widget-right-col"
|
|
32279
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32280
|
-
label: "Grid Step"
|
|
32281
|
-
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
32282
|
-
value: this.state.gridStepTextbox,
|
|
32283
|
-
onChange: this.changeGridStep
|
|
32284
|
-
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32285
|
-
className: "perseus-widget-row"
|
|
32286
|
-
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
32287
|
-
className: "perseus-widget-left-col"
|
|
32288
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32289
|
-
label: "Snap Step"
|
|
32290
|
-
}, /*#__PURE__*/React__namespace.createElement(RangeInput$4, {
|
|
32291
|
-
value: this.state.snapStepTextbox,
|
|
32292
|
-
onChange: this.changeSnapStep
|
|
32293
|
-
})))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32294
|
-
className: "perseus-widget-row"
|
|
32295
|
-
}, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32296
|
-
label: "Markings:"
|
|
32297
|
-
}, /*#__PURE__*/React__namespace.createElement(ButtonGroup$2, {
|
|
32298
|
-
value: this.props.markings,
|
|
32299
|
-
allowEmpty: false,
|
|
32300
|
-
buttons: [{
|
|
32301
|
-
value: "graph",
|
|
32302
|
-
content: "Graph"
|
|
32303
|
-
}, {
|
|
32304
|
-
value: "grid",
|
|
32305
|
-
content: "Grid"
|
|
32306
|
-
}, {
|
|
32307
|
-
value: "none",
|
|
32308
|
-
content: "None"
|
|
32309
|
-
}],
|
|
32310
|
-
onChange: this.change("markings")
|
|
32311
|
-
}))), /*#__PURE__*/React__namespace.createElement("div", {
|
|
32312
|
-
className: "perseus-widget-left-col"
|
|
32313
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
|
|
32314
|
-
label: "Show tooltips",
|
|
32315
|
-
checked: this.props.showTooltips,
|
|
32316
|
-
onChange: value => {
|
|
32317
|
-
this.change({
|
|
32318
|
-
showTooltips: value
|
|
32319
|
-
});
|
|
32320
|
-
}
|
|
32321
|
-
}))), /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
32322
|
-
label: "Background image URL:",
|
|
32323
|
-
style: styles$j.resetSpaceTop
|
|
32324
|
-
}, /*#__PURE__*/React__namespace.createElement("input", {
|
|
32325
|
-
type: "text",
|
|
32326
|
-
className: aphrodite.css(styles$j.backgroundUrlInput),
|
|
32327
|
-
ref: this.bgUrlRef,
|
|
32328
|
-
value: this.state.backgroundImage.url || "",
|
|
32329
|
-
onChange: e => {
|
|
32330
|
-
// Shallow-copied clone
|
|
32331
|
-
const image = {
|
|
32332
|
-
...this.props.backgroundImage
|
|
32333
|
-
};
|
|
32334
|
-
image.url = e.target.value;
|
|
32335
|
-
this.setState({
|
|
32336
|
-
backgroundImage: image
|
|
32337
|
-
});
|
|
32338
|
-
},
|
|
32339
|
-
onKeyPress: this.changeBackgroundUrl,
|
|
32340
|
-
onBlur: this.changeBackgroundUrl
|
|
32341
|
-
}), /*#__PURE__*/React__namespace.createElement(InfoTip$c, null, /*#__PURE__*/React__namespace.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32342
|
-
style: styles$j.protractorSection
|
|
32343
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32344
|
-
style: styles$j.checkboxRow
|
|
32345
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksForm.Checkbox, {
|
|
32346
|
-
label: "Show protractor",
|
|
32347
|
-
checked: this.props.showProtractor,
|
|
32348
|
-
onChange: value => {
|
|
32349
|
-
this.change({
|
|
32350
|
-
showProtractor: value
|
|
32351
|
-
});
|
|
32352
|
-
},
|
|
32353
|
-
style: styles$j.resetSpaceTop
|
|
32354
|
-
})), this.props.showProtractor && /*#__PURE__*/React__namespace.createElement(Banner__default["default"], {
|
|
32355
|
-
layout: "floating",
|
|
32356
|
-
text: "The protractor is not accessible. Please consider an alternate approach.",
|
|
32357
|
-
kind: "warning"
|
|
32358
|
-
}))));
|
|
32235
|
+
// Update expanded states
|
|
32236
|
+
const newExpandedStates = [...expandedStates];
|
|
32237
|
+
newExpandedStates.splice(index, 1);
|
|
32238
|
+
setExpandedStates(newExpandedStates);
|
|
32239
|
+
}
|
|
32359
32240
|
}
|
|
32360
|
-
|
|
32361
|
-
|
|
32362
|
-
|
|
32363
|
-
|
|
32364
|
-
|
|
32365
|
-
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
|
|
32370
|
-
|
|
32241
|
+
function changeProps(index,
|
|
32242
|
+
// Omit the type from the figure props so it doesn't think
|
|
32243
|
+
// we're trying to pass in the props for the wrong type.
|
|
32244
|
+
figureProps) {
|
|
32245
|
+
const lockedFigures = figures || [];
|
|
32246
|
+
const newFigures = {
|
|
32247
|
+
lockedFigures: [...lockedFigures.slice(0, index), {
|
|
32248
|
+
...lockedFigures[index],
|
|
32249
|
+
...figureProps
|
|
32250
|
+
}, ...lockedFigures.slice(index + 1)]
|
|
32251
|
+
};
|
|
32252
|
+
onChange(newFigures);
|
|
32253
|
+
}
|
|
32254
|
+
function toggleExpanded(newValue) {
|
|
32255
|
+
setExpandedStates(Array(figures?.length).fill(newValue));
|
|
32256
|
+
}
|
|
32257
|
+
const allCollapsed = expandedStates.every(value => !value);
|
|
32258
|
+
const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
|
|
32259
|
+
const showExpandButton = !!figures?.length;
|
|
32260
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Heading, {
|
|
32261
|
+
title: "Locked Figures",
|
|
32262
|
+
isOpen: isExpanded,
|
|
32263
|
+
onToggle: () => setIsExpanded(!isExpanded),
|
|
32264
|
+
isCollapsible: true
|
|
32265
|
+
}), isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, figures?.map((figure, index) => {
|
|
32266
|
+
return /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
|
|
32267
|
+
key: `${uniqueId}-locked-${figure}-${index}`,
|
|
32268
|
+
showLabelsFlag: props.showLabelsFlag,
|
|
32269
|
+
expanded: expandedStates[index],
|
|
32270
|
+
onToggle: newValue => {
|
|
32271
|
+
const newExpanded = [...expandedStates];
|
|
32272
|
+
newExpanded[index] = newValue;
|
|
32273
|
+
setExpandedStates(newExpanded);
|
|
32274
|
+
}
|
|
32275
|
+
}, figure, {
|
|
32276
|
+
onChangeProps: newProps => changeProps(index, newProps),
|
|
32277
|
+
onMove: movement => moveLockedFigure(index, movement),
|
|
32278
|
+
onRemove: () => removeLockedFigure(index)
|
|
32279
|
+
}));
|
|
32280
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32281
|
+
style: styles$i.buttonContainer
|
|
32282
|
+
}, /*#__PURE__*/React__namespace.createElement(LockedFigureSelect, {
|
|
32283
|
+
showLabelsFlag: props.showLabelsFlag,
|
|
32284
|
+
id: `${uniqueId}-select`,
|
|
32285
|
+
onChange: addLockedFigure
|
|
32286
|
+
}), /*#__PURE__*/React__namespace.createElement(Strut, {
|
|
32287
|
+
size: wonderBlocksTokens.spacing.small_12
|
|
32288
|
+
}), showExpandButton && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
32289
|
+
kind: "secondary",
|
|
32290
|
+
onClick: () => toggleExpanded(allCollapsed),
|
|
32291
|
+
style: styles$i.button
|
|
32292
|
+
}, buttonLabel))));
|
|
32293
|
+
};
|
|
32294
|
+
const styles$i = aphrodite.StyleSheet.create({
|
|
32295
|
+
buttonContainer: {
|
|
32371
32296
|
flexDirection: "row",
|
|
32372
|
-
alignItems: "center"
|
|
32373
|
-
justifyContent: "space-between",
|
|
32374
|
-
marginBottom: wonderBlocksTokens.spacing.xSmall_8
|
|
32297
|
+
alignItems: "center"
|
|
32375
32298
|
},
|
|
32376
|
-
|
|
32299
|
+
button: {
|
|
32377
32300
|
marginTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
32378
|
-
|
|
32379
|
-
paddingTop: wonderBlocksTokens.spacing.xSmall_8,
|
|
32380
|
-
paddingBottom: wonderBlocksTokens.spacing.xSmall_8,
|
|
32381
|
-
borderBottom: `1px solid ${wonderBlocksTokens.color.offBlack16}`
|
|
32301
|
+
flexGrow: 1
|
|
32382
32302
|
}
|
|
32383
32303
|
});
|
|
32384
32304
|
|
|
32385
|
-
|
|
32386
|
-
|
|
32387
|
-
|
|
32388
|
-
|
|
32389
|
-
|
|
32390
|
-
|
|
32391
|
-
|
|
32392
|
-
|
|
32393
|
-
|
|
32394
|
-
|
|
32395
|
-
|
|
32396
|
-
|
|
32397
|
-
|
|
32398
|
-
|
|
32399
|
-
|
|
32400
|
-
|
|
32401
|
-
|
|
32402
|
-
|
|
32403
|
-
|
|
32404
|
-
|
|
32405
|
-
|
|
32305
|
+
function getStartCoords(graph) {
|
|
32306
|
+
if ("startCoords" in graph) {
|
|
32307
|
+
return graph.startCoords;
|
|
32308
|
+
}
|
|
32309
|
+
return undefined;
|
|
32310
|
+
}
|
|
32311
|
+
function getDefaultGraphStartCoords(graph, range, step) {
|
|
32312
|
+
switch (graph.type) {
|
|
32313
|
+
case "linear":
|
|
32314
|
+
case "ray":
|
|
32315
|
+
return perseus.getLineCoords({
|
|
32316
|
+
...graph,
|
|
32317
|
+
startCoords: undefined
|
|
32318
|
+
}, range, step);
|
|
32319
|
+
case "segment":
|
|
32320
|
+
return perseus.getSegmentCoords({
|
|
32321
|
+
...graph,
|
|
32322
|
+
startCoords: undefined
|
|
32323
|
+
}, range, step);
|
|
32324
|
+
case "linear-system":
|
|
32325
|
+
return perseus.getLinearSystemCoords({
|
|
32326
|
+
...graph,
|
|
32327
|
+
startCoords: undefined
|
|
32328
|
+
}, range, step);
|
|
32329
|
+
case "circle":
|
|
32330
|
+
const startCoords = perseus.getCircleCoords({
|
|
32331
|
+
...graph,
|
|
32332
|
+
startCoords: undefined
|
|
32333
|
+
});
|
|
32334
|
+
const radius = kmath.vector.length(kmath.vector.subtract(startCoords.radiusPoint, startCoords.center));
|
|
32335
|
+
return {
|
|
32336
|
+
center: startCoords.center,
|
|
32337
|
+
radius
|
|
32338
|
+
};
|
|
32339
|
+
case "sinusoid":
|
|
32340
|
+
return perseus.getSinusoidCoords({
|
|
32341
|
+
...graph,
|
|
32342
|
+
startCoords: undefined
|
|
32343
|
+
}, range, step);
|
|
32344
|
+
case "quadratic":
|
|
32345
|
+
return perseus.getQuadraticCoords({
|
|
32346
|
+
...graph,
|
|
32347
|
+
startCoords: undefined
|
|
32348
|
+
}, range, step);
|
|
32349
|
+
case "point":
|
|
32350
|
+
return perseus.getPointCoords({
|
|
32351
|
+
...graph,
|
|
32352
|
+
startCoords: undefined
|
|
32353
|
+
}, range, step);
|
|
32354
|
+
case "polygon":
|
|
32355
|
+
return perseus.getPolygonCoords({
|
|
32356
|
+
...graph,
|
|
32357
|
+
startCoords: undefined
|
|
32358
|
+
}, range, step);
|
|
32359
|
+
case "angle":
|
|
32360
|
+
return perseus.getAngleCoords({
|
|
32361
|
+
graph: {
|
|
32362
|
+
...graph,
|
|
32363
|
+
startCoords: undefined
|
|
32364
|
+
},
|
|
32365
|
+
range,
|
|
32366
|
+
step
|
|
32367
|
+
});
|
|
32368
|
+
default:
|
|
32369
|
+
return undefined;
|
|
32370
|
+
}
|
|
32371
|
+
}
|
|
32372
|
+
const getSinusoidEquation = startCoords => {
|
|
32373
|
+
// Get coefficients
|
|
32374
|
+
// It's assumed that p1 is the root and p2 is the first peak
|
|
32375
|
+
const p1 = startCoords[0];
|
|
32376
|
+
const p2 = startCoords[1];
|
|
32377
|
+
|
|
32378
|
+
// Resulting coefficients are canonical for this sine curve
|
|
32379
|
+
const amplitude = p2[1] - p1[1];
|
|
32380
|
+
const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
|
|
32381
|
+
const phase = p1[0] * angularFrequency;
|
|
32382
|
+
const verticalOffset = p1[1];
|
|
32383
|
+
return "y = " + amplitude.toFixed(3) + "sin(" + angularFrequency.toFixed(3) + "x - " + phase.toFixed(3) + ") + " + verticalOffset.toFixed(3);
|
|
32406
32384
|
};
|
|
32407
|
-
const
|
|
32408
|
-
|
|
32409
|
-
|
|
32410
|
-
|
|
32411
|
-
|
|
32385
|
+
const getQuadraticEquation = startCoords => {
|
|
32386
|
+
const p1 = startCoords[0];
|
|
32387
|
+
const p2 = startCoords[1];
|
|
32388
|
+
const p3 = startCoords[2];
|
|
32389
|
+
const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
|
|
32390
|
+
if (denom === 0) {
|
|
32391
|
+
// Many of the callers assume that the return value is always defined.
|
|
32392
|
+
return "Division by zero error";
|
|
32412
32393
|
}
|
|
32413
|
-
|
|
32394
|
+
const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
|
|
32395
|
+
const b = (p3[0] * p3[0] * (p1[1] - p2[1]) + p2[0] * p2[0] * (p3[1] - p1[1]) + p1[0] * p1[0] * (p2[1] - p3[1])) / denom;
|
|
32396
|
+
const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
|
|
32397
|
+
return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
|
|
32398
|
+
};
|
|
32399
|
+
const findAngle = (point1, point2) => {
|
|
32400
|
+
const x = point1[0] - point2[0];
|
|
32401
|
+
const y = point1[1] - point2[1];
|
|
32402
|
+
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
32403
|
+
};
|
|
32404
|
+
const getAngleEquation = startCoords => {
|
|
32405
|
+
const [point1, vertex, point2] = startCoords;
|
|
32406
|
+
const angle = findAngle(point2, vertex) - findAngle(point1, vertex);
|
|
32407
|
+
const roundedAngle = angle.toFixed(0);
|
|
32408
|
+
return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`;
|
|
32409
|
+
};
|
|
32410
|
+
const shouldShowStartCoordsUI = (graph, isStatic) => {
|
|
32411
|
+
// We don't show the start coords UI for static graphs, since
|
|
32412
|
+
// the coords shown for this are determined by the coords on the
|
|
32413
|
+
// "correct" graph. The start coords would not be used here.
|
|
32414
|
+
if (isStatic) {
|
|
32415
|
+
return false;
|
|
32416
|
+
}
|
|
32417
|
+
switch (graph.type) {
|
|
32418
|
+
case "point":
|
|
32419
|
+
return graph.numPoints !== "unlimited";
|
|
32420
|
+
case "polygon":
|
|
32421
|
+
return graph.numSides !== "unlimited" && graph.snapTo !== "angles" && graph.snapTo !== "sides";
|
|
32422
|
+
case "none":
|
|
32423
|
+
return false;
|
|
32424
|
+
case "angle":
|
|
32425
|
+
case "circle":
|
|
32426
|
+
case "linear":
|
|
32427
|
+
case "linear-system":
|
|
32428
|
+
case "quadratic":
|
|
32429
|
+
case "ray":
|
|
32430
|
+
case "segment":
|
|
32431
|
+
case "sinusoid":
|
|
32432
|
+
return true;
|
|
32433
|
+
default:
|
|
32434
|
+
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
32435
|
+
}
|
|
32436
|
+
};
|
|
32414
32437
|
|
|
32415
32438
|
const StartCoordsAngle = props => {
|
|
32416
32439
|
const {
|
|
@@ -32922,7 +32945,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
|
|
|
32922
32945
|
___default["default"].extend(json, {
|
|
32923
32946
|
graph: {
|
|
32924
32947
|
type: correct.type,
|
|
32925
|
-
startCoords: this.props.graph
|
|
32948
|
+
startCoords: this.props.graph && getStartCoords(this.props.graph)
|
|
32926
32949
|
},
|
|
32927
32950
|
correct: correct
|
|
32928
32951
|
});
|
|
@@ -33017,7 +33040,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
|
|
|
33017
33040
|
}, this.props.valid);
|
|
33018
33041
|
}
|
|
33019
33042
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(LabeledRow, {
|
|
33020
|
-
label: "
|
|
33043
|
+
label: "Answer type:"
|
|
33021
33044
|
}, /*#__PURE__*/React__namespace.createElement(GraphTypeSelector, {
|
|
33022
33045
|
graphType: this.props.graph?.type ?? InteractiveGraph.defaultProps.graph.type,
|
|
33023
33046
|
onChange: type => {
|
|
@@ -33029,7 +33052,8 @@ class InteractiveGraphEditor extends React__namespace.Component {
|
|
|
33029
33052
|
type
|
|
33030
33053
|
}
|
|
33031
33054
|
});
|
|
33032
|
-
}
|
|
33055
|
+
},
|
|
33056
|
+
showNoneOption: this.props.apiOptions?.flags?.mafs?.["none"]
|
|
33033
33057
|
})), this.props.graph && this.props.apiOptions?.flags?.mafs?.[this.props.graph.type] && /*#__PURE__*/React__namespace.createElement(InteractiveGraphDescription, {
|
|
33034
33058
|
ariaLabelValue: this.props.fullGraphAriaLabel ?? "",
|
|
33035
33059
|
ariaDescriptionValue: this.props.fullGraphAriaDescription ?? "",
|
|
@@ -33305,6 +33329,12 @@ function mergeGraphs(a, b) {
|
|
|
33305
33329
|
...a,
|
|
33306
33330
|
...b
|
|
33307
33331
|
};
|
|
33332
|
+
case "none":
|
|
33333
|
+
invariant(b.type === "none");
|
|
33334
|
+
return {
|
|
33335
|
+
...a,
|
|
33336
|
+
...b
|
|
33337
|
+
};
|
|
33308
33338
|
case "point":
|
|
33309
33339
|
invariant(b.type === "point");
|
|
33310
33340
|
return {
|