@khanacademy/perseus-editor 14.1.3 → 14.3.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 +1542 -1450
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +1375 -1274
- 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 +281 -128
- package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-settings-actions.d.ts +1 -1
- package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figure-settings.d.ts +2 -0
- package/dist/{components/graph-locked-figures → widgets/interactive-graph-editor/locked-figures}/locked-figures-section.d.ts +3 -2
- package/dist/widgets/interactive-graph-editor/locked-figures/locked-label-settings.d.ts +35 -0
- 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/graph-locked-figures/locked-label-settings.d.ts +0 -17
- 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-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-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/es/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { addLibraryVersionToPerseusDebug, PerseusError, Errors } from '@khanacademy/perseus-core';
|
|
2
|
-
import { constants, components, Widgets, icons, WIDGET_PROP_DENYLIST, Util, Log, PerseusMarkdown, preprocessTex, ApiOptions, buildMapper, itemToTree, buildEmptyItemTreeForShape, shapes, ItemExtras, itemDataVersion, ClassNames, MultiItems, traverse, Categorizer as Categorizer$1, Changeable, EditorJsonify, Dependencies, PerseusExpressionAnswerFormConsidered, Expression, interactiveSizes, KhanMath, GrapherWidget, GrapherUtil, SizingUtils, PerseusI18nContext, KhanColors, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords,
|
|
2
|
+
import { constants, components, Widgets, icons, WIDGET_PROP_DENYLIST, Util, Log, PerseusMarkdown, preprocessTex, ApiOptions, buildMapper, itemToTree, buildEmptyItemTreeForShape, shapes, ItemExtras, itemDataVersion, ClassNames, MultiItems, traverse, Categorizer as Categorizer$1, Changeable, EditorJsonify, Dependencies, PerseusExpressionAnswerFormConsidered, Expression, interactiveSizes, KhanMath, GrapherWidget, GrapherUtil, SizingUtils, PerseusI18nContext, KhanColors, lockedFigureColors, lockedFigureFillStyles, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords, InteractiveGraphWidget, globalStyles, globalConstants, MatrixWidget, makeSafeUrl, PlotterWidget, plotterPlotTypes, BaseRadio, TableWidget, widgets } from '@khanacademy/perseus';
|
|
3
3
|
export { widgets } from '@khanacademy/perseus';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { useRef, useEffect, useState, useId } from 'react';
|
|
@@ -19,11 +19,12 @@ import { Checkbox as Checkbox$1, LabeledTextField, TextField, TextArea } from '@
|
|
|
19
19
|
import ReactDOM from 'react-dom';
|
|
20
20
|
import * as KAS from '@khanacademy/kas';
|
|
21
21
|
import Button from '@khanacademy/wonder-blocks-button';
|
|
22
|
-
import { HeadingSmall, HeadingXSmall,
|
|
22
|
+
import { HeadingSmall, HeadingXSmall, LabelLarge, LabelXSmall, BodyMonospace, LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
23
23
|
import { isTruthy, UnreachableCaseError } from '@khanacademy/wonder-stuff-core';
|
|
24
24
|
import { useMathInputI18n, createMathField } from '@khanacademy/math-input';
|
|
25
25
|
import { vector, number } from '@khanacademy/kmath';
|
|
26
|
-
import {
|
|
26
|
+
import { SingleSelect, OptionItem, ActionMenu, ActionItem } from '@khanacademy/wonder-blocks-dropdown';
|
|
27
|
+
import Banner from '@khanacademy/wonder-blocks-banner';
|
|
27
28
|
import { AccordionSection } from '@khanacademy/wonder-blocks-accordion';
|
|
28
29
|
import IconButton from '@khanacademy/wonder-blocks-icon-button';
|
|
29
30
|
import caretDoubleDownIcon from '@phosphor-icons/core/bold/caret-double-down-bold.svg';
|
|
@@ -33,18 +34,17 @@ import caretUpIcon from '@phosphor-icons/core/bold/caret-up-bold.svg';
|
|
|
33
34
|
import trashIcon from '@phosphor-icons/core/bold/trash-bold.svg';
|
|
34
35
|
import copyIcon from '@phosphor-icons/core/assets/regular/copy.svg';
|
|
35
36
|
import autoPasteIcon from '@phosphor-icons/core/assets/regular/note-pencil.svg';
|
|
37
|
+
import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
|
|
36
38
|
import arrowFatDown from '@phosphor-icons/core/regular/arrow-fat-down.svg';
|
|
37
39
|
import arrowFatLeft from '@phosphor-icons/core/regular/arrow-fat-left.svg';
|
|
38
40
|
import arrowFatRight from '@phosphor-icons/core/regular/arrow-fat-right.svg';
|
|
39
41
|
import arrowFatUp from '@phosphor-icons/core/regular/arrow-fat-up.svg';
|
|
40
42
|
import minusCircle from '@phosphor-icons/core/regular/minus-circle.svg';
|
|
41
|
-
import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
|
|
42
|
-
import Banner from '@khanacademy/wonder-blocks-banner';
|
|
43
43
|
import arrowCounterClockwise from '@phosphor-icons/core/bold/arrow-counter-clockwise-bold.svg';
|
|
44
44
|
|
|
45
45
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
46
46
|
const libName = "@khanacademy/perseus-editor";
|
|
47
|
-
const libVersion = "14.
|
|
47
|
+
const libVersion = "14.3.0";
|
|
48
48
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
49
49
|
|
|
50
50
|
function _extends() {
|
|
@@ -29496,39 +29496,95 @@ function invariant(condition, message) {
|
|
|
29496
29496
|
throw new Error(value);
|
|
29497
29497
|
}
|
|
29498
29498
|
|
|
29499
|
-
|
|
29500
|
-
|
|
29501
|
-
|
|
29502
|
-
|
|
29503
|
-
|
|
29504
|
-
|
|
29505
|
-
|
|
29506
|
-
|
|
29507
|
-
|
|
29508
|
-
|
|
29509
|
-
|
|
29510
|
-
|
|
29511
|
-
|
|
29512
|
-
|
|
29513
|
-
|
|
29514
|
-
|
|
29515
|
-
|
|
29499
|
+
const UNLIMITED = "unlimited";
|
|
29500
|
+
// Parses a string (ostensibly from some UI element that only supports string
|
|
29501
|
+
// types, such as a <select />) into a numeric point count or the special sigil
|
|
29502
|
+
// "unlimited". Note that 0 is a special case, and means "unlimited".
|
|
29503
|
+
const parsePointCount = points => {
|
|
29504
|
+
const parsed = parseInt(points, 10);
|
|
29505
|
+
if (isNaN(parsed)) {
|
|
29506
|
+
return UNLIMITED;
|
|
29507
|
+
}
|
|
29508
|
+
return parsed === 0 ? UNLIMITED : parsed;
|
|
29509
|
+
};
|
|
29510
|
+
|
|
29511
|
+
const GraphPointsCountSelector = ({
|
|
29512
|
+
numPoints: _numPoints = 1,
|
|
29513
|
+
onChange
|
|
29514
|
+
}) => {
|
|
29515
|
+
return /*#__PURE__*/React.createElement(SingleSelect, {
|
|
29516
|
+
selectedValue: `${_numPoints}`,
|
|
29517
|
+
onChange: newValue => {
|
|
29518
|
+
onChange(parsePointCount(newValue));
|
|
29519
|
+
}
|
|
29520
|
+
// Never uses placeholder, always has value
|
|
29521
|
+
,
|
|
29522
|
+
placeholder: "",
|
|
29523
|
+
style: styles$J.singleSelectShort
|
|
29524
|
+
}, [...[...Array(7).keys()].map(n => /*#__PURE__*/React.createElement(OptionItem, {
|
|
29525
|
+
key: n,
|
|
29526
|
+
value: `${n}`,
|
|
29527
|
+
label: `${n} point${n > 1 ? "s" : ""}`
|
|
29528
|
+
})), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29529
|
+
key: "unlimited",
|
|
29530
|
+
value: UNLIMITED,
|
|
29531
|
+
label: "unlimited"
|
|
29532
|
+
})]);
|
|
29516
29533
|
};
|
|
29517
29534
|
const styles$J = StyleSheet.create({
|
|
29518
|
-
|
|
29519
|
-
|
|
29520
|
-
|
|
29521
|
-
|
|
29522
|
-
|
|
29523
|
-
|
|
29524
|
-
|
|
29525
|
-
|
|
29526
|
-
|
|
29527
|
-
|
|
29528
|
-
|
|
29529
|
-
|
|
29530
|
-
|
|
29531
|
-
|
|
29535
|
+
singleSelectShort: {
|
|
29536
|
+
// Non-standard spacing, but it's the smallest we can go
|
|
29537
|
+
// without running into styling issues with the dropdown.
|
|
29538
|
+
height: 26
|
|
29539
|
+
}
|
|
29540
|
+
});
|
|
29541
|
+
|
|
29542
|
+
const GraphTypeSelector = props => {
|
|
29543
|
+
return /*#__PURE__*/React.createElement(SingleSelect, {
|
|
29544
|
+
selectedValue: props.graphType,
|
|
29545
|
+
onChange: props.onChange,
|
|
29546
|
+
placeholder: "Select an answer type",
|
|
29547
|
+
style: styles$I.singleSelectShort
|
|
29548
|
+
}, props.showNoneOption && /*#__PURE__*/React.createElement(OptionItem, {
|
|
29549
|
+
value: "none",
|
|
29550
|
+
label: "None"
|
|
29551
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29552
|
+
value: "linear",
|
|
29553
|
+
label: "Linear function"
|
|
29554
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29555
|
+
value: "quadratic",
|
|
29556
|
+
label: "Quadratic function"
|
|
29557
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29558
|
+
value: "sinusoid",
|
|
29559
|
+
label: "Sinusoid function"
|
|
29560
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29561
|
+
value: "circle",
|
|
29562
|
+
label: "Circle"
|
|
29563
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29564
|
+
value: "point",
|
|
29565
|
+
label: "Point(s)"
|
|
29566
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29567
|
+
value: "linear-system",
|
|
29568
|
+
label: "Linear System"
|
|
29569
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29570
|
+
value: "polygon",
|
|
29571
|
+
label: "Polygon"
|
|
29572
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29573
|
+
value: "segment",
|
|
29574
|
+
label: "Line Segment(s)"
|
|
29575
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29576
|
+
value: "ray",
|
|
29577
|
+
label: "Ray"
|
|
29578
|
+
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
29579
|
+
value: "angle",
|
|
29580
|
+
label: "Angle"
|
|
29581
|
+
}));
|
|
29582
|
+
};
|
|
29583
|
+
const styles$I = StyleSheet.create({
|
|
29584
|
+
singleSelectShort: {
|
|
29585
|
+
// Non-standard spacing, but it's the smallest we can go
|
|
29586
|
+
// without running into styling issues with the dropdown.
|
|
29587
|
+
height: 26
|
|
29532
29588
|
}
|
|
29533
29589
|
});
|
|
29534
29590
|
|
|
@@ -29539,11 +29595,11 @@ function Heading({
|
|
|
29539
29595
|
onToggle
|
|
29540
29596
|
}) {
|
|
29541
29597
|
return /*#__PURE__*/React.createElement(Clickable, {
|
|
29542
|
-
style: [styles$
|
|
29598
|
+
style: [styles$H.container, !isCollapsible && styles$H.notClickable],
|
|
29543
29599
|
disabled: !isCollapsible,
|
|
29544
29600
|
onClick: () => isCollapsible && (onToggle == null ? void 0 : onToggle(!isOpen))
|
|
29545
29601
|
}, () => /*#__PURE__*/React.createElement(View, {
|
|
29546
|
-
style: styles$
|
|
29602
|
+
style: styles$H.heading
|
|
29547
29603
|
}, /*#__PURE__*/React.createElement(LabelLarge, {
|
|
29548
29604
|
style: {
|
|
29549
29605
|
fontSize: 14,
|
|
@@ -29553,7 +29609,7 @@ function Heading({
|
|
|
29553
29609
|
isExpanded: isOpen
|
|
29554
29610
|
})));
|
|
29555
29611
|
}
|
|
29556
|
-
const styles$
|
|
29612
|
+
const styles$H = StyleSheet.create({
|
|
29557
29613
|
container: {
|
|
29558
29614
|
marginTop: spacing.small_12,
|
|
29559
29615
|
// NOTE(jeremy): This is the inverse of the @editorPadding CSS
|
|
@@ -29577,349 +29633,759 @@ const styles$I = StyleSheet.create({
|
|
|
29577
29633
|
}
|
|
29578
29634
|
});
|
|
29579
29635
|
|
|
29580
|
-
function
|
|
29581
|
-
|
|
29582
|
-
|
|
29583
|
-
|
|
29584
|
-
|
|
29585
|
-
|
|
29586
|
-
|
|
29587
|
-
|
|
29588
|
-
|
|
29589
|
-
|
|
29590
|
-
|
|
29591
|
-
|
|
29592
|
-
|
|
29593
|
-
|
|
29594
|
-
|
|
29595
|
-
|
|
29596
|
-
|
|
29597
|
-
|
|
29598
|
-
|
|
29599
|
-
|
|
29600
|
-
|
|
29601
|
-
// `preventScroll` option otherwise.
|
|
29602
|
-
//
|
|
29603
|
-
// focusOptions documentation:
|
|
29604
|
-
//
|
|
29605
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
|
|
29606
|
-
//
|
|
29607
|
-
// Note that there could be cases where we want default focus() behavior.
|
|
29608
|
-
// One that comes to mind is a dropdown with a long list of options that
|
|
29609
|
-
// might be rendered off screen when opened. With this workaround the
|
|
29610
|
-
// selected option would not be scrolled into view if the option is near
|
|
29611
|
-
// the end of the list. We're not aware of any uses of the dropdown where
|
|
29612
|
-
// this is an issue, however, so there isn't currently a way to out of the
|
|
29613
|
-
// `preventScroll` behavior.
|
|
29614
|
-
|
|
29615
|
-
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
|
|
29616
|
-
element.focus({
|
|
29617
|
-
preventScroll: true
|
|
29618
|
-
});
|
|
29619
|
-
}
|
|
29620
|
-
const DEFAULT_COLOR = "grayH";
|
|
29621
|
-
function getDefaultFigureForType(type) {
|
|
29622
|
-
switch (type) {
|
|
29623
|
-
case "point":
|
|
29624
|
-
return {
|
|
29625
|
-
type: "point",
|
|
29626
|
-
coord: [0, 0],
|
|
29627
|
-
color: DEFAULT_COLOR,
|
|
29628
|
-
filled: true
|
|
29629
|
-
};
|
|
29630
|
-
case "line":
|
|
29631
|
-
return {
|
|
29632
|
-
type: "line",
|
|
29633
|
-
kind: "line",
|
|
29634
|
-
points: [getDefaultFigureForType("point"), _extends({}, getDefaultFigureForType("point"), {
|
|
29635
|
-
coord: [2, 2]
|
|
29636
|
-
})],
|
|
29637
|
-
color: DEFAULT_COLOR,
|
|
29638
|
-
lineStyle: "solid",
|
|
29639
|
-
showPoint1: false,
|
|
29640
|
-
showPoint2: false
|
|
29641
|
-
};
|
|
29642
|
-
case "vector":
|
|
29643
|
-
return {
|
|
29644
|
-
type: "vector",
|
|
29645
|
-
points: [[0, 0], [2, 2]],
|
|
29646
|
-
color: DEFAULT_COLOR
|
|
29647
|
-
};
|
|
29648
|
-
case "ellipse":
|
|
29649
|
-
return {
|
|
29650
|
-
type: "ellipse",
|
|
29651
|
-
center: [0, 0],
|
|
29652
|
-
radius: [1, 1],
|
|
29653
|
-
angle: 0,
|
|
29654
|
-
color: DEFAULT_COLOR,
|
|
29655
|
-
fillStyle: "none",
|
|
29656
|
-
strokeStyle: "solid"
|
|
29657
|
-
};
|
|
29658
|
-
case "polygon":
|
|
29659
|
-
return {
|
|
29660
|
-
type: "polygon",
|
|
29661
|
-
points: [[0, 2], [-1, 0], [1, 0]],
|
|
29662
|
-
color: DEFAULT_COLOR,
|
|
29663
|
-
showVertices: false,
|
|
29664
|
-
fillStyle: "none",
|
|
29665
|
-
strokeStyle: "solid"
|
|
29666
|
-
};
|
|
29667
|
-
case "function":
|
|
29668
|
-
return {
|
|
29669
|
-
type: "function",
|
|
29670
|
-
color: DEFAULT_COLOR,
|
|
29671
|
-
strokeStyle: "solid",
|
|
29672
|
-
equation: "x^2",
|
|
29673
|
-
directionalAxis: "x"
|
|
29674
|
-
};
|
|
29675
|
-
case "label":
|
|
29676
|
-
return {
|
|
29677
|
-
type: "label",
|
|
29678
|
-
coord: [0, 0],
|
|
29679
|
-
text: "",
|
|
29680
|
-
color: DEFAULT_COLOR,
|
|
29681
|
-
size: "medium"
|
|
29682
|
-
};
|
|
29683
|
-
default:
|
|
29684
|
-
throw new UnreachableCaseError(type);
|
|
29685
|
-
}
|
|
29686
|
-
}
|
|
29687
|
-
function degreeToRadian(degrees) {
|
|
29688
|
-
return degrees / 180 * Math.PI;
|
|
29689
|
-
}
|
|
29690
|
-
function radianToDegree(radians) {
|
|
29691
|
-
return radians / Math.PI * 180;
|
|
29692
|
-
}
|
|
29693
|
-
function getDefaultGraphStartCoords(graph, range, step) {
|
|
29694
|
-
switch (graph.type) {
|
|
29695
|
-
case "linear":
|
|
29696
|
-
case "ray":
|
|
29697
|
-
return getLineCoords(_extends({}, graph, {
|
|
29698
|
-
startCoords: undefined
|
|
29699
|
-
}), range, step);
|
|
29700
|
-
case "segment":
|
|
29701
|
-
return getSegmentCoords(_extends({}, graph, {
|
|
29702
|
-
startCoords: undefined
|
|
29703
|
-
}), range, step);
|
|
29704
|
-
case "linear-system":
|
|
29705
|
-
return getLinearSystemCoords(_extends({}, graph, {
|
|
29706
|
-
startCoords: undefined
|
|
29707
|
-
}), range, step);
|
|
29708
|
-
case "circle":
|
|
29709
|
-
const startCoords = getCircleCoords(_extends({}, graph, {
|
|
29710
|
-
startCoords: undefined
|
|
29711
|
-
}));
|
|
29712
|
-
const radius = vector.length(vector.subtract(startCoords.radiusPoint, startCoords.center));
|
|
29713
|
-
return {
|
|
29714
|
-
center: startCoords.center,
|
|
29715
|
-
radius
|
|
29716
|
-
};
|
|
29717
|
-
case "sinusoid":
|
|
29718
|
-
return getSinusoidCoords(_extends({}, graph, {
|
|
29719
|
-
startCoords: undefined
|
|
29720
|
-
}), range, step);
|
|
29721
|
-
case "quadratic":
|
|
29722
|
-
return getQuadraticCoords(_extends({}, graph, {
|
|
29723
|
-
startCoords: undefined
|
|
29724
|
-
}), range, step);
|
|
29725
|
-
case "point":
|
|
29726
|
-
return getPointCoords(_extends({}, graph, {
|
|
29727
|
-
startCoords: undefined
|
|
29728
|
-
}), range, step);
|
|
29729
|
-
case "polygon":
|
|
29730
|
-
return getPolygonCoords(_extends({}, graph, {
|
|
29731
|
-
startCoords: undefined
|
|
29732
|
-
}), range, step);
|
|
29733
|
-
case "angle":
|
|
29734
|
-
return getAngleCoords({
|
|
29735
|
-
graph: _extends({}, graph, {
|
|
29736
|
-
startCoords: undefined
|
|
29737
|
-
}),
|
|
29738
|
-
range,
|
|
29739
|
-
step
|
|
29740
|
-
});
|
|
29741
|
-
default:
|
|
29742
|
-
return undefined;
|
|
29743
|
-
}
|
|
29636
|
+
function InteractiveGraphCorrectAnswer(props) {
|
|
29637
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Heading, {
|
|
29638
|
+
title: "Correct Answer",
|
|
29639
|
+
isOpen: true,
|
|
29640
|
+
isCollapsible: false
|
|
29641
|
+
}), /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(LabelXSmall, {
|
|
29642
|
+
style: {
|
|
29643
|
+
paddingTop: spacing.xxSmall_6,
|
|
29644
|
+
paddingBottom: spacing.xxSmall_6,
|
|
29645
|
+
color: color.offBlack64
|
|
29646
|
+
}
|
|
29647
|
+
}, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."), /*#__PURE__*/React.createElement(BodyMonospace, {
|
|
29648
|
+
style: {
|
|
29649
|
+
fontSize: 12,
|
|
29650
|
+
backgroundColor: "#eee",
|
|
29651
|
+
paddingInline: spacing.xxSmall_6,
|
|
29652
|
+
borderColor: "#ccc",
|
|
29653
|
+
borderStyle: "solid",
|
|
29654
|
+
borderWidth: 1
|
|
29655
|
+
}
|
|
29656
|
+
}, props.equationString)), props.children));
|
|
29744
29657
|
}
|
|
29745
|
-
const getSinusoidEquation = startCoords => {
|
|
29746
|
-
// Get coefficients
|
|
29747
|
-
// It's assumed that p1 is the root and p2 is the first peak
|
|
29748
|
-
const p1 = startCoords[0];
|
|
29749
|
-
const p2 = startCoords[1];
|
|
29750
|
-
|
|
29751
|
-
// Resulting coefficients are canonical for this sine curve
|
|
29752
|
-
const amplitude = p2[1] - p1[1];
|
|
29753
|
-
const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
|
|
29754
|
-
const phase = p1[0] * angularFrequency;
|
|
29755
|
-
const verticalOffset = p1[1];
|
|
29756
|
-
return "y = " + amplitude.toFixed(3) + "sin(" + angularFrequency.toFixed(3) + "x - " + phase.toFixed(3) + ") + " + verticalOffset.toFixed(3);
|
|
29757
|
-
};
|
|
29758
|
-
const getQuadraticEquation = startCoords => {
|
|
29759
|
-
const p1 = startCoords[0];
|
|
29760
|
-
const p2 = startCoords[1];
|
|
29761
|
-
const p3 = startCoords[2];
|
|
29762
|
-
const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
|
|
29763
|
-
if (denom === 0) {
|
|
29764
|
-
// Many of the callers assume that the return value is always defined.
|
|
29765
|
-
return "Division by zero error";
|
|
29766
|
-
}
|
|
29767
|
-
const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
|
|
29768
|
-
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;
|
|
29769
|
-
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;
|
|
29770
|
-
return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
|
|
29771
|
-
};
|
|
29772
|
-
const findAngle = (point1, point2) => {
|
|
29773
|
-
const x = point1[0] - point2[0];
|
|
29774
|
-
const y = point1[1] - point2[1];
|
|
29775
|
-
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
29776
|
-
};
|
|
29777
|
-
const getAngleEquation = startCoords => {
|
|
29778
|
-
const [point1, vertex, point2] = startCoords;
|
|
29779
|
-
const angle = findAngle(point2, vertex) - findAngle(point1, vertex);
|
|
29780
|
-
const roundedAngle = angle.toFixed(0);
|
|
29781
|
-
return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`;
|
|
29782
|
-
};
|
|
29783
|
-
const shouldShowStartCoordsUI = (graph, isStatic) => {
|
|
29784
|
-
// We don't show the start coords UI for static graphs, since
|
|
29785
|
-
// the coords shown for this are determined by the coords on the
|
|
29786
|
-
// "correct" graph. The start coords would not be used here.
|
|
29787
|
-
if (isStatic) {
|
|
29788
|
-
return false;
|
|
29789
|
-
}
|
|
29790
|
-
if (graph.type === "point" && graph.numPoints === "unlimited") {
|
|
29791
|
-
return false;
|
|
29792
|
-
}
|
|
29793
|
-
if (graph.type === "polygon" && (graph.numSides === "unlimited" || graph.snapTo === "angles" || graph.snapTo === "sides")) {
|
|
29794
|
-
return false;
|
|
29795
|
-
}
|
|
29796
|
-
return true;
|
|
29797
|
-
};
|
|
29798
29658
|
|
|
29799
|
-
|
|
29800
|
-
* Dropdown for selecting a locked figure to add to an interactive graph.
|
|
29801
|
-
* Locked figures are elements (points, segmeents, etc.) that are not
|
|
29802
|
-
* interactive, just present in the graph's background.
|
|
29803
|
-
*
|
|
29804
|
-
* Used in the interactive graph editor's locked figures section.
|
|
29805
|
-
*/
|
|
29806
|
-
const LockedFigureSelect = props => {
|
|
29659
|
+
function InteractiveGraphDescription(props) {
|
|
29807
29660
|
const {
|
|
29808
|
-
|
|
29661
|
+
ariaLabelValue,
|
|
29662
|
+
ariaDescriptionValue,
|
|
29809
29663
|
onChange
|
|
29810
29664
|
} = props;
|
|
29811
|
-
const
|
|
29812
|
-
|
|
29813
|
-
|
|
29814
|
-
|
|
29815
|
-
|
|
29816
|
-
|
|
29817
|
-
}, /*#__PURE__*/React.createElement(
|
|
29818
|
-
|
|
29819
|
-
|
|
29820
|
-
|
|
29821
|
-
|
|
29822
|
-
|
|
29823
|
-
|
|
29665
|
+
const [isOpen, setIsOpen] = React.useState(true);
|
|
29666
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Heading, {
|
|
29667
|
+
title: "Description",
|
|
29668
|
+
isCollapsible: true,
|
|
29669
|
+
isOpen: isOpen,
|
|
29670
|
+
onToggle: setIsOpen
|
|
29671
|
+
}), isOpen && /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(LabelXSmall, {
|
|
29672
|
+
style: styles$G.caption
|
|
29673
|
+
}, "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.createElement(LabelLarge, {
|
|
29674
|
+
tag: "label"
|
|
29675
|
+
}, "Title", /*#__PURE__*/React.createElement(TextField, {
|
|
29676
|
+
value: ariaLabelValue,
|
|
29677
|
+
onChange: newValue => onChange({
|
|
29678
|
+
fullGraphAriaLabel: newValue
|
|
29679
|
+
}),
|
|
29680
|
+
style: styles$G.spaceAbove
|
|
29681
|
+
})), /*#__PURE__*/React.createElement(Strut, {
|
|
29682
|
+
size: spacing.small_12
|
|
29683
|
+
}), /*#__PURE__*/React.createElement(LabelLarge, {
|
|
29684
|
+
tag: "label"
|
|
29685
|
+
}, "Description", /*#__PURE__*/React.createElement(TextArea, {
|
|
29686
|
+
rows: 8,
|
|
29687
|
+
resizeType: "vertical",
|
|
29688
|
+
value: ariaDescriptionValue,
|
|
29689
|
+
onChange: newValue => onChange({
|
|
29690
|
+
fullGraphAriaDescription: newValue
|
|
29691
|
+
}),
|
|
29692
|
+
style: styles$G.spaceAbove
|
|
29824
29693
|
}))));
|
|
29825
|
-
}
|
|
29826
|
-
const styles$
|
|
29827
|
-
|
|
29828
|
-
|
|
29694
|
+
}
|
|
29695
|
+
const styles$G = StyleSheet.create({
|
|
29696
|
+
caption: {
|
|
29697
|
+
color: color.offBlack64,
|
|
29698
|
+
paddingTop: spacing.xxSmall_6,
|
|
29699
|
+
paddingBottom: spacing.xxSmall_6
|
|
29829
29700
|
},
|
|
29830
|
-
|
|
29831
|
-
|
|
29832
|
-
borderRadius: spacing.xxxSmall_4
|
|
29701
|
+
spaceAbove: {
|
|
29702
|
+
marginTop: spacing.xxxSmall_4
|
|
29833
29703
|
}
|
|
29834
29704
|
});
|
|
29835
29705
|
|
|
29836
|
-
|
|
29837
|
-
|
|
29838
|
-
*
|
|
29839
|
-
* This makes it so that the text field's input number updates on scroll
|
|
29840
|
-
* without scrolling the page.
|
|
29841
|
-
*
|
|
29842
|
-
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
|
|
29843
|
-
* they only scroll the page. Inputs in React do NOT work this way (explanation
|
|
29844
|
-
* here: https://stackoverflow.com/a/68266494). By default, scrolling on a
|
|
29845
|
-
* focused number input in React causes BOTH the input value to change AND
|
|
29846
|
-
* the page to scroll. The behavior in this component is an improvement on
|
|
29847
|
-
* the React behavior, but it's the opposite of the native HTML behavior.
|
|
29848
|
-
*
|
|
29849
|
-
* NOTE 2: Firefox seems to have a custom override for this. Even with this
|
|
29850
|
-
* stopPropogation, Firefox matches the native HTML behavior.
|
|
29851
|
-
*/
|
|
29852
|
-
const ScrolllessNumberTextField = props => {
|
|
29853
|
-
const inputRef = React.useRef(null);
|
|
29854
|
-
React.useEffect(() => {
|
|
29855
|
-
const ref = inputRef.current;
|
|
29856
|
-
|
|
29857
|
-
// stopPropogation makes it so that the page scroll event is not
|
|
29858
|
-
// triggered when the input is focused and the user scrolls.
|
|
29859
|
-
// The input value will still change on scroll.
|
|
29860
|
-
const ignoreScroll = e => {
|
|
29861
|
-
e.stopPropagation();
|
|
29862
|
-
};
|
|
29863
|
-
ref == null || ref.addEventListener("wheel", ignoreScroll);
|
|
29864
|
-
return () => {
|
|
29865
|
-
ref == null || ref.removeEventListener("wheel", ignoreScroll);
|
|
29866
|
-
};
|
|
29867
|
-
}, [inputRef]);
|
|
29868
|
-
return /*#__PURE__*/React.createElement(TextField, _extends({
|
|
29869
|
-
type: "number"
|
|
29870
|
-
}, props, {
|
|
29871
|
-
ref: inputRef
|
|
29872
|
-
}));
|
|
29873
|
-
};
|
|
29874
|
-
|
|
29875
|
-
const AngleInput = props => {
|
|
29706
|
+
// Renders the given children in a View laid out horizontally.
|
|
29707
|
+
const LabeledRow = props => {
|
|
29876
29708
|
const {
|
|
29877
|
-
|
|
29878
|
-
|
|
29709
|
+
children,
|
|
29710
|
+
label,
|
|
29711
|
+
labelSide = "left",
|
|
29712
|
+
style
|
|
29879
29713
|
} = props;
|
|
29880
|
-
|
|
29881
|
-
|
|
29882
|
-
|
|
29883
|
-
|
|
29884
|
-
|
|
29885
|
-
|
|
29886
|
-
|
|
29887
|
-
|
|
29888
|
-
|
|
29889
|
-
}
|
|
29890
|
-
|
|
29891
|
-
// Update the graph.
|
|
29892
|
-
onChange(degreeToRadian(newValue));
|
|
29893
|
-
}
|
|
29894
|
-
return /*#__PURE__*/React.createElement(LabelMedium, {
|
|
29895
|
-
tag: "label",
|
|
29896
|
-
style: styles$G.row
|
|
29897
|
-
}, "angle (degrees)", /*#__PURE__*/React.createElement(Strut, {
|
|
29898
|
-
size: spacing.xxSmall_6
|
|
29899
|
-
}), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
|
|
29900
|
-
value: angleInput,
|
|
29901
|
-
onChange: handleAngleChange,
|
|
29902
|
-
style: styles$G.textField
|
|
29903
|
-
}), /*#__PURE__*/React.createElement(Strut, {
|
|
29904
|
-
size: spacing.xxSmall_6
|
|
29905
|
-
}));
|
|
29714
|
+
return /*#__PURE__*/React.createElement("label", {
|
|
29715
|
+
className: css(styles$F.label)
|
|
29716
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
29717
|
+
style: [styles$F.row, style]
|
|
29718
|
+
}, labelSide === "start" || /*#__PURE__*/React.createElement(LabelSmall, {
|
|
29719
|
+
style: styles$F.spaceEnd
|
|
29720
|
+
}, label), children, labelSide === "end" && /*#__PURE__*/React.createElement(LabelSmall, {
|
|
29721
|
+
style: styles$F.spaceStart
|
|
29722
|
+
}, label)));
|
|
29906
29723
|
};
|
|
29907
|
-
const styles$
|
|
29724
|
+
const styles$F = StyleSheet.create({
|
|
29725
|
+
label: {
|
|
29726
|
+
width: "fit-content"
|
|
29727
|
+
},
|
|
29908
29728
|
row: {
|
|
29909
|
-
display: "flex",
|
|
29910
29729
|
flexDirection: "row",
|
|
29911
|
-
|
|
29730
|
+
marginTop: spacing.xSmall_8,
|
|
29731
|
+
alignItems: "center",
|
|
29732
|
+
width: "fit-content"
|
|
29912
29733
|
},
|
|
29913
|
-
|
|
29914
|
-
|
|
29734
|
+
spaceStart: {
|
|
29735
|
+
marginInlineStart: spacing.xSmall_8
|
|
29736
|
+
},
|
|
29737
|
+
spaceEnd: {
|
|
29738
|
+
marginInlineEnd: spacing.xSmall_8
|
|
29915
29739
|
}
|
|
29916
29740
|
});
|
|
29917
29741
|
|
|
29918
|
-
const
|
|
29919
|
-
|
|
29920
|
-
|
|
29921
|
-
|
|
29922
|
-
|
|
29742
|
+
const {
|
|
29743
|
+
ButtonGroup: ButtonGroup$2,
|
|
29744
|
+
InfoTip: InfoTip$d,
|
|
29745
|
+
RangeInput: RangeInput$4
|
|
29746
|
+
} = components;
|
|
29747
|
+
const defaultBackgroundImage$1 = {
|
|
29748
|
+
url: null,
|
|
29749
|
+
width: 0,
|
|
29750
|
+
height: 0
|
|
29751
|
+
};
|
|
29752
|
+
function numSteps(range, step) {
|
|
29753
|
+
return Math.floor((range[1] - range[0]) / step);
|
|
29754
|
+
}
|
|
29755
|
+
class InteractiveGraphSettings extends React.Component {
|
|
29756
|
+
static stateFromProps(props) {
|
|
29757
|
+
return {
|
|
29758
|
+
labelsTextbox: props.labels,
|
|
29759
|
+
gridStepTextbox: props.gridStep,
|
|
29760
|
+
snapStepTextbox: props.snapStep,
|
|
29761
|
+
stepTextbox: props.step,
|
|
29762
|
+
rangeTextbox: props.range,
|
|
29763
|
+
// Shallow-copied clone
|
|
29764
|
+
backgroundImage: _extends({}, props.backgroundImage)
|
|
29765
|
+
};
|
|
29766
|
+
}
|
|
29767
|
+
constructor(props) {
|
|
29768
|
+
super(props);
|
|
29769
|
+
this._isMounted = false;
|
|
29770
|
+
this.bgUrlRef = /*#__PURE__*/React.createRef();
|
|
29771
|
+
this.labelXRef = /*#__PURE__*/React.createRef();
|
|
29772
|
+
this.labelYRef = /*#__PURE__*/React.createRef();
|
|
29773
|
+
this.change = (...args) => {
|
|
29774
|
+
return Changeable.change.apply(this, args);
|
|
29775
|
+
};
|
|
29776
|
+
this.changeBackgroundUrl = e => {
|
|
29777
|
+
var _this$bgUrlRef$curren;
|
|
29778
|
+
// Only continue on blur or "enter"
|
|
29779
|
+
if (e.type === "keypress" && e.key !== "Enter") {
|
|
29780
|
+
return;
|
|
29781
|
+
}
|
|
29782
|
+
const setUrl = (url, width, height) => {
|
|
29783
|
+
// Shallow-copied clone
|
|
29784
|
+
const image = _extends({}, this.props.backgroundImage);
|
|
29785
|
+
image.url = url;
|
|
29786
|
+
image.width = width;
|
|
29787
|
+
image.height = height;
|
|
29788
|
+
this.setState({
|
|
29789
|
+
backgroundImage: image
|
|
29790
|
+
}, this.changeGraph);
|
|
29791
|
+
};
|
|
29792
|
+
const url = (_this$bgUrlRef$curren = this.bgUrlRef.current) == null ? void 0 : _this$bgUrlRef$curren.value;
|
|
29793
|
+
if (url) {
|
|
29794
|
+
Util.getImageSize(url, (width, height) => {
|
|
29795
|
+
if (this._isMounted) {
|
|
29796
|
+
setUrl(url, width, height);
|
|
29797
|
+
}
|
|
29798
|
+
});
|
|
29799
|
+
} else {
|
|
29800
|
+
setUrl(null, 0, 0);
|
|
29801
|
+
}
|
|
29802
|
+
};
|
|
29803
|
+
this.renderLabelChoices = choices => {
|
|
29804
|
+
return choices.map(nameAndValue => /*#__PURE__*/React.createElement("option", {
|
|
29805
|
+
key: nameAndValue[1],
|
|
29806
|
+
value: nameAndValue[1]
|
|
29807
|
+
}, nameAndValue[0]));
|
|
29808
|
+
};
|
|
29809
|
+
this.validRange = range => {
|
|
29810
|
+
const numbers = _.every(range, function (num) {
|
|
29811
|
+
return _.isFinite(num);
|
|
29812
|
+
});
|
|
29813
|
+
if (!numbers) {
|
|
29814
|
+
return "Range must be a valid number";
|
|
29815
|
+
}
|
|
29816
|
+
if (range[0] >= range[1]) {
|
|
29817
|
+
return "Range must have a higher number on the right";
|
|
29818
|
+
}
|
|
29819
|
+
return true;
|
|
29820
|
+
};
|
|
29821
|
+
this.validateStepValue = settings => {
|
|
29822
|
+
const {
|
|
29823
|
+
step,
|
|
29824
|
+
range,
|
|
29825
|
+
name,
|
|
29826
|
+
minTicks,
|
|
29827
|
+
maxTicks
|
|
29828
|
+
} = settings;
|
|
29829
|
+
const nSteps = numSteps(range, step);
|
|
29830
|
+
if (nSteps < minTicks) {
|
|
29831
|
+
return name + " is too large, there must be at least " + minTicks + " ticks.";
|
|
29832
|
+
}
|
|
29833
|
+
if (nSteps > maxTicks) {
|
|
29834
|
+
return name + " is too small, there can be at most " + maxTicks + " ticks.";
|
|
29835
|
+
}
|
|
29836
|
+
return true;
|
|
29837
|
+
};
|
|
29838
|
+
this.validSnapStep = (step, range) => {
|
|
29839
|
+
return this.validateStepValue({
|
|
29840
|
+
step: step,
|
|
29841
|
+
range: range,
|
|
29842
|
+
name: "Snap step",
|
|
29843
|
+
minTicks: 5,
|
|
29844
|
+
maxTicks: 60
|
|
29845
|
+
});
|
|
29846
|
+
};
|
|
29847
|
+
this.validGridStep = (step, range) => {
|
|
29848
|
+
return this.validateStepValue({
|
|
29849
|
+
step: step,
|
|
29850
|
+
range: range,
|
|
29851
|
+
name: "Grid step",
|
|
29852
|
+
minTicks: 3,
|
|
29853
|
+
maxTicks: 60
|
|
29854
|
+
});
|
|
29855
|
+
};
|
|
29856
|
+
this.validStep = (step, range) => {
|
|
29857
|
+
return this.validateStepValue({
|
|
29858
|
+
step: step,
|
|
29859
|
+
range: range,
|
|
29860
|
+
name: "Step",
|
|
29861
|
+
minTicks: 3,
|
|
29862
|
+
maxTicks: 20
|
|
29863
|
+
});
|
|
29864
|
+
};
|
|
29865
|
+
this.validBackgroundImageSize = image => {
|
|
29866
|
+
// Ignore empty images
|
|
29867
|
+
if (!image.url) {
|
|
29868
|
+
return true;
|
|
29869
|
+
}
|
|
29870
|
+
const validSize = image.width <= 450 && image.height <= 450;
|
|
29871
|
+
if (!validSize) {
|
|
29872
|
+
return "Image must be smaller than 450px x 450px.";
|
|
29873
|
+
}
|
|
29874
|
+
return true;
|
|
29875
|
+
};
|
|
29876
|
+
this.validateGraphSettings = (range, step, gridStep, snapStep, image) => {
|
|
29877
|
+
const self = this;
|
|
29878
|
+
let msg;
|
|
29879
|
+
const goodRange = _.every(range, function (range) {
|
|
29880
|
+
msg = self.validRange(range);
|
|
29881
|
+
return msg === true;
|
|
29882
|
+
});
|
|
29883
|
+
if (!goodRange) {
|
|
29884
|
+
return msg;
|
|
29885
|
+
}
|
|
29886
|
+
const goodStep = _.every(step, function (step, i) {
|
|
29887
|
+
msg = self.validStep(step, range[i]);
|
|
29888
|
+
return msg === true;
|
|
29889
|
+
});
|
|
29890
|
+
if (!goodStep) {
|
|
29891
|
+
return msg;
|
|
29892
|
+
}
|
|
29893
|
+
const goodGridStep = _.every(gridStep, function (gridStep, i) {
|
|
29894
|
+
msg = self.validGridStep(gridStep, range[i]);
|
|
29895
|
+
return msg === true;
|
|
29896
|
+
});
|
|
29897
|
+
if (!goodGridStep) {
|
|
29898
|
+
return msg;
|
|
29899
|
+
}
|
|
29900
|
+
const goodSnapStep = _.every(snapStep, function (snapStep, i) {
|
|
29901
|
+
msg = self.validSnapStep(snapStep, range[i]);
|
|
29902
|
+
return msg === true;
|
|
29903
|
+
});
|
|
29904
|
+
if (!goodSnapStep) {
|
|
29905
|
+
return msg;
|
|
29906
|
+
}
|
|
29907
|
+
const goodImageSize = this.validBackgroundImageSize(image);
|
|
29908
|
+
if (goodImageSize !== true) {
|
|
29909
|
+
msg = goodImageSize;
|
|
29910
|
+
return msg;
|
|
29911
|
+
}
|
|
29912
|
+
return true;
|
|
29913
|
+
};
|
|
29914
|
+
this.changeLabel = (i, e) => {
|
|
29915
|
+
const val = e.target.value;
|
|
29916
|
+
const labels = this.state.labelsTextbox.slice();
|
|
29917
|
+
labels[i] = val;
|
|
29918
|
+
this.setState({
|
|
29919
|
+
labelsTextbox: labels
|
|
29920
|
+
}, this.changeGraph);
|
|
29921
|
+
};
|
|
29922
|
+
this.changeRange = (i, values) => {
|
|
29923
|
+
const ranges = this.state.rangeTextbox.slice();
|
|
29924
|
+
ranges[i] = values;
|
|
29925
|
+
const step = this.state.stepTextbox.slice();
|
|
29926
|
+
const gridStep = this.state.gridStepTextbox.slice();
|
|
29927
|
+
const snapStep = this.state.snapStepTextbox.slice();
|
|
29928
|
+
const scale = Util.scaleFromExtent(ranges[i], this.props.box[i]);
|
|
29929
|
+
if (this.validRange(ranges[i]) === true) {
|
|
29930
|
+
step[i] = Util.tickStepFromExtent(ranges[i], this.props.box[i]);
|
|
29931
|
+
const gridStepValue = Util.gridStepFromTickStep(step[i], scale);
|
|
29932
|
+
if (gridStepValue) {
|
|
29933
|
+
gridStep[i] = gridStepValue;
|
|
29934
|
+
}
|
|
29935
|
+
snapStep[i] = gridStep[i] / 2;
|
|
29936
|
+
}
|
|
29937
|
+
this.setState({
|
|
29938
|
+
stepTextbox: step,
|
|
29939
|
+
gridStepTextbox: gridStep,
|
|
29940
|
+
snapStepTextbox: snapStep,
|
|
29941
|
+
rangeTextbox: ranges
|
|
29942
|
+
}, this.changeGraph);
|
|
29943
|
+
};
|
|
29944
|
+
this.changeStep = step => {
|
|
29945
|
+
this.setState({
|
|
29946
|
+
stepTextbox: step
|
|
29947
|
+
}, this.changeGraph);
|
|
29948
|
+
};
|
|
29949
|
+
this.changeSnapStep = snapStep => {
|
|
29950
|
+
this.setState({
|
|
29951
|
+
snapStepTextbox: snapStep
|
|
29952
|
+
}, this.changeGraph);
|
|
29953
|
+
};
|
|
29954
|
+
this.changeGridStep = gridStep => {
|
|
29955
|
+
this.setState({
|
|
29956
|
+
gridStepTextbox: gridStep,
|
|
29957
|
+
snapStepTextbox: _.map(gridStep, function (step) {
|
|
29958
|
+
return step / 2;
|
|
29959
|
+
})
|
|
29960
|
+
}, this.changeGraph);
|
|
29961
|
+
};
|
|
29962
|
+
this.changeGraph = () => {
|
|
29963
|
+
const labels = this.state.labelsTextbox;
|
|
29964
|
+
const range = _.map(this.state.rangeTextbox, function (range) {
|
|
29965
|
+
return _.map(range, Number);
|
|
29966
|
+
});
|
|
29967
|
+
const step = _.map(this.state.stepTextbox, Number);
|
|
29968
|
+
const gridStep = this.state.gridStepTextbox;
|
|
29969
|
+
const snapStep = this.state.snapStepTextbox;
|
|
29970
|
+
const image = this.state.backgroundImage;
|
|
29971
|
+
|
|
29972
|
+
// validationResult is either:
|
|
29973
|
+
// true -> the settings are valid
|
|
29974
|
+
// a string -> the settings are invalid, and the explanation
|
|
29975
|
+
// is contained in the string
|
|
29976
|
+
// TODO(aria): Refactor this to not be confusing
|
|
29977
|
+
const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
|
|
29978
|
+
if (validationResult === true) {
|
|
29979
|
+
// either true or a string
|
|
29980
|
+
this.change({
|
|
29981
|
+
valid: true,
|
|
29982
|
+
labels: labels,
|
|
29983
|
+
range: range,
|
|
29984
|
+
step: step,
|
|
29985
|
+
gridStep: gridStep,
|
|
29986
|
+
snapStep: snapStep,
|
|
29987
|
+
backgroundImage: image
|
|
29988
|
+
});
|
|
29989
|
+
} else {
|
|
29990
|
+
this.change({
|
|
29991
|
+
valid: validationResult // a string message, not false
|
|
29992
|
+
});
|
|
29993
|
+
}
|
|
29994
|
+
};
|
|
29995
|
+
this.state = _extends({
|
|
29996
|
+
isExpanded: true
|
|
29997
|
+
}, InteractiveGraphSettings.stateFromProps(props));
|
|
29998
|
+
}
|
|
29999
|
+
componentDidMount() {
|
|
30000
|
+
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
30001
|
+
// this.isMounted() but is still considered an anti-pattern.
|
|
30002
|
+
this._isMounted = true;
|
|
30003
|
+
this.changeGraph = _.debounce(this.changeGraph, 300);
|
|
30004
|
+
}
|
|
30005
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
30006
|
+
// Make sure that state updates when switching
|
|
30007
|
+
// between different items in a multi-item editor.
|
|
30008
|
+
if (!_.isEqual(this.props.labels, nextProps.labels) || !_.isEqual(this.props.gridStep, nextProps.gridStep) || !_.isEqual(this.props.snapStep, nextProps.snapStep) || !_.isEqual(this.props.step, nextProps.step) || !_.isEqual(this.props.range, nextProps.range) || !_.isEqual(this.props.backgroundImage, nextProps.backgroundImage)) {
|
|
30009
|
+
this.setState(InteractiveGraphSettings.stateFromProps(nextProps));
|
|
30010
|
+
}
|
|
30011
|
+
}
|
|
30012
|
+
componentWillUnmount() {
|
|
30013
|
+
this._isMounted = false;
|
|
30014
|
+
}
|
|
30015
|
+
render() {
|
|
30016
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Heading, {
|
|
30017
|
+
title: "Common Graph Settings",
|
|
30018
|
+
isOpen: this.state.isExpanded,
|
|
30019
|
+
isCollapsible: true,
|
|
30020
|
+
onToggle: () => this.setState({
|
|
30021
|
+
isExpanded: !this.state.isExpanded
|
|
30022
|
+
})
|
|
30023
|
+
}), this.state.isExpanded && /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement("div", {
|
|
30024
|
+
className: "graph-settings"
|
|
30025
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
30026
|
+
className: "perseus-widget-row"
|
|
30027
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
30028
|
+
className: "perseus-widget-left-col"
|
|
30029
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30030
|
+
label: "x Label"
|
|
30031
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
30032
|
+
type: "text",
|
|
30033
|
+
className: "graph-settings-axis-label",
|
|
30034
|
+
ref: this.labelXRef,
|
|
30035
|
+
onChange: e => this.changeLabel(0, e),
|
|
30036
|
+
value: this.state.labelsTextbox[0] || ""
|
|
30037
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
30038
|
+
className: "perseus-widget-right-col"
|
|
30039
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30040
|
+
label: "y Label"
|
|
30041
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
30042
|
+
type: "text",
|
|
30043
|
+
className: "graph-settings-axis-label",
|
|
30044
|
+
ref: this.labelYRef,
|
|
30045
|
+
onChange: e => this.changeLabel(1, e),
|
|
30046
|
+
value: this.state.labelsTextbox[1] || ""
|
|
30047
|
+
})))), /*#__PURE__*/React.createElement("div", {
|
|
30048
|
+
className: "perseus-widget-row"
|
|
30049
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
30050
|
+
className: "perseus-widget-left-col"
|
|
30051
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30052
|
+
label: "x Range"
|
|
30053
|
+
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
30054
|
+
value: this.state.rangeTextbox[0],
|
|
30055
|
+
onChange: vals => this.changeRange(0, vals)
|
|
30056
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
30057
|
+
className: "perseus-widget-right-col"
|
|
30058
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30059
|
+
label: "y Range"
|
|
30060
|
+
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
30061
|
+
value: this.state.rangeTextbox[1],
|
|
30062
|
+
onChange: vals => this.changeRange(1, vals)
|
|
30063
|
+
})))), /*#__PURE__*/React.createElement("div", {
|
|
30064
|
+
className: "perseus-widget-row"
|
|
30065
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
30066
|
+
className: "perseus-widget-left-col"
|
|
30067
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30068
|
+
label: "Tick Step"
|
|
30069
|
+
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
30070
|
+
value: this.state.stepTextbox,
|
|
30071
|
+
onChange: this.changeStep
|
|
30072
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
30073
|
+
className: "perseus-widget-right-col"
|
|
30074
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30075
|
+
label: "Grid Step"
|
|
30076
|
+
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
30077
|
+
value: this.state.gridStepTextbox,
|
|
30078
|
+
onChange: this.changeGridStep
|
|
30079
|
+
})))), /*#__PURE__*/React.createElement("div", {
|
|
30080
|
+
className: "perseus-widget-row"
|
|
30081
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
30082
|
+
className: "perseus-widget-left-col"
|
|
30083
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30084
|
+
label: "Snap Step"
|
|
30085
|
+
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
30086
|
+
value: this.state.snapStepTextbox,
|
|
30087
|
+
onChange: this.changeSnapStep
|
|
30088
|
+
})))), /*#__PURE__*/React.createElement("div", {
|
|
30089
|
+
className: "perseus-widget-row"
|
|
30090
|
+
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30091
|
+
label: "Markings:"
|
|
30092
|
+
}, /*#__PURE__*/React.createElement(ButtonGroup$2, {
|
|
30093
|
+
value: this.props.markings,
|
|
30094
|
+
allowEmpty: false,
|
|
30095
|
+
buttons: [{
|
|
30096
|
+
value: "graph",
|
|
30097
|
+
content: "Graph"
|
|
30098
|
+
}, {
|
|
30099
|
+
value: "grid",
|
|
30100
|
+
content: "Grid"
|
|
30101
|
+
}, {
|
|
30102
|
+
value: "none",
|
|
30103
|
+
content: "None"
|
|
30104
|
+
}],
|
|
30105
|
+
onChange: this.change("markings")
|
|
30106
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
30107
|
+
className: "perseus-widget-left-col"
|
|
30108
|
+
}, /*#__PURE__*/React.createElement(Checkbox$1, {
|
|
30109
|
+
label: "Show tooltips",
|
|
30110
|
+
checked: this.props.showTooltips,
|
|
30111
|
+
onChange: value => {
|
|
30112
|
+
this.change({
|
|
30113
|
+
showTooltips: value
|
|
30114
|
+
});
|
|
30115
|
+
}
|
|
30116
|
+
}))), /*#__PURE__*/React.createElement(LabeledRow, {
|
|
30117
|
+
label: "Background image URL:",
|
|
30118
|
+
style: styles$E.resetSpaceTop
|
|
30119
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
30120
|
+
type: "text",
|
|
30121
|
+
className: css(styles$E.backgroundUrlInput),
|
|
30122
|
+
ref: this.bgUrlRef,
|
|
30123
|
+
value: this.state.backgroundImage.url || "",
|
|
30124
|
+
onChange: e => {
|
|
30125
|
+
// Shallow-copied clone
|
|
30126
|
+
const image = _extends({}, this.props.backgroundImage);
|
|
30127
|
+
image.url = e.target.value;
|
|
30128
|
+
this.setState({
|
|
30129
|
+
backgroundImage: image
|
|
30130
|
+
});
|
|
30131
|
+
},
|
|
30132
|
+
onKeyPress: this.changeBackgroundUrl,
|
|
30133
|
+
onBlur: this.changeBackgroundUrl
|
|
30134
|
+
}), /*#__PURE__*/React.createElement(InfoTip$d, null, /*#__PURE__*/React.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React.createElement(View, {
|
|
30135
|
+
style: styles$E.protractorSection
|
|
30136
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
30137
|
+
style: styles$E.checkboxRow
|
|
30138
|
+
}, /*#__PURE__*/React.createElement(Checkbox$1, {
|
|
30139
|
+
label: "Show protractor",
|
|
30140
|
+
checked: this.props.showProtractor,
|
|
30141
|
+
onChange: value => {
|
|
30142
|
+
this.change({
|
|
30143
|
+
showProtractor: value
|
|
30144
|
+
});
|
|
30145
|
+
},
|
|
30146
|
+
style: styles$E.resetSpaceTop
|
|
30147
|
+
})), this.props.showProtractor && /*#__PURE__*/React.createElement(Banner, {
|
|
30148
|
+
layout: "floating",
|
|
30149
|
+
text: "The protractor is not accessible. Please consider an alternate approach.",
|
|
30150
|
+
kind: "warning"
|
|
30151
|
+
}))));
|
|
30152
|
+
}
|
|
30153
|
+
}
|
|
30154
|
+
InteractiveGraphSettings.defaultProps = {
|
|
30155
|
+
box: [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall],
|
|
30156
|
+
labels: ["x", "y"],
|
|
30157
|
+
range: [[-10, 10], [-10, 10]],
|
|
30158
|
+
step: [1, 1],
|
|
30159
|
+
gridStep: [1, 1],
|
|
30160
|
+
snapStep: [1, 1],
|
|
30161
|
+
valid: true,
|
|
30162
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
30163
|
+
markings: "graph",
|
|
30164
|
+
showProtractor: false,
|
|
30165
|
+
showTooltips: false
|
|
30166
|
+
};
|
|
30167
|
+
const styles$E = StyleSheet.create({
|
|
30168
|
+
resetSpaceTop: {
|
|
30169
|
+
marginTop: 0
|
|
30170
|
+
},
|
|
30171
|
+
backgroundUrlInput: {
|
|
30172
|
+
border: `1px solid ${color.offBlack32}`,
|
|
30173
|
+
borderRadius: spacing.xxxSmall_4,
|
|
30174
|
+
padding: spacing.xxxSmall_4
|
|
30175
|
+
},
|
|
30176
|
+
checkboxRow: {
|
|
30177
|
+
flexDirection: "row",
|
|
30178
|
+
alignItems: "center",
|
|
30179
|
+
justifyContent: "space-between",
|
|
30180
|
+
marginBottom: spacing.xSmall_8
|
|
30181
|
+
},
|
|
30182
|
+
protractorSection: {
|
|
30183
|
+
marginTop: spacing.xSmall_8,
|
|
30184
|
+
borderTop: `1px solid ${color.offBlack16}`,
|
|
30185
|
+
paddingTop: spacing.xSmall_8,
|
|
30186
|
+
paddingBottom: spacing.xSmall_8,
|
|
30187
|
+
borderBottom: `1px solid ${color.offBlack16}`
|
|
30188
|
+
}
|
|
30189
|
+
});
|
|
30190
|
+
|
|
30191
|
+
const SegmentCountSelector = ({
|
|
30192
|
+
numSegments: _numSegments = 1,
|
|
30193
|
+
onChange
|
|
30194
|
+
}) => /*#__PURE__*/React.createElement(SingleSelect, {
|
|
30195
|
+
key: "segment-select",
|
|
30196
|
+
selectedValue: `${_numSegments}`
|
|
30197
|
+
// Never uses placeholder, always has value
|
|
30198
|
+
,
|
|
30199
|
+
placeholder: "",
|
|
30200
|
+
onChange: newValue => {
|
|
30201
|
+
const num = +newValue;
|
|
30202
|
+
onChange(num);
|
|
30203
|
+
},
|
|
30204
|
+
style: styles$D.singleSelectShort
|
|
30205
|
+
}, _.range(1, 7).map(n => /*#__PURE__*/React.createElement(OptionItem, {
|
|
30206
|
+
key: n,
|
|
30207
|
+
value: `${n}`,
|
|
30208
|
+
label: `${n} segment${n > 1 ? "s" : ""}`
|
|
30209
|
+
})));
|
|
30210
|
+
const styles$D = StyleSheet.create({
|
|
30211
|
+
singleSelectShort: {
|
|
30212
|
+
// Non-standard spacing, but it's the smallest we can go
|
|
30213
|
+
// without running into styling issues with the dropdown.
|
|
30214
|
+
height: 26
|
|
30215
|
+
}
|
|
30216
|
+
});
|
|
30217
|
+
|
|
30218
|
+
/**
|
|
30219
|
+
* Dropdown for selecting a locked figure to add to an interactive graph.
|
|
30220
|
+
* Locked figures are elements (points, segmeents, etc.) that are not
|
|
30221
|
+
* interactive, just present in the graph's background.
|
|
30222
|
+
*
|
|
30223
|
+
* Used in the interactive graph editor's locked figures section.
|
|
30224
|
+
*/
|
|
30225
|
+
const LockedFigureSelect = props => {
|
|
30226
|
+
const {
|
|
30227
|
+
id,
|
|
30228
|
+
onChange
|
|
30229
|
+
} = props;
|
|
30230
|
+
const figureTypes = ["point", "line", "vector", "ellipse", "polygon", "function"];
|
|
30231
|
+
if (props.showLabelsFlag) {
|
|
30232
|
+
figureTypes.push("label");
|
|
30233
|
+
}
|
|
30234
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
30235
|
+
style: styles$C.container
|
|
30236
|
+
}, /*#__PURE__*/React.createElement(ActionMenu, {
|
|
30237
|
+
menuText: "Add locked figure",
|
|
30238
|
+
style: styles$C.addElementSelect
|
|
30239
|
+
}, figureTypes.map(figureType => /*#__PURE__*/React.createElement(ActionItem, {
|
|
30240
|
+
key: `${id}-${figureType}`,
|
|
30241
|
+
label: figureType,
|
|
30242
|
+
onClick: () => onChange(figureType)
|
|
30243
|
+
}))));
|
|
30244
|
+
};
|
|
30245
|
+
const styles$C = StyleSheet.create({
|
|
30246
|
+
container: {
|
|
30247
|
+
marginTop: spacing.xSmall_8
|
|
30248
|
+
},
|
|
30249
|
+
addElementSelect: {
|
|
30250
|
+
backgroundColor: color.fadedBlue8,
|
|
30251
|
+
borderRadius: spacing.xxxSmall_4
|
|
30252
|
+
}
|
|
30253
|
+
});
|
|
30254
|
+
|
|
30255
|
+
/**
|
|
30256
|
+
* This is a custom text field of type="number" for use in Perseus Editors.
|
|
30257
|
+
*
|
|
30258
|
+
* This makes it so that the text field's input number updates on scroll
|
|
30259
|
+
* without scrolling the page.
|
|
30260
|
+
*
|
|
30261
|
+
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
|
|
30262
|
+
* they only scroll the page. Inputs in React do NOT work this way (explanation
|
|
30263
|
+
* here: https://stackoverflow.com/a/68266494). By default, scrolling on a
|
|
30264
|
+
* focused number input in React causes BOTH the input value to change AND
|
|
30265
|
+
* the page to scroll. The behavior in this component is an improvement on
|
|
30266
|
+
* the React behavior, but it's the opposite of the native HTML behavior.
|
|
30267
|
+
*
|
|
30268
|
+
* NOTE 2: Firefox seems to have a custom override for this. Even with this
|
|
30269
|
+
* stopPropogation, Firefox matches the native HTML behavior.
|
|
30270
|
+
*/
|
|
30271
|
+
const ScrolllessNumberTextField = props => {
|
|
30272
|
+
const inputRef = React.useRef(null);
|
|
30273
|
+
React.useEffect(() => {
|
|
30274
|
+
const ref = inputRef.current;
|
|
30275
|
+
|
|
30276
|
+
// stopPropogation makes it so that the page scroll event is not
|
|
30277
|
+
// triggered when the input is focused and the user scrolls.
|
|
30278
|
+
// The input value will still change on scroll.
|
|
30279
|
+
const ignoreScroll = e => {
|
|
30280
|
+
e.stopPropagation();
|
|
30281
|
+
};
|
|
30282
|
+
ref == null || ref.addEventListener("wheel", ignoreScroll);
|
|
30283
|
+
return () => {
|
|
30284
|
+
ref == null || ref.removeEventListener("wheel", ignoreScroll);
|
|
30285
|
+
};
|
|
30286
|
+
}, [inputRef]);
|
|
30287
|
+
return /*#__PURE__*/React.createElement(TextField, _extends({
|
|
30288
|
+
type: "number"
|
|
30289
|
+
}, props, {
|
|
30290
|
+
ref: inputRef
|
|
30291
|
+
}));
|
|
30292
|
+
};
|
|
30293
|
+
|
|
30294
|
+
function focusWithChromeStickyFocusBugWorkaround(element) {
|
|
30295
|
+
// NOTE(marksandstrom) Chrome sticky focus bug.
|
|
30296
|
+
//
|
|
30297
|
+
// There is a bug in Chrome related to sticky positioning and
|
|
30298
|
+
// focus: When a child of an element with sticky positioning is
|
|
30299
|
+
// focused with the focus() method, the scrollable area
|
|
30300
|
+
// containing that element will scroll to the top (even though
|
|
30301
|
+
// the element is already visble on the page). For a dropdown
|
|
30302
|
+
// this means that the area will be scrolled to the top when
|
|
30303
|
+
// the user interacts with the dropdown (since we actively
|
|
30304
|
+
// manage dropdown header and option focus for keyboard users).
|
|
30305
|
+
//
|
|
30306
|
+
// To work around this bug the `preventScroll` focus option is
|
|
30307
|
+
// used.
|
|
30308
|
+
//
|
|
30309
|
+
// Using `focusOptions` is an experimental browser feature
|
|
30310
|
+
// "that should not be used in production code". However, since
|
|
30311
|
+
// Chrome is the only browser we support that exhibits this
|
|
30312
|
+
// buggy behavior and using `focusOptions` works around the
|
|
30313
|
+
// bug, it is perfectly reasonable to use the feature in this
|
|
30314
|
+
// case. We are not relying on the effect of the
|
|
30315
|
+
// `preventScroll` option otherwise.
|
|
30316
|
+
//
|
|
30317
|
+
// focusOptions documentation:
|
|
30318
|
+
//
|
|
30319
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
|
|
30320
|
+
//
|
|
30321
|
+
// Note that there could be cases where we want default focus() behavior.
|
|
30322
|
+
// One that comes to mind is a dropdown with a long list of options that
|
|
30323
|
+
// might be rendered off screen when opened. With this workaround the
|
|
30324
|
+
// selected option would not be scrolled into view if the option is near
|
|
30325
|
+
// the end of the list. We're not aware of any uses of the dropdown where
|
|
30326
|
+
// this is an issue, however, so there isn't currently a way to out of the
|
|
30327
|
+
// `preventScroll` behavior.
|
|
30328
|
+
|
|
30329
|
+
// @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'Element'.
|
|
30330
|
+
element.focus({
|
|
30331
|
+
preventScroll: true
|
|
30332
|
+
});
|
|
30333
|
+
}
|
|
30334
|
+
function degreeToRadian(degrees) {
|
|
30335
|
+
return degrees / 180 * Math.PI;
|
|
30336
|
+
}
|
|
30337
|
+
function radianToDegree(radians) {
|
|
30338
|
+
return radians / Math.PI * 180;
|
|
30339
|
+
}
|
|
30340
|
+
|
|
30341
|
+
const AngleInput = props => {
|
|
30342
|
+
const {
|
|
30343
|
+
angle,
|
|
30344
|
+
onChange
|
|
30345
|
+
} = props;
|
|
30346
|
+
const [angleInput, setAngleInput] = React.useState(radianToDegree(angle).toString());
|
|
30347
|
+
function handleAngleChange(newValue) {
|
|
30348
|
+
// Update the local state (update the input field value).
|
|
30349
|
+
setAngleInput(newValue);
|
|
30350
|
+
|
|
30351
|
+
// If the new value is not a number, don't update the props.
|
|
30352
|
+
// If it's empty, keep the props the same value instead of setting to 0.
|
|
30353
|
+
if (isNaN(+newValue) || newValue === "") {
|
|
30354
|
+
return;
|
|
30355
|
+
}
|
|
30356
|
+
|
|
30357
|
+
// Update the graph.
|
|
30358
|
+
onChange(degreeToRadian(newValue));
|
|
30359
|
+
}
|
|
30360
|
+
return /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30361
|
+
tag: "label",
|
|
30362
|
+
style: styles$B.row
|
|
30363
|
+
}, "angle (degrees)", /*#__PURE__*/React.createElement(Strut, {
|
|
30364
|
+
size: spacing.xxSmall_6
|
|
30365
|
+
}), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
|
|
30366
|
+
value: angleInput,
|
|
30367
|
+
onChange: handleAngleChange,
|
|
30368
|
+
style: styles$B.textField
|
|
30369
|
+
}), /*#__PURE__*/React.createElement(Strut, {
|
|
30370
|
+
size: spacing.xxSmall_6
|
|
30371
|
+
}));
|
|
30372
|
+
};
|
|
30373
|
+
const styles$B = StyleSheet.create({
|
|
30374
|
+
row: {
|
|
30375
|
+
display: "flex",
|
|
30376
|
+
flexDirection: "row",
|
|
30377
|
+
alignItems: "center"
|
|
30378
|
+
},
|
|
30379
|
+
textField: {
|
|
30380
|
+
width: spacing.xxxLarge_64
|
|
30381
|
+
}
|
|
30382
|
+
});
|
|
30383
|
+
|
|
30384
|
+
const CoordinatePairInput = props => {
|
|
30385
|
+
const {
|
|
30386
|
+
coord,
|
|
30387
|
+
labels,
|
|
30388
|
+
error,
|
|
29923
30389
|
style,
|
|
29924
30390
|
onChange
|
|
29925
30391
|
} = props;
|
|
@@ -29953,30 +30419,30 @@ const CoordinatePairInput = props => {
|
|
|
29953
30419
|
onChange(newCoords);
|
|
29954
30420
|
}
|
|
29955
30421
|
return /*#__PURE__*/React.createElement(View, {
|
|
29956
|
-
style: [styles$
|
|
30422
|
+
style: [styles$A.row, style]
|
|
29957
30423
|
}, /*#__PURE__*/React.createElement(LabelMedium, {
|
|
29958
30424
|
tag: "label",
|
|
29959
|
-
style: styles$
|
|
30425
|
+
style: styles$A.row
|
|
29960
30426
|
}, labels ? labels[0] : "x coord", /*#__PURE__*/React.createElement(Strut, {
|
|
29961
30427
|
size: spacing.xxSmall_6
|
|
29962
30428
|
}), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
|
|
29963
30429
|
value: coordState[0],
|
|
29964
30430
|
onChange: newValue => handleCoordChange(newValue, 0),
|
|
29965
|
-
style: [styles$
|
|
30431
|
+
style: [styles$A.textField, error ? styles$A.errorField : undefined]
|
|
29966
30432
|
})), /*#__PURE__*/React.createElement(Strut, {
|
|
29967
30433
|
size: spacing.medium_16
|
|
29968
30434
|
}), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
29969
30435
|
tag: "label",
|
|
29970
|
-
style: styles$
|
|
30436
|
+
style: styles$A.row
|
|
29971
30437
|
}, labels ? labels[1] : "y coord", /*#__PURE__*/React.createElement(Strut, {
|
|
29972
30438
|
size: spacing.xxSmall_6
|
|
29973
30439
|
}), /*#__PURE__*/React.createElement(ScrolllessNumberTextField, {
|
|
29974
30440
|
value: coordState[1],
|
|
29975
30441
|
onChange: newValue => handleCoordChange(newValue, 1),
|
|
29976
|
-
style: [styles$
|
|
30442
|
+
style: [styles$A.textField, error ? styles$A.errorField : undefined]
|
|
29977
30443
|
})));
|
|
29978
30444
|
};
|
|
29979
|
-
const styles$
|
|
30445
|
+
const styles$A = StyleSheet.create({
|
|
29980
30446
|
row: {
|
|
29981
30447
|
display: "flex",
|
|
29982
30448
|
flexDirection: "row",
|
|
@@ -30009,14 +30475,14 @@ const PerseusEditorAccordion = props => {
|
|
|
30009
30475
|
}, /*#__PURE__*/React.createElement(AccordionSection, {
|
|
30010
30476
|
expanded: expanded,
|
|
30011
30477
|
onToggle: onToggle,
|
|
30012
|
-
style: [styles$
|
|
30013
|
-
headerStyle: styles$
|
|
30478
|
+
style: [styles$z.container, containerStyle],
|
|
30479
|
+
headerStyle: styles$z.accordionHeader,
|
|
30014
30480
|
header: header
|
|
30015
30481
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30016
|
-
style: [styles$
|
|
30482
|
+
style: [styles$z.accordionPanel, panelStyle]
|
|
30017
30483
|
}, children)));
|
|
30018
30484
|
};
|
|
30019
|
-
const styles$
|
|
30485
|
+
const styles$z = StyleSheet.create({
|
|
30020
30486
|
container: {
|
|
30021
30487
|
backgroundColor: color.fadedBlue8,
|
|
30022
30488
|
marginTop: spacing.xSmall_8
|
|
@@ -30047,13 +30513,13 @@ const ColorSwatch = props => {
|
|
|
30047
30513
|
"aria-label":
|
|
30048
30514
|
// Don't include an aria label for decorative circles.
|
|
30049
30515
|
!decorative ? `${color$1}, ${filled ? "filled" : "open"}` : undefined,
|
|
30050
|
-
style: [styles$
|
|
30516
|
+
style: [styles$y.colorSwatch, {
|
|
30051
30517
|
border: `4px solid ${lockedFigureColors[color$1]}`,
|
|
30052
30518
|
backgroundColor: filled ? lockedFigureColors[color$1] : color.white
|
|
30053
30519
|
}]
|
|
30054
30520
|
});
|
|
30055
30521
|
};
|
|
30056
|
-
const styles$
|
|
30522
|
+
const styles$y = StyleSheet.create({
|
|
30057
30523
|
colorSwatch: {
|
|
30058
30524
|
// Add a white outline so that the color swatch is visible when
|
|
30059
30525
|
// the dropdown option is highlighted with its blue background.
|
|
@@ -30072,10 +30538,10 @@ const ColorSelect = props => {
|
|
|
30072
30538
|
onChange
|
|
30073
30539
|
} = props;
|
|
30074
30540
|
return /*#__PURE__*/React.createElement(View, {
|
|
30075
|
-
style: [styles$
|
|
30541
|
+
style: [styles$x.row, style]
|
|
30076
30542
|
}, /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30077
30543
|
tag: "label",
|
|
30078
|
-
style: styles$
|
|
30544
|
+
style: styles$x.row
|
|
30079
30545
|
}, "color", /*#__PURE__*/React.createElement(Strut, {
|
|
30080
30546
|
size: spacing.xxSmall_6
|
|
30081
30547
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -30094,7 +30560,7 @@ const ColorSelect = props => {
|
|
|
30094
30560
|
})
|
|
30095
30561
|
})))));
|
|
30096
30562
|
};
|
|
30097
|
-
const styles$
|
|
30563
|
+
const styles$x = StyleSheet.create({
|
|
30098
30564
|
row: {
|
|
30099
30565
|
display: "flex",
|
|
30100
30566
|
flexDirection: "row",
|
|
@@ -30113,17 +30579,17 @@ const EllipseSwatch = props => {
|
|
|
30113
30579
|
} = props;
|
|
30114
30580
|
return /*#__PURE__*/React.createElement(View, {
|
|
30115
30581
|
"aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
|
|
30116
|
-
style: [styles$
|
|
30582
|
+
style: [styles$w.container, {
|
|
30117
30583
|
border: `4px ${strokeStyle} ${lockedFigureColors[color]}`
|
|
30118
30584
|
}]
|
|
30119
30585
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30120
|
-
style: [styles$
|
|
30586
|
+
style: [styles$w.innerCircle, {
|
|
30121
30587
|
backgroundColor: lockedFigureColors[color],
|
|
30122
30588
|
opacity: fillStyle === "white" ? 0 : lockedFigureFillStyles[fillStyle]
|
|
30123
30589
|
}]
|
|
30124
30590
|
}));
|
|
30125
30591
|
};
|
|
30126
|
-
const styles$
|
|
30592
|
+
const styles$w = StyleSheet.create({
|
|
30127
30593
|
container: {
|
|
30128
30594
|
// Add a white outline so that the color swatch is visible when
|
|
30129
30595
|
// the dropdown option is highlighted with its blue background.
|
|
@@ -30149,7 +30615,7 @@ const LineStrokeSelect = props => {
|
|
|
30149
30615
|
} = props;
|
|
30150
30616
|
return /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30151
30617
|
tag: "label",
|
|
30152
|
-
style: styles$
|
|
30618
|
+
style: styles$v.lineStrokeSelect
|
|
30153
30619
|
}, "stroke", /*#__PURE__*/React.createElement(Strut, {
|
|
30154
30620
|
size: spacing.xxxSmall_4
|
|
30155
30621
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -30166,7 +30632,7 @@ const LineStrokeSelect = props => {
|
|
|
30166
30632
|
label: "dashed"
|
|
30167
30633
|
})));
|
|
30168
30634
|
};
|
|
30169
|
-
const styles$
|
|
30635
|
+
const styles$v = StyleSheet.create({
|
|
30170
30636
|
lineStrokeSelect: {
|
|
30171
30637
|
display: "flex",
|
|
30172
30638
|
flexDirection: "row",
|
|
@@ -30188,40 +30654,40 @@ const LockedFigureSettingsActions = props => {
|
|
|
30188
30654
|
onRemove
|
|
30189
30655
|
} = props;
|
|
30190
30656
|
return /*#__PURE__*/React.createElement(View, {
|
|
30191
|
-
style: styles$
|
|
30657
|
+
style: styles$u.container
|
|
30192
30658
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
30193
30659
|
startIcon: trashIcon,
|
|
30194
30660
|
"aria-label": `Delete locked ${figureType}`,
|
|
30195
30661
|
onClick: onRemove,
|
|
30196
30662
|
kind: "tertiary",
|
|
30197
|
-
style: styles$
|
|
30198
|
-
}, "Delete"), /*#__PURE__*/React.createElement(Spring, null), /*#__PURE__*/React.createElement(IconButton, {
|
|
30663
|
+
style: styles$u.deleteButton
|
|
30664
|
+
}, "Delete"), onMove && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Spring, null), /*#__PURE__*/React.createElement(IconButton, {
|
|
30199
30665
|
icon: caretDoubleUpIcon,
|
|
30200
30666
|
size: "small",
|
|
30201
30667
|
"aria-label": `Move locked ${figureType} to the back`,
|
|
30202
30668
|
onClick: () => onMove("back"),
|
|
30203
|
-
style: styles$
|
|
30669
|
+
style: styles$u.iconButton
|
|
30204
30670
|
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
30205
30671
|
icon: caretUpIcon,
|
|
30206
30672
|
size: "small",
|
|
30207
30673
|
"aria-label": `Move locked ${figureType} backward`,
|
|
30208
30674
|
onClick: () => onMove("backward"),
|
|
30209
|
-
style: styles$
|
|
30675
|
+
style: styles$u.iconButton
|
|
30210
30676
|
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
30211
30677
|
icon: caretDownIcon,
|
|
30212
30678
|
size: "small",
|
|
30213
30679
|
"aria-label": `Move locked ${figureType} forward`,
|
|
30214
30680
|
onClick: () => onMove("forward"),
|
|
30215
|
-
style: styles$
|
|
30681
|
+
style: styles$u.iconButton
|
|
30216
30682
|
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
30217
30683
|
icon: caretDoubleDownIcon,
|
|
30218
30684
|
size: "small",
|
|
30219
30685
|
"aria-label": `Move locked ${figureType} to the front`,
|
|
30220
30686
|
onClick: () => onMove("front"),
|
|
30221
|
-
style: styles$
|
|
30222
|
-
}));
|
|
30687
|
+
style: styles$u.iconButton
|
|
30688
|
+
})));
|
|
30223
30689
|
};
|
|
30224
|
-
const styles$
|
|
30690
|
+
const styles$u = StyleSheet.create({
|
|
30225
30691
|
container: {
|
|
30226
30692
|
width: "100%",
|
|
30227
30693
|
flexDirection: "row",
|
|
@@ -30240,7 +30706,7 @@ const styles$z = StyleSheet.create({
|
|
|
30240
30706
|
});
|
|
30241
30707
|
|
|
30242
30708
|
const {
|
|
30243
|
-
InfoTip: InfoTip$
|
|
30709
|
+
InfoTip: InfoTip$c
|
|
30244
30710
|
} = components;
|
|
30245
30711
|
const LockedEllipseSettings = props => {
|
|
30246
30712
|
const {
|
|
@@ -30268,7 +30734,7 @@ const LockedEllipseSettings = props => {
|
|
|
30268
30734
|
/*#__PURE__*/
|
|
30269
30735
|
// Summary: Ellipse, center, radius, color (opacity, dashed)
|
|
30270
30736
|
React.createElement(View, {
|
|
30271
|
-
style: styles$
|
|
30737
|
+
style: styles$t.row
|
|
30272
30738
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`), /*#__PURE__*/React.createElement(Strut, {
|
|
30273
30739
|
size: spacing.xSmall_8
|
|
30274
30740
|
}), /*#__PURE__*/React.createElement(EllipseSwatch, {
|
|
@@ -30277,19 +30743,19 @@ const LockedEllipseSettings = props => {
|
|
|
30277
30743
|
strokeStyle: strokeStyle
|
|
30278
30744
|
}))
|
|
30279
30745
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30280
|
-
style: styles$
|
|
30746
|
+
style: styles$t.row
|
|
30281
30747
|
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
30282
30748
|
coord: center,
|
|
30283
|
-
style: styles$
|
|
30749
|
+
style: styles$t.spaceUnder,
|
|
30284
30750
|
onChange: newCoords => onChangeProps({
|
|
30285
30751
|
center: newCoords
|
|
30286
30752
|
})
|
|
30287
30753
|
}), /*#__PURE__*/React.createElement(View, {
|
|
30288
|
-
style: styles$
|
|
30289
|
-
}, /*#__PURE__*/React.createElement(InfoTip$
|
|
30754
|
+
style: styles$t.spaceUnder
|
|
30755
|
+
}, /*#__PURE__*/React.createElement(InfoTip$c, null, "The coordinates for the center of the ellipse."))), /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
30290
30756
|
coord: radius,
|
|
30291
30757
|
labels: ["x radius", "y radius"],
|
|
30292
|
-
style: styles$
|
|
30758
|
+
style: styles$t.spaceUnder,
|
|
30293
30759
|
onChange: newCoords => onChangeProps({
|
|
30294
30760
|
radius: newCoords
|
|
30295
30761
|
})
|
|
@@ -30301,7 +30767,7 @@ const LockedEllipseSettings = props => {
|
|
|
30301
30767
|
}), /*#__PURE__*/React.createElement(Strut, {
|
|
30302
30768
|
size: spacing.xSmall_8
|
|
30303
30769
|
}), /*#__PURE__*/React.createElement(View, {
|
|
30304
|
-
style: [styles$
|
|
30770
|
+
style: [styles$t.row, styles$t.spaceUnder]
|
|
30305
30771
|
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
30306
30772
|
selectedValue: color,
|
|
30307
30773
|
onChange: handleColorChange
|
|
@@ -30309,7 +30775,7 @@ const LockedEllipseSettings = props => {
|
|
|
30309
30775
|
size: spacing.medium_16
|
|
30310
30776
|
}), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30311
30777
|
tag: "label",
|
|
30312
|
-
style: [styles$
|
|
30778
|
+
style: [styles$t.row, styles$t.truncatedWidth]
|
|
30313
30779
|
}, "fill", /*#__PURE__*/React.createElement(Strut, {
|
|
30314
30780
|
size: spacing.xxSmall_6
|
|
30315
30781
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -30335,7 +30801,7 @@ const LockedEllipseSettings = props => {
|
|
|
30335
30801
|
onRemove: onRemove
|
|
30336
30802
|
}));
|
|
30337
30803
|
};
|
|
30338
|
-
const styles$
|
|
30804
|
+
const styles$t = StyleSheet.create({
|
|
30339
30805
|
row: {
|
|
30340
30806
|
display: "flex",
|
|
30341
30807
|
flexDirection: "row",
|
|
@@ -30356,15 +30822,15 @@ const LineSwatch = props => {
|
|
|
30356
30822
|
lineStyle
|
|
30357
30823
|
} = props;
|
|
30358
30824
|
return /*#__PURE__*/React.createElement(View, {
|
|
30359
|
-
style: styles$
|
|
30825
|
+
style: styles$s.container
|
|
30360
30826
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30361
30827
|
"aria-label": `${color}, ${lineStyle}`,
|
|
30362
|
-
style: [styles$
|
|
30828
|
+
style: [styles$s.lineSwatch, {
|
|
30363
30829
|
border: `5px ${lineStyle} ${lockedFigureColors[color]}`
|
|
30364
30830
|
}]
|
|
30365
30831
|
}));
|
|
30366
30832
|
};
|
|
30367
|
-
const styles$
|
|
30833
|
+
const styles$s = StyleSheet.create({
|
|
30368
30834
|
container: {
|
|
30369
30835
|
backgroundColor: color.white,
|
|
30370
30836
|
justifyContent: "center",
|
|
@@ -30449,9 +30915,9 @@ const LockedFunctionSettings = props => {
|
|
|
30449
30915
|
expanded: props.expanded,
|
|
30450
30916
|
onToggle: props.onToggle,
|
|
30451
30917
|
header: /*#__PURE__*/React.createElement(View, {
|
|
30452
|
-
style: styles$
|
|
30918
|
+
style: styles$r.row
|
|
30453
30919
|
}, /*#__PURE__*/React.createElement(LabelLarge, {
|
|
30454
|
-
style: styles$
|
|
30920
|
+
style: styles$r.accordionHeader
|
|
30455
30921
|
}, lineLabel), /*#__PURE__*/React.createElement(Strut, {
|
|
30456
30922
|
size: spacing.xSmall_8
|
|
30457
30923
|
}), /*#__PURE__*/React.createElement(LineSwatch, {
|
|
@@ -30459,7 +30925,7 @@ const LockedFunctionSettings = props => {
|
|
|
30459
30925
|
lineStyle: strokeStyle
|
|
30460
30926
|
}))
|
|
30461
30927
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30462
|
-
style: [styles$
|
|
30928
|
+
style: [styles$r.row, styles$r.spaceUnder]
|
|
30463
30929
|
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
30464
30930
|
selectedValue: lineColor,
|
|
30465
30931
|
onChange: newValue => {
|
|
@@ -30473,14 +30939,14 @@ const LockedFunctionSettings = props => {
|
|
|
30473
30939
|
handlePropChange("strokeStyle", newValue);
|
|
30474
30940
|
}
|
|
30475
30941
|
})), /*#__PURE__*/React.createElement(View, {
|
|
30476
|
-
style: [styles$
|
|
30942
|
+
style: [styles$r.row, styles$r.rowSpace]
|
|
30477
30943
|
}, /*#__PURE__*/React.createElement(SingleSelect, {
|
|
30478
30944
|
selectedValue: directionalAxis,
|
|
30479
30945
|
onChange: newValue => {
|
|
30480
30946
|
handlePropChange("directionalAxis", newValue);
|
|
30481
30947
|
},
|
|
30482
30948
|
"aria-label": "equation prefix",
|
|
30483
|
-
style: [styles$
|
|
30949
|
+
style: [styles$r.dropdownLabel, styles$r.axisMenu]
|
|
30484
30950
|
// Placeholder is required, but never gets used.
|
|
30485
30951
|
,
|
|
30486
30952
|
placeholder: ""
|
|
@@ -30499,17 +30965,17 @@ const LockedFunctionSettings = props => {
|
|
|
30499
30965
|
onChange: newValue => {
|
|
30500
30966
|
handlePropChange("equation", newValue);
|
|
30501
30967
|
},
|
|
30502
|
-
style: [styles$
|
|
30968
|
+
style: [styles$r.textField]
|
|
30503
30969
|
})), /*#__PURE__*/React.createElement(View, {
|
|
30504
|
-
style: [styles$
|
|
30970
|
+
style: [styles$r.row, styles$r.rowSpace]
|
|
30505
30971
|
}, /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30506
30972
|
tag: "label",
|
|
30507
|
-
style: [styles$
|
|
30973
|
+
style: [styles$r.dropdownLabel, styles$r.domainMin]
|
|
30508
30974
|
}, `${domainRangeText} min`, /*#__PURE__*/React.createElement(Strut, {
|
|
30509
30975
|
size: spacing.xxSmall_6
|
|
30510
30976
|
}), /*#__PURE__*/React.createElement(TextField, {
|
|
30511
30977
|
type: "number",
|
|
30512
|
-
style: styles$
|
|
30978
|
+
style: styles$r.domainMinField,
|
|
30513
30979
|
value: domainEntries[0],
|
|
30514
30980
|
onChange: newValue => {
|
|
30515
30981
|
handleDomainChange(0, newValue);
|
|
@@ -30519,12 +30985,12 @@ const LockedFunctionSettings = props => {
|
|
|
30519
30985
|
}), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30520
30986
|
tag: "label",
|
|
30521
30987
|
"aria-label": `${domainRangeText} max`,
|
|
30522
|
-
style: [styles$
|
|
30988
|
+
style: [styles$r.dropdownLabel, styles$r.domainMax]
|
|
30523
30989
|
}, "max", /*#__PURE__*/React.createElement(Strut, {
|
|
30524
30990
|
size: spacing.xxSmall_6
|
|
30525
30991
|
}), /*#__PURE__*/React.createElement(TextField, {
|
|
30526
30992
|
type: "number",
|
|
30527
|
-
style: styles$
|
|
30993
|
+
style: styles$r.domainMaxField,
|
|
30528
30994
|
value: domainEntries[1],
|
|
30529
30995
|
onChange: newValue => {
|
|
30530
30996
|
handleDomainChange(1, newValue);
|
|
@@ -30532,11 +30998,11 @@ const LockedFunctionSettings = props => {
|
|
|
30532
30998
|
}))), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
30533
30999
|
header: /*#__PURE__*/React.createElement(LabelLarge, null, "Example Functions"),
|
|
30534
31000
|
expanded: false,
|
|
30535
|
-
containerStyle: styles$
|
|
30536
|
-
panelStyle: styles$
|
|
31001
|
+
containerStyle: styles$r.exampleWorkspace,
|
|
31002
|
+
panelStyle: styles$r.exampleAccordionPanel
|
|
30537
31003
|
}, /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30538
31004
|
tag: "label",
|
|
30539
|
-
style: styles$
|
|
31005
|
+
style: styles$r.dropdownLabel
|
|
30540
31006
|
}, "Choose a category", /*#__PURE__*/React.createElement(Strut, {
|
|
30541
31007
|
size: spacing.xxSmall_6
|
|
30542
31008
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -30550,7 +31016,7 @@ const LockedFunctionSettings = props => {
|
|
|
30550
31016
|
label: category
|
|
30551
31017
|
});
|
|
30552
31018
|
}))), exampleCategorySelected && /*#__PURE__*/React.createElement("ul", {
|
|
30553
|
-
className: css(styles$
|
|
31019
|
+
className: css(styles$r.exampleContainer)
|
|
30554
31020
|
}, exampleContent.map((example, index) => /*#__PURE__*/React.createElement(ExampleItem, {
|
|
30555
31021
|
category: exampleCategory,
|
|
30556
31022
|
example: example,
|
|
@@ -30572,29 +31038,29 @@ const ExampleItem = props => {
|
|
|
30572
31038
|
const exampleId = useId();
|
|
30573
31039
|
return /*#__PURE__*/React.createElement("li", {
|
|
30574
31040
|
key: `${category}-${index}`,
|
|
30575
|
-
className: css(styles$
|
|
31041
|
+
className: css(styles$r.exampleRow)
|
|
30576
31042
|
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
30577
31043
|
icon: autoPasteIcon,
|
|
30578
31044
|
"aria-label": "paste example",
|
|
30579
31045
|
"aria-describedby": exampleId,
|
|
30580
31046
|
onClick: () => pasteEquationFn("equation", example),
|
|
30581
31047
|
size: "medium",
|
|
30582
|
-
style: styles$
|
|
31048
|
+
style: styles$r.copyPasteButton
|
|
30583
31049
|
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
30584
31050
|
icon: copyIcon,
|
|
30585
31051
|
"aria-label": "copy example",
|
|
30586
31052
|
"aria-describedby": exampleId,
|
|
30587
31053
|
onClick: () => navigator.clipboard.writeText(example),
|
|
30588
31054
|
size: "medium",
|
|
30589
|
-
style: styles$
|
|
31055
|
+
style: styles$r.copyPasteButton
|
|
30590
31056
|
}), /*#__PURE__*/React.createElement(Strut, {
|
|
30591
31057
|
size: spacing.xxxSmall_4
|
|
30592
31058
|
}), /*#__PURE__*/React.createElement(View, {
|
|
30593
|
-
style: styles$
|
|
31059
|
+
style: styles$r.exampleContent,
|
|
30594
31060
|
id: exampleId
|
|
30595
31061
|
}, example));
|
|
30596
31062
|
};
|
|
30597
|
-
const styles$
|
|
31063
|
+
const styles$r = StyleSheet.create({
|
|
30598
31064
|
accordionHeader: {
|
|
30599
31065
|
textOverflow: "ellipsis",
|
|
30600
31066
|
// A maximum width needs to be specified in order for the ellipsis to work.
|
|
@@ -30712,15 +31178,16 @@ function LockedLabelSettings(props) {
|
|
|
30712
31178
|
expanded: expanded,
|
|
30713
31179
|
onToggle: onToggle,
|
|
30714
31180
|
header: /*#__PURE__*/React.createElement(View, {
|
|
30715
|
-
style: [styles$
|
|
31181
|
+
style: [styles$q.row, styles$q.accordionHeaderContainer]
|
|
30716
31182
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, "Label (", coord[0], ", ", coord[1], ")"), /*#__PURE__*/React.createElement(Strut, {
|
|
30717
31183
|
size: spacing.xSmall_8
|
|
30718
31184
|
}), text !== "" && /*#__PURE__*/React.createElement(LabelLarge, {
|
|
30719
31185
|
style: [{
|
|
30720
31186
|
backgroundColor: color.white,
|
|
30721
31187
|
color: lockedFigureColors[color$1]
|
|
30722
|
-
}, styles$
|
|
30723
|
-
}, text))
|
|
31188
|
+
}, styles$q.accordionHeader]
|
|
31189
|
+
}, text)),
|
|
31190
|
+
containerStyle: !onMove && styles$q.innerLabelAccordionPanel
|
|
30724
31191
|
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
30725
31192
|
coord: coord,
|
|
30726
31193
|
onChange: newCoords => {
|
|
@@ -30728,10 +31195,10 @@ function LockedLabelSettings(props) {
|
|
|
30728
31195
|
coord: newCoords
|
|
30729
31196
|
});
|
|
30730
31197
|
},
|
|
30731
|
-
style: styles$
|
|
31198
|
+
style: styles$q.spaceUnder
|
|
30732
31199
|
}), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30733
31200
|
tag: "label",
|
|
30734
|
-
style: [styles$
|
|
31201
|
+
style: [styles$q.row, styles$q.spaceUnder]
|
|
30735
31202
|
}, "TeX", /*#__PURE__*/React.createElement(Strut, {
|
|
30736
31203
|
size: spacing.xSmall_8
|
|
30737
31204
|
}), /*#__PURE__*/React.createElement(TextField, {
|
|
@@ -30741,20 +31208,20 @@ function LockedLabelSettings(props) {
|
|
|
30741
31208
|
text: newValue
|
|
30742
31209
|
})
|
|
30743
31210
|
})), /*#__PURE__*/React.createElement(View, {
|
|
30744
|
-
style: styles$
|
|
30745
|
-
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
31211
|
+
style: styles$q.row
|
|
31212
|
+
}, onMove && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
30746
31213
|
selectedValue: color$1,
|
|
30747
31214
|
onChange: newColor => {
|
|
30748
31215
|
onChangeProps({
|
|
30749
31216
|
color: newColor
|
|
30750
31217
|
});
|
|
30751
31218
|
},
|
|
30752
|
-
style: styles$
|
|
31219
|
+
style: styles$q.spaceUnder
|
|
30753
31220
|
}), /*#__PURE__*/React.createElement(Strut, {
|
|
30754
31221
|
size: spacing.medium_16
|
|
30755
|
-
}), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
31222
|
+
})), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30756
31223
|
tag: "label",
|
|
30757
|
-
style: styles$
|
|
31224
|
+
style: styles$q.row
|
|
30758
31225
|
}, "size", /*#__PURE__*/React.createElement(Strut, {
|
|
30759
31226
|
size: spacing.xSmall_8
|
|
30760
31227
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -30781,7 +31248,7 @@ function LockedLabelSettings(props) {
|
|
|
30781
31248
|
onRemove: onRemove
|
|
30782
31249
|
}));
|
|
30783
31250
|
}
|
|
30784
|
-
const styles$
|
|
31251
|
+
const styles$q = StyleSheet.create({
|
|
30785
31252
|
accordionHeaderContainer: {
|
|
30786
31253
|
// Stop the label summary from wrapping.
|
|
30787
31254
|
whiteSpace: "nowrap"
|
|
@@ -30802,6 +31269,9 @@ const styles$v = StyleSheet.create({
|
|
|
30802
31269
|
},
|
|
30803
31270
|
spaceUnder: {
|
|
30804
31271
|
marginBottom: spacing.xSmall_8
|
|
31272
|
+
},
|
|
31273
|
+
innerLabelAccordionPanel: {
|
|
31274
|
+
backgroundColor: color.white
|
|
30805
31275
|
}
|
|
30806
31276
|
});
|
|
30807
31277
|
|
|
@@ -30815,7 +31285,7 @@ const LabeledSwitch = props => {
|
|
|
30815
31285
|
const ids = useUniqueIdWithMock();
|
|
30816
31286
|
const switchId = ids.get("switch");
|
|
30817
31287
|
return /*#__PURE__*/React.createElement(View, {
|
|
30818
|
-
style: [styles$
|
|
31288
|
+
style: [styles$p.row, style]
|
|
30819
31289
|
}, /*#__PURE__*/React.createElement(Switch, {
|
|
30820
31290
|
id: switchId,
|
|
30821
31291
|
checked: checked,
|
|
@@ -30827,7 +31297,7 @@ const LabeledSwitch = props => {
|
|
|
30827
31297
|
htmlFor: switchId
|
|
30828
31298
|
}, label));
|
|
30829
31299
|
};
|
|
30830
|
-
const styles$
|
|
31300
|
+
const styles$p = StyleSheet.create({
|
|
30831
31301
|
row: {
|
|
30832
31302
|
flexDirection: "row",
|
|
30833
31303
|
alignItems: "center"
|
|
@@ -30861,13 +31331,13 @@ const DefiningPointSettings = props => {
|
|
|
30861
31331
|
return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
30862
31332
|
expanded: expanded,
|
|
30863
31333
|
onToggle: onToggle,
|
|
30864
|
-
containerStyle: styles$
|
|
30865
|
-
panelStyle: styles$
|
|
31334
|
+
containerStyle: styles$o.container,
|
|
31335
|
+
panelStyle: styles$o.accordionPanel,
|
|
30866
31336
|
header:
|
|
30867
31337
|
/*#__PURE__*/
|
|
30868
31338
|
// Summary: Point, coords, color (filled/open)
|
|
30869
31339
|
React.createElement(View, {
|
|
30870
|
-
style: styles$
|
|
31340
|
+
style: styles$o.row
|
|
30871
31341
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, `${label || "Point"} (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React.createElement(Strut, {
|
|
30872
31342
|
size: spacing.xSmall_8
|
|
30873
31343
|
}), showPoint && /*#__PURE__*/React.createElement(ColorSwatch, {
|
|
@@ -30877,7 +31347,7 @@ const DefiningPointSettings = props => {
|
|
|
30877
31347
|
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
30878
31348
|
coord: coord,
|
|
30879
31349
|
error: !!error,
|
|
30880
|
-
style: styles$
|
|
31350
|
+
style: styles$o.spaceUnder,
|
|
30881
31351
|
onChange: newCoords => {
|
|
30882
31352
|
onChangeProps({
|
|
30883
31353
|
coord: newCoords
|
|
@@ -30886,12 +31356,12 @@ const DefiningPointSettings = props => {
|
|
|
30886
31356
|
}), onTogglePoint && /*#__PURE__*/React.createElement(LabeledSwitch, {
|
|
30887
31357
|
label: "show point on graph",
|
|
30888
31358
|
checked: !!showPoint,
|
|
30889
|
-
style: showPoint && styles$
|
|
31359
|
+
style: showPoint && styles$o.spaceUnder,
|
|
30890
31360
|
onChange: onTogglePoint
|
|
30891
31361
|
}), showPoint && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
30892
31362
|
selectedValue: pointColor,
|
|
30893
31363
|
onChange: handleColorChange,
|
|
30894
|
-
style: styles$
|
|
31364
|
+
style: styles$o.spaceUnder
|
|
30895
31365
|
}), /*#__PURE__*/React.createElement(LabeledSwitch, {
|
|
30896
31366
|
label: "open point",
|
|
30897
31367
|
checked: !filled,
|
|
@@ -30902,7 +31372,7 @@ const DefiningPointSettings = props => {
|
|
|
30902
31372
|
}
|
|
30903
31373
|
})));
|
|
30904
31374
|
};
|
|
30905
|
-
const styles$
|
|
31375
|
+
const styles$o = StyleSheet.create({
|
|
30906
31376
|
container: {
|
|
30907
31377
|
marginTop: spacing.xSmall_8,
|
|
30908
31378
|
marginBottom: 0,
|
|
@@ -30965,7 +31435,7 @@ const LockedLineSettings = props => {
|
|
|
30965
31435
|
expanded: props.expanded,
|
|
30966
31436
|
onToggle: props.onToggle,
|
|
30967
31437
|
header: /*#__PURE__*/React.createElement(View, {
|
|
30968
|
-
style: styles$
|
|
31438
|
+
style: styles$n.row
|
|
30969
31439
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, lineLabel), /*#__PURE__*/React.createElement(Strut, {
|
|
30970
31440
|
size: spacing.xSmall_8
|
|
30971
31441
|
}), /*#__PURE__*/React.createElement(LineSwatch, {
|
|
@@ -30974,7 +31444,7 @@ const LockedLineSettings = props => {
|
|
|
30974
31444
|
}))
|
|
30975
31445
|
}, /*#__PURE__*/React.createElement(LabelMedium, {
|
|
30976
31446
|
tag: "label",
|
|
30977
|
-
style: [styles$
|
|
31447
|
+
style: [styles$n.row, styles$n.spaceUnder]
|
|
30978
31448
|
}, "kind", /*#__PURE__*/React.createElement(Strut, {
|
|
30979
31449
|
size: spacing.xxxSmall_4
|
|
30980
31450
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -30995,7 +31465,7 @@ const LockedLineSettings = props => {
|
|
|
30995
31465
|
value: "segment",
|
|
30996
31466
|
label: "segment"
|
|
30997
31467
|
}))), /*#__PURE__*/React.createElement(View, {
|
|
30998
|
-
style: styles$
|
|
31468
|
+
style: styles$n.row
|
|
30999
31469
|
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
31000
31470
|
selectedValue: lineColor,
|
|
31001
31471
|
onChange: handleColorChange
|
|
@@ -31007,7 +31477,7 @@ const LockedLineSettings = props => {
|
|
|
31007
31477
|
lineStyle: value
|
|
31008
31478
|
})
|
|
31009
31479
|
})), isInvalid && /*#__PURE__*/React.createElement(LabelMedium, {
|
|
31010
|
-
style: styles$
|
|
31480
|
+
style: styles$n.errorText
|
|
31011
31481
|
}, lengthZeroStr), /*#__PURE__*/React.createElement(DefiningPointSettings, _extends({
|
|
31012
31482
|
label: "Point 1",
|
|
31013
31483
|
showPoint: showPoint1,
|
|
@@ -31032,7 +31502,7 @@ const LockedLineSettings = props => {
|
|
|
31032
31502
|
onRemove: onRemove
|
|
31033
31503
|
}));
|
|
31034
31504
|
};
|
|
31035
|
-
const styles$
|
|
31505
|
+
const styles$n = StyleSheet.create({
|
|
31036
31506
|
row: {
|
|
31037
31507
|
display: "flex",
|
|
31038
31508
|
flexDirection: "row",
|
|
@@ -31046,24 +31516,122 @@ const styles$s = StyleSheet.create({
|
|
|
31046
31516
|
}
|
|
31047
31517
|
});
|
|
31048
31518
|
|
|
31049
|
-
|
|
31050
|
-
|
|
31051
|
-
|
|
31052
|
-
|
|
31053
|
-
|
|
31054
|
-
|
|
31519
|
+
const DEFAULT_COLOR = "grayH";
|
|
31520
|
+
function getDefaultFigureForType(type) {
|
|
31521
|
+
switch (type) {
|
|
31522
|
+
case "point":
|
|
31523
|
+
return {
|
|
31524
|
+
type: "point",
|
|
31525
|
+
coord: [0, 0],
|
|
31526
|
+
color: DEFAULT_COLOR,
|
|
31527
|
+
filled: true,
|
|
31528
|
+
labels: []
|
|
31529
|
+
};
|
|
31530
|
+
case "line":
|
|
31531
|
+
return {
|
|
31532
|
+
type: "line",
|
|
31533
|
+
kind: "line",
|
|
31534
|
+
points: [getDefaultFigureForType("point"), _extends({}, getDefaultFigureForType("point"), {
|
|
31535
|
+
coord: [2, 2]
|
|
31536
|
+
})],
|
|
31537
|
+
color: DEFAULT_COLOR,
|
|
31538
|
+
lineStyle: "solid",
|
|
31539
|
+
showPoint1: false,
|
|
31540
|
+
showPoint2: false
|
|
31541
|
+
};
|
|
31542
|
+
case "vector":
|
|
31543
|
+
return {
|
|
31544
|
+
type: "vector",
|
|
31545
|
+
points: [[0, 0], [2, 2]],
|
|
31546
|
+
color: DEFAULT_COLOR
|
|
31547
|
+
};
|
|
31548
|
+
case "ellipse":
|
|
31549
|
+
return {
|
|
31550
|
+
type: "ellipse",
|
|
31551
|
+
center: [0, 0],
|
|
31552
|
+
radius: [1, 1],
|
|
31553
|
+
angle: 0,
|
|
31554
|
+
color: DEFAULT_COLOR,
|
|
31555
|
+
fillStyle: "none",
|
|
31556
|
+
strokeStyle: "solid"
|
|
31557
|
+
};
|
|
31558
|
+
case "polygon":
|
|
31559
|
+
return {
|
|
31560
|
+
type: "polygon",
|
|
31561
|
+
points: [[0, 2], [-1, 0], [1, 0]],
|
|
31562
|
+
color: DEFAULT_COLOR,
|
|
31563
|
+
showVertices: false,
|
|
31564
|
+
fillStyle: "none",
|
|
31565
|
+
strokeStyle: "solid"
|
|
31566
|
+
};
|
|
31567
|
+
case "function":
|
|
31568
|
+
return {
|
|
31569
|
+
type: "function",
|
|
31570
|
+
color: DEFAULT_COLOR,
|
|
31571
|
+
strokeStyle: "solid",
|
|
31572
|
+
equation: "x^2",
|
|
31573
|
+
directionalAxis: "x"
|
|
31574
|
+
};
|
|
31575
|
+
case "label":
|
|
31576
|
+
return {
|
|
31577
|
+
type: "label",
|
|
31578
|
+
coord: [0, 0],
|
|
31579
|
+
text: "",
|
|
31580
|
+
color: DEFAULT_COLOR,
|
|
31581
|
+
size: "medium"
|
|
31582
|
+
};
|
|
31583
|
+
default:
|
|
31584
|
+
throw new UnreachableCaseError(type);
|
|
31585
|
+
}
|
|
31586
|
+
}
|
|
31587
|
+
|
|
31055
31588
|
const LockedPointSettings = props => {
|
|
31589
|
+
var _flags$mafs;
|
|
31056
31590
|
const {
|
|
31591
|
+
flags,
|
|
31057
31592
|
coord,
|
|
31058
31593
|
color: pointColor,
|
|
31059
31594
|
filled = true,
|
|
31595
|
+
labels,
|
|
31060
31596
|
onChangeProps,
|
|
31061
31597
|
onMove,
|
|
31062
31598
|
onRemove
|
|
31063
31599
|
} = props;
|
|
31064
31600
|
function handleColorChange(newValue) {
|
|
31065
|
-
|
|
31601
|
+
const newProps = {
|
|
31602
|
+
color: newValue
|
|
31603
|
+
};
|
|
31604
|
+
|
|
31605
|
+
// Update the color of the all labels to match the point
|
|
31606
|
+
newProps.labels = labels.map(label => _extends({}, label, {
|
|
31066
31607
|
color: newValue
|
|
31608
|
+
}));
|
|
31609
|
+
onChangeProps(newProps);
|
|
31610
|
+
}
|
|
31611
|
+
function handleCoordChange(newCoord) {
|
|
31612
|
+
const xOffset = newCoord[0] - coord[0];
|
|
31613
|
+
const yOffset = newCoord[1] - coord[1];
|
|
31614
|
+
const newProps = {
|
|
31615
|
+
coord: newCoord
|
|
31616
|
+
};
|
|
31617
|
+
|
|
31618
|
+
// Update the coord by the same amount as the point for all labels
|
|
31619
|
+
newProps.labels = labels.map(label => _extends({}, label, {
|
|
31620
|
+
coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
|
|
31621
|
+
}));
|
|
31622
|
+
onChangeProps(newProps);
|
|
31623
|
+
}
|
|
31624
|
+
function handleLabelChange(updatedLabel, labelIndex) {
|
|
31625
|
+
const updatedLabels = [...labels];
|
|
31626
|
+
updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
|
|
31627
|
+
onChangeProps({
|
|
31628
|
+
labels: updatedLabels
|
|
31629
|
+
});
|
|
31630
|
+
}
|
|
31631
|
+
function handleLabelRemove(labelIndex) {
|
|
31632
|
+
const updatedLabels = labels.filter((_, index) => index !== labelIndex);
|
|
31633
|
+
onChangeProps({
|
|
31634
|
+
labels: updatedLabels
|
|
31067
31635
|
});
|
|
31068
31636
|
}
|
|
31069
31637
|
return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
@@ -31073,7 +31641,7 @@ const LockedPointSettings = props => {
|
|
|
31073
31641
|
/*#__PURE__*/
|
|
31074
31642
|
// Summary: Point, coords, color (filled/open)
|
|
31075
31643
|
React.createElement(View, {
|
|
31076
|
-
style: styles$
|
|
31644
|
+
style: styles$m.row
|
|
31077
31645
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Point (${coord[0]}, ${coord[1]})`), /*#__PURE__*/React.createElement(Strut, {
|
|
31078
31646
|
size: spacing.xSmall_8
|
|
31079
31647
|
}), /*#__PURE__*/React.createElement(ColorSwatch, {
|
|
@@ -31082,16 +31650,12 @@ const LockedPointSettings = props => {
|
|
|
31082
31650
|
}))
|
|
31083
31651
|
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
31084
31652
|
coord: coord,
|
|
31085
|
-
style: styles$
|
|
31086
|
-
onChange:
|
|
31087
|
-
onChangeProps({
|
|
31088
|
-
coord: newCoord
|
|
31089
|
-
});
|
|
31090
|
-
}
|
|
31653
|
+
style: styles$m.spaceUnder,
|
|
31654
|
+
onChange: handleCoordChange
|
|
31091
31655
|
}), /*#__PURE__*/React.createElement(ColorSelect, {
|
|
31092
31656
|
selectedValue: pointColor,
|
|
31093
31657
|
onChange: handleColorChange,
|
|
31094
|
-
style: styles$
|
|
31658
|
+
style: styles$m.spaceUnder
|
|
31095
31659
|
}), /*#__PURE__*/React.createElement(LabeledSwitch, {
|
|
31096
31660
|
label: "open point",
|
|
31097
31661
|
checked: !filled,
|
|
@@ -31099,20 +31663,52 @@ const LockedPointSettings = props => {
|
|
|
31099
31663
|
onChangeProps({
|
|
31100
31664
|
filled: !newValue
|
|
31101
31665
|
});
|
|
31666
|
+
},
|
|
31667
|
+
style: styles$m.spaceUnder
|
|
31668
|
+
}), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-point-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
|
|
31669
|
+
expanded: true,
|
|
31670
|
+
onChangeProps: newLabel => {
|
|
31671
|
+
handleLabelChange(newLabel, labelIndex);
|
|
31672
|
+
},
|
|
31673
|
+
onRemove: () => {
|
|
31674
|
+
handleLabelRemove(labelIndex);
|
|
31102
31675
|
}
|
|
31103
|
-
}), /*#__PURE__*/React.createElement(
|
|
31676
|
+
}))), /*#__PURE__*/React.createElement(Button, {
|
|
31677
|
+
kind: "tertiary",
|
|
31678
|
+
startIcon: plusCircle,
|
|
31679
|
+
onClick: () => {
|
|
31680
|
+
const newLabel = _extends({}, getDefaultFigureForType("label"), {
|
|
31681
|
+
// Place the label at the same position
|
|
31682
|
+
// as the point. Add a small offset to
|
|
31683
|
+
// avoid crowding.
|
|
31684
|
+
coord: [coord[0] + 0.5,
|
|
31685
|
+
// Additional offset for each label so
|
|
31686
|
+
// they don't overlap.
|
|
31687
|
+
coord[1] - 1 * (labels == null ? void 0 : labels.length)],
|
|
31688
|
+
// Default to the same color as the point
|
|
31689
|
+
color: pointColor
|
|
31690
|
+
});
|
|
31691
|
+
onChangeProps({
|
|
31692
|
+
labels: [...labels, newLabel]
|
|
31693
|
+
});
|
|
31694
|
+
},
|
|
31695
|
+
style: styles$m.addButton
|
|
31696
|
+
}, "Add visible label")), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
|
|
31104
31697
|
figureType: props.type,
|
|
31105
31698
|
onMove: onMove,
|
|
31106
31699
|
onRemove: onRemove
|
|
31107
31700
|
}));
|
|
31108
31701
|
};
|
|
31109
|
-
const styles$
|
|
31702
|
+
const styles$m = StyleSheet.create({
|
|
31110
31703
|
row: {
|
|
31111
31704
|
flexDirection: "row",
|
|
31112
31705
|
alignItems: "center"
|
|
31113
31706
|
},
|
|
31114
31707
|
spaceUnder: {
|
|
31115
31708
|
marginBottom: spacing.xSmall_8
|
|
31709
|
+
},
|
|
31710
|
+
addButton: {
|
|
31711
|
+
alignSelf: "start"
|
|
31116
31712
|
}
|
|
31117
31713
|
});
|
|
31118
31714
|
|
|
@@ -31124,17 +31720,17 @@ const PolygonSwatch = props => {
|
|
|
31124
31720
|
} = props;
|
|
31125
31721
|
return /*#__PURE__*/React.createElement(View, {
|
|
31126
31722
|
"aria-label": `${color}, stroke ${strokeStyle}, fill ${fillStyle}`,
|
|
31127
|
-
style: [styles$
|
|
31723
|
+
style: [styles$l.container, {
|
|
31128
31724
|
border: `4px ${strokeStyle} ${lockedFigureColors[color]}`
|
|
31129
31725
|
}]
|
|
31130
31726
|
}, /*#__PURE__*/React.createElement(View, {
|
|
31131
|
-
style: [styles$
|
|
31727
|
+
style: [styles$l.innerSquare, {
|
|
31132
31728
|
backgroundColor: lockedFigureColors[color],
|
|
31133
31729
|
opacity: fillStyle === "white" ? 0 : lockedFigureFillStyles[fillStyle]
|
|
31134
31730
|
}]
|
|
31135
31731
|
}));
|
|
31136
31732
|
};
|
|
31137
|
-
const styles$
|
|
31733
|
+
const styles$l = StyleSheet.create({
|
|
31138
31734
|
container: {
|
|
31139
31735
|
// Add a white outline so that the color swatch is visible when
|
|
31140
31736
|
// the dropdown option is highlighted with its blue background.
|
|
@@ -31200,7 +31796,7 @@ const LockedPolygonSettings = props => {
|
|
|
31200
31796
|
/*#__PURE__*/
|
|
31201
31797
|
// Summary: Polygon, number of sides, style swatch
|
|
31202
31798
|
React.createElement(View, {
|
|
31203
|
-
style: styles$
|
|
31799
|
+
style: styles$k.row
|
|
31204
31800
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Polygon, ${points.length} sides`), /*#__PURE__*/React.createElement(Strut, {
|
|
31205
31801
|
size: spacing.xSmall_8
|
|
31206
31802
|
}), /*#__PURE__*/React.createElement(PolygonSwatch, {
|
|
@@ -31209,7 +31805,7 @@ const LockedPolygonSettings = props => {
|
|
|
31209
31805
|
strokeStyle: strokeStyle
|
|
31210
31806
|
}))
|
|
31211
31807
|
}, /*#__PURE__*/React.createElement(View, {
|
|
31212
|
-
style: [styles$
|
|
31808
|
+
style: [styles$k.row, styles$k.spaceUnder]
|
|
31213
31809
|
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
31214
31810
|
selectedValue: color,
|
|
31215
31811
|
onChange: handleColorChange
|
|
@@ -31217,7 +31813,7 @@ const LockedPolygonSettings = props => {
|
|
|
31217
31813
|
size: spacing.medium_16
|
|
31218
31814
|
}), /*#__PURE__*/React.createElement(LabelMedium, {
|
|
31219
31815
|
tag: "label",
|
|
31220
|
-
style: [styles$
|
|
31816
|
+
style: [styles$k.row, styles$k.truncatedWidth]
|
|
31221
31817
|
}, "fill", /*#__PURE__*/React.createElement(Strut, {
|
|
31222
31818
|
size: spacing.xxSmall_6
|
|
31223
31819
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
@@ -31243,17 +31839,17 @@ const LockedPolygonSettings = props => {
|
|
|
31243
31839
|
onChange: newValue => onChangeProps({
|
|
31244
31840
|
showVertices: newValue
|
|
31245
31841
|
}),
|
|
31246
|
-
style: styles$
|
|
31842
|
+
style: styles$k.spaceUnder
|
|
31247
31843
|
}), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
31248
31844
|
header: /*#__PURE__*/React.createElement(LabelLarge, null, "Points"),
|
|
31249
31845
|
expanded: true,
|
|
31250
|
-
containerStyle: styles$
|
|
31251
|
-
panelStyle: styles$
|
|
31846
|
+
containerStyle: styles$k.pointAccordionContainer,
|
|
31847
|
+
panelStyle: styles$k.pointAccordionPanel
|
|
31252
31848
|
}, points.map((point, index) => {
|
|
31253
31849
|
const pointLabel = String.fromCharCode(65 + index);
|
|
31254
31850
|
return /*#__PURE__*/React.createElement(View, {
|
|
31255
31851
|
key: `locked-polygon-point-index-${index}`,
|
|
31256
|
-
style: [styles$
|
|
31852
|
+
style: [styles$k.row, styles$k.spaceUnder]
|
|
31257
31853
|
}, /*#__PURE__*/React.createElement(LabelLarge, null, `${pointLabel}:`), /*#__PURE__*/React.createElement(Strut, {
|
|
31258
31854
|
size: spacing.medium_16
|
|
31259
31855
|
}), /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
@@ -31281,10 +31877,10 @@ const LockedPolygonSettings = props => {
|
|
|
31281
31877
|
points: newPoints
|
|
31282
31878
|
});
|
|
31283
31879
|
},
|
|
31284
|
-
style: styles$
|
|
31880
|
+
style: styles$k.icon
|
|
31285
31881
|
}));
|
|
31286
31882
|
}), /*#__PURE__*/React.createElement(View, {
|
|
31287
|
-
style: [styles$
|
|
31883
|
+
style: [styles$k.row, styles$k.polygonActionsContainer]
|
|
31288
31884
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
31289
31885
|
kind: "tertiary",
|
|
31290
31886
|
startIcon: plusCircle,
|
|
@@ -31294,986 +31890,476 @@ const LockedPolygonSettings = props => {
|
|
|
31294
31890
|
});
|
|
31295
31891
|
}
|
|
31296
31892
|
}, "Add point"), /*#__PURE__*/React.createElement(Spring, null), /*#__PURE__*/React.createElement(View, {
|
|
31297
|
-
style: styles$
|
|
31893
|
+
style: styles$k.movementButtonsContainer
|
|
31298
31894
|
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
31299
31895
|
"aria-label": "Move polygon up",
|
|
31300
|
-
style: styles$
|
|
31896
|
+
style: styles$k.iconButton,
|
|
31301
31897
|
size: "small",
|
|
31302
31898
|
icon: arrowFatUp,
|
|
31303
31899
|
onClick: () => handlePolygonMove("up")
|
|
31304
31900
|
}), /*#__PURE__*/React.createElement(View, {
|
|
31305
|
-
style: styles$
|
|
31306
|
-
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
31307
|
-
"aria-label": "Move polygon left",
|
|
31308
|
-
style: styles$
|
|
31309
|
-
size: "small",
|
|
31310
|
-
icon: arrowFatLeft,
|
|
31311
|
-
onClick: () => handlePolygonMove("left")
|
|
31312
|
-
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
31313
|
-
"aria-label": "Move polygon down",
|
|
31314
|
-
style: styles$
|
|
31315
|
-
size: "small",
|
|
31316
|
-
icon: arrowFatDown,
|
|
31317
|
-
onClick: () => handlePolygonMove("down")
|
|
31318
|
-
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
31319
|
-
"aria-label": "Move polygon right",
|
|
31320
|
-
style: styles$
|
|
31321
|
-
size: "small",
|
|
31322
|
-
icon: arrowFatRight,
|
|
31323
|
-
onClick: () => handlePolygonMove("right")
|
|
31324
|
-
}))))), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
|
|
31325
|
-
figureType: props.type,
|
|
31326
|
-
onMove: onMove,
|
|
31327
|
-
onRemove: onRemove
|
|
31328
|
-
}));
|
|
31329
|
-
};
|
|
31330
|
-
const styles$p = StyleSheet.create({
|
|
31331
|
-
row: {
|
|
31332
|
-
display: "flex",
|
|
31333
|
-
flexDirection: "row",
|
|
31334
|
-
alignItems: "center"
|
|
31335
|
-
},
|
|
31336
|
-
pointAccordionContainer: {
|
|
31337
|
-
backgroundColor: color.white
|
|
31338
|
-
},
|
|
31339
|
-
pointAccordionPanel: {
|
|
31340
|
-
alignItems: "start"
|
|
31341
|
-
},
|
|
31342
|
-
icon: {
|
|
31343
|
-
marginInlineStart: spacing.xxxSmall_4
|
|
31344
|
-
},
|
|
31345
|
-
polygonActionsContainer: {
|
|
31346
|
-
width: "100%"
|
|
31347
|
-
},
|
|
31348
|
-
iconButton: {
|
|
31349
|
-
margin: 0
|
|
31350
|
-
},
|
|
31351
|
-
movementButtonsContainer: {
|
|
31352
|
-
display: "flex",
|
|
31353
|
-
flexDirection: "column",
|
|
31354
|
-
alignItems: "center",
|
|
31355
|
-
minWidth: "fit-content"
|
|
31356
|
-
},
|
|
31357
|
-
spaceUnder: {
|
|
31358
|
-
marginBottom: spacing.xSmall_8
|
|
31359
|
-
},
|
|
31360
|
-
truncatedWidth: {
|
|
31361
|
-
// Allow truncation, stop bleeding over the edge.
|
|
31362
|
-
minWidth: 0
|
|
31363
|
-
}
|
|
31364
|
-
});
|
|
31365
|
-
|
|
31366
|
-
/**
|
|
31367
|
-
* LockedVectorSettings is a component that allows the user to edit the
|
|
31368
|
-
* settings of specifically a locked vector on the graph.
|
|
31369
|
-
*
|
|
31370
|
-
* Used in the interactive graph editor's locked figures section.
|
|
31371
|
-
*/
|
|
31372
|
-
const lengthErrorMessage = "The vector cannot have length 0.";
|
|
31373
|
-
const LockedVectorSettings = props => {
|
|
31374
|
-
const {
|
|
31375
|
-
points,
|
|
31376
|
-
color: lineColor,
|
|
31377
|
-
onChangeProps,
|
|
31378
|
-
onMove,
|
|
31379
|
-
onRemove
|
|
31380
|
-
} = props;
|
|
31381
|
-
const [tail, tip] = points;
|
|
31382
|
-
const lineLabel = `Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;
|
|
31383
|
-
|
|
31384
|
-
// Check if the line has length 0.
|
|
31385
|
-
const isInvalid = vector.equal(tail, tip);
|
|
31386
|
-
function handleChangePoint(newCoord, index) {
|
|
31387
|
-
if (typeof newCoord !== "undefined") {
|
|
31388
|
-
const newPoints = [...points];
|
|
31389
|
-
newPoints[index] = [...newCoord];
|
|
31390
|
-
onChangeProps({
|
|
31391
|
-
points: newPoints
|
|
31392
|
-
});
|
|
31393
|
-
}
|
|
31394
|
-
}
|
|
31395
|
-
function handleColorChange(newColor) {
|
|
31396
|
-
onChangeProps({
|
|
31397
|
-
color: newColor
|
|
31398
|
-
});
|
|
31399
|
-
}
|
|
31400
|
-
return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
31401
|
-
expanded: props.expanded,
|
|
31402
|
-
onToggle: props.onToggle,
|
|
31403
|
-
header: /*#__PURE__*/React.createElement(View, {
|
|
31404
|
-
style: styles$o.row
|
|
31405
|
-
}, /*#__PURE__*/React.createElement(LabelLarge, null, lineLabel), /*#__PURE__*/React.createElement(Strut, {
|
|
31406
|
-
size: spacing.xSmall_8
|
|
31407
|
-
}), /*#__PURE__*/React.createElement(LineSwatch, {
|
|
31408
|
-
color: lineColor,
|
|
31409
|
-
lineStyle: "solid"
|
|
31410
|
-
}))
|
|
31411
|
-
}, /*#__PURE__*/React.createElement(View, {
|
|
31412
|
-
style: [styles$o.row, styles$o.spaceUnder]
|
|
31413
|
-
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
31414
|
-
selectedValue: lineColor,
|
|
31415
|
-
onChange: handleColorChange
|
|
31416
|
-
})), isInvalid && /*#__PURE__*/React.createElement(LabelMedium, {
|
|
31417
|
-
style: styles$o.errorText
|
|
31418
|
-
}, lengthErrorMessage), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
31419
|
-
expanded: true // Initial state is expanded
|
|
31420
|
-
,
|
|
31421
|
-
containerStyle: styles$o.container,
|
|
31422
|
-
panelStyle: styles$o.accordionPanel,
|
|
31423
|
-
header: /*#__PURE__*/React.createElement(View, {
|
|
31424
|
-
style: styles$o.row
|
|
31425
|
-
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Tail (${tail[0]}, ${tail[1]})`))
|
|
31426
|
-
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
31427
|
-
coord: tail,
|
|
31428
|
-
error: isInvalid,
|
|
31429
|
-
onChange: newProps => {
|
|
31430
|
-
handleChangePoint(newProps, 0);
|
|
31431
|
-
}
|
|
31432
|
-
})), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
31433
|
-
expanded: true // Initial state is expanded
|
|
31434
|
-
,
|
|
31435
|
-
containerStyle: styles$o.container,
|
|
31436
|
-
panelStyle: styles$o.accordionPanel,
|
|
31437
|
-
header: /*#__PURE__*/React.createElement(View, {
|
|
31438
|
-
style: styles$o.row
|
|
31439
|
-
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Tip (${tip[0]}, ${tip[1]})`))
|
|
31440
|
-
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
31441
|
-
coord: tip,
|
|
31442
|
-
error: isInvalid,
|
|
31443
|
-
onChange: newProps => {
|
|
31444
|
-
handleChangePoint(newProps, 1);
|
|
31445
|
-
}
|
|
31446
|
-
})), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
|
|
31447
|
-
figureType: props.type,
|
|
31448
|
-
onMove: onMove,
|
|
31449
|
-
onRemove: onRemove
|
|
31450
|
-
}));
|
|
31451
|
-
};
|
|
31452
|
-
const styles$o = StyleSheet.create({
|
|
31453
|
-
accordionPanel: {
|
|
31454
|
-
paddingBottom: spacing.medium_16
|
|
31455
|
-
},
|
|
31456
|
-
container: {
|
|
31457
|
-
marginTop: spacing.xSmall_8,
|
|
31458
|
-
marginBottom: 0,
|
|
31459
|
-
marginLeft: -spacing.xxxSmall_4,
|
|
31460
|
-
marginRight: -spacing.xxxSmall_4,
|
|
31461
|
-
backgroundColor: color.white
|
|
31462
|
-
},
|
|
31463
|
-
errorText: {
|
|
31464
|
-
color: color.red,
|
|
31465
|
-
marginTop: spacing.xSmall_8
|
|
31466
|
-
},
|
|
31467
|
-
row: {
|
|
31468
|
-
flexDirection: "row",
|
|
31469
|
-
alignItems: "center"
|
|
31470
|
-
}
|
|
31471
|
-
});
|
|
31472
|
-
|
|
31473
|
-
/**
|
|
31474
|
-
* LockedFigureSettings takes in a figure and renders the
|
|
31475
|
-
* respective settings for that figure type.
|
|
31476
|
-
*
|
|
31477
|
-
* Used in the interactive graph editor's locked figures section.
|
|
31478
|
-
*/
|
|
31479
|
-
|
|
31480
|
-
// Union this type with other locked figure types when they are added.
|
|
31481
|
-
|
|
31482
|
-
const LockedFigureSettings = props => {
|
|
31483
|
-
switch (props.type) {
|
|
31484
|
-
case "point":
|
|
31485
|
-
return /*#__PURE__*/React.createElement(LockedPointSettings, props);
|
|
31486
|
-
case "line":
|
|
31487
|
-
return /*#__PURE__*/React.createElement(LockedLineSettings, props);
|
|
31488
|
-
case "vector":
|
|
31489
|
-
return /*#__PURE__*/React.createElement(LockedVectorSettings, props);
|
|
31490
|
-
case "ellipse":
|
|
31491
|
-
return /*#__PURE__*/React.createElement(LockedEllipseSettings, props);
|
|
31492
|
-
case "polygon":
|
|
31493
|
-
return /*#__PURE__*/React.createElement(LockedPolygonSettings, props);
|
|
31494
|
-
case "function":
|
|
31495
|
-
return /*#__PURE__*/React.createElement(LockedFunctionSettings, props);
|
|
31496
|
-
case "label":
|
|
31497
|
-
if (props.showLabelsFlag) {
|
|
31498
|
-
return /*#__PURE__*/React.createElement(LockedLabelSettings, props);
|
|
31499
|
-
}
|
|
31500
|
-
break;
|
|
31501
|
-
}
|
|
31502
|
-
return null;
|
|
31503
|
-
};
|
|
31504
|
-
|
|
31505
|
-
const LockedFiguresSection = props => {
|
|
31506
|
-
var _props$figures;
|
|
31507
|
-
// Keep track of all figures' accordions' expanded states for the
|
|
31508
|
-
// expand/collapse all button. Set the whole array to false initially.
|
|
31509
|
-
const collapsedStateArray = Array(((_props$figures = props.figures) != null ? _props$figures : []).length).fill(false);
|
|
31510
|
-
const [expandedStates, setExpandedStates] = React.useState(collapsedStateArray);
|
|
31511
|
-
const [isExpanded, setIsExpanded] = React.useState(true);
|
|
31512
|
-
const uniqueId = useUniqueIdWithMock().get("locked-figures-section");
|
|
31513
|
-
const {
|
|
31514
|
-
figures,
|
|
31515
|
-
onChange
|
|
31516
|
-
} = props;
|
|
31517
|
-
function addLockedFigure(newFigure) {
|
|
31518
|
-
const lockedFigures = figures || [];
|
|
31519
|
-
const newProps = {
|
|
31520
|
-
lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
|
|
31521
|
-
};
|
|
31522
|
-
onChange(newProps);
|
|
31523
|
-
setExpandedStates([...expandedStates, true]);
|
|
31524
|
-
}
|
|
31525
|
-
function moveLockedFigure(index, movement) {
|
|
31526
|
-
// Don't allow moving the first figure up or the last figure down.
|
|
31527
|
-
if (index === 0 && (movement === "back" || movement === "backward")) {
|
|
31528
|
-
return;
|
|
31529
|
-
}
|
|
31530
|
-
if (figures && index === figures.length - 1 && (movement === "front" || movement === "forward")) {
|
|
31531
|
-
return;
|
|
31532
|
-
}
|
|
31533
|
-
const lockedFigures = figures || [];
|
|
31534
|
-
const newFigures = [...lockedFigures];
|
|
31535
|
-
const newExpandedStates = [...expandedStates];
|
|
31536
|
-
|
|
31537
|
-
// First, remove the figure from its current position
|
|
31538
|
-
// in the figures array and the expanded states array.
|
|
31539
|
-
const [removedFigure] = newFigures.splice(index, 1);
|
|
31540
|
-
newExpandedStates.splice(index, 1);
|
|
31541
|
-
|
|
31542
|
-
// Then, add it back in the new position. Add "true" to the
|
|
31543
|
-
// expanded states array for the new position (it must already
|
|
31544
|
-
// be open since the button to move it is being pressed from there).
|
|
31545
|
-
switch (movement) {
|
|
31546
|
-
case "back":
|
|
31547
|
-
newFigures.unshift(removedFigure);
|
|
31548
|
-
newExpandedStates.unshift(true);
|
|
31549
|
-
break;
|
|
31550
|
-
case "backward":
|
|
31551
|
-
newFigures.splice(index - 1, 0, removedFigure);
|
|
31552
|
-
newExpandedStates.splice(index - 1, 0, true);
|
|
31553
|
-
break;
|
|
31554
|
-
case "forward":
|
|
31555
|
-
newFigures.splice(index + 1, 0, removedFigure);
|
|
31556
|
-
newExpandedStates.splice(index + 1, 0, true);
|
|
31557
|
-
break;
|
|
31558
|
-
case "front":
|
|
31559
|
-
newFigures.push(removedFigure);
|
|
31560
|
-
newExpandedStates.push(true);
|
|
31561
|
-
break;
|
|
31562
|
-
}
|
|
31563
|
-
onChange({
|
|
31564
|
-
lockedFigures: newFigures
|
|
31565
|
-
});
|
|
31566
|
-
setExpandedStates(newExpandedStates);
|
|
31567
|
-
}
|
|
31568
|
-
function removeLockedFigure(index) {
|
|
31569
|
-
// eslint-disable-next-line no-alert
|
|
31570
|
-
if (window.confirm("Are you sure you want to delete this figure?")) {
|
|
31571
|
-
const lockedFigures = figures || [];
|
|
31572
|
-
onChange({
|
|
31573
|
-
lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
|
|
31574
|
-
});
|
|
31575
|
-
|
|
31576
|
-
// Update expanded states
|
|
31577
|
-
const newExpandedStates = [...expandedStates];
|
|
31578
|
-
newExpandedStates.splice(index, 1);
|
|
31579
|
-
setExpandedStates(newExpandedStates);
|
|
31580
|
-
}
|
|
31581
|
-
}
|
|
31582
|
-
function changeProps(index,
|
|
31583
|
-
// Omit the type from the figure props so it doesn't think
|
|
31584
|
-
// we're trying to pass in the props for the wrong type.
|
|
31585
|
-
figureProps) {
|
|
31586
|
-
const lockedFigures = figures || [];
|
|
31587
|
-
const newFigures = {
|
|
31588
|
-
lockedFigures: [...lockedFigures.slice(0, index), _extends({}, lockedFigures[index], figureProps), ...lockedFigures.slice(index + 1)]
|
|
31589
|
-
};
|
|
31590
|
-
onChange(newFigures);
|
|
31591
|
-
}
|
|
31592
|
-
function toggleExpanded(newValue) {
|
|
31593
|
-
setExpandedStates(Array(figures == null ? void 0 : figures.length).fill(newValue));
|
|
31594
|
-
}
|
|
31595
|
-
const allCollapsed = expandedStates.every(value => !value);
|
|
31596
|
-
const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
|
|
31597
|
-
const showExpandButton = !!(figures != null && figures.length);
|
|
31598
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Heading, {
|
|
31599
|
-
title: "Locked Figures",
|
|
31600
|
-
isOpen: isExpanded,
|
|
31601
|
-
onToggle: () => setIsExpanded(!isExpanded),
|
|
31602
|
-
isCollapsible: true
|
|
31603
|
-
}), isExpanded && /*#__PURE__*/React.createElement(View, null, figures == null ? void 0 : figures.map((figure, index) => {
|
|
31604
|
-
return /*#__PURE__*/React.createElement(LockedFigureSettings, _extends({
|
|
31605
|
-
key: `${uniqueId}-locked-${figure}-${index}`,
|
|
31606
|
-
showLabelsFlag: props.showLabelsFlag,
|
|
31607
|
-
expanded: expandedStates[index],
|
|
31608
|
-
onToggle: newValue => {
|
|
31609
|
-
const newExpanded = [...expandedStates];
|
|
31610
|
-
newExpanded[index] = newValue;
|
|
31611
|
-
setExpandedStates(newExpanded);
|
|
31612
|
-
}
|
|
31613
|
-
}, figure, {
|
|
31614
|
-
onChangeProps: newProps => changeProps(index, newProps),
|
|
31615
|
-
onMove: movement => moveLockedFigure(index, movement),
|
|
31616
|
-
onRemove: () => removeLockedFigure(index)
|
|
31617
|
-
}));
|
|
31618
|
-
}), /*#__PURE__*/React.createElement(View, {
|
|
31619
|
-
style: styles$n.buttonContainer
|
|
31620
|
-
}, /*#__PURE__*/React.createElement(LockedFigureSelect, {
|
|
31621
|
-
showLabelsFlag: props.showLabelsFlag,
|
|
31622
|
-
id: `${uniqueId}-select`,
|
|
31623
|
-
onChange: addLockedFigure
|
|
31624
|
-
}), /*#__PURE__*/React.createElement(Strut, {
|
|
31625
|
-
size: spacing.small_12
|
|
31626
|
-
}), showExpandButton && /*#__PURE__*/React.createElement(Button, {
|
|
31627
|
-
kind: "secondary",
|
|
31628
|
-
onClick: () => toggleExpanded(allCollapsed),
|
|
31629
|
-
style: styles$n.button
|
|
31630
|
-
}, buttonLabel))));
|
|
31901
|
+
style: styles$k.row
|
|
31902
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
31903
|
+
"aria-label": "Move polygon left",
|
|
31904
|
+
style: styles$k.iconButton,
|
|
31905
|
+
size: "small",
|
|
31906
|
+
icon: arrowFatLeft,
|
|
31907
|
+
onClick: () => handlePolygonMove("left")
|
|
31908
|
+
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
31909
|
+
"aria-label": "Move polygon down",
|
|
31910
|
+
style: styles$k.iconButton,
|
|
31911
|
+
size: "small",
|
|
31912
|
+
icon: arrowFatDown,
|
|
31913
|
+
onClick: () => handlePolygonMove("down")
|
|
31914
|
+
}), /*#__PURE__*/React.createElement(IconButton, {
|
|
31915
|
+
"aria-label": "Move polygon right",
|
|
31916
|
+
style: styles$k.iconButton,
|
|
31917
|
+
size: "small",
|
|
31918
|
+
icon: arrowFatRight,
|
|
31919
|
+
onClick: () => handlePolygonMove("right")
|
|
31920
|
+
}))))), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
|
|
31921
|
+
figureType: props.type,
|
|
31922
|
+
onMove: onMove,
|
|
31923
|
+
onRemove: onRemove
|
|
31924
|
+
}));
|
|
31631
31925
|
};
|
|
31632
|
-
const styles$
|
|
31633
|
-
|
|
31926
|
+
const styles$k = StyleSheet.create({
|
|
31927
|
+
row: {
|
|
31928
|
+
display: "flex",
|
|
31634
31929
|
flexDirection: "row",
|
|
31635
31930
|
alignItems: "center"
|
|
31636
31931
|
},
|
|
31637
|
-
|
|
31638
|
-
|
|
31639
|
-
|
|
31932
|
+
pointAccordionContainer: {
|
|
31933
|
+
backgroundColor: color.white
|
|
31934
|
+
},
|
|
31935
|
+
pointAccordionPanel: {
|
|
31936
|
+
alignItems: "start"
|
|
31937
|
+
},
|
|
31938
|
+
icon: {
|
|
31939
|
+
marginInlineStart: spacing.xxxSmall_4
|
|
31940
|
+
},
|
|
31941
|
+
polygonActionsContainer: {
|
|
31942
|
+
width: "100%"
|
|
31943
|
+
},
|
|
31944
|
+
iconButton: {
|
|
31945
|
+
margin: 0
|
|
31946
|
+
},
|
|
31947
|
+
movementButtonsContainer: {
|
|
31948
|
+
display: "flex",
|
|
31949
|
+
flexDirection: "column",
|
|
31950
|
+
alignItems: "center",
|
|
31951
|
+
minWidth: "fit-content"
|
|
31952
|
+
},
|
|
31953
|
+
spaceUnder: {
|
|
31954
|
+
marginBottom: spacing.xSmall_8
|
|
31955
|
+
},
|
|
31956
|
+
truncatedWidth: {
|
|
31957
|
+
// Allow truncation, stop bleeding over the edge.
|
|
31958
|
+
minWidth: 0
|
|
31640
31959
|
}
|
|
31641
31960
|
});
|
|
31642
31961
|
|
|
31643
|
-
|
|
31644
|
-
|
|
31645
|
-
|
|
31646
|
-
|
|
31647
|
-
|
|
31648
|
-
|
|
31649
|
-
|
|
31650
|
-
|
|
31651
|
-
|
|
31652
|
-
|
|
31653
|
-
|
|
31962
|
+
/**
|
|
31963
|
+
* LockedVectorSettings is a component that allows the user to edit the
|
|
31964
|
+
* settings of specifically a locked vector on the graph.
|
|
31965
|
+
*
|
|
31966
|
+
* Used in the interactive graph editor's locked figures section.
|
|
31967
|
+
*/
|
|
31968
|
+
const lengthErrorMessage = "The vector cannot have length 0.";
|
|
31969
|
+
const LockedVectorSettings = props => {
|
|
31970
|
+
const {
|
|
31971
|
+
points,
|
|
31972
|
+
color: lineColor,
|
|
31973
|
+
onChangeProps,
|
|
31974
|
+
onMove,
|
|
31975
|
+
onRemove
|
|
31976
|
+
} = props;
|
|
31977
|
+
const [tail, tip] = points;
|
|
31978
|
+
const lineLabel = `Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;
|
|
31654
31979
|
|
|
31655
|
-
|
|
31656
|
-
|
|
31657
|
-
|
|
31658
|
-
|
|
31659
|
-
|
|
31660
|
-
|
|
31661
|
-
|
|
31662
|
-
|
|
31980
|
+
// Check if the line has length 0.
|
|
31981
|
+
const isInvalid = vector.equal(tail, tip);
|
|
31982
|
+
function handleChangePoint(newCoord, index) {
|
|
31983
|
+
if (typeof newCoord !== "undefined") {
|
|
31984
|
+
const newPoints = [...points];
|
|
31985
|
+
newPoints[index] = [...newCoord];
|
|
31986
|
+
onChangeProps({
|
|
31987
|
+
points: newPoints
|
|
31988
|
+
});
|
|
31663
31989
|
}
|
|
31664
|
-
// Never uses placeholder, always has value
|
|
31665
|
-
,
|
|
31666
|
-
placeholder: "",
|
|
31667
|
-
style: styles$m.singleSelectShort
|
|
31668
|
-
}, [...[...Array(7).keys()].map(n => /*#__PURE__*/React.createElement(OptionItem, {
|
|
31669
|
-
key: n,
|
|
31670
|
-
value: `${n}`,
|
|
31671
|
-
label: `${n} point${n > 1 ? "s" : ""}`
|
|
31672
|
-
})), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31673
|
-
key: "unlimited",
|
|
31674
|
-
value: UNLIMITED,
|
|
31675
|
-
label: "unlimited"
|
|
31676
|
-
})]);
|
|
31677
|
-
};
|
|
31678
|
-
const styles$m = StyleSheet.create({
|
|
31679
|
-
singleSelectShort: {
|
|
31680
|
-
// Non-standard spacing, but it's the smallest we can go
|
|
31681
|
-
// without running into styling issues with the dropdown.
|
|
31682
|
-
height: 26
|
|
31683
31990
|
}
|
|
31684
|
-
|
|
31685
|
-
|
|
31686
|
-
|
|
31687
|
-
|
|
31688
|
-
selectedValue: props.graphType,
|
|
31689
|
-
onChange: props.onChange,
|
|
31690
|
-
placeholder: "Select a graph type",
|
|
31691
|
-
style: styles$l.singleSelectShort
|
|
31692
|
-
}, /*#__PURE__*/React.createElement(OptionItem, {
|
|
31693
|
-
value: "linear",
|
|
31694
|
-
label: "Linear function"
|
|
31695
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31696
|
-
value: "quadratic",
|
|
31697
|
-
label: "Quadratic function"
|
|
31698
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31699
|
-
value: "sinusoid",
|
|
31700
|
-
label: "Sinusoid function"
|
|
31701
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31702
|
-
value: "circle",
|
|
31703
|
-
label: "Circle"
|
|
31704
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31705
|
-
value: "point",
|
|
31706
|
-
label: "Point(s)"
|
|
31707
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31708
|
-
value: "linear-system",
|
|
31709
|
-
label: "Linear System"
|
|
31710
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31711
|
-
value: "polygon",
|
|
31712
|
-
label: "Polygon"
|
|
31713
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31714
|
-
value: "segment",
|
|
31715
|
-
label: "Line Segment(s)"
|
|
31716
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31717
|
-
value: "ray",
|
|
31718
|
-
label: "Ray"
|
|
31719
|
-
}), /*#__PURE__*/React.createElement(OptionItem, {
|
|
31720
|
-
value: "angle",
|
|
31721
|
-
label: "Angle"
|
|
31722
|
-
}));
|
|
31723
|
-
};
|
|
31724
|
-
const styles$l = StyleSheet.create({
|
|
31725
|
-
singleSelectShort: {
|
|
31726
|
-
// Non-standard spacing, but it's the smallest we can go
|
|
31727
|
-
// without running into styling issues with the dropdown.
|
|
31728
|
-
height: 26
|
|
31991
|
+
function handleColorChange(newColor) {
|
|
31992
|
+
onChangeProps({
|
|
31993
|
+
color: newColor
|
|
31994
|
+
});
|
|
31729
31995
|
}
|
|
31730
|
-
|
|
31731
|
-
|
|
31732
|
-
|
|
31733
|
-
|
|
31734
|
-
|
|
31735
|
-
|
|
31736
|
-
|
|
31737
|
-
|
|
31738
|
-
|
|
31739
|
-
|
|
31740
|
-
|
|
31741
|
-
|
|
31996
|
+
return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
31997
|
+
expanded: props.expanded,
|
|
31998
|
+
onToggle: props.onToggle,
|
|
31999
|
+
header: /*#__PURE__*/React.createElement(View, {
|
|
32000
|
+
style: styles$j.row
|
|
32001
|
+
}, /*#__PURE__*/React.createElement(LabelLarge, null, lineLabel), /*#__PURE__*/React.createElement(Strut, {
|
|
32002
|
+
size: spacing.xSmall_8
|
|
32003
|
+
}), /*#__PURE__*/React.createElement(LineSwatch, {
|
|
32004
|
+
color: lineColor,
|
|
32005
|
+
lineStyle: "solid"
|
|
32006
|
+
}))
|
|
32007
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
32008
|
+
style: [styles$j.row, styles$j.spaceUnder]
|
|
32009
|
+
}, /*#__PURE__*/React.createElement(ColorSelect, {
|
|
32010
|
+
selectedValue: lineColor,
|
|
32011
|
+
onChange: handleColorChange
|
|
32012
|
+
})), isInvalid && /*#__PURE__*/React.createElement(LabelMedium, {
|
|
32013
|
+
style: styles$j.errorText
|
|
32014
|
+
}, lengthErrorMessage), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
32015
|
+
expanded: true // Initial state is expanded
|
|
32016
|
+
,
|
|
32017
|
+
containerStyle: styles$j.container,
|
|
32018
|
+
panelStyle: styles$j.accordionPanel,
|
|
32019
|
+
header: /*#__PURE__*/React.createElement(View, {
|
|
32020
|
+
style: styles$j.row
|
|
32021
|
+
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Tail (${tail[0]}, ${tail[1]})`))
|
|
32022
|
+
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
32023
|
+
coord: tail,
|
|
32024
|
+
error: isInvalid,
|
|
32025
|
+
onChange: newProps => {
|
|
32026
|
+
handleChangePoint(newProps, 0);
|
|
31742
32027
|
}
|
|
31743
|
-
}
|
|
31744
|
-
|
|
31745
|
-
|
|
31746
|
-
|
|
31747
|
-
|
|
31748
|
-
|
|
31749
|
-
|
|
31750
|
-
|
|
32028
|
+
})), /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
|
|
32029
|
+
expanded: true // Initial state is expanded
|
|
32030
|
+
,
|
|
32031
|
+
containerStyle: styles$j.container,
|
|
32032
|
+
panelStyle: styles$j.accordionPanel,
|
|
32033
|
+
header: /*#__PURE__*/React.createElement(View, {
|
|
32034
|
+
style: styles$j.row
|
|
32035
|
+
}, /*#__PURE__*/React.createElement(LabelLarge, null, `Tip (${tip[0]}, ${tip[1]})`))
|
|
32036
|
+
}, /*#__PURE__*/React.createElement(CoordinatePairInput, {
|
|
32037
|
+
coord: tip,
|
|
32038
|
+
error: isInvalid,
|
|
32039
|
+
onChange: newProps => {
|
|
32040
|
+
handleChangePoint(newProps, 1);
|
|
31751
32041
|
}
|
|
31752
|
-
},
|
|
31753
|
-
|
|
31754
|
-
|
|
31755
|
-
|
|
31756
|
-
|
|
31757
|
-
ariaLabelValue,
|
|
31758
|
-
ariaDescriptionValue,
|
|
31759
|
-
onChange
|
|
31760
|
-
} = props;
|
|
31761
|
-
const [isOpen, setIsOpen] = React.useState(true);
|
|
31762
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Heading, {
|
|
31763
|
-
title: "Description",
|
|
31764
|
-
isCollapsible: true,
|
|
31765
|
-
isOpen: isOpen,
|
|
31766
|
-
onToggle: setIsOpen
|
|
31767
|
-
}), isOpen && /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(LabelXSmall, {
|
|
31768
|
-
style: styles$k.caption
|
|
31769
|
-
}, "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.createElement(LabelLarge, {
|
|
31770
|
-
tag: "label"
|
|
31771
|
-
}, "Title", /*#__PURE__*/React.createElement(TextField, {
|
|
31772
|
-
value: ariaLabelValue,
|
|
31773
|
-
onChange: newValue => onChange({
|
|
31774
|
-
fullGraphAriaLabel: newValue
|
|
31775
|
-
}),
|
|
31776
|
-
style: styles$k.spaceAbove
|
|
31777
|
-
})), /*#__PURE__*/React.createElement(Strut, {
|
|
31778
|
-
size: spacing.small_12
|
|
31779
|
-
}), /*#__PURE__*/React.createElement(LabelLarge, {
|
|
31780
|
-
tag: "label"
|
|
31781
|
-
}, "Description", /*#__PURE__*/React.createElement(TextArea, {
|
|
31782
|
-
rows: 8,
|
|
31783
|
-
resizeType: "vertical",
|
|
31784
|
-
value: ariaDescriptionValue,
|
|
31785
|
-
onChange: newValue => onChange({
|
|
31786
|
-
fullGraphAriaDescription: newValue
|
|
31787
|
-
}),
|
|
31788
|
-
style: styles$k.spaceAbove
|
|
31789
|
-
}))));
|
|
31790
|
-
}
|
|
31791
|
-
const styles$k = StyleSheet.create({
|
|
31792
|
-
caption: {
|
|
31793
|
-
color: color.offBlack64,
|
|
31794
|
-
paddingTop: spacing.xxSmall_6,
|
|
31795
|
-
paddingBottom: spacing.xxSmall_6
|
|
31796
|
-
},
|
|
31797
|
-
spaceAbove: {
|
|
31798
|
-
marginTop: spacing.xxxSmall_4
|
|
31799
|
-
}
|
|
31800
|
-
});
|
|
31801
|
-
|
|
31802
|
-
const {
|
|
31803
|
-
ButtonGroup: ButtonGroup$2,
|
|
31804
|
-
InfoTip: InfoTip$c,
|
|
31805
|
-
RangeInput: RangeInput$4
|
|
31806
|
-
} = components;
|
|
31807
|
-
const defaultBackgroundImage$1 = {
|
|
31808
|
-
url: null,
|
|
31809
|
-
width: 0,
|
|
31810
|
-
height: 0
|
|
32042
|
+
})), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
|
|
32043
|
+
figureType: props.type,
|
|
32044
|
+
onMove: onMove,
|
|
32045
|
+
onRemove: onRemove
|
|
32046
|
+
}));
|
|
31811
32047
|
};
|
|
31812
|
-
|
|
31813
|
-
|
|
31814
|
-
|
|
31815
|
-
|
|
31816
|
-
|
|
31817
|
-
|
|
31818
|
-
|
|
31819
|
-
|
|
31820
|
-
|
|
31821
|
-
|
|
31822
|
-
|
|
31823
|
-
|
|
31824
|
-
|
|
31825
|
-
|
|
31826
|
-
}
|
|
31827
|
-
|
|
31828
|
-
|
|
31829
|
-
|
|
31830
|
-
|
|
31831
|
-
|
|
31832
|
-
this.labelYRef = /*#__PURE__*/React.createRef();
|
|
31833
|
-
this.change = (...args) => {
|
|
31834
|
-
return Changeable.change.apply(this, args);
|
|
31835
|
-
};
|
|
31836
|
-
this.changeBackgroundUrl = e => {
|
|
31837
|
-
var _this$bgUrlRef$curren;
|
|
31838
|
-
// Only continue on blur or "enter"
|
|
31839
|
-
if (e.type === "keypress" && e.key !== "Enter") {
|
|
31840
|
-
return;
|
|
31841
|
-
}
|
|
31842
|
-
const setUrl = (url, width, height) => {
|
|
31843
|
-
// Shallow-copied clone
|
|
31844
|
-
const image = _extends({}, this.props.backgroundImage);
|
|
31845
|
-
image.url = url;
|
|
31846
|
-
image.width = width;
|
|
31847
|
-
image.height = height;
|
|
31848
|
-
this.setState({
|
|
31849
|
-
backgroundImage: image
|
|
31850
|
-
}, this.changeGraph);
|
|
31851
|
-
};
|
|
31852
|
-
const url = (_this$bgUrlRef$curren = this.bgUrlRef.current) == null ? void 0 : _this$bgUrlRef$curren.value;
|
|
31853
|
-
if (url) {
|
|
31854
|
-
Util.getImageSize(url, (width, height) => {
|
|
31855
|
-
if (this._isMounted) {
|
|
31856
|
-
setUrl(url, width, height);
|
|
31857
|
-
}
|
|
31858
|
-
});
|
|
31859
|
-
} else {
|
|
31860
|
-
setUrl(null, 0, 0);
|
|
31861
|
-
}
|
|
31862
|
-
};
|
|
31863
|
-
this.renderLabelChoices = choices => {
|
|
31864
|
-
return choices.map(nameAndValue => /*#__PURE__*/React.createElement("option", {
|
|
31865
|
-
key: nameAndValue[1],
|
|
31866
|
-
value: nameAndValue[1]
|
|
31867
|
-
}, nameAndValue[0]));
|
|
31868
|
-
};
|
|
31869
|
-
this.validRange = range => {
|
|
31870
|
-
const numbers = _.every(range, function (num) {
|
|
31871
|
-
return _.isFinite(num);
|
|
31872
|
-
});
|
|
31873
|
-
if (!numbers) {
|
|
31874
|
-
return "Range must be a valid number";
|
|
31875
|
-
}
|
|
31876
|
-
if (range[0] >= range[1]) {
|
|
31877
|
-
return "Range must have a higher number on the right";
|
|
31878
|
-
}
|
|
31879
|
-
return true;
|
|
31880
|
-
};
|
|
31881
|
-
this.validateStepValue = settings => {
|
|
31882
|
-
const {
|
|
31883
|
-
step,
|
|
31884
|
-
range,
|
|
31885
|
-
name,
|
|
31886
|
-
minTicks,
|
|
31887
|
-
maxTicks
|
|
31888
|
-
} = settings;
|
|
31889
|
-
const nSteps = numSteps(range, step);
|
|
31890
|
-
if (nSteps < minTicks) {
|
|
31891
|
-
return name + " is too large, there must be at least " + minTicks + " ticks.";
|
|
31892
|
-
}
|
|
31893
|
-
if (nSteps > maxTicks) {
|
|
31894
|
-
return name + " is too small, there can be at most " + maxTicks + " ticks.";
|
|
31895
|
-
}
|
|
31896
|
-
return true;
|
|
31897
|
-
};
|
|
31898
|
-
this.validSnapStep = (step, range) => {
|
|
31899
|
-
return this.validateStepValue({
|
|
31900
|
-
step: step,
|
|
31901
|
-
range: range,
|
|
31902
|
-
name: "Snap step",
|
|
31903
|
-
minTicks: 5,
|
|
31904
|
-
maxTicks: 60
|
|
31905
|
-
});
|
|
31906
|
-
};
|
|
31907
|
-
this.validGridStep = (step, range) => {
|
|
31908
|
-
return this.validateStepValue({
|
|
31909
|
-
step: step,
|
|
31910
|
-
range: range,
|
|
31911
|
-
name: "Grid step",
|
|
31912
|
-
minTicks: 3,
|
|
31913
|
-
maxTicks: 60
|
|
31914
|
-
});
|
|
31915
|
-
};
|
|
31916
|
-
this.validStep = (step, range) => {
|
|
31917
|
-
return this.validateStepValue({
|
|
31918
|
-
step: step,
|
|
31919
|
-
range: range,
|
|
31920
|
-
name: "Step",
|
|
31921
|
-
minTicks: 3,
|
|
31922
|
-
maxTicks: 20
|
|
31923
|
-
});
|
|
31924
|
-
};
|
|
31925
|
-
this.validBackgroundImageSize = image => {
|
|
31926
|
-
// Ignore empty images
|
|
31927
|
-
if (!image.url) {
|
|
31928
|
-
return true;
|
|
31929
|
-
}
|
|
31930
|
-
const validSize = image.width <= 450 && image.height <= 450;
|
|
31931
|
-
if (!validSize) {
|
|
31932
|
-
return "Image must be smaller than 450px x 450px.";
|
|
31933
|
-
}
|
|
31934
|
-
return true;
|
|
31935
|
-
};
|
|
31936
|
-
this.validateGraphSettings = (range, step, gridStep, snapStep, image) => {
|
|
31937
|
-
const self = this;
|
|
31938
|
-
let msg;
|
|
31939
|
-
const goodRange = _.every(range, function (range) {
|
|
31940
|
-
msg = self.validRange(range);
|
|
31941
|
-
return msg === true;
|
|
31942
|
-
});
|
|
31943
|
-
if (!goodRange) {
|
|
31944
|
-
return msg;
|
|
31945
|
-
}
|
|
31946
|
-
const goodStep = _.every(step, function (step, i) {
|
|
31947
|
-
msg = self.validStep(step, range[i]);
|
|
31948
|
-
return msg === true;
|
|
31949
|
-
});
|
|
31950
|
-
if (!goodStep) {
|
|
31951
|
-
return msg;
|
|
31952
|
-
}
|
|
31953
|
-
const goodGridStep = _.every(gridStep, function (gridStep, i) {
|
|
31954
|
-
msg = self.validGridStep(gridStep, range[i]);
|
|
31955
|
-
return msg === true;
|
|
31956
|
-
});
|
|
31957
|
-
if (!goodGridStep) {
|
|
31958
|
-
return msg;
|
|
31959
|
-
}
|
|
31960
|
-
const goodSnapStep = _.every(snapStep, function (snapStep, i) {
|
|
31961
|
-
msg = self.validSnapStep(snapStep, range[i]);
|
|
31962
|
-
return msg === true;
|
|
31963
|
-
});
|
|
31964
|
-
if (!goodSnapStep) {
|
|
31965
|
-
return msg;
|
|
31966
|
-
}
|
|
31967
|
-
const goodImageSize = this.validBackgroundImageSize(image);
|
|
31968
|
-
if (goodImageSize !== true) {
|
|
31969
|
-
msg = goodImageSize;
|
|
31970
|
-
return msg;
|
|
31971
|
-
}
|
|
31972
|
-
return true;
|
|
31973
|
-
};
|
|
31974
|
-
this.changeLabel = (i, e) => {
|
|
31975
|
-
const val = e.target.value;
|
|
31976
|
-
const labels = this.state.labelsTextbox.slice();
|
|
31977
|
-
labels[i] = val;
|
|
31978
|
-
this.setState({
|
|
31979
|
-
labelsTextbox: labels
|
|
31980
|
-
}, this.changeGraph);
|
|
31981
|
-
};
|
|
31982
|
-
this.changeRange = (i, values) => {
|
|
31983
|
-
const ranges = this.state.rangeTextbox.slice();
|
|
31984
|
-
ranges[i] = values;
|
|
31985
|
-
const step = this.state.stepTextbox.slice();
|
|
31986
|
-
const gridStep = this.state.gridStepTextbox.slice();
|
|
31987
|
-
const snapStep = this.state.snapStepTextbox.slice();
|
|
31988
|
-
const scale = Util.scaleFromExtent(ranges[i], this.props.box[i]);
|
|
31989
|
-
if (this.validRange(ranges[i]) === true) {
|
|
31990
|
-
step[i] = Util.tickStepFromExtent(ranges[i], this.props.box[i]);
|
|
31991
|
-
const gridStepValue = Util.gridStepFromTickStep(step[i], scale);
|
|
31992
|
-
if (gridStepValue) {
|
|
31993
|
-
gridStep[i] = gridStepValue;
|
|
31994
|
-
}
|
|
31995
|
-
snapStep[i] = gridStep[i] / 2;
|
|
31996
|
-
}
|
|
31997
|
-
this.setState({
|
|
31998
|
-
stepTextbox: step,
|
|
31999
|
-
gridStepTextbox: gridStep,
|
|
32000
|
-
snapStepTextbox: snapStep,
|
|
32001
|
-
rangeTextbox: ranges
|
|
32002
|
-
}, this.changeGraph);
|
|
32003
|
-
};
|
|
32004
|
-
this.changeStep = step => {
|
|
32005
|
-
this.setState({
|
|
32006
|
-
stepTextbox: step
|
|
32007
|
-
}, this.changeGraph);
|
|
32008
|
-
};
|
|
32009
|
-
this.changeSnapStep = snapStep => {
|
|
32010
|
-
this.setState({
|
|
32011
|
-
snapStepTextbox: snapStep
|
|
32012
|
-
}, this.changeGraph);
|
|
32013
|
-
};
|
|
32014
|
-
this.changeGridStep = gridStep => {
|
|
32015
|
-
this.setState({
|
|
32016
|
-
gridStepTextbox: gridStep,
|
|
32017
|
-
snapStepTextbox: _.map(gridStep, function (step) {
|
|
32018
|
-
return step / 2;
|
|
32019
|
-
})
|
|
32020
|
-
}, this.changeGraph);
|
|
32021
|
-
};
|
|
32022
|
-
this.changeGraph = () => {
|
|
32023
|
-
const labels = this.state.labelsTextbox;
|
|
32024
|
-
const range = _.map(this.state.rangeTextbox, function (range) {
|
|
32025
|
-
return _.map(range, Number);
|
|
32026
|
-
});
|
|
32027
|
-
const step = _.map(this.state.stepTextbox, Number);
|
|
32028
|
-
const gridStep = this.state.gridStepTextbox;
|
|
32029
|
-
const snapStep = this.state.snapStepTextbox;
|
|
32030
|
-
const image = this.state.backgroundImage;
|
|
32048
|
+
const styles$j = StyleSheet.create({
|
|
32049
|
+
accordionPanel: {
|
|
32050
|
+
paddingBottom: spacing.medium_16
|
|
32051
|
+
},
|
|
32052
|
+
container: {
|
|
32053
|
+
marginTop: spacing.xSmall_8,
|
|
32054
|
+
marginBottom: 0,
|
|
32055
|
+
marginLeft: -spacing.xxxSmall_4,
|
|
32056
|
+
marginRight: -spacing.xxxSmall_4,
|
|
32057
|
+
backgroundColor: color.white
|
|
32058
|
+
},
|
|
32059
|
+
errorText: {
|
|
32060
|
+
color: color.red,
|
|
32061
|
+
marginTop: spacing.xSmall_8
|
|
32062
|
+
},
|
|
32063
|
+
row: {
|
|
32064
|
+
flexDirection: "row",
|
|
32065
|
+
alignItems: "center"
|
|
32066
|
+
}
|
|
32067
|
+
});
|
|
32031
32068
|
|
|
32032
|
-
|
|
32033
|
-
|
|
32034
|
-
|
|
32035
|
-
|
|
32036
|
-
|
|
32037
|
-
|
|
32038
|
-
|
|
32039
|
-
|
|
32040
|
-
|
|
32041
|
-
|
|
32042
|
-
|
|
32043
|
-
|
|
32044
|
-
|
|
32045
|
-
|
|
32046
|
-
|
|
32047
|
-
|
|
32048
|
-
|
|
32049
|
-
|
|
32050
|
-
|
|
32051
|
-
|
|
32052
|
-
|
|
32069
|
+
/**
|
|
32070
|
+
* LockedFigureSettings takes in a figure and renders the
|
|
32071
|
+
* respective settings for that figure type.
|
|
32072
|
+
*
|
|
32073
|
+
* Used in the interactive graph editor's locked figures section.
|
|
32074
|
+
*/
|
|
32075
|
+
|
|
32076
|
+
// Union this type with other locked figure types when they are added.
|
|
32077
|
+
|
|
32078
|
+
const LockedFigureSettings = props => {
|
|
32079
|
+
switch (props.type) {
|
|
32080
|
+
case "point":
|
|
32081
|
+
return /*#__PURE__*/React.createElement(LockedPointSettings, props);
|
|
32082
|
+
case "line":
|
|
32083
|
+
return /*#__PURE__*/React.createElement(LockedLineSettings, props);
|
|
32084
|
+
case "vector":
|
|
32085
|
+
return /*#__PURE__*/React.createElement(LockedVectorSettings, props);
|
|
32086
|
+
case "ellipse":
|
|
32087
|
+
return /*#__PURE__*/React.createElement(LockedEllipseSettings, props);
|
|
32088
|
+
case "polygon":
|
|
32089
|
+
return /*#__PURE__*/React.createElement(LockedPolygonSettings, props);
|
|
32090
|
+
case "function":
|
|
32091
|
+
return /*#__PURE__*/React.createElement(LockedFunctionSettings, props);
|
|
32092
|
+
case "label":
|
|
32093
|
+
if (props.showLabelsFlag) {
|
|
32094
|
+
return /*#__PURE__*/React.createElement(LockedLabelSettings, props);
|
|
32053
32095
|
}
|
|
32096
|
+
break;
|
|
32097
|
+
}
|
|
32098
|
+
return null;
|
|
32099
|
+
};
|
|
32100
|
+
|
|
32101
|
+
const LockedFiguresSection = props => {
|
|
32102
|
+
var _props$figures;
|
|
32103
|
+
// Keep track of all figures' accordions' expanded states for the
|
|
32104
|
+
// expand/collapse all button. Set the whole array to false initially.
|
|
32105
|
+
const collapsedStateArray = Array(((_props$figures = props.figures) != null ? _props$figures : []).length).fill(false);
|
|
32106
|
+
const [expandedStates, setExpandedStates] = React.useState(collapsedStateArray);
|
|
32107
|
+
const [isExpanded, setIsExpanded] = React.useState(true);
|
|
32108
|
+
const uniqueId = useUniqueIdWithMock().get("locked-figures-section");
|
|
32109
|
+
const {
|
|
32110
|
+
figures,
|
|
32111
|
+
onChange
|
|
32112
|
+
} = props;
|
|
32113
|
+
function addLockedFigure(newFigure) {
|
|
32114
|
+
const lockedFigures = figures || [];
|
|
32115
|
+
const newProps = {
|
|
32116
|
+
lockedFigures: [...lockedFigures, getDefaultFigureForType(newFigure)]
|
|
32054
32117
|
};
|
|
32055
|
-
|
|
32056
|
-
|
|
32057
|
-
}, InteractiveGraphSettings.stateFromProps(props));
|
|
32118
|
+
onChange(newProps);
|
|
32119
|
+
setExpandedStates([...expandedStates, true]);
|
|
32058
32120
|
}
|
|
32059
|
-
|
|
32060
|
-
//
|
|
32061
|
-
|
|
32062
|
-
|
|
32063
|
-
|
|
32121
|
+
function moveLockedFigure(index, movement) {
|
|
32122
|
+
// Don't allow moving the first figure up or the last figure down.
|
|
32123
|
+
if (index === 0 && (movement === "back" || movement === "backward")) {
|
|
32124
|
+
return;
|
|
32125
|
+
}
|
|
32126
|
+
if (figures && index === figures.length - 1 && (movement === "front" || movement === "forward")) {
|
|
32127
|
+
return;
|
|
32128
|
+
}
|
|
32129
|
+
const lockedFigures = figures || [];
|
|
32130
|
+
const newFigures = [...lockedFigures];
|
|
32131
|
+
const newExpandedStates = [...expandedStates];
|
|
32132
|
+
|
|
32133
|
+
// First, remove the figure from its current position
|
|
32134
|
+
// in the figures array and the expanded states array.
|
|
32135
|
+
const [removedFigure] = newFigures.splice(index, 1);
|
|
32136
|
+
newExpandedStates.splice(index, 1);
|
|
32137
|
+
|
|
32138
|
+
// Then, add it back in the new position. Add "true" to the
|
|
32139
|
+
// expanded states array for the new position (it must already
|
|
32140
|
+
// be open since the button to move it is being pressed from there).
|
|
32141
|
+
switch (movement) {
|
|
32142
|
+
case "back":
|
|
32143
|
+
newFigures.unshift(removedFigure);
|
|
32144
|
+
newExpandedStates.unshift(true);
|
|
32145
|
+
break;
|
|
32146
|
+
case "backward":
|
|
32147
|
+
newFigures.splice(index - 1, 0, removedFigure);
|
|
32148
|
+
newExpandedStates.splice(index - 1, 0, true);
|
|
32149
|
+
break;
|
|
32150
|
+
case "forward":
|
|
32151
|
+
newFigures.splice(index + 1, 0, removedFigure);
|
|
32152
|
+
newExpandedStates.splice(index + 1, 0, true);
|
|
32153
|
+
break;
|
|
32154
|
+
case "front":
|
|
32155
|
+
newFigures.push(removedFigure);
|
|
32156
|
+
newExpandedStates.push(true);
|
|
32157
|
+
break;
|
|
32158
|
+
}
|
|
32159
|
+
onChange({
|
|
32160
|
+
lockedFigures: newFigures
|
|
32161
|
+
});
|
|
32162
|
+
setExpandedStates(newExpandedStates);
|
|
32064
32163
|
}
|
|
32065
|
-
|
|
32066
|
-
//
|
|
32067
|
-
|
|
32068
|
-
|
|
32069
|
-
|
|
32164
|
+
function removeLockedFigure(index) {
|
|
32165
|
+
// eslint-disable-next-line no-alert
|
|
32166
|
+
if (window.confirm("Are you sure you want to delete this figure?")) {
|
|
32167
|
+
const lockedFigures = figures || [];
|
|
32168
|
+
onChange({
|
|
32169
|
+
lockedFigures: [...lockedFigures.slice(0, index), ...lockedFigures.slice(index + 1)]
|
|
32170
|
+
});
|
|
32171
|
+
|
|
32172
|
+
// Update expanded states
|
|
32173
|
+
const newExpandedStates = [...expandedStates];
|
|
32174
|
+
newExpandedStates.splice(index, 1);
|
|
32175
|
+
setExpandedStates(newExpandedStates);
|
|
32070
32176
|
}
|
|
32071
32177
|
}
|
|
32072
|
-
|
|
32073
|
-
|
|
32178
|
+
function changeProps(index,
|
|
32179
|
+
// Omit the type from the figure props so it doesn't think
|
|
32180
|
+
// we're trying to pass in the props for the wrong type.
|
|
32181
|
+
figureProps) {
|
|
32182
|
+
const lockedFigures = figures || [];
|
|
32183
|
+
const newFigures = {
|
|
32184
|
+
lockedFigures: [...lockedFigures.slice(0, index), _extends({}, lockedFigures[index], figureProps), ...lockedFigures.slice(index + 1)]
|
|
32185
|
+
};
|
|
32186
|
+
onChange(newFigures);
|
|
32074
32187
|
}
|
|
32075
|
-
|
|
32076
|
-
|
|
32077
|
-
title: "Common Graph Settings",
|
|
32078
|
-
isOpen: this.state.isExpanded,
|
|
32079
|
-
isCollapsible: true,
|
|
32080
|
-
onToggle: () => this.setState({
|
|
32081
|
-
isExpanded: !this.state.isExpanded
|
|
32082
|
-
})
|
|
32083
|
-
}), this.state.isExpanded && /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement("div", {
|
|
32084
|
-
className: "graph-settings"
|
|
32085
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
32086
|
-
className: "perseus-widget-row"
|
|
32087
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
32088
|
-
className: "perseus-widget-left-col"
|
|
32089
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32090
|
-
label: "x Label"
|
|
32091
|
-
}, /*#__PURE__*/React.createElement("input", {
|
|
32092
|
-
type: "text",
|
|
32093
|
-
className: "graph-settings-axis-label",
|
|
32094
|
-
ref: this.labelXRef,
|
|
32095
|
-
onChange: e => this.changeLabel(0, e),
|
|
32096
|
-
value: this.state.labelsTextbox[0] || ""
|
|
32097
|
-
}))), /*#__PURE__*/React.createElement("div", {
|
|
32098
|
-
className: "perseus-widget-right-col"
|
|
32099
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32100
|
-
label: "y Label"
|
|
32101
|
-
}, /*#__PURE__*/React.createElement("input", {
|
|
32102
|
-
type: "text",
|
|
32103
|
-
className: "graph-settings-axis-label",
|
|
32104
|
-
ref: this.labelYRef,
|
|
32105
|
-
onChange: e => this.changeLabel(1, e),
|
|
32106
|
-
value: this.state.labelsTextbox[1] || ""
|
|
32107
|
-
})))), /*#__PURE__*/React.createElement("div", {
|
|
32108
|
-
className: "perseus-widget-row"
|
|
32109
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
32110
|
-
className: "perseus-widget-left-col"
|
|
32111
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32112
|
-
label: "x Range"
|
|
32113
|
-
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
32114
|
-
value: this.state.rangeTextbox[0],
|
|
32115
|
-
onChange: vals => this.changeRange(0, vals)
|
|
32116
|
-
}))), /*#__PURE__*/React.createElement("div", {
|
|
32117
|
-
className: "perseus-widget-right-col"
|
|
32118
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32119
|
-
label: "y Range"
|
|
32120
|
-
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
32121
|
-
value: this.state.rangeTextbox[1],
|
|
32122
|
-
onChange: vals => this.changeRange(1, vals)
|
|
32123
|
-
})))), /*#__PURE__*/React.createElement("div", {
|
|
32124
|
-
className: "perseus-widget-row"
|
|
32125
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
32126
|
-
className: "perseus-widget-left-col"
|
|
32127
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32128
|
-
label: "Tick Step"
|
|
32129
|
-
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
32130
|
-
value: this.state.stepTextbox,
|
|
32131
|
-
onChange: this.changeStep
|
|
32132
|
-
}))), /*#__PURE__*/React.createElement("div", {
|
|
32133
|
-
className: "perseus-widget-right-col"
|
|
32134
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32135
|
-
label: "Grid Step"
|
|
32136
|
-
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
32137
|
-
value: this.state.gridStepTextbox,
|
|
32138
|
-
onChange: this.changeGridStep
|
|
32139
|
-
})))), /*#__PURE__*/React.createElement("div", {
|
|
32140
|
-
className: "perseus-widget-row"
|
|
32141
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
32142
|
-
className: "perseus-widget-left-col"
|
|
32143
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32144
|
-
label: "Snap Step"
|
|
32145
|
-
}, /*#__PURE__*/React.createElement(RangeInput$4, {
|
|
32146
|
-
value: this.state.snapStepTextbox,
|
|
32147
|
-
onChange: this.changeSnapStep
|
|
32148
|
-
})))), /*#__PURE__*/React.createElement("div", {
|
|
32149
|
-
className: "perseus-widget-row"
|
|
32150
|
-
}, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32151
|
-
label: "Markings:"
|
|
32152
|
-
}, /*#__PURE__*/React.createElement(ButtonGroup$2, {
|
|
32153
|
-
value: this.props.markings,
|
|
32154
|
-
allowEmpty: false,
|
|
32155
|
-
buttons: [{
|
|
32156
|
-
value: "graph",
|
|
32157
|
-
content: "Graph"
|
|
32158
|
-
}, {
|
|
32159
|
-
value: "grid",
|
|
32160
|
-
content: "Grid"
|
|
32161
|
-
}, {
|
|
32162
|
-
value: "none",
|
|
32163
|
-
content: "None"
|
|
32164
|
-
}],
|
|
32165
|
-
onChange: this.change("markings")
|
|
32166
|
-
}))), /*#__PURE__*/React.createElement("div", {
|
|
32167
|
-
className: "perseus-widget-left-col"
|
|
32168
|
-
}, /*#__PURE__*/React.createElement(Checkbox$1, {
|
|
32169
|
-
label: "Show tooltips",
|
|
32170
|
-
checked: this.props.showTooltips,
|
|
32171
|
-
onChange: value => {
|
|
32172
|
-
this.change({
|
|
32173
|
-
showTooltips: value
|
|
32174
|
-
});
|
|
32175
|
-
}
|
|
32176
|
-
}))), /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32177
|
-
label: "Background image URL:",
|
|
32178
|
-
style: styles$j.resetSpaceTop
|
|
32179
|
-
}, /*#__PURE__*/React.createElement("input", {
|
|
32180
|
-
type: "text",
|
|
32181
|
-
className: css(styles$j.backgroundUrlInput),
|
|
32182
|
-
ref: this.bgUrlRef,
|
|
32183
|
-
value: this.state.backgroundImage.url || "",
|
|
32184
|
-
onChange: e => {
|
|
32185
|
-
// Shallow-copied clone
|
|
32186
|
-
const image = _extends({}, this.props.backgroundImage);
|
|
32187
|
-
image.url = e.target.value;
|
|
32188
|
-
this.setState({
|
|
32189
|
-
backgroundImage: image
|
|
32190
|
-
});
|
|
32191
|
-
},
|
|
32192
|
-
onKeyPress: this.changeBackgroundUrl,
|
|
32193
|
-
onBlur: this.changeBackgroundUrl
|
|
32194
|
-
}), /*#__PURE__*/React.createElement(InfoTip$c, null, /*#__PURE__*/React.createElement("p", null, "Create an image in graphie, or use the \"Add image\" function to create a background."))), /*#__PURE__*/React.createElement(View, {
|
|
32195
|
-
style: styles$j.protractorSection
|
|
32196
|
-
}, /*#__PURE__*/React.createElement(View, {
|
|
32197
|
-
style: styles$j.checkboxRow
|
|
32198
|
-
}, /*#__PURE__*/React.createElement(Checkbox$1, {
|
|
32199
|
-
label: "Show protractor",
|
|
32200
|
-
checked: this.props.showProtractor,
|
|
32201
|
-
onChange: value => {
|
|
32202
|
-
this.change({
|
|
32203
|
-
showProtractor: value
|
|
32204
|
-
});
|
|
32205
|
-
},
|
|
32206
|
-
style: styles$j.resetSpaceTop
|
|
32207
|
-
})), this.props.showProtractor && /*#__PURE__*/React.createElement(Banner, {
|
|
32208
|
-
layout: "floating",
|
|
32209
|
-
text: "The protractor is not accessible. Please consider an alternate approach.",
|
|
32210
|
-
kind: "warning"
|
|
32211
|
-
}))));
|
|
32188
|
+
function toggleExpanded(newValue) {
|
|
32189
|
+
setExpandedStates(Array(figures == null ? void 0 : figures.length).fill(newValue));
|
|
32212
32190
|
}
|
|
32213
|
-
|
|
32214
|
-
|
|
32215
|
-
|
|
32216
|
-
|
|
32217
|
-
|
|
32218
|
-
|
|
32219
|
-
|
|
32220
|
-
|
|
32221
|
-
|
|
32222
|
-
|
|
32223
|
-
|
|
32224
|
-
|
|
32225
|
-
|
|
32191
|
+
const allCollapsed = expandedStates.every(value => !value);
|
|
32192
|
+
const buttonLabel = allCollapsed ? "Expand all" : "Collapse all";
|
|
32193
|
+
const showExpandButton = !!(figures != null && figures.length);
|
|
32194
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Heading, {
|
|
32195
|
+
title: "Locked Figures",
|
|
32196
|
+
isOpen: isExpanded,
|
|
32197
|
+
onToggle: () => setIsExpanded(!isExpanded),
|
|
32198
|
+
isCollapsible: true
|
|
32199
|
+
}), isExpanded && /*#__PURE__*/React.createElement(View, null, figures == null ? void 0 : figures.map((figure, index) => {
|
|
32200
|
+
return /*#__PURE__*/React.createElement(LockedFigureSettings, _extends({
|
|
32201
|
+
key: `${uniqueId}-locked-${figure}-${index}`,
|
|
32202
|
+
flags: props.flags,
|
|
32203
|
+
showLabelsFlag: props.showLabelsFlag,
|
|
32204
|
+
expanded: expandedStates[index],
|
|
32205
|
+
onToggle: newValue => {
|
|
32206
|
+
const newExpanded = [...expandedStates];
|
|
32207
|
+
newExpanded[index] = newValue;
|
|
32208
|
+
setExpandedStates(newExpanded);
|
|
32209
|
+
}
|
|
32210
|
+
}, figure, {
|
|
32211
|
+
onChangeProps: newProps => changeProps(index, newProps),
|
|
32212
|
+
onMove: movement => moveLockedFigure(index, movement),
|
|
32213
|
+
onRemove: () => removeLockedFigure(index)
|
|
32214
|
+
}));
|
|
32215
|
+
}), /*#__PURE__*/React.createElement(View, {
|
|
32216
|
+
style: styles$i.buttonContainer
|
|
32217
|
+
}, /*#__PURE__*/React.createElement(LockedFigureSelect, {
|
|
32218
|
+
showLabelsFlag: props.showLabelsFlag,
|
|
32219
|
+
id: `${uniqueId}-select`,
|
|
32220
|
+
onChange: addLockedFigure
|
|
32221
|
+
}), /*#__PURE__*/React.createElement(Strut, {
|
|
32222
|
+
size: spacing.small_12
|
|
32223
|
+
}), showExpandButton && /*#__PURE__*/React.createElement(Button, {
|
|
32224
|
+
kind: "secondary",
|
|
32225
|
+
onClick: () => toggleExpanded(allCollapsed),
|
|
32226
|
+
style: styles$i.button
|
|
32227
|
+
}, buttonLabel))));
|
|
32226
32228
|
};
|
|
32227
|
-
const styles$
|
|
32228
|
-
|
|
32229
|
-
marginTop: 0
|
|
32230
|
-
},
|
|
32231
|
-
backgroundUrlInput: {
|
|
32232
|
-
border: `1px solid ${color.offBlack32}`,
|
|
32233
|
-
borderRadius: spacing.xxxSmall_4,
|
|
32234
|
-
padding: spacing.xxxSmall_4
|
|
32235
|
-
},
|
|
32236
|
-
checkboxRow: {
|
|
32229
|
+
const styles$i = StyleSheet.create({
|
|
32230
|
+
buttonContainer: {
|
|
32237
32231
|
flexDirection: "row",
|
|
32238
|
-
alignItems: "center"
|
|
32239
|
-
justifyContent: "space-between",
|
|
32240
|
-
marginBottom: spacing.xSmall_8
|
|
32232
|
+
alignItems: "center"
|
|
32241
32233
|
},
|
|
32242
|
-
|
|
32234
|
+
button: {
|
|
32243
32235
|
marginTop: spacing.xSmall_8,
|
|
32244
|
-
|
|
32245
|
-
paddingTop: spacing.xSmall_8,
|
|
32246
|
-
paddingBottom: spacing.xSmall_8,
|
|
32247
|
-
borderBottom: `1px solid ${color.offBlack16}`
|
|
32236
|
+
flexGrow: 1
|
|
32248
32237
|
}
|
|
32249
32238
|
});
|
|
32250
32239
|
|
|
32251
|
-
|
|
32252
|
-
|
|
32253
|
-
|
|
32254
|
-
}) => /*#__PURE__*/React.createElement(SingleSelect, {
|
|
32255
|
-
key: "segment-select",
|
|
32256
|
-
selectedValue: `${_numSegments}`
|
|
32257
|
-
// Never uses placeholder, always has value
|
|
32258
|
-
,
|
|
32259
|
-
placeholder: "",
|
|
32260
|
-
onChange: newValue => {
|
|
32261
|
-
const num = +newValue;
|
|
32262
|
-
onChange(num);
|
|
32263
|
-
},
|
|
32264
|
-
style: styles$i.singleSelectShort
|
|
32265
|
-
}, _.range(1, 7).map(n => /*#__PURE__*/React.createElement(OptionItem, {
|
|
32266
|
-
key: n,
|
|
32267
|
-
value: `${n}`,
|
|
32268
|
-
label: `${n} segment${n > 1 ? "s" : ""}`
|
|
32269
|
-
})));
|
|
32270
|
-
const styles$i = StyleSheet.create({
|
|
32271
|
-
singleSelectShort: {
|
|
32272
|
-
// Non-standard spacing, but it's the smallest we can go
|
|
32273
|
-
// without running into styling issues with the dropdown.
|
|
32274
|
-
height: 26
|
|
32240
|
+
function getStartCoords(graph) {
|
|
32241
|
+
if ("startCoords" in graph) {
|
|
32242
|
+
return graph.startCoords;
|
|
32275
32243
|
}
|
|
32276
|
-
|
|
32244
|
+
return undefined;
|
|
32245
|
+
}
|
|
32246
|
+
function getDefaultGraphStartCoords(graph, range, step) {
|
|
32247
|
+
switch (graph.type) {
|
|
32248
|
+
case "linear":
|
|
32249
|
+
case "ray":
|
|
32250
|
+
return getLineCoords(_extends({}, graph, {
|
|
32251
|
+
startCoords: undefined
|
|
32252
|
+
}), range, step);
|
|
32253
|
+
case "segment":
|
|
32254
|
+
return getSegmentCoords(_extends({}, graph, {
|
|
32255
|
+
startCoords: undefined
|
|
32256
|
+
}), range, step);
|
|
32257
|
+
case "linear-system":
|
|
32258
|
+
return getLinearSystemCoords(_extends({}, graph, {
|
|
32259
|
+
startCoords: undefined
|
|
32260
|
+
}), range, step);
|
|
32261
|
+
case "circle":
|
|
32262
|
+
const startCoords = getCircleCoords(_extends({}, graph, {
|
|
32263
|
+
startCoords: undefined
|
|
32264
|
+
}));
|
|
32265
|
+
const radius = vector.length(vector.subtract(startCoords.radiusPoint, startCoords.center));
|
|
32266
|
+
return {
|
|
32267
|
+
center: startCoords.center,
|
|
32268
|
+
radius
|
|
32269
|
+
};
|
|
32270
|
+
case "sinusoid":
|
|
32271
|
+
return getSinusoidCoords(_extends({}, graph, {
|
|
32272
|
+
startCoords: undefined
|
|
32273
|
+
}), range, step);
|
|
32274
|
+
case "quadratic":
|
|
32275
|
+
return getQuadraticCoords(_extends({}, graph, {
|
|
32276
|
+
startCoords: undefined
|
|
32277
|
+
}), range, step);
|
|
32278
|
+
case "point":
|
|
32279
|
+
return getPointCoords(_extends({}, graph, {
|
|
32280
|
+
startCoords: undefined
|
|
32281
|
+
}), range, step);
|
|
32282
|
+
case "polygon":
|
|
32283
|
+
return getPolygonCoords(_extends({}, graph, {
|
|
32284
|
+
startCoords: undefined
|
|
32285
|
+
}), range, step);
|
|
32286
|
+
case "angle":
|
|
32287
|
+
return getAngleCoords({
|
|
32288
|
+
graph: _extends({}, graph, {
|
|
32289
|
+
startCoords: undefined
|
|
32290
|
+
}),
|
|
32291
|
+
range,
|
|
32292
|
+
step
|
|
32293
|
+
});
|
|
32294
|
+
default:
|
|
32295
|
+
return undefined;
|
|
32296
|
+
}
|
|
32297
|
+
}
|
|
32298
|
+
const getSinusoidEquation = startCoords => {
|
|
32299
|
+
// Get coefficients
|
|
32300
|
+
// It's assumed that p1 is the root and p2 is the first peak
|
|
32301
|
+
const p1 = startCoords[0];
|
|
32302
|
+
const p2 = startCoords[1];
|
|
32303
|
+
|
|
32304
|
+
// Resulting coefficients are canonical for this sine curve
|
|
32305
|
+
const amplitude = p2[1] - p1[1];
|
|
32306
|
+
const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
|
|
32307
|
+
const phase = p1[0] * angularFrequency;
|
|
32308
|
+
const verticalOffset = p1[1];
|
|
32309
|
+
return "y = " + amplitude.toFixed(3) + "sin(" + angularFrequency.toFixed(3) + "x - " + phase.toFixed(3) + ") + " + verticalOffset.toFixed(3);
|
|
32310
|
+
};
|
|
32311
|
+
const getQuadraticEquation = startCoords => {
|
|
32312
|
+
const p1 = startCoords[0];
|
|
32313
|
+
const p2 = startCoords[1];
|
|
32314
|
+
const p3 = startCoords[2];
|
|
32315
|
+
const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
|
|
32316
|
+
if (denom === 0) {
|
|
32317
|
+
// Many of the callers assume that the return value is always defined.
|
|
32318
|
+
return "Division by zero error";
|
|
32319
|
+
}
|
|
32320
|
+
const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
|
|
32321
|
+
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;
|
|
32322
|
+
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;
|
|
32323
|
+
return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
|
|
32324
|
+
};
|
|
32325
|
+
const findAngle = (point1, point2) => {
|
|
32326
|
+
const x = point1[0] - point2[0];
|
|
32327
|
+
const y = point1[1] - point2[1];
|
|
32328
|
+
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
32329
|
+
};
|
|
32330
|
+
const getAngleEquation = startCoords => {
|
|
32331
|
+
const [point1, vertex, point2] = startCoords;
|
|
32332
|
+
const angle = findAngle(point2, vertex) - findAngle(point1, vertex);
|
|
32333
|
+
const roundedAngle = angle.toFixed(0);
|
|
32334
|
+
return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`;
|
|
32335
|
+
};
|
|
32336
|
+
const shouldShowStartCoordsUI = (graph, isStatic) => {
|
|
32337
|
+
// We don't show the start coords UI for static graphs, since
|
|
32338
|
+
// the coords shown for this are determined by the coords on the
|
|
32339
|
+
// "correct" graph. The start coords would not be used here.
|
|
32340
|
+
if (isStatic) {
|
|
32341
|
+
return false;
|
|
32342
|
+
}
|
|
32343
|
+
switch (graph.type) {
|
|
32344
|
+
case "point":
|
|
32345
|
+
return graph.numPoints !== "unlimited";
|
|
32346
|
+
case "polygon":
|
|
32347
|
+
return graph.numSides !== "unlimited" && graph.snapTo !== "angles" && graph.snapTo !== "sides";
|
|
32348
|
+
case "none":
|
|
32349
|
+
return false;
|
|
32350
|
+
case "angle":
|
|
32351
|
+
case "circle":
|
|
32352
|
+
case "linear":
|
|
32353
|
+
case "linear-system":
|
|
32354
|
+
case "quadratic":
|
|
32355
|
+
case "ray":
|
|
32356
|
+
case "segment":
|
|
32357
|
+
case "sinusoid":
|
|
32358
|
+
return true;
|
|
32359
|
+
default:
|
|
32360
|
+
throw new UnreachableCaseError(graph);
|
|
32361
|
+
}
|
|
32362
|
+
};
|
|
32277
32363
|
|
|
32278
32364
|
const StartCoordsAngle = props => {
|
|
32279
32365
|
const {
|
|
@@ -32783,13 +32869,12 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32783
32869
|
// eslint-disable-next-line react/no-string-refs
|
|
32784
32870
|
const graph = this.refs.graph;
|
|
32785
32871
|
if (graph) {
|
|
32786
|
-
var _this$props$graph2;
|
|
32787
32872
|
// @ts-expect-error TS2339 Property 'getUserInput' does not exist on type 'ReactInstance'. Property 'getUserInput' does not exist on type 'Component<any, {}, any>'.
|
|
32788
32873
|
const correct = graph && graph.getUserInput();
|
|
32789
32874
|
_.extend(json, {
|
|
32790
32875
|
graph: {
|
|
32791
32876
|
type: correct.type,
|
|
32792
|
-
startCoords:
|
|
32877
|
+
startCoords: this.props.graph && getStartCoords(this.props.graph)
|
|
32793
32878
|
},
|
|
32794
32879
|
correct: correct
|
|
32795
32880
|
});
|
|
@@ -32804,7 +32889,7 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32804
32889
|
return json;
|
|
32805
32890
|
}
|
|
32806
32891
|
render() {
|
|
32807
|
-
var _this$props$graph$typ, _this$props$
|
|
32892
|
+
var _this$props$graph$typ, _this$props$graph2, _this$props$apiOption, _this$props$apiOption2, _this$props$fullGraph, _this$props$fullGraph2, _this$props$correct, _this$props$correct2, _this$props$correct3, _this$props$correct4, _this$props$correct5, _this$props$correct6, _this$props$correct7, _this$props$correct8, _this$props$correct9, _this$props$correct10, _this$props$correct11, _this$props$graph8, _this$props$apiOption3, _this$props$apiOption4;
|
|
32808
32893
|
let graph;
|
|
32809
32894
|
let equationString;
|
|
32810
32895
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, interactiveSizes.defaultBoxSize);
|
|
@@ -32872,9 +32957,9 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32872
32957
|
}, this.props.valid);
|
|
32873
32958
|
}
|
|
32874
32959
|
return /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(LabeledRow, {
|
|
32875
|
-
label: "
|
|
32960
|
+
label: "Answer type:"
|
|
32876
32961
|
}, /*#__PURE__*/React.createElement(GraphTypeSelector, {
|
|
32877
|
-
graphType: (_this$props$graph$typ = (_this$props$
|
|
32962
|
+
graphType: (_this$props$graph$typ = (_this$props$graph2 = this.props.graph) == null ? void 0 : _this$props$graph2.type) != null ? _this$props$graph$typ : InteractiveGraph.defaultProps.graph.type,
|
|
32878
32963
|
onChange: type => {
|
|
32879
32964
|
this.props.onChange({
|
|
32880
32965
|
graph: {
|
|
@@ -32884,8 +32969,9 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32884
32969
|
type
|
|
32885
32970
|
}
|
|
32886
32971
|
});
|
|
32887
|
-
}
|
|
32888
|
-
|
|
32972
|
+
},
|
|
32973
|
+
showNoneOption: (_this$props$apiOption = this.props.apiOptions) == null || (_this$props$apiOption = _this$props$apiOption.flags) == null || (_this$props$apiOption = _this$props$apiOption.mafs) == null ? void 0 : _this$props$apiOption["none"]
|
|
32974
|
+
})), this.props.graph && ((_this$props$apiOption2 = this.props.apiOptions) == null || (_this$props$apiOption2 = _this$props$apiOption2.flags) == null || (_this$props$apiOption2 = _this$props$apiOption2.mafs) == null ? void 0 : _this$props$apiOption2[this.props.graph.type]) && /*#__PURE__*/React.createElement(InteractiveGraphDescription, {
|
|
32889
32975
|
ariaLabelValue: (_this$props$fullGraph = this.props.fullGraphAriaLabel) != null ? _this$props$fullGraph : "",
|
|
32890
32976
|
ariaDescriptionValue: (_this$props$fullGraph2 = this.props.fullGraphAriaDescription) != null ? _this$props$fullGraph2 : "",
|
|
32891
32977
|
onChange: this.props.onChange
|
|
@@ -32914,8 +33000,8 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32914
33000
|
selectedValue: (_this$props$correct4 = this.props.correct) != null && _this$props$correct4.numSides ? `${this.props.correct.numSides}` : "3",
|
|
32915
33001
|
placeholder: "",
|
|
32916
33002
|
onChange: newValue => {
|
|
32917
|
-
var _this$props$
|
|
32918
|
-
invariant(((_this$props$
|
|
33003
|
+
var _this$props$graph3;
|
|
33004
|
+
invariant(((_this$props$graph3 = this.props.graph) == null ? void 0 : _this$props$graph3.type) === "polygon");
|
|
32919
33005
|
const updates = {
|
|
32920
33006
|
numSides: parsePointCount(newValue),
|
|
32921
33007
|
coords: null,
|
|
@@ -32942,9 +33028,9 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32942
33028
|
,
|
|
32943
33029
|
placeholder: "",
|
|
32944
33030
|
onChange: newValue => {
|
|
32945
|
-
var _this$props$
|
|
33031
|
+
var _this$props$graph4, _this$props$graph5;
|
|
32946
33032
|
invariant(this.props.correct.type === "polygon", `Expected correct answer type to be polygon, but got ${this.props.correct.type}`);
|
|
32947
|
-
invariant(((_this$props$
|
|
33033
|
+
invariant(((_this$props$graph4 = this.props.graph) == null ? void 0 : _this$props$graph4.type) === "polygon", `Expected graph type to be polygon, but got ${(_this$props$graph5 = this.props.graph) == null ? void 0 : _this$props$graph5.type}`);
|
|
32948
33034
|
const updates = {
|
|
32949
33035
|
snapTo: newValue,
|
|
32950
33036
|
coords: null
|
|
@@ -32972,8 +33058,8 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32972
33058
|
// Don't show indeterminate checkbox state
|
|
32973
33059
|
!!((_this$props$correct8 = this.props.correct) != null && _this$props$correct8.showAngles),
|
|
32974
33060
|
onChange: () => {
|
|
32975
|
-
var _this$props$
|
|
32976
|
-
if (((_this$props$
|
|
33061
|
+
var _this$props$graph6;
|
|
33062
|
+
if (((_this$props$graph6 = this.props.graph) == null ? void 0 : _this$props$graph6.type) === "polygon") {
|
|
32977
33063
|
invariant(this.props.correct.type === "polygon", `Expected graph type to be polygon, but got ${this.props.correct.type}`);
|
|
32978
33064
|
this.props.onChange({
|
|
32979
33065
|
correct: _extends({}, this.props.correct, {
|
|
@@ -32993,8 +33079,8 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
32993
33079
|
// Don't show indeterminate checkbox state
|
|
32994
33080
|
!!((_this$props$correct9 = this.props.correct) != null && _this$props$correct9.showSides),
|
|
32995
33081
|
onChange: () => {
|
|
32996
|
-
var _this$props$
|
|
32997
|
-
if (((_this$props$
|
|
33082
|
+
var _this$props$graph7;
|
|
33083
|
+
if (((_this$props$graph7 = this.props.graph) == null ? void 0 : _this$props$graph7.type) === "polygon" && this.props.correct.type === "polygon") {
|
|
32998
33084
|
this.props.onChange({
|
|
32999
33085
|
correct: _extends({}, this.props.correct, {
|
|
33000
33086
|
showSides: !this.props.correct.showSides
|
|
@@ -33022,7 +33108,7 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
33022
33108
|
}
|
|
33023
33109
|
});
|
|
33024
33110
|
}
|
|
33025
|
-
})), ((_this$props$
|
|
33111
|
+
})), ((_this$props$graph8 = this.props.graph) == null ? void 0 : _this$props$graph8.type) && shouldShowStartCoordsUI(this.props.graph, this.props.static) && /*#__PURE__*/React.createElement(StartCoordsSettings, _extends({}, this.props.graph, {
|
|
33026
33112
|
range: this.props.range,
|
|
33027
33113
|
step: this.props.step,
|
|
33028
33114
|
onChange: this.changeStartCoords
|
|
@@ -33106,8 +33192,9 @@ class InteractiveGraphEditor extends React.Component {
|
|
|
33106
33192
|
})), /*#__PURE__*/React.createElement(InfoTip$b, null, /*#__PURE__*/React.createElement("p", null, "Congruency requires only that the angle measures are the same. An exact match implies congruency, but also requires that the angles have the same orientation and that the vertices are in the same position."))),
|
|
33107
33193
|
// Only show the "Add locked figure" dropdown if the graph
|
|
33108
33194
|
// is using Mafs.
|
|
33109
|
-
this.props.graph && ((_this$props$
|
|
33110
|
-
|
|
33195
|
+
this.props.graph && ((_this$props$apiOption3 = this.props.apiOptions) == null || (_this$props$apiOption3 = _this$props$apiOption3.flags) == null || (_this$props$apiOption3 = _this$props$apiOption3.mafs) == null ? void 0 : _this$props$apiOption3[this.props.graph.type]) && /*#__PURE__*/React.createElement(LockedFiguresSection, {
|
|
33196
|
+
flags: this.props.apiOptions.flags,
|
|
33197
|
+
showLabelsFlag: (_this$props$apiOption4 = this.props.apiOptions) == null || (_this$props$apiOption4 = _this$props$apiOption4.flags) == null || (_this$props$apiOption4 = _this$props$apiOption4.mafs) == null ? void 0 : _this$props$apiOption4["interactive-graph-locked-features-labels"],
|
|
33111
33198
|
figures: this.props.lockedFigures,
|
|
33112
33199
|
onChange: this.props.onChange
|
|
33113
33200
|
}));
|
|
@@ -33144,6 +33231,9 @@ function mergeGraphs(a, b) {
|
|
|
33144
33231
|
case "linear-system":
|
|
33145
33232
|
invariant(b.type === "linear-system");
|
|
33146
33233
|
return _extends({}, a, b);
|
|
33234
|
+
case "none":
|
|
33235
|
+
invariant(b.type === "none");
|
|
33236
|
+
return _extends({}, a, b);
|
|
33147
33237
|
case "point":
|
|
33148
33238
|
invariant(b.type === "point");
|
|
33149
33239
|
return _extends({}, a, b);
|
|
@@ -36901,14 +36991,6 @@ class TableEditor extends React.Component {
|
|
|
36901
36991
|
};
|
|
36902
36992
|
}
|
|
36903
36993
|
render() {
|
|
36904
|
-
const tableProps = _.pick(this.props, "headers", "answers", "onChange", "apiOptions");
|
|
36905
|
-
_.extend(tableProps, {
|
|
36906
|
-
editableHeaders: true,
|
|
36907
|
-
Editor,
|
|
36908
|
-
onFocus: () => {},
|
|
36909
|
-
onBlur: () => {},
|
|
36910
|
-
trackInteraction: () => {}
|
|
36911
|
-
});
|
|
36912
36994
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
36913
36995
|
className: "perseus-widget-row"
|
|
36914
36996
|
}, /*#__PURE__*/React.createElement("label", null, "Number of columns:", " ", /*#__PURE__*/React.createElement(NumberInput, {
|
|
@@ -36933,7 +37015,17 @@ class TableEditor extends React.Component {
|
|
|
36933
37015
|
}
|
|
36934
37016
|
},
|
|
36935
37017
|
useArrowKeys: true
|
|
36936
|
-
}))), /*#__PURE__*/React.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React.createElement(InfoTip$1, null, /*#__PURE__*/React.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Table,
|
|
37018
|
+
}))), /*#__PURE__*/React.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React.createElement(InfoTip$1, null, /*#__PURE__*/React.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Table, {
|
|
37019
|
+
headers: this.props.headers,
|
|
37020
|
+
answers: this.props.answers,
|
|
37021
|
+
onChange: this.props.onChange,
|
|
37022
|
+
apiOptions: this.props.apiOptions,
|
|
37023
|
+
editableHeaders: true,
|
|
37024
|
+
onFocus: () => {},
|
|
37025
|
+
onBlur: () => {},
|
|
37026
|
+
trackInteraction: () => {},
|
|
37027
|
+
Editor: Editor
|
|
37028
|
+
})));
|
|
36937
37029
|
}
|
|
36938
37030
|
}
|
|
36939
37031
|
TableEditor.propTypes = {
|