@khanacademy/perseus-editor 0.0.1 → 0.1.2

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.
Files changed (127) hide show
  1. package/.babelrc.js +1 -1
  2. package/CHANGELOG.md +26 -0
  3. package/dist/es/index.css +1020 -0
  4. package/dist/es/index.js +9 -1
  5. package/dist/es/index.js.map +1 -1
  6. package/dist/index.css +1020 -0
  7. package/dist/index.js +9 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/strings.js +6 -1
  10. package/package.json +16 -4
  11. package/src/README.md +7 -0
  12. package/src/__stories__/editor.stories.js +33 -0
  13. package/src/__stories__/section-control-button.stories.jsx +27 -0
  14. package/src/__testdata__/input-number_testdata.js +28 -0
  15. package/src/__tests__/editor_test.jsx +123 -0
  16. package/src/__tests__/i18n_test.jsx +585 -0
  17. package/src/__tests__/traversal_test.jsx +378 -0
  18. package/src/all-editors.js +85 -0
  19. package/src/all-editors_test.js +17 -0
  20. package/src/all-widgets.js +10 -0
  21. package/src/article-editor.jsx +437 -0
  22. package/src/components/__stories__/blur-input.stories.jsx +24 -0
  23. package/src/components/blur-input.jsx +62 -0
  24. package/src/components/checkbox.jsx +194 -0
  25. package/src/components/device-framer.jsx +91 -0
  26. package/src/components/drag-target.jsx +88 -0
  27. package/src/components/dropdown-option.jsx +318 -0
  28. package/src/components/form-wrapped-text-field.jsx +248 -0
  29. package/src/components/graph-settings.jsx +631 -0
  30. package/src/components/hover-behavior.jsx +178 -0
  31. package/src/components/json-editor.jsx +121 -0
  32. package/src/components/link.jsx +173 -0
  33. package/src/components/simple-button.jsx +86 -0
  34. package/src/components/sortable.jsx +186 -0
  35. package/src/components/util.js +39 -0
  36. package/src/components/viewport-resizer.jsx +73 -0
  37. package/src/diffs/__stories__/perseus-diff-wrapper.jsx +8 -0
  38. package/src/diffs/__stories__/structured-item-diff.stories.jsx +855 -0
  39. package/src/diffs/__stories__/tags-diff.stories.jsx +38 -0
  40. package/src/diffs/__stories__/text-diff.stories.jsx +37 -0
  41. package/src/diffs/__tests__/split-diff_test.js +34 -0
  42. package/src/diffs/__tests__/string-array-diff_test.js +74 -0
  43. package/src/diffs/__tests__/structured-item-diff_test.js +432 -0
  44. package/src/diffs/__tests__/widget-diff-performer_test.js +44 -0
  45. package/src/diffs/article-diff.jsx +70 -0
  46. package/src/diffs/item-diff.jsx +77 -0
  47. package/src/diffs/renderer-diff.jsx +143 -0
  48. package/src/diffs/split-diff.jsx +30 -0
  49. package/src/diffs/string-array-diff.jsx +75 -0
  50. package/src/diffs/structured-item-diff.jsx +269 -0
  51. package/src/diffs/tags-diff.jsx +50 -0
  52. package/src/diffs/text-diff.jsx +194 -0
  53. package/src/diffs/widget-diff-performer.jsx +74 -0
  54. package/src/diffs/widget-diff.jsx +291 -0
  55. package/src/editor-page.jsx +351 -0
  56. package/src/editor.jsx +1364 -0
  57. package/src/hint-editor.jsx +447 -0
  58. package/src/i18n.jsx +139 -0
  59. package/src/iframe-content-renderer.jsx +201 -0
  60. package/src/index.js +27 -8
  61. package/src/item-editor.jsx +159 -0
  62. package/src/item-extras-editor.jsx +150 -0
  63. package/src/katex-error-view.jsx +87 -0
  64. package/src/multirenderer-editor.jsx +1074 -0
  65. package/src/section-control-button.jsx +53 -0
  66. package/src/stateful-article-editor.jsx +176 -0
  67. package/src/stateful-editor-page.jsx +90 -0
  68. package/src/styles/perseus-editor.less +1339 -0
  69. package/src/testing-widgets.js +12 -0
  70. package/src/util/register-all-widgets-and-editors-for-testing.js +15 -0
  71. package/src/util/register-all-widgets-and-editors-for-testing_test.js +18 -0
  72. package/src/widgets/__stories__/label-image-editor.stories.jsx +97 -0
  73. package/src/widgets/categorizer-editor.jsx +103 -0
  74. package/src/widgets/cs-program-editor.jsx +258 -0
  75. package/src/widgets/definition-editor.jsx +75 -0
  76. package/src/widgets/dropdown-editor.jsx +201 -0
  77. package/src/widgets/example-graphie-widget-editor.jsx +70 -0
  78. package/src/widgets/example-graphie-widget.jsx +175 -0
  79. package/src/widgets/example-widget-editor.jsx +60 -0
  80. package/src/widgets/example-widget.jsx +153 -0
  81. package/src/widgets/explanation-editor.jsx +89 -0
  82. package/src/widgets/expression-editor.jsx +560 -0
  83. package/src/widgets/graded-group-editor.jsx +162 -0
  84. package/src/widgets/graded-group-set-editor.jsx +101 -0
  85. package/src/widgets/grapher-editor.jsx +154 -0
  86. package/src/widgets/group-editor.jsx +83 -0
  87. package/src/widgets/iframe-editor.jsx +200 -0
  88. package/src/widgets/image-editor.jsx +326 -0
  89. package/src/widgets/input-number-editor.jsx +269 -0
  90. package/src/widgets/interaction/constraint-editor.jsx +147 -0
  91. package/src/widgets/interaction-editor.jsx +1389 -0
  92. package/src/widgets/interactive-graph-editor.jsx +322 -0
  93. package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +81 -0
  94. package/src/widgets/label-image/__stories__/behavior.stories.jsx +32 -0
  95. package/src/widgets/label-image/__stories__/marker.stories.jsx +76 -0
  96. package/src/widgets/label-image/__stories__/question-markers.stories.jsx +106 -0
  97. package/src/widgets/label-image/__stories__/select-image.stories.jsx +60 -0
  98. package/src/widgets/label-image/answer-choices.jsx +231 -0
  99. package/src/widgets/label-image/behavior.jsx +92 -0
  100. package/src/widgets/label-image/marker.jsx +292 -0
  101. package/src/widgets/label-image/question-markers.jsx +181 -0
  102. package/src/widgets/label-image/select-image.jsx +86 -0
  103. package/src/widgets/label-image-editor.jsx +257 -0
  104. package/src/widgets/lights-puzzle-editor.jsx +267 -0
  105. package/src/widgets/matcher-editor.jsx +147 -0
  106. package/src/widgets/matrix-editor.jsx +155 -0
  107. package/src/widgets/measurer-editor.jsx +245 -0
  108. package/src/widgets/molecule-editor.jsx +63 -0
  109. package/src/widgets/number-line-editor.jsx +498 -0
  110. package/src/widgets/numeric-input-editor.jsx +554 -0
  111. package/src/widgets/orderer-editor.jsx +166 -0
  112. package/src/widgets/passage-editor.jsx +115 -0
  113. package/src/widgets/passage-ref-editor.jsx +77 -0
  114. package/src/widgets/passage-ref-target-editor.jsx +47 -0
  115. package/src/widgets/plotter-editor.jsx +537 -0
  116. package/src/widgets/radio/editor.jsx +398 -0
  117. package/src/widgets/reaction-diagram-editor.jsx +127 -0
  118. package/src/widgets/sequence-editor.jsx +205 -0
  119. package/src/widgets/simple-markdown-tester-editor.jsx +84 -0
  120. package/src/widgets/simple-markdown-tester.jsx +91 -0
  121. package/src/widgets/simulator-editor.jsx +144 -0
  122. package/src/widgets/sorter-editor.jsx +100 -0
  123. package/src/widgets/table-editor.jsx +164 -0
  124. package/src/widgets/transformer-editor.jsx +1006 -0
  125. package/src/widgets/unit-editor.jsx +293 -0
  126. package/src/widgets/video-editor.jsx +74 -0
  127. package/src/__tests__/index.test.js +0 -15
@@ -0,0 +1,245 @@
1
+ /* eslint-disable react/sort-comp */
2
+ // @flow
3
+ import {components, Changeable, EditorJsonify} from "@khanacademy/perseus";
4
+ import PropTypes from "prop-types";
5
+ import * as React from "react";
6
+ import _ from "underscore";
7
+
8
+ const {InfoTip, NumberInput, PropCheckBox, RangeInput} = components;
9
+
10
+ const defaultImage = {
11
+ url: null,
12
+ top: 0,
13
+ left: 0,
14
+ };
15
+
16
+ type Props = $FlowFixMe;
17
+
18
+ class MeasurerEditor extends React.Component<Props> {
19
+ static widgetName: "measurer" = "measurer";
20
+
21
+ static propTypes = {
22
+ ...Changeable.propTypes,
23
+ box: PropTypes.arrayOf(PropTypes.number),
24
+ image: PropTypes.shape({
25
+ url: PropTypes.string,
26
+ top: PropTypes.number,
27
+ left: PropTypes.number,
28
+ }),
29
+ showProtractor: PropTypes.bool,
30
+ showRuler: PropTypes.bool,
31
+ rulerLabel: PropTypes.string,
32
+ rulerTicks: PropTypes.number,
33
+ rulerPixels: PropTypes.number,
34
+ rulerLength: PropTypes.number,
35
+ };
36
+
37
+ static defaultProps: Props = {
38
+ box: [480, 480],
39
+ image: {},
40
+ showProtractor: true,
41
+ showRuler: false,
42
+ rulerLabel: "",
43
+ rulerTicks: 10,
44
+ rulerPixels: 40,
45
+ rulerLength: 10,
46
+ };
47
+
48
+ className: string = "perseus-widget-measurer";
49
+
50
+ render(): React.Node {
51
+ const image = _.extend({}, defaultImage, this.props.image);
52
+
53
+ return (
54
+ <div className="perseus-widget-measurer">
55
+ <div>Image displayed under protractor and/or ruler:</div>
56
+ <div>
57
+ URL:{" "}
58
+ <input
59
+ type="text"
60
+ className="perseus-widget-measurer-url"
61
+ // eslint-disable-next-line react/no-string-refs
62
+ ref="image-url"
63
+ defaultValue={image.url}
64
+ onChange={this._changeUrl}
65
+ />
66
+ <InfoTip>
67
+ <p>
68
+ Create an image in graphie, or use the "Add image"
69
+ function to create a background.
70
+ </p>
71
+ </InfoTip>
72
+ </div>
73
+ {image.url && (
74
+ <div className="perseus-widget-row">
75
+ <label className="perseus-widget-left-col">
76
+ Pixels from top:{" "}
77
+ <NumberInput
78
+ placeholder={0}
79
+ onChange={this._changeTop}
80
+ value={image.top}
81
+ useArrowKeys={true}
82
+ />
83
+ </label>
84
+ <label className="perseus-widget-right-col">
85
+ Pixels from left:{" "}
86
+ <NumberInput
87
+ placeholder={0}
88
+ onChange={this._changeLeft}
89
+ value={image.left}
90
+ useArrowKeys={true}
91
+ />
92
+ </label>
93
+ </div>
94
+ )}
95
+ <div>
96
+ Containing area [width, height]:{" "}
97
+ <RangeInput
98
+ onChange={this.change("box")}
99
+ value={this.props.box}
100
+ useArrowKeys={true}
101
+ />
102
+ </div>
103
+ <div className="perseus-widget-row">
104
+ <div className="perseus-widget-left-col">
105
+ <PropCheckBox
106
+ label="Show ruler"
107
+ showRuler={this.props.showRuler}
108
+ onChange={this.props.onChange}
109
+ />
110
+ </div>
111
+ <div className="perseus-widget-right-col">
112
+ <PropCheckBox
113
+ label="Show protractor"
114
+ showProtractor={this.props.showProtractor}
115
+ onChange={this.props.onChange}
116
+ />
117
+ </div>
118
+ </div>
119
+ {this.props.showRuler && (
120
+ <div>
121
+ <div>
122
+ <label>
123
+ {" "}
124
+ Ruler label:{" "}
125
+ <select
126
+ onChange={(e) =>
127
+ this.change(
128
+ "rulerLabel",
129
+ e.target.value,
130
+ )
131
+ }
132
+ value={this.props.rulerLabel}
133
+ >
134
+ <option value="">None</option>
135
+ <optgroup label="Metric">
136
+ {this.renderLabelChoices([
137
+ ["milimeters", "mm"],
138
+ ["centimeters", "cm"],
139
+ ["meters", "m"],
140
+ ["kilometers", "km"],
141
+ ])}
142
+ </optgroup>
143
+ <optgroup label="Imperial">
144
+ {this.renderLabelChoices([
145
+ ["inches", "in"],
146
+ ["feet", "ft"],
147
+ ["yards", "yd"],
148
+ ["miles", "mi"],
149
+ ])}
150
+ </optgroup>
151
+ </select>
152
+ </label>
153
+ </div>
154
+ <div>
155
+ <label>
156
+ {" "}
157
+ Ruler ticks:{" "}
158
+ <select
159
+ onChange={(e) =>
160
+ this.change(
161
+ "rulerTicks",
162
+ +e.target.value,
163
+ )
164
+ }
165
+ value={this.props.rulerTicks}
166
+ >
167
+ {_.map([1, 2, 4, 8, 10, 16], function (n) {
168
+ return (
169
+ <option key={n} value={n}>
170
+ {n}
171
+ </option>
172
+ );
173
+ })}
174
+ </select>
175
+ </label>
176
+ </div>
177
+ <div>
178
+ <label>
179
+ Ruler pixels per unit:{" "}
180
+ <NumberInput
181
+ placeholder={40}
182
+ onChange={this.change("rulerPixels")}
183
+ value={this.props.rulerPixels}
184
+ useArrowKeys={true}
185
+ />
186
+ </label>
187
+ </div>
188
+ <div>
189
+ <label>
190
+ Ruler length in units:{" "}
191
+ <NumberInput
192
+ placeholder={10}
193
+ onChange={this.change("rulerLength")}
194
+ value={this.props.rulerLength}
195
+ useArrowKeys={true}
196
+ />
197
+ </label>
198
+ </div>
199
+ </div>
200
+ )}
201
+ </div>
202
+ );
203
+ }
204
+
205
+ change: ($FlowFixMe, $FlowFixMe, $FlowFixMe) => $FlowFixMe = (...args) => {
206
+ return Changeable.change.apply(this, args);
207
+ };
208
+
209
+ _changeUrl: (SyntheticInputEvent<>) => void = (e) => {
210
+ this._changeImage("url", e.target.value);
211
+ };
212
+
213
+ _changeTop: ($FlowFixMe) => void = (newTop) => {
214
+ this._changeImage("top", newTop);
215
+ };
216
+
217
+ _changeLeft: ($FlowFixMe) => void = (newLeft) => {
218
+ this._changeImage("left", newLeft);
219
+ };
220
+
221
+ _changeImage: (string, $FlowFixMe) => void = (subProp, newValue) => {
222
+ const image = _.clone(this.props.image);
223
+ image[subProp] = newValue;
224
+ this.change("image", image);
225
+ };
226
+
227
+ renderLabelChoices: (
228
+ $ReadOnlyArray<[string, string]>,
229
+ ) => $ReadOnlyArray<React.Element<"option">> = (choices) => {
230
+ return _.map(choices, function (nameAndValue) {
231
+ const [name, value] = nameAndValue;
232
+ return (
233
+ <option key={value} value={value}>
234
+ {name}
235
+ </option>
236
+ );
237
+ });
238
+ };
239
+
240
+ serialize: () => $FlowFixMe = () => {
241
+ return EditorJsonify.serialize.call(this);
242
+ };
243
+ }
244
+
245
+ export default MeasurerEditor;
@@ -0,0 +1,63 @@
1
+ // @flow
2
+ import {components, Changeable, EditorJsonify} from "@khanacademy/perseus";
3
+ import PropTypes from "prop-types";
4
+ import * as React from "react";
5
+
6
+ const {NumberInput, TextInput} = components;
7
+
8
+ type Props = $FlowFixMe;
9
+
10
+ class MoleculeWidgetEditor extends React.Component<Props> {
11
+ static propTypes = {
12
+ ...Changeable.propTypes,
13
+ rotationAngle: PropTypes.number,
14
+ smiles: PropTypes.string,
15
+ };
16
+
17
+ static widgetName: "molecule-renderer" = "molecule-renderer";
18
+
19
+ change: ($FlowFixMe, $FlowFixMe, $FlowFixMe) => $FlowFixMe = (...args) => {
20
+ return Changeable.change.apply(this, args);
21
+ };
22
+
23
+ updateMolecule: (string) => void = (newValue) => {
24
+ this.change({smiles: newValue});
25
+ };
26
+
27
+ updateRotation: (string) => void = (newValue) => {
28
+ this.change({rotationAngle: newValue});
29
+ };
30
+
31
+ serialize: () => $FlowFixMe = () => {
32
+ return EditorJsonify.serialize.call(this);
33
+ };
34
+
35
+ render(): React.Node {
36
+ return (
37
+ <div>
38
+ <div>
39
+ {/* TODO(colin): instead of nbsp hacks, use styles to get
40
+ the spacing right. */}
41
+ <label>
42
+ SMILES:&nbsp;
43
+ <TextInput
44
+ onChange={this.updateMolecule}
45
+ value={this.props.smiles}
46
+ />
47
+ </label>
48
+ </div>
49
+ <div>
50
+ <label>
51
+ Rotation (deg):&nbsp;
52
+ <NumberInput
53
+ onChange={this.updateRotation}
54
+ value={this.props.rotationAngle}
55
+ />
56
+ </label>
57
+ </div>
58
+ </div>
59
+ );
60
+ }
61
+ }
62
+
63
+ export default MoleculeWidgetEditor;