@khanacademy/perseus-editor 2.2.2 → 2.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/CHANGELOG.md +15 -0
- package/dist/all-widgets.d.ts +2 -2
- package/dist/all-widgets.js.flow +2 -2
- package/dist/components/graph-points-count-selector.d.ts +7 -0
- package/dist/components/graph-points-count-selector.js.flow +12 -0
- package/dist/components/graph-type-selector.d.ts +7 -0
- package/dist/components/graph-type-selector.js.flow +12 -0
- package/dist/components/segment-count-selector.d.ts +6 -0
- package/dist/components/segment-count-selector.js.flow +11 -0
- package/dist/components/widget-editor.d.ts +31 -0
- package/dist/components/widget-editor.js.flow +91 -0
- package/dist/components/widget-select.d.ts +10 -0
- package/dist/components/widget-select.js.flow +16 -0
- package/dist/es/index.js +423 -229
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +431 -225
- package/dist/index.js.map +1 -1
- package/dist/testing-widgets.d.ts +2 -2
- package/dist/testing-widgets.js.flow +2 -2
- package/dist/util/points.d.ts +3 -0
- package/dist/util/points.js.flow +9 -0
- package/dist/widgets/example-graphie-widget.d.ts +2 -2
- package/dist/widgets/example-graphie-widget.js.flow +2 -2
- package/dist/widgets/example-widget.d.ts +2 -2
- package/dist/widgets/example-widget.js.flow +2 -2
- package/dist/widgets/interactive-graph-editor.d.ts +3182 -1
- package/dist/widgets/interactive-graph-editor.js.flow +5290 -1
- package/package.json +9 -3
- package/src/__stories__/editor.stories.tsx +105 -4
- package/src/article-editor.tsx +1 -1
- package/src/{__stories__ → components/__stories__}/section-control-button.stories.tsx +1 -1
- package/src/components/graph-points-count-selector.tsx +29 -0
- package/src/components/graph-type-selector.tsx +31 -0
- package/src/components/json-editor.tsx +0 -1
- package/src/components/segment-count-selector.tsx +27 -0
- package/src/components/widget-editor.tsx +232 -0
- package/src/components/widget-select.tsx +48 -0
- package/src/editor.tsx +4 -270
- package/src/util/points.test.ts +24 -0
- package/src/util/points.ts +13 -0
- package/src/widgets/interactive-graph-editor.tsx +294 -48
- package/tsconfig-build.json +0 -1
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/diffs/__stories__/perseus-diff-wrapper.d.ts +0 -6
- package/dist/diffs/__stories__/perseus-diff-wrapper.js.flow +0 -12
- /package/dist/{section-control-button.d.ts → components/section-control-button.d.ts} +0 -0
- /package/dist/{section-control-button.js.flow → components/section-control-button.js.flow} +0 -0
- /package/src/{section-control-button.tsx → components/section-control-button.tsx} +0 -0
package/dist/es/index.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { constants, components, Widgets, Util, Log, PerseusError, Errors, PerseusMarkdown, preprocessTex,
|
|
1
|
+
import { constants, components, Widgets, icons, WIDGET_PROP_DENYLIST, Util, Log, PerseusError, Errors, PerseusMarkdown, preprocessTex, ApiOptions, buildMapper, itemToTree, buildEmptyItemTreeForShape, shapes, itemDataVersion, ClassNames, MultiItems, traverse, Categorizer as Categorizer$1, Changeable, EditorJsonify, Dependencies, WidgetJsonifyDeprecated, Expression, interactiveSizes, KhanMath, GrapherWidget, GrapherUtil, SizingUtils, KhanColors, ColorPicker, DashPicker, ArrowPicker, ElementContainer, InteractiveGraphWidget, globalStyles, globalConstants, MatrixWidget, PlotterWidget, BaseRadio, TableWidget, TransformerWidget, displaySigFigs, widgets } from '@khanacademy/perseus';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import _ from 'underscore';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import createReactClass from 'create-react-class';
|
|
6
|
+
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
7
|
+
import Color from '@khanacademy/wonder-blocks-color';
|
|
8
|
+
import { StyleSheet, css } from 'aphrodite';
|
|
6
9
|
import $ from 'jquery';
|
|
7
10
|
import * as ReactDOM from 'react-dom';
|
|
8
11
|
import ReactDOM__default from 'react-dom';
|
|
9
|
-
import { StyleSheet, css } from 'aphrodite';
|
|
10
|
-
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
11
|
-
import Color from '@khanacademy/wonder-blocks-color';
|
|
12
12
|
import classNames from 'classnames';
|
|
13
13
|
import { point, number, line, ray, vector } from '@khanacademy/kmath';
|
|
14
14
|
import * as KAS from '@khanacademy/kas';
|
|
15
|
+
import { View } from '@khanacademy/wonder-blocks-core';
|
|
16
|
+
import Spacing from '@khanacademy/wonder-blocks-spacing';
|
|
17
|
+
import * as Typography from '@khanacademy/wonder-blocks-typography';
|
|
15
18
|
import Button from '@khanacademy/wonder-blocks-button';
|
|
16
19
|
import * as i18n$1 from '@khanacademy/wonder-blocks-i18n';
|
|
17
20
|
|
|
@@ -96,7 +99,7 @@ DeviceFramer.propTypes = {
|
|
|
96
99
|
nochrome: PropTypes.bool
|
|
97
100
|
};
|
|
98
101
|
|
|
99
|
-
/* eslint-disable
|
|
102
|
+
/* eslint-disable @babel/no-invalid-this */
|
|
100
103
|
const JsonEditor = createReactClass({
|
|
101
104
|
displayName: "JsonEditor",
|
|
102
105
|
getInitialState: function () {
|
|
@@ -190,6 +193,43 @@ const JsonEditor = createReactClass({
|
|
|
190
193
|
}
|
|
191
194
|
});
|
|
192
195
|
|
|
196
|
+
const {
|
|
197
|
+
InlineIcon: InlineIcon$c
|
|
198
|
+
} = components;
|
|
199
|
+
class SectionControlButton extends React.Component {
|
|
200
|
+
render() {
|
|
201
|
+
const {
|
|
202
|
+
icon,
|
|
203
|
+
onClick,
|
|
204
|
+
title
|
|
205
|
+
} = this.props;
|
|
206
|
+
return /*#__PURE__*/React.createElement(Clickable, {
|
|
207
|
+
className: "section-control-button " + "simple-button " + "simple-button--small ",
|
|
208
|
+
onClick: e => {
|
|
209
|
+
e.preventDefault();
|
|
210
|
+
onClick();
|
|
211
|
+
},
|
|
212
|
+
role: "button",
|
|
213
|
+
hideDefaultFocusRing: true,
|
|
214
|
+
"aria-label": title,
|
|
215
|
+
style: styles$f.button
|
|
216
|
+
}, ({
|
|
217
|
+
hovered,
|
|
218
|
+
focused,
|
|
219
|
+
pressed
|
|
220
|
+
}) => /*#__PURE__*/React.createElement(InlineIcon$c, icon));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const styles$f = StyleSheet.create({
|
|
224
|
+
button: {
|
|
225
|
+
backgroundColor: Color.gold,
|
|
226
|
+
margin: 2,
|
|
227
|
+
paddingRight: 10,
|
|
228
|
+
paddingLeft: 10,
|
|
229
|
+
paddingBottom: 2
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
193
233
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
194
234
|
|
|
195
235
|
function getDefaultExportFromCjs (x) {
|
|
@@ -17683,115 +17723,6 @@ const DragTarget = createReactClass({
|
|
|
17683
17723
|
}
|
|
17684
17724
|
});
|
|
17685
17725
|
|
|
17686
|
-
/**
|
|
17687
|
-
* Displays a collapsable list of KaTeX rendering errors.
|
|
17688
|
-
*/
|
|
17689
|
-
class KatexErrorView extends React.Component {
|
|
17690
|
-
constructor(...args) {
|
|
17691
|
-
super(...args);
|
|
17692
|
-
this.state = {
|
|
17693
|
-
showErrors: false
|
|
17694
|
-
};
|
|
17695
|
-
this.handleToggleKatexErrors = e => {
|
|
17696
|
-
this.setState({
|
|
17697
|
-
showErrors: !this.state.showErrors
|
|
17698
|
-
});
|
|
17699
|
-
};
|
|
17700
|
-
}
|
|
17701
|
-
render() {
|
|
17702
|
-
const {
|
|
17703
|
-
errorList
|
|
17704
|
-
} = this.props;
|
|
17705
|
-
const {
|
|
17706
|
-
showErrors
|
|
17707
|
-
} = this.state;
|
|
17708
|
-
|
|
17709
|
-
// TODO(riley) replace with SVG icons
|
|
17710
|
-
const disclosureClass = showErrors ? "icon-chevron-down" : "icon-chevron-right";
|
|
17711
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
17712
|
-
className: css(styles$f.errorContainer)
|
|
17713
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
17714
|
-
className: css(styles$f.title),
|
|
17715
|
-
onClick: this.handleToggleKatexErrors
|
|
17716
|
-
}, /*#__PURE__*/React.createElement("i", {
|
|
17717
|
-
className: disclosureClass,
|
|
17718
|
-
style: {
|
|
17719
|
-
fontSize: 14
|
|
17720
|
-
}
|
|
17721
|
-
}), "\xA0 KaTeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React.createElement("div", {
|
|
17722
|
-
className: css(styles$f.errorExplanation)
|
|
17723
|
-
}, "These errors will cause your LaTeX to load really slowly for the student. Please fix them if you can. If you can\u2019t because KaTeX doesn\u2019t support the feature you need, please message Cam."), showErrors && errorList.map((e, index) => /*#__PURE__*/React.createElement("div", {
|
|
17724
|
-
className: css(styles$f.error),
|
|
17725
|
-
key: index
|
|
17726
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
17727
|
-
style: {
|
|
17728
|
-
color: "red"
|
|
17729
|
-
}
|
|
17730
|
-
}, e.math), /*#__PURE__*/React.createElement("div", null, e.message))));
|
|
17731
|
-
}
|
|
17732
|
-
}
|
|
17733
|
-
KatexErrorView.propTypes = {
|
|
17734
|
-
errorList: PropTypes.arrayOf(PropTypes.shape({
|
|
17735
|
-
math: PropTypes.string.isRequired,
|
|
17736
|
-
message: PropTypes.string.isRequired
|
|
17737
|
-
})).isRequired
|
|
17738
|
-
};
|
|
17739
|
-
const styles$f = StyleSheet.create({
|
|
17740
|
-
title: {
|
|
17741
|
-
backgroundColor: "#eee",
|
|
17742
|
-
fontSize: "1.25em",
|
|
17743
|
-
padding: "4px 10px"
|
|
17744
|
-
},
|
|
17745
|
-
errorContainer: {
|
|
17746
|
-
border: "1px solid #ddd",
|
|
17747
|
-
borderTop: "none"
|
|
17748
|
-
},
|
|
17749
|
-
errorExplanation: {
|
|
17750
|
-
padding: "4px 10px",
|
|
17751
|
-
backgroundColor: "pink"
|
|
17752
|
-
},
|
|
17753
|
-
error: {
|
|
17754
|
-
padding: "4px 10px"
|
|
17755
|
-
}
|
|
17756
|
-
});
|
|
17757
|
-
|
|
17758
|
-
const {
|
|
17759
|
-
InlineIcon: InlineIcon$c
|
|
17760
|
-
} = components;
|
|
17761
|
-
class SectionControlButton extends React.Component {
|
|
17762
|
-
render() {
|
|
17763
|
-
const {
|
|
17764
|
-
icon,
|
|
17765
|
-
onClick,
|
|
17766
|
-
title
|
|
17767
|
-
} = this.props;
|
|
17768
|
-
return /*#__PURE__*/React.createElement(Clickable, {
|
|
17769
|
-
className: "section-control-button " + "simple-button " + "simple-button--small ",
|
|
17770
|
-
onClick: e => {
|
|
17771
|
-
e.preventDefault();
|
|
17772
|
-
onClick();
|
|
17773
|
-
},
|
|
17774
|
-
role: "button",
|
|
17775
|
-
hideDefaultFocusRing: true,
|
|
17776
|
-
"aria-label": title,
|
|
17777
|
-
style: styles$e.button
|
|
17778
|
-
}, ({
|
|
17779
|
-
hovered,
|
|
17780
|
-
focused,
|
|
17781
|
-
pressed
|
|
17782
|
-
}) => /*#__PURE__*/React.createElement(InlineIcon$c, icon));
|
|
17783
|
-
}
|
|
17784
|
-
}
|
|
17785
|
-
const styles$e = StyleSheet.create({
|
|
17786
|
-
button: {
|
|
17787
|
-
backgroundColor: Color.gold,
|
|
17788
|
-
margin: 2,
|
|
17789
|
-
paddingRight: 10,
|
|
17790
|
-
paddingLeft: 10,
|
|
17791
|
-
paddingBottom: 2
|
|
17792
|
-
}
|
|
17793
|
-
});
|
|
17794
|
-
|
|
17795
17726
|
const {
|
|
17796
17727
|
InlineIcon: InlineIcon$b,
|
|
17797
17728
|
PropCheckBox: PropCheckBox$e
|
|
@@ -17801,80 +17732,6 @@ const {
|
|
|
17801
17732
|
iconChevronRight,
|
|
17802
17733
|
iconTrash: iconTrash$8
|
|
17803
17734
|
} = icons;
|
|
17804
|
-
|
|
17805
|
-
// like [[snowman input-number 1]]
|
|
17806
|
-
const widgetPlaceholder = "[[\u2603 {id}]]";
|
|
17807
|
-
const widgetRegExp = "(\\[\\[\u2603 {id}\\]\\])";
|
|
17808
|
-
const rWidgetSplit = new RegExp(widgetRegExp.replace("{id}", "[a-z-]+ [0-9]+"), "g");
|
|
17809
|
-
const shortcutRegexp = /^\[\[([a-z-]+)$/; // like [[nu, [[int, etc
|
|
17810
|
-
|
|
17811
|
-
const ENDS_WITH_A_PARAGRAPH = /(?:\n{2,}|^\n*)$/;
|
|
17812
|
-
const TRAILING_NEWLINES = /(\n*)$/;
|
|
17813
|
-
const LEADING_NEWLINES = /^(\n*)/;
|
|
17814
|
-
const commafyInteger = n => {
|
|
17815
|
-
let str = n.toString();
|
|
17816
|
-
if (str.length >= 5) {
|
|
17817
|
-
str = str.replace(/(\d)(?=(\d{3})+$)/g, "$1{,}");
|
|
17818
|
-
}
|
|
17819
|
-
return str;
|
|
17820
|
-
};
|
|
17821
|
-
const makeEndWithAParagraphIfNecessary = content => {
|
|
17822
|
-
if (!ENDS_WITH_A_PARAGRAPH.test(content)) {
|
|
17823
|
-
const match = TRAILING_NEWLINES.exec(content);
|
|
17824
|
-
if (match) {
|
|
17825
|
-
const newlines = match[1];
|
|
17826
|
-
return content + "\n\n".slice(0, 2 - newlines.length);
|
|
17827
|
-
}
|
|
17828
|
-
}
|
|
17829
|
-
return content;
|
|
17830
|
-
};
|
|
17831
|
-
const makeStartWithAParagraphAlways = content => {
|
|
17832
|
-
const match = LEADING_NEWLINES.exec(content);
|
|
17833
|
-
if (!match) {
|
|
17834
|
-
return content;
|
|
17835
|
-
}
|
|
17836
|
-
const newlines = match[1];
|
|
17837
|
-
return "\n\n".slice(0, 2 - newlines.length) + content;
|
|
17838
|
-
};
|
|
17839
|
-
class WidgetSelect extends React.Component {
|
|
17840
|
-
constructor(...args) {
|
|
17841
|
-
super(...args);
|
|
17842
|
-
this.handleChange = e => {
|
|
17843
|
-
const widgetType = e.currentTarget.value;
|
|
17844
|
-
if (widgetType === "") {
|
|
17845
|
-
// TODO(alpert): Not sure if change will trigger here
|
|
17846
|
-
// but might as well be safe
|
|
17847
|
-
return;
|
|
17848
|
-
}
|
|
17849
|
-
if (this.props.onChange) {
|
|
17850
|
-
this.props.onChange(widgetType);
|
|
17851
|
-
}
|
|
17852
|
-
};
|
|
17853
|
-
}
|
|
17854
|
-
shouldComponentUpdate() {
|
|
17855
|
-
return false;
|
|
17856
|
-
}
|
|
17857
|
-
render() {
|
|
17858
|
-
const widgets = Widgets.getPublicWidgets();
|
|
17859
|
-
const orderedWidgetNames = _.sortBy(_.keys(widgets), name => {
|
|
17860
|
-
return widgets[name].displayName;
|
|
17861
|
-
});
|
|
17862
|
-
const addWidgetString = "Add a widget\u2026";
|
|
17863
|
-
return /*#__PURE__*/React.createElement("select", {
|
|
17864
|
-
value: "",
|
|
17865
|
-
onChange: this.handleChange
|
|
17866
|
-
}, /*#__PURE__*/React.createElement("option", {
|
|
17867
|
-
value: ""
|
|
17868
|
-
}, addWidgetString), /*#__PURE__*/React.createElement("option", {
|
|
17869
|
-
disabled: true
|
|
17870
|
-
}, "--"), _.map(orderedWidgetNames, name => {
|
|
17871
|
-
return /*#__PURE__*/React.createElement("option", {
|
|
17872
|
-
key: name,
|
|
17873
|
-
value: name
|
|
17874
|
-
}, widgets[name].displayName);
|
|
17875
|
-
}));
|
|
17876
|
-
}
|
|
17877
|
-
}
|
|
17878
17735
|
const _upgradeWidgetInfo = props => {
|
|
17879
17736
|
// We can't call serialize here because this.refs.widget
|
|
17880
17737
|
// doesn't exist before this component is mounted.
|
|
@@ -18009,6 +17866,153 @@ class WidgetEditor extends React.Component {
|
|
|
18009
17866
|
}
|
|
18010
17867
|
}
|
|
18011
17868
|
|
|
17869
|
+
class WidgetSelect extends React.Component {
|
|
17870
|
+
constructor(...args) {
|
|
17871
|
+
super(...args);
|
|
17872
|
+
this.handleChange = e => {
|
|
17873
|
+
const widgetType = e.currentTarget.value;
|
|
17874
|
+
if (widgetType === "") {
|
|
17875
|
+
// TODO(alpert): Not sure if change will trigger here
|
|
17876
|
+
// but might as well be safe
|
|
17877
|
+
return;
|
|
17878
|
+
}
|
|
17879
|
+
if (this.props.onChange) {
|
|
17880
|
+
this.props.onChange(widgetType);
|
|
17881
|
+
}
|
|
17882
|
+
};
|
|
17883
|
+
}
|
|
17884
|
+
shouldComponentUpdate() {
|
|
17885
|
+
return false;
|
|
17886
|
+
}
|
|
17887
|
+
render() {
|
|
17888
|
+
const widgets = Widgets.getPublicWidgets();
|
|
17889
|
+
const orderedWidgetNames = _.sortBy(_.keys(widgets), name => {
|
|
17890
|
+
return widgets[name].displayName;
|
|
17891
|
+
});
|
|
17892
|
+
const addWidgetString = "Add a widget\u2026";
|
|
17893
|
+
return /*#__PURE__*/React.createElement("select", {
|
|
17894
|
+
value: "",
|
|
17895
|
+
onChange: this.handleChange
|
|
17896
|
+
}, /*#__PURE__*/React.createElement("option", {
|
|
17897
|
+
value: ""
|
|
17898
|
+
}, addWidgetString), /*#__PURE__*/React.createElement("option", {
|
|
17899
|
+
disabled: true
|
|
17900
|
+
}, "--"), _.map(orderedWidgetNames, name => {
|
|
17901
|
+
return /*#__PURE__*/React.createElement("option", {
|
|
17902
|
+
key: name,
|
|
17903
|
+
value: name
|
|
17904
|
+
}, widgets[name].displayName);
|
|
17905
|
+
}));
|
|
17906
|
+
}
|
|
17907
|
+
}
|
|
17908
|
+
|
|
17909
|
+
/**
|
|
17910
|
+
* Displays a collapsable list of KaTeX rendering errors.
|
|
17911
|
+
*/
|
|
17912
|
+
class KatexErrorView extends React.Component {
|
|
17913
|
+
constructor(...args) {
|
|
17914
|
+
super(...args);
|
|
17915
|
+
this.state = {
|
|
17916
|
+
showErrors: false
|
|
17917
|
+
};
|
|
17918
|
+
this.handleToggleKatexErrors = e => {
|
|
17919
|
+
this.setState({
|
|
17920
|
+
showErrors: !this.state.showErrors
|
|
17921
|
+
});
|
|
17922
|
+
};
|
|
17923
|
+
}
|
|
17924
|
+
render() {
|
|
17925
|
+
const {
|
|
17926
|
+
errorList
|
|
17927
|
+
} = this.props;
|
|
17928
|
+
const {
|
|
17929
|
+
showErrors
|
|
17930
|
+
} = this.state;
|
|
17931
|
+
|
|
17932
|
+
// TODO(riley) replace with SVG icons
|
|
17933
|
+
const disclosureClass = showErrors ? "icon-chevron-down" : "icon-chevron-right";
|
|
17934
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
17935
|
+
className: css(styles$e.errorContainer)
|
|
17936
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
17937
|
+
className: css(styles$e.title),
|
|
17938
|
+
onClick: this.handleToggleKatexErrors
|
|
17939
|
+
}, /*#__PURE__*/React.createElement("i", {
|
|
17940
|
+
className: disclosureClass,
|
|
17941
|
+
style: {
|
|
17942
|
+
fontSize: 14
|
|
17943
|
+
}
|
|
17944
|
+
}), "\xA0 KaTeX Errors (", errorList.length, ")"), showErrors && /*#__PURE__*/React.createElement("div", {
|
|
17945
|
+
className: css(styles$e.errorExplanation)
|
|
17946
|
+
}, "These errors will cause your LaTeX to load really slowly for the student. Please fix them if you can. If you can\u2019t because KaTeX doesn\u2019t support the feature you need, please message Cam."), showErrors && errorList.map((e, index) => /*#__PURE__*/React.createElement("div", {
|
|
17947
|
+
className: css(styles$e.error),
|
|
17948
|
+
key: index
|
|
17949
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
17950
|
+
style: {
|
|
17951
|
+
color: "red"
|
|
17952
|
+
}
|
|
17953
|
+
}, e.math), /*#__PURE__*/React.createElement("div", null, e.message))));
|
|
17954
|
+
}
|
|
17955
|
+
}
|
|
17956
|
+
KatexErrorView.propTypes = {
|
|
17957
|
+
errorList: PropTypes.arrayOf(PropTypes.shape({
|
|
17958
|
+
math: PropTypes.string.isRequired,
|
|
17959
|
+
message: PropTypes.string.isRequired
|
|
17960
|
+
})).isRequired
|
|
17961
|
+
};
|
|
17962
|
+
const styles$e = StyleSheet.create({
|
|
17963
|
+
title: {
|
|
17964
|
+
backgroundColor: "#eee",
|
|
17965
|
+
fontSize: "1.25em",
|
|
17966
|
+
padding: "4px 10px"
|
|
17967
|
+
},
|
|
17968
|
+
errorContainer: {
|
|
17969
|
+
border: "1px solid #ddd",
|
|
17970
|
+
borderTop: "none"
|
|
17971
|
+
},
|
|
17972
|
+
errorExplanation: {
|
|
17973
|
+
padding: "4px 10px",
|
|
17974
|
+
backgroundColor: "pink"
|
|
17975
|
+
},
|
|
17976
|
+
error: {
|
|
17977
|
+
padding: "4px 10px"
|
|
17978
|
+
}
|
|
17979
|
+
});
|
|
17980
|
+
|
|
17981
|
+
// like [[snowman input-number 1]]
|
|
17982
|
+
const widgetPlaceholder = "[[\u2603 {id}]]";
|
|
17983
|
+
const widgetRegExp = "(\\[\\[\u2603 {id}\\]\\])";
|
|
17984
|
+
const rWidgetSplit = new RegExp(widgetRegExp.replace("{id}", "[a-z-]+ [0-9]+"), "g");
|
|
17985
|
+
const shortcutRegexp = /^\[\[([a-z-]+)$/; // like [[nu, [[int, etc
|
|
17986
|
+
|
|
17987
|
+
const ENDS_WITH_A_PARAGRAPH = /(?:\n{2,}|^\n*)$/;
|
|
17988
|
+
const TRAILING_NEWLINES = /(\n*)$/;
|
|
17989
|
+
const LEADING_NEWLINES = /^(\n*)/;
|
|
17990
|
+
const commafyInteger = n => {
|
|
17991
|
+
let str = n.toString();
|
|
17992
|
+
if (str.length >= 5) {
|
|
17993
|
+
str = str.replace(/(\d)(?=(\d{3})+$)/g, "$1{,}");
|
|
17994
|
+
}
|
|
17995
|
+
return str;
|
|
17996
|
+
};
|
|
17997
|
+
const makeEndWithAParagraphIfNecessary = content => {
|
|
17998
|
+
if (!ENDS_WITH_A_PARAGRAPH.test(content)) {
|
|
17999
|
+
const match = TRAILING_NEWLINES.exec(content);
|
|
18000
|
+
if (match) {
|
|
18001
|
+
const newlines = match[1];
|
|
18002
|
+
return content + "\n\n".slice(0, 2 - newlines.length);
|
|
18003
|
+
}
|
|
18004
|
+
}
|
|
18005
|
+
return content;
|
|
18006
|
+
};
|
|
18007
|
+
const makeStartWithAParagraphAlways = content => {
|
|
18008
|
+
const match = LEADING_NEWLINES.exec(content);
|
|
18009
|
+
if (!match) {
|
|
18010
|
+
return content;
|
|
18011
|
+
}
|
|
18012
|
+
const newlines = match[1];
|
|
18013
|
+
return "\n\n".slice(0, 2 - newlines.length) + content;
|
|
18014
|
+
};
|
|
18015
|
+
|
|
18012
18016
|
// This is more general than the actual markdown image parsing regex,
|
|
18013
18017
|
// which is fine for correctness since it should only mean we could
|
|
18014
18018
|
// store extra image dimensions, unless the question is insanely
|
|
@@ -18708,11 +18712,7 @@ class Editor extends React.Component {
|
|
|
18708
18712
|
// }, this);
|
|
18709
18713
|
|
|
18710
18714
|
this.widgetIds = _.keys(widgets);
|
|
18711
|
-
widgetsDropDown =
|
|
18712
|
-
/*#__PURE__*/
|
|
18713
|
-
// eslint-disable-next-line react/no-string-refs
|
|
18714
|
-
React.createElement(WidgetSelect, {
|
|
18715
|
-
ref: "widgetSelect",
|
|
18715
|
+
widgetsDropDown = /*#__PURE__*/React.createElement(WidgetSelect, {
|
|
18716
18716
|
onChange: this._addWidget
|
|
18717
18717
|
});
|
|
18718
18718
|
const insertTemplateString = "Insert template\u2026";
|
|
@@ -26898,6 +26898,80 @@ InteractionEditor.propTypes = _extends({}, Changeable.propTypes, {
|
|
|
26898
26898
|
InteractionEditor.widgetName = "interaction";
|
|
26899
26899
|
InteractionEditor.defaultProps = defaultInteractionProps;
|
|
26900
26900
|
|
|
26901
|
+
const UNLIMITED = "unlimited";
|
|
26902
|
+
// Parses a string (ostensibly from some UI element that only supports string
|
|
26903
|
+
// types, such as a <select />) into a numeric point count or the special sigil
|
|
26904
|
+
// "unlimited". Note that 0 is a special case, and means "unlimited".
|
|
26905
|
+
const parsePointCount = points => {
|
|
26906
|
+
const parsed = parseInt(points, 10);
|
|
26907
|
+
if (isNaN(parsed)) {
|
|
26908
|
+
return UNLIMITED;
|
|
26909
|
+
}
|
|
26910
|
+
return parsed === 0 ? UNLIMITED : parsed;
|
|
26911
|
+
};
|
|
26912
|
+
|
|
26913
|
+
const GraphPointsCountSelector = ({
|
|
26914
|
+
numPoints: _numPoints = 1,
|
|
26915
|
+
onChange
|
|
26916
|
+
}) => {
|
|
26917
|
+
return /*#__PURE__*/React.createElement("select", {
|
|
26918
|
+
value: _numPoints,
|
|
26919
|
+
onChange: e => {
|
|
26920
|
+
onChange(parsePointCount(e.target.value));
|
|
26921
|
+
}
|
|
26922
|
+
}, [...Array(7).keys()].map(n => /*#__PURE__*/React.createElement("option", {
|
|
26923
|
+
key: n,
|
|
26924
|
+
value: n
|
|
26925
|
+
}, `${n} point${n > 1 ? "s" : ""}`)), /*#__PURE__*/React.createElement("option", {
|
|
26926
|
+
value: UNLIMITED
|
|
26927
|
+
}, "unlimited"));
|
|
26928
|
+
};
|
|
26929
|
+
|
|
26930
|
+
const GraphTypeSelector = props => {
|
|
26931
|
+
return /*#__PURE__*/React.createElement("select", {
|
|
26932
|
+
value: props.graphType,
|
|
26933
|
+
onChange: e => {
|
|
26934
|
+
const type = e.target.value;
|
|
26935
|
+
props.onChange(type);
|
|
26936
|
+
}
|
|
26937
|
+
}, /*#__PURE__*/React.createElement("option", {
|
|
26938
|
+
value: "linear"
|
|
26939
|
+
}, "Linear function"), /*#__PURE__*/React.createElement("option", {
|
|
26940
|
+
value: "quadratic"
|
|
26941
|
+
}, "Quadratic function"), /*#__PURE__*/React.createElement("option", {
|
|
26942
|
+
value: "sinusoid"
|
|
26943
|
+
}, "Sinusoid function"), /*#__PURE__*/React.createElement("option", {
|
|
26944
|
+
value: "circle"
|
|
26945
|
+
}, "Circle"), /*#__PURE__*/React.createElement("option", {
|
|
26946
|
+
value: "point"
|
|
26947
|
+
}, "Point(s)"), /*#__PURE__*/React.createElement("option", {
|
|
26948
|
+
value: "linear-system"
|
|
26949
|
+
}, "Linear System"), /*#__PURE__*/React.createElement("option", {
|
|
26950
|
+
value: "polygon"
|
|
26951
|
+
}, "Polygon"), /*#__PURE__*/React.createElement("option", {
|
|
26952
|
+
value: "segment"
|
|
26953
|
+
}, "Line Segment(s)"), /*#__PURE__*/React.createElement("option", {
|
|
26954
|
+
value: "ray"
|
|
26955
|
+
}, "Ray"), /*#__PURE__*/React.createElement("option", {
|
|
26956
|
+
value: "angle"
|
|
26957
|
+
}, "Angle"));
|
|
26958
|
+
};
|
|
26959
|
+
|
|
26960
|
+
const SegmentCountSelector = ({
|
|
26961
|
+
numSegments: _numSegments = 1,
|
|
26962
|
+
onChange
|
|
26963
|
+
}) => /*#__PURE__*/React.createElement("select", {
|
|
26964
|
+
key: "segment-select",
|
|
26965
|
+
value: _numSegments,
|
|
26966
|
+
onChange: e => {
|
|
26967
|
+
const num = +e.target.value;
|
|
26968
|
+
onChange(num);
|
|
26969
|
+
}
|
|
26970
|
+
}, _.range(1, 7).map(n => /*#__PURE__*/React.createElement("option", {
|
|
26971
|
+
key: n,
|
|
26972
|
+
value: n
|
|
26973
|
+
}, `${n} segment${n > 1 ? "s" : ""}`)));
|
|
26974
|
+
|
|
26901
26975
|
const {
|
|
26902
26976
|
InfoTip: InfoTip$e
|
|
26903
26977
|
} = components;
|
|
@@ -26917,38 +26991,41 @@ const deprecatedProps = {
|
|
|
26917
26991
|
};
|
|
26918
26992
|
}
|
|
26919
26993
|
};
|
|
26920
|
-
|
|
26921
|
-
|
|
26922
|
-
|
|
26923
|
-
|
|
26924
|
-
|
|
26925
|
-
|
|
26926
|
-
|
|
26927
|
-
|
|
26928
|
-
|
|
26929
|
-
|
|
26930
|
-
|
|
26931
|
-
|
|
26932
|
-
|
|
26933
|
-
|
|
26934
|
-
|
|
26935
|
-
|
|
26936
|
-
|
|
26937
|
-
|
|
26938
|
-
|
|
26939
|
-
|
|
26940
|
-
|
|
26941
|
-
|
|
26942
|
-
|
|
26943
|
-
|
|
26944
|
-
|
|
26945
|
-
|
|
26946
|
-
|
|
26994
|
+
// [min, max]
|
|
26995
|
+
|
|
26996
|
+
// Renders the given children in a View laid out horizontally.
|
|
26997
|
+
const Row = props => {
|
|
26998
|
+
const {
|
|
26999
|
+
children,
|
|
27000
|
+
style
|
|
27001
|
+
} = props;
|
|
27002
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
27003
|
+
style: _extends({}, style, {
|
|
27004
|
+
flexDirection: "row",
|
|
27005
|
+
marginTop: Spacing.xSmall_8
|
|
27006
|
+
})
|
|
27007
|
+
}, children);
|
|
27008
|
+
};
|
|
27009
|
+
const FieldLabel = props => {
|
|
27010
|
+
return /*#__PURE__*/React.createElement(Typography.LabelSmall, {
|
|
27011
|
+
style: {
|
|
27012
|
+
marginRight: Spacing.xSmall_8
|
|
27013
|
+
}
|
|
27014
|
+
}, props.children);
|
|
27015
|
+
};
|
|
27016
|
+
class InteractiveGraphEditor extends React.Component {
|
|
27017
|
+
constructor(...args) {
|
|
27018
|
+
super(...args);
|
|
27019
|
+
this.displayName = "InteractiveGraphEditor";
|
|
27020
|
+
this.className = "perseus-widget-interactive-graph";
|
|
27021
|
+
this.deprecatedProps = deprecatedProps;
|
|
27022
|
+
}
|
|
26947
27023
|
// TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
|
|
26948
27024
|
UNSAFE_componentWillMount() {
|
|
26949
27025
|
DeprecationMixin.UNSAFE_componentWillMount.call(this);
|
|
26950
|
-
}
|
|
26951
|
-
render
|
|
27026
|
+
}
|
|
27027
|
+
render() {
|
|
27028
|
+
var _this$props$graph$typ, _this$props$graph, _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;
|
|
26952
27029
|
let graph;
|
|
26953
27030
|
let equationString;
|
|
26954
27031
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, interactiveSizes.defaultBoxSize);
|
|
@@ -27007,9 +27084,114 @@ const InteractiveGraphEditor = createReactClass({
|
|
|
27007
27084
|
className: "perseus-error"
|
|
27008
27085
|
}, this.props.valid);
|
|
27009
27086
|
}
|
|
27010
|
-
return /*#__PURE__*/React.createElement("
|
|
27011
|
-
|
|
27012
|
-
|
|
27087
|
+
return /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(FieldLabel, null, "Type of Graph:"), /*#__PURE__*/React.createElement(GraphTypeSelector, {
|
|
27088
|
+
graphType: (_this$props$graph$typ = (_this$props$graph = this.props.graph) == null ? void 0 : _this$props$graph.type) != null ? _this$props$graph$typ : InteractiveGraph.defaultProps.graph.type,
|
|
27089
|
+
onChange: type => {
|
|
27090
|
+
this.props.onChange({
|
|
27091
|
+
graph: {
|
|
27092
|
+
type
|
|
27093
|
+
},
|
|
27094
|
+
correct: {
|
|
27095
|
+
type
|
|
27096
|
+
}
|
|
27097
|
+
});
|
|
27098
|
+
}
|
|
27099
|
+
})), ((_this$props$correct = this.props.correct) == null ? void 0 : _this$props$correct.type) === "point" && /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(FieldLabel, null, "Number of Points:"), /*#__PURE__*/React.createElement(GraphPointsCountSelector, {
|
|
27100
|
+
numPoints: (_this$props$correct2 = this.props.correct) == null ? void 0 : _this$props$correct2.numPoints,
|
|
27101
|
+
onChange: points => {
|
|
27102
|
+
this.props.onChange({
|
|
27103
|
+
correct: {
|
|
27104
|
+
type: "point",
|
|
27105
|
+
numPoints: points
|
|
27106
|
+
}
|
|
27107
|
+
});
|
|
27108
|
+
}
|
|
27109
|
+
})), ((_this$props$correct3 = this.props.correct) == null ? void 0 : _this$props$correct3.type) === "polygon" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(FieldLabel, null, "Number of sides:"), /*#__PURE__*/React.createElement("select", {
|
|
27110
|
+
key: "polygon-select",
|
|
27111
|
+
value: ((_this$props$correct4 = this.props.correct) == null ? void 0 : _this$props$correct4.numSides) || 3,
|
|
27112
|
+
onChange: e => {
|
|
27113
|
+
const graph = _extends({}, this.props.correct, {
|
|
27114
|
+
numSides: parsePointCount(e.target.value),
|
|
27115
|
+
coords: null,
|
|
27116
|
+
// reset the snap for UNLIMITED, which
|
|
27117
|
+
// only supports "grid"
|
|
27118
|
+
// From: D6578
|
|
27119
|
+
snapTo: "grid"
|
|
27120
|
+
});
|
|
27121
|
+
this.props.onChange({
|
|
27122
|
+
correct: graph
|
|
27123
|
+
});
|
|
27124
|
+
}
|
|
27125
|
+
}, _.map(_.range(3, 13), function (n) {
|
|
27126
|
+
return /*#__PURE__*/React.createElement("option", {
|
|
27127
|
+
key: n,
|
|
27128
|
+
value: n
|
|
27129
|
+
}, `${n} sides`);
|
|
27130
|
+
}), /*#__PURE__*/React.createElement("option", {
|
|
27131
|
+
value: "unlimited"
|
|
27132
|
+
}, "unlimited sides"))), /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(FieldLabel, null, "Snap to:"), /*#__PURE__*/React.createElement("select", {
|
|
27133
|
+
key: "polygon-snap",
|
|
27134
|
+
value: (_this$props$correct5 = this.props.correct) == null ? void 0 : _this$props$correct5.snapTo,
|
|
27135
|
+
onChange: e => {
|
|
27136
|
+
const graph = _extends({}, this.props.correct, {
|
|
27137
|
+
snapTo: e.target.value,
|
|
27138
|
+
coords: null
|
|
27139
|
+
});
|
|
27140
|
+
this.props.onChange({
|
|
27141
|
+
correct: graph
|
|
27142
|
+
});
|
|
27143
|
+
}
|
|
27144
|
+
}, /*#__PURE__*/React.createElement("option", {
|
|
27145
|
+
value: "grid"
|
|
27146
|
+
}, "grid"), ((_this$props$correct6 = this.props.correct) == null ? void 0 : _this$props$correct6.numSides) !== "unlimited" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("option", {
|
|
27147
|
+
value: "angles"
|
|
27148
|
+
}, "interior angles"), /*#__PURE__*/React.createElement("option", {
|
|
27149
|
+
value: "sides"
|
|
27150
|
+
}, "side measures"))), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "These options affect the movement of the vertex points. The grid option will guide the points to the nearest half step along the grid."), /*#__PURE__*/React.createElement("p", null, "The interior angle and side measure options guide the points to the nearest whole angle or side"), " ", "measure respectively.")), /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(Typography.LabelSmall, {
|
|
27151
|
+
tag: "label"
|
|
27152
|
+
}, "Show angle measures:", " ", /*#__PURE__*/React.createElement("input", {
|
|
27153
|
+
type: "checkbox",
|
|
27154
|
+
checked: (_this$props$correct7 = this.props.correct) == null ? void 0 : _this$props$correct7.showAngles,
|
|
27155
|
+
onChange: () => {
|
|
27156
|
+
this.props.onChange({
|
|
27157
|
+
correct: _extends({}, this.props.correct, {
|
|
27158
|
+
showAngles: !this.props.correct.showAngles
|
|
27159
|
+
})
|
|
27160
|
+
});
|
|
27161
|
+
}
|
|
27162
|
+
})), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Displays the interior angle measures."))), /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(Typography.LabelSmall, {
|
|
27163
|
+
tag: "label"
|
|
27164
|
+
}, "Show side measures:", " ", /*#__PURE__*/React.createElement("input", {
|
|
27165
|
+
type: "checkbox",
|
|
27166
|
+
checked: (_this$props$correct8 = this.props.correct) == null ? void 0 : _this$props$correct8.showSides,
|
|
27167
|
+
onChange: () => {
|
|
27168
|
+
this.props.onChange({
|
|
27169
|
+
correct: _extends({}, this.props.correct, {
|
|
27170
|
+
showSides: !this.props.correct.showSides
|
|
27171
|
+
})
|
|
27172
|
+
});
|
|
27173
|
+
}
|
|
27174
|
+
})), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Displays the side lengths.")))), ((_this$props$correct9 = this.props.correct) == null ? void 0 : _this$props$correct9.type) === "segment" && /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(FieldLabel, null, "Number of segments: "), /*#__PURE__*/React.createElement(SegmentCountSelector, {
|
|
27175
|
+
numSegments: (_this$props$correct10 = this.props.correct) == null ? void 0 : _this$props$correct10.numSegments,
|
|
27176
|
+
onChange: sides => {
|
|
27177
|
+
this.props.onChange({
|
|
27178
|
+
correct: {
|
|
27179
|
+
type: "segment",
|
|
27180
|
+
numSegments: sides,
|
|
27181
|
+
coords: null
|
|
27182
|
+
}
|
|
27183
|
+
});
|
|
27184
|
+
}
|
|
27185
|
+
})), /*#__PURE__*/React.createElement(Row, null, /*#__PURE__*/React.createElement(FieldLabel, null, "Correct answer:"), /*#__PURE__*/React.createElement(Typography.BodyMonospace, {
|
|
27186
|
+
style: {
|
|
27187
|
+
fontSize: 12,
|
|
27188
|
+
backgroundColor: "#eee",
|
|
27189
|
+
paddingInline: Spacing.xxSmall_6,
|
|
27190
|
+
borderColor: "#ccc",
|
|
27191
|
+
borderStyle: "solid",
|
|
27192
|
+
borderWidth: 1
|
|
27193
|
+
}
|
|
27194
|
+
}, equationString), /*#__PURE__*/React.createElement(InfoTip$e, null, /*#__PURE__*/React.createElement("p", null, "Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."))), /*#__PURE__*/React.createElement(GraphSettings, {
|
|
27013
27195
|
box: getInteractiveBoxFromSizeClass(sizeClass),
|
|
27014
27196
|
range: this.props.range,
|
|
27015
27197
|
labels: this.props.labels,
|
|
@@ -27048,21 +27230,22 @@ const InteractiveGraphEditor = createReactClass({
|
|
|
27048
27230
|
}, "match exactly"), /*#__PURE__*/React.createElement("option", {
|
|
27049
27231
|
value: "congruent"
|
|
27050
27232
|
}, "be congruent"))), /*#__PURE__*/React.createElement(InfoTip$e, 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.")))), graph);
|
|
27051
|
-
}
|
|
27052
|
-
changeMatchType
|
|
27233
|
+
}
|
|
27234
|
+
changeMatchType(e) {
|
|
27053
27235
|
const correct = _.extend({}, this.props.correct, {
|
|
27054
27236
|
match: e.target.value
|
|
27055
27237
|
});
|
|
27056
27238
|
this.props.onChange({
|
|
27057
27239
|
correct: correct
|
|
27058
27240
|
});
|
|
27059
|
-
}
|
|
27060
|
-
serialize
|
|
27241
|
+
}
|
|
27242
|
+
serialize() {
|
|
27061
27243
|
const json = _.pick(this.props, "step", "backgroundImage", "markings", "labels", "showProtractor", "showRuler", "showTooltips", "rulerLabel", "rulerTicks", "range", "gridStep", "snapStep");
|
|
27062
27244
|
|
|
27063
27245
|
// eslint-disable-next-line react/no-string-refs
|
|
27064
27246
|
const graph = this.refs.graph;
|
|
27065
27247
|
if (graph) {
|
|
27248
|
+
// @ts-expect-error TS2339 Property 'getUserInput' does not exist on type 'ReactInstance'. Property 'getUserInput' does not exist on type 'Component<any, {}, any>'.
|
|
27066
27249
|
const correct = graph && graph.getUserInput();
|
|
27067
27250
|
_.extend(json, {
|
|
27068
27251
|
graph: {
|
|
@@ -27077,8 +27260,19 @@ const InteractiveGraphEditor = createReactClass({
|
|
|
27077
27260
|
}
|
|
27078
27261
|
});
|
|
27079
27262
|
}
|
|
27263
|
+
// @ts-expect-error TS2739 Type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "step" | "gridStep" | "snapStep" | "backgroundImage" | "markings" | "labels" | ... 5 more ... | "range">' is missing the following properties from type 'PerseusInteractiveGraphWidgetOptions': graph, correct
|
|
27080
27264
|
return json;
|
|
27081
27265
|
}
|
|
27266
|
+
}
|
|
27267
|
+
InteractiveGraphEditor.widgetName = "interactive-graph";
|
|
27268
|
+
InteractiveGraphEditor.defaultProps = _extends({}, InteractiveGraph.defaultProps, {
|
|
27269
|
+
valid: true,
|
|
27270
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
27271
|
+
showTooltips: false,
|
|
27272
|
+
correct: {
|
|
27273
|
+
type: InteractiveGraph.defaultProps.graph.type,
|
|
27274
|
+
coords: null
|
|
27275
|
+
}
|
|
27082
27276
|
});
|
|
27083
27277
|
|
|
27084
27278
|
const _excluded$1 = ["forwardedRef", "width", "grow", "shrink", "icon", "backgroundColor", "focusBorderColor", "borderColor", "color", "onSubmit", "leftSideIcon", "id", "testId", "type", "labelMediumInputText"];
|