@khanacademy/perseus-editor 4.1.5 → 4.1.6

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 (175) hide show
  1. package/dist/es/index.js +1 -1
  2. package/dist/index.js +1 -1
  3. package/package.json +9 -6
  4. package/.babelrc.js +0 -8
  5. package/.eslintrc.js +0 -12
  6. package/CHANGELOG.md +0 -1155
  7. package/src/README.md +0 -7
  8. package/src/__stories__/editor-page.stories.tsx +0 -65
  9. package/src/__stories__/editor.stories.tsx +0 -134
  10. package/src/__stories__/item-editor.stories.tsx +0 -41
  11. package/src/__stories__/tex-error-view.stories.tsx +0 -26
  12. package/src/__testdata__/input-number.testdata.ts +0 -27
  13. package/src/__tests__/editor.test.tsx +0 -142
  14. package/src/__tests__/hint-editor.test.tsx +0 -83
  15. package/src/__tests__/i18n.test.ts +0 -501
  16. package/src/__tests__/integration.test.ts +0 -5
  17. package/src/__tests__/item-extras-editor.test.tsx +0 -85
  18. package/src/__tests__/traversal.test.ts +0 -377
  19. package/src/all-editors.test.ts +0 -16
  20. package/src/all-editors.ts +0 -83
  21. package/src/all-widgets.ts +0 -7
  22. package/src/article-editor.tsx +0 -438
  23. package/src/components/__stories__/blur-input.stories.tsx +0 -22
  24. package/src/components/__stories__/section-control-button.stories.tsx +0 -26
  25. package/src/components/__tests__/blur-input.test.tsx +0 -67
  26. package/src/components/blur-input.tsx +0 -69
  27. package/src/components/checkbox.tsx +0 -194
  28. package/src/components/device-framer.tsx +0 -90
  29. package/src/components/drag-target.tsx +0 -87
  30. package/src/components/dropdown-option.tsx +0 -311
  31. package/src/components/form-wrapped-text-field.tsx +0 -245
  32. package/src/components/graph-points-count-selector.tsx +0 -31
  33. package/src/components/graph-settings.tsx +0 -627
  34. package/src/components/graph-type-selector.tsx +0 -31
  35. package/src/components/hover-behavior.ts +0 -177
  36. package/src/components/json-editor.tsx +0 -121
  37. package/src/components/link.ts +0 -173
  38. package/src/components/section-control-button.tsx +0 -53
  39. package/src/components/segment-count-selector.tsx +0 -27
  40. package/src/components/simple-button.tsx +0 -85
  41. package/src/components/sortable.tsx +0 -187
  42. package/src/components/util.ts +0 -38
  43. package/src/components/viewport-resizer.tsx +0 -72
  44. package/src/components/widget-editor.tsx +0 -222
  45. package/src/components/widget-select.tsx +0 -48
  46. package/src/diffs/__stories__/perseus-diff-wrapper.tsx +0 -11
  47. package/src/diffs/__stories__/structured-item-diff.stories.tsx +0 -855
  48. package/src/diffs/__stories__/tags-diff.stories.tsx +0 -36
  49. package/src/diffs/__stories__/text-diff.stories.tsx +0 -35
  50. package/src/diffs/__tests__/split-diff.test.ts +0 -33
  51. package/src/diffs/__tests__/string-array-diff.test.ts +0 -73
  52. package/src/diffs/__tests__/structured-item-diff.test.ts +0 -433
  53. package/src/diffs/__tests__/widget-diff-performer.test.ts +0 -43
  54. package/src/diffs/article-diff.tsx +0 -69
  55. package/src/diffs/item-diff.tsx +0 -76
  56. package/src/diffs/renderer-diff.tsx +0 -137
  57. package/src/diffs/split-diff.ts +0 -31
  58. package/src/diffs/string-array-diff.ts +0 -74
  59. package/src/diffs/structured-item-diff.tsx +0 -275
  60. package/src/diffs/tags-diff.tsx +0 -49
  61. package/src/diffs/text-diff.tsx +0 -193
  62. package/src/diffs/widget-diff-performer.ts +0 -69
  63. package/src/diffs/widget-diff.tsx +0 -290
  64. package/src/editor-page.tsx +0 -325
  65. package/src/editor.tsx +0 -1099
  66. package/src/hint-editor.tsx +0 -469
  67. package/src/i18n.ts +0 -140
  68. package/src/iframe-content-renderer.tsx +0 -188
  69. package/src/index.ts +0 -30
  70. package/src/item-editor.tsx +0 -158
  71. package/src/item-extras-editor.tsx +0 -230
  72. package/src/katex-mhchem/index.js +0 -73
  73. package/src/katex-mhchem/parser.js +0 -2659
  74. package/src/multirenderer-editor.tsx +0 -1061
  75. package/src/stateful-article-editor.tsx +0 -173
  76. package/src/stateful-editor-page.tsx +0 -88
  77. package/src/styles/perseus-editor.less +0 -1321
  78. package/src/testing-widgets.ts +0 -11
  79. package/src/tex-error-view.tsx +0 -90
  80. package/src/util/points.test.ts +0 -24
  81. package/src/util/points.ts +0 -13
  82. package/src/util/register-all-widgets-and-editors-for-testing.test.ts +0 -17
  83. package/src/util/register-all-widgets-and-editors-for-testing.ts +0 -17
  84. package/src/version.ts +0 -10
  85. package/src/widgets/__stories__/categorizer-editor.stories.tsx +0 -24
  86. package/src/widgets/__stories__/definition-editor.stories.tsx +0 -18
  87. package/src/widgets/__stories__/dropdown-editor.stories.tsx +0 -18
  88. package/src/widgets/__stories__/explanation-editor.stories.tsx +0 -18
  89. package/src/widgets/__stories__/expression-editor.stories.tsx +0 -122
  90. package/src/widgets/__stories__/image-editor.stories.tsx +0 -72
  91. package/src/widgets/__stories__/input-number-editor.stories.tsx +0 -18
  92. package/src/widgets/__stories__/interaction-editor.stories.tsx +0 -37
  93. package/src/widgets/__stories__/label-image-editor.stories.tsx +0 -99
  94. package/src/widgets/__stories__/matcher-editor.stories.tsx +0 -18
  95. package/src/widgets/__stories__/number-line-editor.stories.tsx +0 -18
  96. package/src/widgets/__stories__/numeric-input-editor.stories.tsx +0 -18
  97. package/src/widgets/__stories__/radio-editor.stories.tsx +0 -116
  98. package/src/widgets/__stories__/sorter-editor.stories.tsx +0 -18
  99. package/src/widgets/__tests__/categorizer-editor.test.tsx +0 -51
  100. package/src/widgets/__tests__/definition-editor.test.tsx +0 -41
  101. package/src/widgets/__tests__/dropdown-editor.test.tsx +0 -57
  102. package/src/widgets/__tests__/explanation-editor.test.tsx +0 -59
  103. package/src/widgets/__tests__/expression-editor.test.tsx +0 -403
  104. package/src/widgets/__tests__/input-number-editor.test.tsx +0 -128
  105. package/src/widgets/__tests__/matcher-editor.test.tsx +0 -47
  106. package/src/widgets/__tests__/number-line-editor.test.tsx +0 -144
  107. package/src/widgets/__tests__/numeric-input-editor.test.tsx +0 -177
  108. package/src/widgets/__tests__/radio-editor.test.tsx +0 -118
  109. package/src/widgets/__tests__/sorter-editor.test.tsx +0 -55
  110. package/src/widgets/categorizer-editor.tsx +0 -104
  111. package/src/widgets/cs-program-editor.tsx +0 -256
  112. package/src/widgets/definition-editor.tsx +0 -77
  113. package/src/widgets/deprecated-standin-editor.tsx +0 -29
  114. package/src/widgets/dropdown-editor.tsx +0 -211
  115. package/src/widgets/example-graphie-widget-editor.tsx +0 -70
  116. package/src/widgets/example-graphie-widget.tsx +0 -172
  117. package/src/widgets/example-widget-editor.tsx +0 -62
  118. package/src/widgets/example-widget.tsx +0 -154
  119. package/src/widgets/explanation-editor.tsx +0 -92
  120. package/src/widgets/expression-editor.tsx +0 -557
  121. package/src/widgets/graded-group-editor.tsx +0 -161
  122. package/src/widgets/graded-group-set-editor.tsx +0 -104
  123. package/src/widgets/grapher-editor.tsx +0 -155
  124. package/src/widgets/group-editor.tsx +0 -83
  125. package/src/widgets/iframe-editor.tsx +0 -202
  126. package/src/widgets/image-editor.tsx +0 -367
  127. package/src/widgets/input-number-editor.tsx +0 -288
  128. package/src/widgets/interaction-editor/constraint-editor.tsx +0 -134
  129. package/src/widgets/interaction-editor/function-editor.tsx +0 -108
  130. package/src/widgets/interaction-editor/index.ts +0 -3
  131. package/src/widgets/interaction-editor/interaction-editor.tsx +0 -749
  132. package/src/widgets/interaction-editor/label-editor.tsx +0 -87
  133. package/src/widgets/interaction-editor/line-editor.tsx +0 -125
  134. package/src/widgets/interaction-editor/mathquill-input.tsx +0 -81
  135. package/src/widgets/interaction-editor/movable-line-editor.tsx +0 -121
  136. package/src/widgets/interaction-editor/movable-point-editor.tsx +0 -89
  137. package/src/widgets/interaction-editor/parametric-editor.tsx +0 -117
  138. package/src/widgets/interaction-editor/point-editor.tsx +0 -72
  139. package/src/widgets/interaction-editor/rectangle-editor.tsx +0 -96
  140. package/src/widgets/interactive-graph-editor.tsx +0 -571
  141. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -82
  142. package/src/widgets/label-image/__stories__/behavior.stories.tsx +0 -31
  143. package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -75
  144. package/src/widgets/label-image/__stories__/question-markers.stories.tsx +0 -107
  145. package/src/widgets/label-image/__stories__/select-image.stories.tsx +0 -59
  146. package/src/widgets/label-image/answer-choices.tsx +0 -231
  147. package/src/widgets/label-image/behavior.tsx +0 -122
  148. package/src/widgets/label-image/marker.tsx +0 -290
  149. package/src/widgets/label-image/question-markers.tsx +0 -176
  150. package/src/widgets/label-image/select-image.tsx +0 -81
  151. package/src/widgets/label-image-editor.tsx +0 -252
  152. package/src/widgets/lights-puzzle-editor.tsx +0 -278
  153. package/src/widgets/matcher-editor.tsx +0 -149
  154. package/src/widgets/matrix-editor.tsx +0 -156
  155. package/src/widgets/measurer-editor.tsx +0 -253
  156. package/src/widgets/molecule-editor.tsx +0 -64
  157. package/src/widgets/number-line-editor.tsx +0 -512
  158. package/src/widgets/numeric-input-editor.tsx +0 -536
  159. package/src/widgets/orderer-editor.tsx +0 -172
  160. package/src/widgets/passage-editor.tsx +0 -117
  161. package/src/widgets/passage-ref-editor.tsx +0 -80
  162. package/src/widgets/passage-ref-target-editor.tsx +0 -49
  163. package/src/widgets/plotter-editor.tsx +0 -542
  164. package/src/widgets/radio/editor.tsx +0 -398
  165. package/src/widgets/reaction-diagram-editor.tsx +0 -131
  166. package/src/widgets/sequence-editor.tsx +0 -205
  167. package/src/widgets/simple-markdown-tester-editor.tsx +0 -86
  168. package/src/widgets/simple-markdown-tester.tsx +0 -92
  169. package/src/widgets/simulator-editor.tsx +0 -146
  170. package/src/widgets/sorter-editor.tsx +0 -103
  171. package/src/widgets/table-editor.tsx +0 -164
  172. package/src/widgets/unit-editor.tsx +0 -299
  173. package/src/widgets/video-editor.tsx +0 -73
  174. package/tsconfig-build.json +0 -22
  175. package/tsconfig-build.tsbuildinfo +0 -1
@@ -1,290 +0,0 @@
1
- /* eslint-disable @khanacademy/ts-no-error-suppressions */
2
- /* eslint-disable react/no-unsafe */
3
- /**
4
- * Controlled editor image marker on the question image.
5
- *
6
- * Allows to select which label choices are the answers for each marker, using
7
- * the dropdown component.
8
- */
9
-
10
- import {globalConstants, globalStyles} from "@khanacademy/perseus";
11
- import {StyleSheet, css} from "aphrodite";
12
- import * as React from "react";
13
-
14
- import Option, {OptionGroup} from "../../components/dropdown-option";
15
- import FormWrappedTextField from "../../components/form-wrapped-text-field";
16
-
17
- import type {MarkerType} from "@khanacademy/perseus";
18
-
19
- const {colors, borderRadius} = globalStyles;
20
-
21
- type Props = MarkerType & {
22
- // The list of possible answer choices.
23
- choices: ReadonlyArray<string>;
24
- // Callback for when any of the marker props are changed.
25
- onChange: (marker: MarkerType) => void;
26
- // Callback to remove marker from the question image.
27
- onRemove: () => void;
28
- };
29
-
30
- type State = {
31
- // Whether answer choices dropdown is shown, controlled by the user clicking
32
- // on the marker icon.
33
- showDropdown: boolean;
34
- };
35
-
36
- export default class Marker extends React.Component<Props, State> {
37
- _marker: HTMLElement | null | undefined;
38
-
39
- constructor(props: Props) {
40
- super(props);
41
-
42
- this.state = {
43
- showDropdown: false,
44
- };
45
- }
46
-
47
- componentDidMount() {
48
- document.addEventListener("click", this.handleClick, true);
49
- }
50
-
51
- UNSAFE_componentWillReceiveProps(nextProps: Props) {
52
- const {answers} = this.props;
53
-
54
- // Exclude those answers that are no longer present in choices.
55
- const filteredAnswers = answers.filter((answer) =>
56
- nextProps.choices.includes(answer),
57
- );
58
-
59
- if (JSON.stringify(answers) !== JSON.stringify(filteredAnswers)) {
60
- // Update marker on the next frame when these props take affect.
61
- // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
62
- // eslint-disable-next-line no-restricted-syntax
63
- setTimeout(() => this.updateMarker({answers: filteredAnswers}));
64
- }
65
- }
66
-
67
- componentWillUnmount() {
68
- document.removeEventListener("click", this.handleClick, true);
69
- }
70
-
71
- openDropdown() {
72
- this.setState({showDropdown: true});
73
- }
74
-
75
- updateMarker(props: any) {
76
- const {answers, label, onChange, x, y} = this.props;
77
-
78
- onChange({
79
- answers,
80
- label,
81
- x,
82
- y,
83
- // Overwrite with updated prop(s).
84
- ...props,
85
- });
86
- }
87
-
88
- handleClick: (e: MouseEvent) => void = (e: MouseEvent) => {
89
- const {showDropdown} = this.state;
90
-
91
- if (this._marker === e.target) {
92
- this.setState({showDropdown: !showDropdown});
93
- } else if (showDropdown) {
94
- // Close dropdown if click event was registered anywhere outside it.
95
- if (this._marker && !this._marker.contains(e.target as any)) {
96
- // Ensure other listeners are not triggered on click event that
97
- // closes the dropdown. A specific case this addresses is when
98
- // user clicks on question image to close dropdown, a new marker
99
- // will be created, this is bad for usability.
100
- e.stopPropagation();
101
-
102
- this.setState({showDropdown: false});
103
- }
104
- }
105
- };
106
-
107
- handleLabelChange: (e: React.ChangeEvent<HTMLInputElement>) => void = (
108
- e,
109
- ) => {
110
- this.updateMarker({label: e.target.value});
111
- };
112
-
113
- handleSelectAnswer: (toggleAnswer: string) => void = (
114
- toggleAnswer: string,
115
- ) => {
116
- let {answers} = this.props;
117
-
118
- if (answers.includes(toggleAnswer)) {
119
- answers = answers.filter((answer) => answer !== toggleAnswer);
120
- } else {
121
- answers = [...answers, toggleAnswer];
122
- }
123
-
124
- this.updateMarker({answers});
125
- };
126
-
127
- render(): React.ReactNode {
128
- const {answers, choices, label, onRemove, x, y} = this.props;
129
-
130
- const {showDropdown} = this.state;
131
-
132
- return (
133
- <div
134
- className={css(
135
- styles.marker,
136
- answers.length > 0 && styles.markerWithAnswers,
137
- showDropdown && styles.markerSelected,
138
- )}
139
- ref={(node) => (this._marker = node)}
140
- style={{
141
- left: `${x}%`,
142
- top: `${y}%`,
143
- }}
144
- title={
145
- "Click to select marker answers or to delete marker. " +
146
- "Repositioning marker is not implemented."
147
- }
148
- >
149
- {showDropdown && (
150
- <div>
151
- <div
152
- className={css(
153
- styles.dropdownBody,
154
- styles.dropdownPositionWithArrow,
155
- )}
156
- >
157
- <Option value="" onClick={() => onRemove()}>
158
- Delete marker
159
- </Option>
160
-
161
- <hr className={css(styles.dividerHorizontal)} />
162
-
163
- <OptionGroup
164
- onSelected={this.handleSelectAnswer}
165
- // TODO(WB-1096): make selectedValues immutable in wonder-blocks
166
- // @ts-expect-error - TS2769 - No overload matches this call.
167
- selectedValues={answers}
168
- >
169
- {choices.map((choice) => (
170
- <Option key={choice} value={choice}>
171
- {choice}
172
- </Option>
173
- ))}
174
- </OptionGroup>
175
-
176
- <div className={css(styles.labelContainer)}>
177
- <FormWrappedTextField
178
- placeholder="ARIA label (for screen readers)"
179
- onChange={this.handleLabelChange}
180
- value={label}
181
- width="100%"
182
- />
183
- </div>
184
- </div>
185
- </div>
186
- )}
187
- </div>
188
- );
189
- }
190
- }
191
-
192
- const styles = StyleSheet.create({
193
- marker: {
194
- position: "absolute",
195
-
196
- boxSizing: "content-box",
197
-
198
- width: 16,
199
- height: 16,
200
- marginLeft: -8,
201
- marginTop: -8,
202
-
203
- cursor: "pointer",
204
-
205
- background:
206
- "linear-gradient(to bottom, rgba(33, 36, 44, 0.2), rgba(33, 36, 44, 0.5))",
207
-
208
- border: "solid 2px #ffffff",
209
- borderRadius: 16,
210
-
211
- boxShadow: "0 2px 10px 0 rgba(33, 36, 44, 0.1)",
212
- },
213
-
214
- markerSelected: {
215
- width: 28,
216
- height: 28,
217
- marginLeft: -12,
218
- marginTop: -12,
219
-
220
- border: "none",
221
- borderRadius: 28,
222
-
223
- // Render selected marker border as inset.
224
- "::before": {
225
- content: "''",
226
- display: "block",
227
-
228
- width: 20,
229
- height: 20,
230
- marginLeft: 2,
231
- marginTop: 2,
232
-
233
- border: "solid 2px #ffffff",
234
- borderRadius: 20,
235
- },
236
- },
237
-
238
- markerWithAnswers: {
239
- background: "#1865f2",
240
- },
241
-
242
- dropdownPositionWithArrow: {
243
- // Position dropdown to the top right of the marker.
244
- left: 46,
245
- bottom: -12,
246
-
247
- // With an arrow pointing left towards the marker.
248
- "::before": {
249
- content: "''",
250
- display: "block",
251
- position: "absolute",
252
-
253
- width: 0,
254
- height: 0,
255
- left: -16,
256
- bottom: 8,
257
-
258
- borderRight: `solid 16px ${colors.gray98}`,
259
- borderTop: "solid 16px transparent",
260
- borderBottom: "solid 16px transparent",
261
- },
262
- },
263
-
264
- labelContainer: {
265
- padding: 4,
266
- },
267
-
268
- dividerHorizontal: {
269
- height: 0,
270
- margin: 0,
271
-
272
- border: `solid ${colors.gray85}`,
273
- borderWidth: "0 0 1px",
274
-
275
- boxShadow: "none",
276
- },
277
-
278
- // TODO (josh): This should probably be its own component, rather than
279
- // sharing styles this way.
280
- dropdownBody: {
281
- position: "absolute",
282
- border: "solid 1px rgba(0, 0, 0, 0.1)",
283
- zIndex: globalConstants.zindexDropdown,
284
- color: colors.gray17,
285
- backgroundColor: colors.gray98,
286
- borderRadius: borderRadius,
287
- maxHeight: 320,
288
- cursor: "pointer",
289
- },
290
- });
@@ -1,176 +0,0 @@
1
- /**
2
- * Controlled component to display question image and create markers to
3
- * label image with answers from list of choices.
4
- */
5
-
6
- import {Util, Dependencies, globalStyles} from "@khanacademy/perseus";
7
- import {StyleSheet, css} from "aphrodite";
8
- import * as React from "react";
9
-
10
- import Marker from "./marker";
11
-
12
- import type {MarkerType} from "@khanacademy/perseus";
13
-
14
- const {colors, typography} = globalStyles;
15
-
16
- type Props = {
17
- // The list of possible answers in a specific order.
18
- choices: ReadonlyArray<string>;
19
- // The question image properties.
20
- imageUrl: string;
21
- imageWidth: number;
22
- imageHeight: number;
23
- // The list of markers placed on the question image.
24
- markers: ReadonlyArray<MarkerType>;
25
- // Callback for when any of markers change.
26
- onChange: (markers: ReadonlyArray<MarkerType>) => void;
27
- };
28
-
29
- export default class QuestionMarkers extends React.Component<Props> {
30
- _markers: Array<Marker | null | undefined> = [];
31
-
32
- openDropdownForMarkerIndices(indices: ReadonlyArray<number>) {
33
- // Open answer selection dropdown for each of the specified markers.
34
- indices.forEach((index) => {
35
- if (this._markers[index]) {
36
- // @ts-expect-error - TS2533 - Object is possibly 'null' or 'undefined'.
37
- this._markers[index].openDropdown();
38
- }
39
- });
40
- }
41
-
42
- handleImageDoubleClick: (e: React.MouseEvent) => void = (
43
- e: React.MouseEvent,
44
- ) => {
45
- e.preventDefault();
46
-
47
- const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
48
-
49
- // Calculate marker position on the question image as percentage offset
50
- // rounded to one decimal place.
51
- const x =
52
- Math.round(((e.clientX - rect.left) / rect.width) * 1000) / 10;
53
- const y =
54
- Math.round(((e.clientY - rect.top) / rect.height) * 1000) / 10;
55
-
56
- const {markers, onChange} = this.props;
57
-
58
- // Add the new marker to the end of the list.
59
- onChange([
60
- ...markers,
61
- {
62
- answers: [],
63
- label: "",
64
- x,
65
- y,
66
- },
67
- ]);
68
- };
69
-
70
- render(): React.ReactNode {
71
- const {choices, imageUrl, imageWidth, imageHeight, markers, onChange} =
72
- this.props;
73
-
74
- const staticUrl = Dependencies.getDependencies().staticUrl;
75
-
76
- // TODO(michaelpolyak): If a Graphie image is specified, only its SVG
77
- // layer will be rendered, as when rendering the full Graphie its
78
- // dynamic content may overflow the widget editor, CP-253
79
- return (
80
- <div>
81
- <div className={css(styles.title)}>Markers</div>
82
-
83
- <div className={css(styles.subtitle)}>
84
- {imageUrl ? (
85
- <span>
86
- Double-click on the image to add a marker.
87
- <br />
88
- <br />
89
- Markers are read by screen readers in the order that
90
- you add them here, so add in a logical order for the
91
- learner (e.g. sequentially, clockwise). You can test
92
- order by using keyboard tabbing.
93
- </span>
94
- ) : (
95
- "Upload an image to place markers."
96
- )}
97
- </div>
98
-
99
- {imageUrl && (
100
- <div
101
- className={css(styles.markersCanvas)}
102
- style={{
103
- maxWidth: imageWidth,
104
- maxHeight: imageHeight,
105
- }}
106
- >
107
- <img
108
- alt=""
109
- className={css(styles.image)}
110
- src={staticUrl(Util.getRealImageUrl(imageUrl))}
111
- onDoubleClick={this.handleImageDoubleClick}
112
- />
113
-
114
- {markers.map((marker, index) => (
115
- <Marker
116
- {...marker}
117
- choices={choices}
118
- key={`${marker.x}.${marker.y}`}
119
- // Update marker in the list.
120
- onChange={(marker) =>
121
- onChange([
122
- ...markers.slice(0, index),
123
- marker,
124
- ...markers.slice(index + 1),
125
- ])
126
- }
127
- // Remove marker from the list.
128
- onRemove={() =>
129
- onChange([
130
- ...markers.slice(0, index),
131
- ...markers.slice(index + 1),
132
- ])
133
- }
134
- ref={(node) => (this._markers[index] = node)}
135
- />
136
- ))}
137
- </div>
138
- )}
139
- </div>
140
- );
141
- }
142
- }
143
-
144
- const styles = StyleSheet.create({
145
- title: {
146
- ...typography.bodyXsmallBold,
147
-
148
- marginBottom: 6,
149
-
150
- color: colors.gray17,
151
- },
152
-
153
- subtitle: {
154
- ...typography.labelSmall,
155
-
156
- marginBottom: 12,
157
-
158
- color: colors.gray68,
159
- },
160
-
161
- markersCanvas: {
162
- position: "relative",
163
-
164
- border: "solid 1px rgba(33, 36, 44, 0.16)",
165
- },
166
-
167
- image: {
168
- // This makes `markersCanvas` have the same height as the image,
169
- // enabling to place markers precisely as they're positioned using
170
- // percentage offsets.
171
- display: "block",
172
-
173
- // Contain question image to the widget editor.
174
- maxWidth: "100%",
175
- },
176
- });
@@ -1,81 +0,0 @@
1
- /**
2
- * Controlled component for selecting the question image, for answer labeling.
3
- */
4
-
5
- import {globalStyles} from "@khanacademy/perseus";
6
- import Button from "@khanacademy/wonder-blocks-button";
7
- import {StyleSheet, css} from "aphrodite";
8
- import * as React from "react";
9
-
10
- import FormWrappedTextField from "../../components/form-wrapped-text-field";
11
-
12
- const {colors, typography} = globalStyles;
13
-
14
- type Props = {
15
- // Callback for when image URL is changed.
16
- onChange: (url: string) => void;
17
- // The selected image URL.
18
- url: string;
19
- };
20
-
21
- const SelectImage = ({onChange, url}: Props): React.ReactElement => (
22
- <div>
23
- <div className={css(styles.title)}>Image</div>
24
-
25
- <div className={css(styles.components)}>
26
- <FormWrappedTextField
27
- placeholder="URL"
28
- grow={1}
29
- onChange={(e) => onChange(e.target.value)}
30
- value={url}
31
- />
32
-
33
- <div className={css(styles.spacer)} />
34
-
35
- <Button
36
- // TODO(michaelpolyak): Design calls for uploading an image from
37
- // the widget. This functionality already exists in
38
- // `perseus-one-package/item-controls.jsx`, it's not obvious if
39
- // it can be triggered from within the widget, or requires
40
- // a similar implementation locally, in which case consider
41
- // refactoring `perseus-admin-package/image-upload-dialog.jsx`
42
- // as common utility, CP-118
43
- disabled={!url}
44
- aria-label={
45
- url
46
- ? ""
47
- : "Not implemented. Use the 'Add Image' button in " +
48
- "the editor to upload image, then copy the URL here."
49
- }
50
- onClick={() => onChange("")}
51
- style={styles.btn}
52
- >
53
- {url ? "Remove" : "Upload"}
54
- </Button>
55
- </div>
56
- </div>
57
- );
58
-
59
- const styles = StyleSheet.create({
60
- title: {
61
- ...typography.bodyXsmallBold,
62
-
63
- marginBottom: 6,
64
-
65
- color: colors.gray17,
66
- },
67
-
68
- components: {
69
- display: "flex",
70
- },
71
-
72
- spacer: {
73
- width: 16,
74
- },
75
-
76
- btn: {
77
- minWidth: 90,
78
- },
79
- });
80
-
81
- export default SelectImage;