@khanacademy/perseus-editor 1.1.1 → 2.0.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/.babelrc.js +1 -1
- package/.eslintrc.js +1 -0
- package/CHANGELOG.md +14 -0
- package/dist/all-editors.d.ts +2 -0
- package/dist/all-editors.js.flow +8 -0
- package/dist/all-widgets.d.ts +22 -0
- package/dist/all-widgets.js.flow +34 -0
- package/dist/article-editor.d.ts +59 -0
- package/dist/article-editor.js.flow +72 -0
- package/dist/components/blur-input.d.ts +19 -0
- package/dist/components/blur-input.js.flow +25 -0
- package/dist/components/checkbox.d.ts +20 -0
- package/dist/components/checkbox.js.flow +26 -0
- package/dist/components/device-framer.d.ts +15 -0
- package/dist/components/device-framer.js.flow +20 -0
- package/dist/components/drag-target.d.ts +2 -0
- package/dist/components/drag-target.js.flow +8 -0
- package/dist/components/dropdown-option.d.ts +35 -0
- package/dist/components/dropdown-option.js.flow +49 -0
- package/dist/components/form-wrapped-text-field.d.ts +48 -0
- package/dist/components/form-wrapped-text-field.js.flow +48 -0
- package/dist/components/graph-settings.d.ts +2 -0
- package/dist/components/graph-settings.js.flow +8 -0
- package/dist/components/hover-behavior.d.ts +85 -0
- package/dist/components/hover-behavior.js.flow +48 -0
- package/dist/components/json-editor.d.ts +2 -0
- package/dist/components/json-editor.js.flow +8 -0
- package/dist/components/link.d.ts +41 -0
- package/dist/components/link.js.flow +50 -0
- package/dist/components/simple-button.d.ts +16 -0
- package/dist/components/simple-button.js.flow +18 -0
- package/dist/components/sortable.d.ts +2 -0
- package/dist/components/sortable.js.flow +8 -0
- package/dist/components/util.d.ts +1 -0
- package/dist/components/util.js.flow +9 -0
- package/dist/components/viewport-resizer.d.ts +16 -0
- package/dist/components/viewport-resizer.js.flow +22 -0
- package/dist/diffs/__stories__/perseus-diff-wrapper.d.ts +5 -0
- package/dist/diffs/__stories__/perseus-diff-wrapper.js.flow +11 -0
- package/dist/diffs/article-diff.d.ts +50 -0
- package/dist/diffs/article-diff.js.flow +71 -0
- package/dist/diffs/item-diff.d.ts +23 -0
- package/dist/diffs/item-diff.js.flow +41 -0
- package/dist/diffs/renderer-diff.d.ts +22 -0
- package/dist/diffs/renderer-diff.js.flow +25 -0
- package/dist/diffs/split-diff.d.ts +2 -0
- package/dist/diffs/split-diff.js.flow +8 -0
- package/dist/diffs/string-array-diff.d.ts +2 -0
- package/dist/diffs/string-array-diff.js.flow +11 -0
- package/dist/diffs/structured-item-diff.d.ts +25 -0
- package/dist/diffs/structured-item-diff.js.flow +37 -0
- package/dist/diffs/tags-diff.d.ts +21 -0
- package/dist/diffs/tags-diff.js.flow +24 -0
- package/dist/diffs/text-diff.d.ts +15 -0
- package/dist/diffs/text-diff.js.flow +21 -0
- package/dist/diffs/widget-diff-performer.d.ts +2 -0
- package/dist/diffs/widget-diff-performer.js.flow +8 -0
- package/dist/diffs/widget-diff.d.ts +21 -0
- package/dist/diffs/widget-diff.js.flow +31 -0
- package/dist/editor-page.d.ts +57 -0
- package/dist/editor-page.js.flow +73 -0
- package/dist/editor.d.ts +82 -0
- package/dist/editor.js.flow +98 -0
- package/dist/es/index.js +1428 -2587
- package/dist/es/index.js.map +1 -1
- package/dist/hint-editor.d.ts +64 -0
- package/dist/hint-editor.js.flow +87 -0
- package/dist/i18n.d.ts +7 -0
- package/dist/i18n.js.flow +13 -0
- package/dist/iframe-content-renderer.d.ts +22 -0
- package/dist/iframe-content-renderer.js.flow +28 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1492 -2548
- package/dist/index.js.flow +23 -2
- package/dist/index.js.map +1 -1
- package/dist/item-editor.d.ts +36 -0
- package/dist/item-editor.js.flow +46 -0
- package/dist/item-extras-editor.d.ts +17 -0
- package/dist/item-extras-editor.js.flow +23 -0
- package/dist/katex-error-view.d.ts +16 -0
- package/dist/katex-error-view.js.flow +24 -0
- package/dist/multirenderer-editor.d.ts +32 -0
- package/dist/multirenderer-editor.js.flow +46 -0
- package/dist/section-control-button.d.ts +12 -0
- package/dist/section-control-button.js.flow +20 -0
- package/dist/stateful-article-editor.d.ts +10 -0
- package/dist/stateful-article-editor.js.flow +16 -0
- package/dist/stateful-editor-page.d.ts +2 -0
- package/dist/stateful-editor-page.js.flow +8 -0
- package/dist/testing-widgets.d.ts +22 -0
- package/dist/testing-widgets.js.flow +34 -0
- package/dist/util/register-all-widgets-and-editors-for-testing.d.ts +1 -0
- package/dist/util/register-all-widgets-and-editors-for-testing.js.flow +7 -0
- package/dist/widgets/categorizer-editor.d.ts +47 -0
- package/dist/widgets/categorizer-editor.js.flow +61 -0
- package/dist/widgets/cs-program-editor.d.ts +21 -0
- package/dist/widgets/cs-program-editor.js.flow +25 -0
- package/dist/widgets/definition-editor.d.ts +17 -0
- package/dist/widgets/definition-editor.js.flow +23 -0
- package/dist/widgets/dropdown-editor.d.ts +23 -0
- package/dist/widgets/dropdown-editor.js.flow +37 -0
- package/dist/widgets/example-graphie-widget-editor.d.ts +18 -0
- package/dist/widgets/example-graphie-widget-editor.js.flow +25 -0
- package/dist/widgets/example-graphie-widget.d.ts +87 -0
- package/dist/widgets/example-graphie-widget.js.flow +101 -0
- package/dist/widgets/example-widget-editor.d.ts +19 -0
- package/dist/widgets/example-widget-editor.js.flow +26 -0
- package/dist/widgets/example-widget.d.ts +71 -0
- package/dist/widgets/example-widget.js.flow +86 -0
- package/dist/widgets/explanation-editor.d.ts +21 -0
- package/dist/widgets/explanation-editor.js.flow +27 -0
- package/dist/widgets/expression-editor.d.ts +33 -0
- package/dist/widgets/expression-editor.js.flow +41 -0
- package/dist/widgets/graded-group-editor.d.ts +53 -0
- package/dist/widgets/graded-group-editor.js.flow +67 -0
- package/dist/widgets/graded-group-set-editor.d.ts +51 -0
- package/dist/widgets/graded-group-set-editor.js.flow +65 -0
- package/dist/widgets/grapher-editor.d.ts +14 -0
- package/dist/widgets/grapher-editor.js.flow +21 -0
- package/dist/widgets/group-editor.d.ts +49 -0
- package/dist/widgets/group-editor.js.flow +63 -0
- package/dist/widgets/iframe-editor.d.ts +18 -0
- package/dist/widgets/iframe-editor.js.flow +24 -0
- package/dist/widgets/image-editor.d.ts +2 -0
- package/dist/widgets/image-editor.js.flow +8 -0
- package/dist/widgets/input-number-editor.d.ts +47 -0
- package/dist/widgets/input-number-editor.js.flow +77 -0
- package/dist/widgets/interaction/constraint-editor.d.ts +26 -0
- package/dist/widgets/interaction/constraint-editor.js.flow +35 -0
- package/dist/widgets/interaction-editor.d.ts +28 -0
- package/dist/widgets/interaction-editor.js.flow +36 -0
- package/dist/widgets/interactive-graph-editor.d.ts +2 -0
- package/dist/widgets/interactive-graph-editor.js.flow +8 -0
- package/dist/widgets/label-image/answer-choices.d.ts +13 -0
- package/dist/widgets/label-image/answer-choices.js.flow +16 -0
- package/dist/widgets/label-image/behavior.d.ts +14 -0
- package/dist/widgets/label-image/behavior.js.flow +17 -0
- package/dist/widgets/label-image/marker.d.ts +30 -0
- package/dist/widgets/label-image/marker.js.flow +34 -0
- package/dist/widgets/label-image/question-markers.d.ts +22 -0
- package/dist/widgets/label-image/question-markers.js.flow +25 -0
- package/dist/widgets/label-image/select-image.d.ts +10 -0
- package/dist/widgets/label-image/select-image.js.flow +13 -0
- package/dist/widgets/label-image-editor.d.ts +45 -0
- package/dist/widgets/label-image-editor.js.flow +44 -0
- package/dist/widgets/lights-puzzle-editor.d.ts +24 -0
- package/dist/widgets/lights-puzzle-editor.js.flow +34 -0
- package/dist/widgets/matcher-editor.d.ts +19 -0
- package/dist/widgets/matcher-editor.js.flow +28 -0
- package/dist/widgets/matrix-editor.d.ts +20 -0
- package/dist/widgets/matrix-editor.js.flow +26 -0
- package/dist/widgets/measurer-editor.d.ts +32 -0
- package/dist/widgets/measurer-editor.js.flow +42 -0
- package/dist/widgets/molecule-editor.d.ts +17 -0
- package/dist/widgets/molecule-editor.js.flow +23 -0
- package/dist/widgets/number-line-editor.d.ts +36 -0
- package/dist/widgets/number-line-editor.js.flow +45 -0
- package/dist/widgets/numeric-input-editor.d.ts +2 -0
- package/dist/widgets/numeric-input-editor.js.flow +8 -0
- package/dist/widgets/orderer-editor.d.ts +20 -0
- package/dist/widgets/orderer-editor.js.flow +30 -0
- package/dist/widgets/passage-editor.d.ts +18 -0
- package/dist/widgets/passage-editor.js.flow +24 -0
- package/dist/widgets/passage-ref-editor.d.ts +11 -0
- package/dist/widgets/passage-ref-editor.js.flow +17 -0
- package/dist/widgets/passage-ref-target-editor.d.ts +16 -0
- package/dist/widgets/passage-ref-target-editor.js.flow +22 -0
- package/dist/widgets/plotter-editor.d.ts +45 -0
- package/dist/widgets/plotter-editor.js.flow +53 -0
- package/dist/widgets/radio/editor.d.ts +64 -0
- package/dist/widgets/radio/editor.js.flow +80 -0
- package/dist/widgets/reaction-diagram-editor.d.ts +20 -0
- package/dist/widgets/reaction-diagram-editor.js.flow +26 -0
- package/dist/widgets/sequence-editor.d.ts +56 -0
- package/dist/widgets/sequence-editor.js.flow +72 -0
- package/dist/widgets/simple-markdown-tester-editor.d.ts +14 -0
- package/dist/widgets/simple-markdown-tester-editor.js.flow +23 -0
- package/dist/widgets/simple-markdown-tester.d.ts +52 -0
- package/dist/widgets/simple-markdown-tester.js.flow +61 -0
- package/dist/widgets/simulator-editor.d.ts +20 -0
- package/dist/widgets/simulator-editor.js.flow +26 -0
- package/dist/widgets/sorter-editor.d.ts +16 -0
- package/dist/widgets/sorter-editor.js.flow +22 -0
- package/dist/widgets/table-editor.d.ts +18 -0
- package/dist/widgets/table-editor.js.flow +24 -0
- package/dist/widgets/transformer-editor.d.ts +11 -0
- package/dist/widgets/transformer-editor.js.flow +17 -0
- package/dist/widgets/unit-editor.d.ts +33 -0
- package/dist/widgets/unit-editor.js.flow +41 -0
- package/dist/widgets/video-editor.d.ts +19 -0
- package/dist/widgets/video-editor.js.flow +25 -0
- package/package.json +6 -5
- package/src/__stories__/{editor.stories.js → editor.stories.tsx} +4 -5
- package/src/__stories__/{section-control-button.stories.jsx → section-control-button.stories.tsx} +10 -11
- package/src/__testdata__/{input-number_testdata.js → input-number.testdata.ts} +2 -3
- package/src/__tests__/{editor_test.jsx → editor.test.tsx} +4 -7
- package/src/__tests__/{i18n_test.jsx → i18n.test.ts} +5 -5
- package/src/__tests__/{traversal_test.jsx → traversal.test.ts} +9 -10
- package/src/{all-editors_test.js → all-editors.test.ts} +1 -2
- package/src/all-editors.ts +83 -0
- package/src/all-widgets.ts +7 -0
- package/src/{article-editor.jsx → article-editor.tsx} +52 -42
- package/src/components/__stories__/{blur-input.stories.jsx → blur-input.stories.tsx} +2 -4
- package/src/components/{blur-input.jsx → blur-input.tsx} +12 -13
- package/src/components/{checkbox.jsx → checkbox.tsx} +18 -19
- package/src/components/{device-framer.jsx → device-framer.tsx} +4 -5
- package/src/components/{drag-target.jsx → drag-target.tsx} +0 -1
- package/src/components/{dropdown-option.jsx → dropdown-option.tsx} +40 -40
- package/src/components/{form-wrapped-text-field.jsx → form-wrapped-text-field.tsx} +47 -53
- package/src/components/{graph-settings.jsx → graph-settings.tsx} +4 -8
- package/src/components/{hover-behavior.jsx → hover-behavior.ts} +32 -33
- package/src/components/{json-editor.jsx → json-editor.tsx} +4 -3
- package/src/components/{link.jsx → link.ts} +33 -33
- package/src/components/{simple-button.jsx → simple-button.tsx} +3 -4
- package/src/components/{sortable.jsx → sortable.tsx} +3 -3
- package/src/components/{util.js → util.ts} +1 -2
- package/src/components/{viewport-resizer.jsx → viewport-resizer.tsx} +5 -6
- package/src/diffs/__stories__/{perseus-diff-wrapper.jsx → perseus-diff-wrapper.tsx} +3 -2
- package/src/diffs/__stories__/{structured-item-diff.stories.jsx → structured-item-diff.stories.tsx} +27 -22
- package/src/diffs/__stories__/{tags-diff.stories.jsx → tags-diff.stories.tsx} +12 -14
- package/src/diffs/__stories__/{text-diff.stories.jsx → text-diff.stories.tsx} +12 -14
- package/src/diffs/__tests__/{split-diff_test.js → split-diff.test.ts} +1 -2
- package/src/diffs/__tests__/{string-array-diff_test.js → string-array-diff.test.ts} +1 -2
- package/src/diffs/__tests__/{structured-item-diff_test.js → structured-item-diff.test.ts} +15 -14
- package/src/diffs/__tests__/{widget-diff-performer_test.js → widget-diff-performer.test.ts} +1 -2
- package/src/diffs/{article-diff.jsx → article-diff.tsx} +5 -6
- package/src/diffs/{item-diff.jsx → item-diff.tsx} +4 -5
- package/src/diffs/{renderer-diff.jsx → renderer-diff.tsx} +22 -28
- package/src/diffs/{split-diff.jsx → split-diff.ts} +4 -3
- package/src/diffs/{string-array-diff.jsx → string-array-diff.ts} +8 -9
- package/src/diffs/{structured-item-diff.jsx → structured-item-diff.tsx} +32 -27
- package/src/diffs/{tags-diff.jsx → tags-diff.tsx} +15 -16
- package/src/diffs/{text-diff.jsx → text-diff.tsx} +13 -13
- package/src/diffs/{widget-diff-performer.jsx → widget-diff-performer.ts} +3 -8
- package/src/diffs/{widget-diff.jsx → widget-diff.tsx} +15 -14
- package/src/{editor-page.jsx → editor-page.tsx} +52 -60
- package/src/{editor.jsx → editor.tsx} +315 -277
- package/src/{hint-editor.jsx → hint-editor.tsx} +105 -79
- package/src/{i18n.jsx → i18n.ts} +9 -6
- package/src/{iframe-content-renderer.jsx → iframe-content-renderer.tsx} +23 -17
- package/src/{index.js → index.ts} +15 -16
- package/src/{item-editor.jsx → item-editor.tsx} +35 -30
- package/src/{item-extras-editor.jsx → item-extras-editor.tsx} +3 -4
- package/src/{katex-error-view.jsx → katex-error-view.tsx} +4 -5
- package/src/{multirenderer-editor.jsx → multirenderer-editor.tsx} +132 -127
- package/src/{section-control-button.jsx → section-control-button.tsx} +10 -9
- package/src/{stateful-article-editor.jsx → stateful-article-editor.tsx} +2 -5
- package/src/{stateful-editor-page.jsx → stateful-editor-page.tsx} +1 -3
- package/src/{testing-widgets.js → testing-widgets.ts} +5 -6
- package/src/util/{register-all-widgets-and-editors-for-testing_test.js → register-all-widgets-and-editors-for-testing.test.ts} +1 -2
- package/src/util/{register-all-widgets-and-editors-for-testing.js → register-all-widgets-and-editors-for-testing.ts} +2 -3
- package/src/widgets/__stories__/{label-image-editor.stories.jsx → label-image-editor.stories.tsx} +22 -18
- package/src/widgets/__stories__/{radio-editor.stories.jsx → radio-editor.stories.tsx} +15 -10
- package/src/widgets/{categorizer-editor.jsx → categorizer-editor.tsx} +8 -6
- package/src/widgets/{cs-program-editor.jsx → cs-program-editor.tsx} +17 -17
- package/src/widgets/{definition-editor.jsx → definition-editor.tsx} +9 -8
- package/src/widgets/{dropdown-editor.jsx → dropdown-editor.tsx} +27 -19
- package/src/widgets/{example-graphie-widget-editor.jsx → example-graphie-widget-editor.tsx} +8 -8
- package/src/widgets/{example-graphie-widget.jsx → example-graphie-widget.tsx} +14 -17
- package/src/widgets/{example-widget-editor.jsx → example-widget-editor.tsx} +10 -7
- package/src/widgets/{example-widget.jsx → example-widget.tsx} +14 -12
- package/src/widgets/{explanation-editor.jsx → explanation-editor.tsx} +12 -10
- package/src/widgets/{expression-editor.jsx → expression-editor.tsx} +36 -26
- package/src/widgets/{graded-group-editor.jsx → graded-group-editor.tsx} +18 -10
- package/src/widgets/{graded-group-set-editor.jsx → graded-group-set-editor.tsx} +15 -12
- package/src/widgets/{grapher-editor.jsx → grapher-editor.tsx} +10 -9
- package/src/widgets/{group-editor.jsx → group-editor.tsx} +11 -9
- package/src/widgets/{iframe-editor.jsx → iframe-editor.tsx} +16 -13
- package/src/widgets/{image-editor.jsx → image-editor.tsx} +4 -7
- package/src/widgets/{input-number-editor.jsx → input-number-editor.tsx} +61 -47
- package/src/widgets/interaction/{constraint-editor.jsx → constraint-editor.tsx} +21 -24
- package/src/widgets/{interaction-editor.jsx → interaction-editor.tsx} +160 -61
- package/src/widgets/{interactive-graph-editor.jsx → interactive-graph-editor.tsx} +13 -10
- package/src/widgets/label-image/__stories__/{answer-choices.stories.jsx → answer-choices.stories.tsx} +22 -17
- package/src/widgets/label-image/__stories__/{behavior.stories.jsx → behavior.stories.tsx} +9 -10
- package/src/widgets/label-image/__stories__/{marker.stories.jsx → marker.stories.tsx} +11 -12
- package/src/widgets/label-image/__stories__/{question-markers.stories.jsx → question-markers.stories.tsx} +17 -16
- package/src/widgets/label-image/__stories__/{select-image.stories.jsx → select-image.stories.tsx} +12 -13
- package/src/widgets/label-image/{answer-choices.jsx → answer-choices.tsx} +18 -18
- package/src/widgets/label-image/{behavior.jsx → behavior.tsx} +9 -11
- package/src/widgets/label-image/{marker.jsx → marker.tsx} +17 -19
- package/src/widgets/label-image/{question-markers.jsx → question-markers.tsx} +16 -21
- package/src/widgets/label-image/{select-image.jsx → select-image.tsx} +5 -7
- package/src/widgets/{label-image-editor.jsx → label-image-editor.tsx} +38 -44
- package/src/widgets/{lights-puzzle-editor.jsx → lights-puzzle-editor.tsx} +34 -24
- package/src/widgets/{matcher-editor.jsx → matcher-editor.tsx} +9 -7
- package/src/widgets/{matrix-editor.jsx → matrix-editor.tsx} +10 -9
- package/src/widgets/{measurer-editor.jsx → measurer-editor.tsx} +21 -14
- package/src/widgets/{molecule-editor.jsx → molecule-editor.tsx} +9 -8
- package/src/widgets/{number-line-editor.jsx → number-line-editor.tsx} +19 -17
- package/src/widgets/{numeric-input-editor.jsx → numeric-input-editor.tsx} +10 -10
- package/src/widgets/{orderer-editor.jsx → orderer-editor.tsx} +17 -12
- package/src/widgets/{passage-editor.jsx → passage-editor.tsx} +9 -7
- package/src/widgets/{passage-ref-editor.jsx → passage-ref-editor.tsx} +8 -6
- package/src/widgets/{passage-ref-target-editor.jsx → passage-ref-target-editor.tsx} +9 -7
- package/src/widgets/{plotter-editor.jsx → plotter-editor.tsx} +34 -33
- package/src/widgets/radio/{editor.jsx → editor.tsx} +22 -21
- package/src/widgets/{reaction-diagram-editor.jsx → reaction-diagram-editor.tsx} +14 -10
- package/src/widgets/{sequence-editor.jsx → sequence-editor.tsx} +13 -13
- package/src/widgets/{simple-markdown-tester-editor.jsx → simple-markdown-tester-editor.tsx} +11 -9
- package/src/widgets/{simple-markdown-tester.jsx → simple-markdown-tester.tsx} +8 -7
- package/src/widgets/{simulator-editor.jsx → simulator-editor.tsx} +10 -8
- package/src/widgets/{sorter-editor.jsx → sorter-editor.tsx} +8 -6
- package/src/widgets/{table-editor.jsx → table-editor.tsx} +11 -10
- package/src/widgets/{transformer-editor.jsx → transformer-editor.tsx} +37 -35
- package/src/widgets/{unit-editor.jsx → unit-editor.tsx} +31 -25
- package/src/widgets/{video-editor.jsx → video-editor.tsx} +8 -9
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/all-editors.js +0 -85
- package/src/all-widgets.js +0 -10
- /package/dist/{strings.js → strings} +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import {
|
|
3
2
|
components,
|
|
4
3
|
icons,
|
|
@@ -13,15 +12,15 @@ import {
|
|
|
13
12
|
WIDGET_PROP_DENYLIST,
|
|
14
13
|
} from "@khanacademy/perseus";
|
|
15
14
|
import $ from "jquery";
|
|
16
|
-
// eslint-disable-next-line import/no-unresolved
|
|
17
|
-
import
|
|
15
|
+
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
|
|
16
|
+
import katex from "katex";
|
|
18
17
|
import * as React from "react";
|
|
19
18
|
import * as ReactDOM from "react-dom";
|
|
20
19
|
import _ from "underscore";
|
|
21
20
|
|
|
22
|
-
import DragTarget from "./components/drag-target
|
|
23
|
-
import KatexErrorView from "./katex-error-view
|
|
24
|
-
import SectionControlButton from "./section-control-button
|
|
21
|
+
import DragTarget from "./components/drag-target";
|
|
22
|
+
import KatexErrorView from "./katex-error-view";
|
|
23
|
+
import SectionControlButton from "./section-control-button";
|
|
25
24
|
|
|
26
25
|
import type {Alignment, ChangeHandler, WidgetInfo} from "@khanacademy/perseus";
|
|
27
26
|
|
|
@@ -42,14 +41,14 @@ const ENDS_WITH_A_PARAGRAPH = /(?:\n{2,}|^\n*)$/;
|
|
|
42
41
|
const TRAILING_NEWLINES = /(\n*)$/;
|
|
43
42
|
const LEADING_NEWLINES = /^(\n*)/;
|
|
44
43
|
|
|
45
|
-
const commafyInteger = (n) => {
|
|
44
|
+
const commafyInteger = (n: number) => {
|
|
46
45
|
let str = n.toString();
|
|
47
46
|
if (str.length >= 5) {
|
|
48
47
|
str = str.replace(/(\d)(?=(\d{3})+$)/g, "$1{,}");
|
|
49
48
|
}
|
|
50
49
|
return str;
|
|
51
50
|
};
|
|
52
|
-
const makeEndWithAParagraphIfNecessary = (content) => {
|
|
51
|
+
const makeEndWithAParagraphIfNecessary = (content: string) => {
|
|
53
52
|
if (!ENDS_WITH_A_PARAGRAPH.test(content)) {
|
|
54
53
|
const match = TRAILING_NEWLINES.exec(content);
|
|
55
54
|
if (match) {
|
|
@@ -68,16 +67,16 @@ const makeStartWithAParagraphAlways = (content) => {
|
|
|
68
67
|
return "\n\n".slice(0, 2 - newlines.length) + content;
|
|
69
68
|
};
|
|
70
69
|
|
|
71
|
-
type WidgetSelectProps = {
|
|
72
|
-
onChange?: (widgetType: string) =>
|
|
73
|
-
|
|
70
|
+
type WidgetSelectProps = {
|
|
71
|
+
onChange?: (widgetType: string) => unknown;
|
|
72
|
+
};
|
|
74
73
|
|
|
75
74
|
class WidgetSelect extends React.Component<WidgetSelectProps> {
|
|
76
75
|
shouldComponentUpdate() {
|
|
77
76
|
return false;
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
handleChange = (e: SyntheticEvent<HTMLSelectElement>) => {
|
|
79
|
+
handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {
|
|
81
80
|
const widgetType = e.currentTarget.value;
|
|
82
81
|
if (widgetType === "") {
|
|
83
82
|
// TODO(alpert): Not sure if change will trigger here
|
|
@@ -89,7 +88,7 @@ class WidgetSelect extends React.Component<WidgetSelectProps> {
|
|
|
89
88
|
}
|
|
90
89
|
};
|
|
91
90
|
|
|
92
|
-
render(): React.
|
|
91
|
+
render(): React.ReactNode {
|
|
93
92
|
const widgets = Widgets.getPublicWidgets();
|
|
94
93
|
const orderedWidgetNames = _.sortBy(_.keys(widgets), (name) => {
|
|
95
94
|
return widgets[name].displayName;
|
|
@@ -111,29 +110,30 @@ class WidgetSelect extends React.Component<WidgetSelectProps> {
|
|
|
111
110
|
}
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
type WidgetEditorProps = {
|
|
113
|
+
type WidgetEditorProps = {
|
|
115
114
|
// Unserialized props
|
|
116
|
-
id: string
|
|
115
|
+
id: string;
|
|
117
116
|
onChange: (
|
|
118
117
|
widgetInfo: WidgetInfo,
|
|
119
|
-
cb?: () =>
|
|
118
|
+
cb?: () => unknown,
|
|
120
119
|
silent?: boolean,
|
|
121
|
-
) =>
|
|
122
|
-
onRemove: () =>
|
|
123
|
-
apiOptions: any
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
widgetInfo: WidgetInfo,
|
|
131
|
-
|};
|
|
120
|
+
) => unknown;
|
|
121
|
+
onRemove: () => unknown;
|
|
122
|
+
apiOptions: any;
|
|
123
|
+
} & WidgetInfo;
|
|
124
|
+
|
|
125
|
+
type WidgetEditorState = {
|
|
126
|
+
showWidget: boolean;
|
|
127
|
+
widgetInfo: WidgetInfo;
|
|
128
|
+
};
|
|
132
129
|
|
|
133
|
-
const _upgradeWidgetInfo
|
|
130
|
+
const _upgradeWidgetInfo: React.FC<WidgetEditorProps> = (
|
|
131
|
+
props,
|
|
132
|
+
): React.ReactElement => {
|
|
134
133
|
// We can't call serialize here because this.refs.widget
|
|
135
134
|
// doesn't exist before this component is mounted.
|
|
136
135
|
const filteredProps = _.omit(props, WIDGET_PROP_DENYLIST);
|
|
136
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'PerseusWidget' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'. | TS2345 - Argument of type 'Partial<{ id: string; onChange: (widgetInfo: PerseusWidget, cb?: (() => unknown) | undefined, silent?: boolean | undefined) => unknown; onRemove: () => unknown; apiOptions: any; } & CategorizerWidget & { ...; }> | ... 38 more ... | Partial<...>' is not assignable to parameter of type 'PerseusWidget'.
|
|
137
137
|
return Widgets.upgradeWidgetInfoToLatestVersion(filteredProps);
|
|
138
138
|
};
|
|
139
139
|
|
|
@@ -144,36 +144,39 @@ const _upgradeWidgetInfo = (props: WidgetEditorProps): WidgetInfo => {
|
|
|
144
144
|
// eslint-disable-next-line react/no-unsafe
|
|
145
145
|
class WidgetEditor extends React.Component<
|
|
146
146
|
WidgetEditorProps,
|
|
147
|
-
WidgetEditorState
|
|
147
|
+
WidgetEditorState
|
|
148
148
|
> {
|
|
149
149
|
constructor(props: WidgetEditorProps) {
|
|
150
150
|
super(props);
|
|
151
151
|
this.state = {
|
|
152
152
|
showWidget: false,
|
|
153
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'ReactElement<any, any> | null' is not assignable to type 'PerseusWidget'.
|
|
153
154
|
widgetInfo: _upgradeWidgetInfo(props),
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
UNSAFE_componentWillReceiveProps(nextProps: WidgetEditorProps) {
|
|
159
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'ReactElement<any, any> | null' is not assignable to type 'PerseusWidget'.
|
|
158
160
|
this.setState({widgetInfo: _upgradeWidgetInfo(nextProps)});
|
|
159
161
|
}
|
|
160
162
|
|
|
161
|
-
_toggleWidget = (e: SyntheticEvent
|
|
163
|
+
_toggleWidget = (e: React.SyntheticEvent) => {
|
|
162
164
|
e.preventDefault();
|
|
163
165
|
this.setState({showWidget: !this.state.showWidget});
|
|
164
166
|
};
|
|
165
167
|
|
|
166
168
|
_handleWidgetChange = (
|
|
167
169
|
newProps: WidgetEditorProps,
|
|
168
|
-
cb: () =>
|
|
170
|
+
cb: () => unknown,
|
|
169
171
|
silent: boolean,
|
|
170
172
|
) => {
|
|
171
|
-
const newWidgetInfo =
|
|
173
|
+
const newWidgetInfo = Object.assign(
|
|
172
174
|
{},
|
|
173
175
|
this.state.widgetInfo,
|
|
174
|
-
)
|
|
176
|
+
) as WidgetInfo;
|
|
175
177
|
newWidgetInfo.options = Object.assign(
|
|
176
178
|
// eslint-disable-next-line react/no-string-refs
|
|
179
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
177
180
|
this.refs.widget.serialize(),
|
|
178
181
|
newProps,
|
|
179
182
|
);
|
|
@@ -182,24 +185,25 @@ class WidgetEditor extends React.Component<
|
|
|
182
185
|
|
|
183
186
|
_toggleStatic = (e: Event) => {
|
|
184
187
|
e.preventDefault();
|
|
185
|
-
const newWidgetInfo =
|
|
188
|
+
const newWidgetInfo = Object.assign({}, this.state.widgetInfo, {
|
|
186
189
|
static: !this.state.widgetInfo.static,
|
|
187
|
-
})
|
|
190
|
+
}) as WidgetInfo;
|
|
188
191
|
this.props.onChange(newWidgetInfo);
|
|
189
192
|
};
|
|
190
193
|
|
|
191
|
-
_handleAlignmentChange = (e: SyntheticEvent<HTMLSelectElement>) => {
|
|
192
|
-
const newAlignment =
|
|
193
|
-
const newWidgetInfo =
|
|
194
|
+
_handleAlignmentChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {
|
|
195
|
+
const newAlignment = e.currentTarget.value as Alignment;
|
|
196
|
+
const newWidgetInfo = Object.assign(
|
|
194
197
|
{},
|
|
195
198
|
this.state.widgetInfo,
|
|
196
|
-
)
|
|
199
|
+
) as WidgetInfo;
|
|
197
200
|
newWidgetInfo.alignment = newAlignment;
|
|
198
201
|
this.props.onChange(newWidgetInfo);
|
|
199
202
|
};
|
|
200
203
|
|
|
201
204
|
getSaveWarnings = () => {
|
|
202
205
|
// eslint-disable-next-line react/no-string-refs
|
|
206
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
203
207
|
const issuesFunc = this.refs.widget.getSaveWarnings;
|
|
204
208
|
return issuesFunc ? issuesFunc() : [];
|
|
205
209
|
};
|
|
@@ -215,16 +219,17 @@ class WidgetEditor extends React.Component<
|
|
|
215
219
|
static: widgetInfo.static,
|
|
216
220
|
graded: widgetInfo.graded,
|
|
217
221
|
// eslint-disable-next-line react/no-string-refs
|
|
222
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
218
223
|
options: this.refs.widget.serialize(),
|
|
219
224
|
version: widgetInfo.version,
|
|
220
225
|
};
|
|
221
226
|
};
|
|
222
227
|
|
|
223
|
-
render(): React.
|
|
228
|
+
render(): React.ReactNode {
|
|
224
229
|
const widgetInfo = this.state.widgetInfo;
|
|
225
230
|
|
|
226
231
|
const Ed = Widgets.getEditor(widgetInfo.type);
|
|
227
|
-
let supportedAlignments:
|
|
232
|
+
let supportedAlignments: ReadonlyArray<Alignment>;
|
|
228
233
|
if (this.props.apiOptions.showAlignmentOptions) {
|
|
229
234
|
supportedAlignments = Widgets.getSupportedAlignments(
|
|
230
235
|
widgetInfo.type,
|
|
@@ -270,6 +275,7 @@ class WidgetEditor extends React.Component<
|
|
|
270
275
|
{supportsStaticMode && (
|
|
271
276
|
<input
|
|
272
277
|
type="button"
|
|
278
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type '(e: Event) => void' is not assignable to type 'MouseEventHandler<HTMLInputElement>'.
|
|
273
279
|
onClick={this._toggleStatic}
|
|
274
280
|
className="simple-button--small"
|
|
275
281
|
value={
|
|
@@ -340,8 +346,9 @@ const IMAGE_REGEX = /!\[[^\]]*\]\(([^\s)]+)[^)]*\)/g;
|
|
|
340
346
|
* Note: Returns an array of the capture objects, whereas String::match
|
|
341
347
|
* ignores captures. If you don't need captures, use String::match
|
|
342
348
|
*/
|
|
343
|
-
const allMatches = function (regex, str) {
|
|
344
|
-
|
|
349
|
+
const allMatches = function (regex: RegExp, str: string) {
|
|
350
|
+
// @ts-expect-error [FEI-5003] - TS2702 - 'RegExp' only refers to a type, but is being used as a namespace here.
|
|
351
|
+
const result: Array<any | RegExp.matchResult> = [];
|
|
345
352
|
// eslint-disable-next-line no-constant-condition
|
|
346
353
|
while (true) {
|
|
347
354
|
const match = regex.exec(str);
|
|
@@ -357,52 +364,59 @@ const allMatches = function (regex, str) {
|
|
|
357
364
|
* Return an array of URLs of all the images in the given renderer
|
|
358
365
|
* markdown.
|
|
359
366
|
*/
|
|
360
|
-
const imageUrlsFromContent = function (content) {
|
|
367
|
+
const imageUrlsFromContent = function (content: string) {
|
|
361
368
|
return _.map(allMatches(IMAGE_REGEX, content), (capture) => capture[1]);
|
|
362
369
|
};
|
|
363
370
|
|
|
364
|
-
type EditorProps =
|
|
365
|
-
apiOptions: any
|
|
366
|
-
className?: string
|
|
367
|
-
content: string
|
|
368
|
-
replace?: any
|
|
369
|
-
placeholder: string
|
|
370
|
-
widgets: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
371
|
+
type EditorProps = Readonly<{
|
|
372
|
+
apiOptions: any;
|
|
373
|
+
className?: string;
|
|
374
|
+
content: string;
|
|
375
|
+
replace?: any;
|
|
376
|
+
placeholder: string;
|
|
377
|
+
widgets: {
|
|
378
|
+
[name: string]: WidgetInfo;
|
|
379
|
+
};
|
|
380
|
+
images: any;
|
|
381
|
+
disabled: boolean;
|
|
382
|
+
widgetEnabled: boolean;
|
|
383
|
+
immutableWidgets: boolean;
|
|
384
|
+
showWordCount: boolean;
|
|
385
|
+
warnNoPrompt: boolean;
|
|
386
|
+
warnNoWidgets: boolean;
|
|
387
|
+
imageUploader?: (
|
|
388
|
+
file: string,
|
|
389
|
+
callback: (url: string) => unknown,
|
|
390
|
+
) => unknown;
|
|
391
|
+
onChange: ChangeHandler;
|
|
392
|
+
}>;
|
|
393
|
+
|
|
394
|
+
type DeafultProps = {
|
|
395
|
+
content: string;
|
|
396
|
+
disabled: boolean;
|
|
397
|
+
images: Record<any, any>;
|
|
398
|
+
immutableWidgets: boolean;
|
|
399
|
+
placeholder: string;
|
|
400
|
+
showWordCount: boolean;
|
|
401
|
+
warnNoPrompt: boolean;
|
|
402
|
+
warnNoWidgets: boolean;
|
|
403
|
+
widgetEnabled: boolean;
|
|
404
|
+
widgets: {
|
|
405
|
+
[name: string]: WidgetInfo;
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
type EditorState = {
|
|
410
|
+
showKatexErrors: boolean;
|
|
411
|
+
textAreaValue: string;
|
|
412
|
+
katex?: katex;
|
|
413
|
+
};
|
|
400
414
|
|
|
401
415
|
// eslint-disable-next-line react/no-unsafe
|
|
402
416
|
class Editor extends React.Component<EditorProps, EditorState> {
|
|
403
|
-
lastUserValue:
|
|
404
|
-
deferredChange:
|
|
405
|
-
widgetIds:
|
|
417
|
+
lastUserValue: string | null | undefined;
|
|
418
|
+
deferredChange: any | null | undefined;
|
|
419
|
+
widgetIds: any | null | undefined;
|
|
406
420
|
|
|
407
421
|
static defaultProps: DeafultProps = {
|
|
408
422
|
content: "",
|
|
@@ -433,7 +447,9 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
433
447
|
// setState
|
|
434
448
|
this._sizeImages(this.props);
|
|
435
449
|
// eslint-disable-next-line react/no-string-refs
|
|
450
|
+
// @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
|
|
436
451
|
$(ReactDOM.findDOMNode(this.refs.textarea))
|
|
452
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'on' does not exist on type 'JQueryStatic'.
|
|
437
453
|
.on("copy cut", this._maybeCopyWidgets)
|
|
438
454
|
.on("paste", this._maybePasteWidgets);
|
|
439
455
|
|
|
@@ -471,13 +487,13 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
471
487
|
* textarea should be refined with an instanceof check to
|
|
472
488
|
* HTMLTextAreaElement so that these props are available.
|
|
473
489
|
*/
|
|
474
|
-
//
|
|
490
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
|
|
475
491
|
textarea.focus();
|
|
476
|
-
//
|
|
492
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
477
493
|
textarea.value = this.lastUserValue;
|
|
478
|
-
//
|
|
494
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'.
|
|
479
495
|
textarea.selectionStart = 0;
|
|
480
|
-
//
|
|
496
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'select' does not exist on type 'Element | Text'.
|
|
481
497
|
textarea.select(0, prevProps.content.length);
|
|
482
498
|
if (
|
|
483
499
|
document.execCommand(
|
|
@@ -488,7 +504,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
488
504
|
) {
|
|
489
505
|
// This command is not implemented. Fall back to setting `value`
|
|
490
506
|
// directly.
|
|
491
|
-
//
|
|
507
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
492
508
|
textarea.value = this.props.content;
|
|
493
509
|
}
|
|
494
510
|
this.lastUserValue = null;
|
|
@@ -507,38 +523,38 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
507
523
|
clearTimeout(this.deferredChange);
|
|
508
524
|
}
|
|
509
525
|
|
|
510
|
-
getWidgetEditor: (id: string, type: string) =>
|
|
511
|
-
id: string,
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
return
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
526
|
+
getWidgetEditor: (id: string, type: string) => undefined | React.ReactNode =
|
|
527
|
+
(id: string, type: string) => {
|
|
528
|
+
if (!Widgets.getEditor(type)) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
return (
|
|
532
|
+
<WidgetEditor
|
|
533
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
|
|
534
|
+
key={id}
|
|
535
|
+
ref={id}
|
|
536
|
+
id={id}
|
|
537
|
+
// @ts-expect-error [FEI-5003] - TS2783 - 'type' is specified more than once, so this usage will be overwritten.
|
|
538
|
+
type={type}
|
|
539
|
+
// eslint-disable-next-line react/jsx-no-bind
|
|
540
|
+
onChange={this._handleWidgetEditorChange.bind(this, id)}
|
|
541
|
+
// eslint-disable-next-line react/jsx-no-bind
|
|
542
|
+
onRemove={this._handleWidgetEditorRemove.bind(this, id)}
|
|
543
|
+
apiOptions={this.props.apiOptions}
|
|
544
|
+
{...this.props.widgets[id]}
|
|
545
|
+
/>
|
|
546
|
+
);
|
|
547
|
+
};
|
|
532
548
|
|
|
533
549
|
_handleWidgetEditorChange: (
|
|
534
550
|
id: string,
|
|
535
551
|
newWidgetInfo: WidgetInfo,
|
|
536
|
-
cb?: () =>
|
|
552
|
+
cb?: () => unknown,
|
|
537
553
|
silent?: boolean,
|
|
538
554
|
) => void = (
|
|
539
555
|
id: string,
|
|
540
556
|
newWidgetInfo: WidgetInfo,
|
|
541
|
-
cb?: () =>
|
|
557
|
+
cb?: () => unknown,
|
|
542
558
|
silent?: boolean,
|
|
543
559
|
) => {
|
|
544
560
|
const widgets = Object.assign({}, this.props.widgets);
|
|
@@ -550,6 +566,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
550
566
|
// eslint-disable-next-line react/no-string-refs
|
|
551
567
|
const textarea = this.refs.textarea;
|
|
552
568
|
const re = new RegExp(widgetRegExp.replace("{id}", id), "gm");
|
|
569
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'value' does not exist on type 'ReactInstance'.
|
|
553
570
|
this.props.onChange({content: textarea.value.replace(re, "")});
|
|
554
571
|
};
|
|
555
572
|
|
|
@@ -589,6 +606,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
589
606
|
{
|
|
590
607
|
images: _.clone(images),
|
|
591
608
|
},
|
|
609
|
+
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'null' is not assignable to parameter of type '(() => unknown) | undefined'.
|
|
592
610
|
null, // callback
|
|
593
611
|
true, // silent
|
|
594
612
|
);
|
|
@@ -664,11 +682,13 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
664
682
|
this.props.onChange({content: content});
|
|
665
683
|
})
|
|
666
684
|
.each((fileAndSentinel) => {
|
|
685
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2345 - Argument of type 'File' is not assignable to parameter of type 'string'.
|
|
667
686
|
imageUploader(fileAndSentinel.file, (url) => {
|
|
668
687
|
// See componentDidUpdate() for how this flag is used
|
|
669
688
|
this.lastUserValue = origContent;
|
|
670
689
|
this.props.onChange({
|
|
671
690
|
content: this.state.textAreaValue.replace(
|
|
691
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
672
692
|
fileAndSentinel.sentinel,
|
|
673
693
|
url,
|
|
674
694
|
),
|
|
@@ -677,8 +697,8 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
677
697
|
});
|
|
678
698
|
};
|
|
679
699
|
|
|
680
|
-
handleChange: (e: SyntheticEvent<HTMLTextAreaElement>) => void = (
|
|
681
|
-
e: SyntheticEvent<HTMLTextAreaElement>,
|
|
700
|
+
handleChange: (e: React.SyntheticEvent<HTMLTextAreaElement>) => void = (
|
|
701
|
+
e: React.SyntheticEvent<HTMLTextAreaElement>,
|
|
682
702
|
) => {
|
|
683
703
|
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
684
704
|
// eslint-disable-next-line no-restricted-syntax
|
|
@@ -693,8 +713,8 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
693
713
|
}, this.props.apiOptions.editorChangeDelay);
|
|
694
714
|
};
|
|
695
715
|
|
|
696
|
-
_handleKeyDown: (e:
|
|
697
|
-
e:
|
|
716
|
+
_handleKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void = (
|
|
717
|
+
e: React.KeyboardEvent<HTMLTextAreaElement>,
|
|
698
718
|
) => {
|
|
699
719
|
e.stopPropagation();
|
|
700
720
|
// Tab-completion of widgets. For example, to insert an image:
|
|
@@ -704,7 +724,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
704
724
|
const textarea = ReactDOM.findDOMNode(this.refs.textarea);
|
|
705
725
|
|
|
706
726
|
// findDOMNode can also return Text, but we know it's an element.
|
|
707
|
-
//
|
|
727
|
+
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'Element | Text | null' is not assignable to parameter of type 'HTMLTextAreaElement'.
|
|
708
728
|
const word = Util.textarea.getWordBeforeCursor(textarea);
|
|
709
729
|
const matches = word.string.toLowerCase().match(shortcutRegexp);
|
|
710
730
|
|
|
@@ -730,165 +750,169 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
730
750
|
}
|
|
731
751
|
};
|
|
732
752
|
|
|
733
|
-
_maybeCopyWidgets: (e: SyntheticEvent<HTMLTextAreaElement>) => void =
|
|
734
|
-
e: SyntheticEvent<HTMLTextAreaElement
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
);
|
|
753
|
+
_maybeCopyWidgets: (e: React.SyntheticEvent<HTMLTextAreaElement>) => void =
|
|
754
|
+
(e: React.SyntheticEvent<HTMLTextAreaElement>) => {
|
|
755
|
+
// If there are widgets being cut/copied, put the widget JSON in
|
|
756
|
+
// localStorage.perseusLastCopiedWidgets to allow copy-pasting of
|
|
757
|
+
// widgets between Editors. Also store the text to be pasted in
|
|
758
|
+
// localStorage.perseusLastCopiedText since we want to know if the user
|
|
759
|
+
// is actually pasting something originally from Perseus later.
|
|
760
|
+
const textarea = e.currentTarget;
|
|
761
|
+
const selectedText = textarea.value.substring(
|
|
762
|
+
textarea.selectionStart,
|
|
763
|
+
textarea.selectionEnd,
|
|
764
|
+
);
|
|
746
765
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
766
|
+
const widgetNames = _.map(
|
|
767
|
+
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'RegExpMatchArray | null' is not assignable to parameter of type 'Collection<any>'.
|
|
768
|
+
selectedText.match(rWidgetSplit),
|
|
769
|
+
(syntax) => {
|
|
770
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
771
|
+
return Util.rWidgetParts.exec(syntax)[1];
|
|
772
|
+
},
|
|
773
|
+
);
|
|
754
774
|
|
|
755
|
-
|
|
775
|
+
const widgetData = _.pick(this.serialize().widgets, widgetNames);
|
|
756
776
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
// $FlowIgnore[prop-missing] localStorage can be used as an object
|
|
760
|
-
localStorage.perseusLastCopiedWidgets = JSON.stringify(widgetData);
|
|
777
|
+
localStorage.perseusLastCopiedText = selectedText;
|
|
778
|
+
localStorage.perseusLastCopiedWidgets = JSON.stringify(widgetData);
|
|
761
779
|
|
|
762
|
-
|
|
763
|
-
|
|
780
|
+
Log.log(`Widgets copied: ${localStorage.perseusLastCopiedWidgets}`);
|
|
781
|
+
};
|
|
764
782
|
|
|
765
|
-
_maybePasteWidgets: (e: SyntheticEvent<HTMLTextAreaElement>) => void =
|
|
766
|
-
e: SyntheticEvent<HTMLTextAreaElement
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
783
|
+
_maybePasteWidgets: (e: React.SyntheticEvent<HTMLTextAreaElement>) => void =
|
|
784
|
+
(e: React.SyntheticEvent<HTMLTextAreaElement>) => {
|
|
785
|
+
// Use the data from localStorage to paste any widgets we copied
|
|
786
|
+
// before. Avoid name conflicts by renumbering pasted widgets so that
|
|
787
|
+
// their numbers are always higher than the highest numbered widget of
|
|
788
|
+
// their type.
|
|
789
|
+
// TODO(sam): Fix widget numbering in the widget editor titles
|
|
790
|
+
|
|
791
|
+
const widgetJSON = localStorage.perseusLastCopiedWidgets;
|
|
792
|
+
const lastCopiedText = localStorage.perseusLastCopiedText;
|
|
793
|
+
const textToBePasted =
|
|
794
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'originalEvent' does not exist on type 'SyntheticEvent<HTMLTextAreaElement, Event>'.
|
|
795
|
+
e.originalEvent.clipboardData.getData("text");
|
|
796
|
+
|
|
797
|
+
// Only intercept if we have widget data to paste and the user is
|
|
798
|
+
// pasting something originally from Perseus.
|
|
799
|
+
// TODO(sam/aria/alex): Make it so that you can paste arbitrary text
|
|
800
|
+
// (e.g. from a text editor) instead of exactly what was copied, and
|
|
801
|
+
// let the widgetJSON match up with it. This would let you copy text
|
|
802
|
+
// into a buffer, perform complex operations on it, then paste it back.
|
|
803
|
+
if (widgetJSON && lastCopiedText === textToBePasted) {
|
|
804
|
+
e.preventDefault();
|
|
805
|
+
|
|
806
|
+
const widgetData = JSON.parse(widgetJSON);
|
|
807
|
+
const safeWidgetMapping =
|
|
808
|
+
this._safeWidgetNameMapping(widgetData);
|
|
809
|
+
|
|
810
|
+
// Use safe widget name map to construct the new widget data
|
|
811
|
+
// TODO(aria/alex): Don't use `rWidgetSplit` or other piecemeal
|
|
812
|
+
// regexes directly; abstract this out so that we don't have to
|
|
813
|
+
// worry about potential edge cases.
|
|
814
|
+
const safeWidgetData: Record<string, any> = {};
|
|
815
|
+
for (const [key, data] of Object.entries(widgetData)) {
|
|
816
|
+
safeWidgetData[safeWidgetMapping[key]] = data;
|
|
817
|
+
}
|
|
818
|
+
const newWidgets = _.extend(safeWidgetData, this.props.widgets);
|
|
819
|
+
|
|
820
|
+
// Use safe widget name map to construct new text
|
|
821
|
+
const safeText = lastCopiedText.replace(
|
|
822
|
+
rWidgetSplit,
|
|
823
|
+
(syntax) => {
|
|
824
|
+
const match = Util.rWidgetParts.exec(syntax);
|
|
825
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
826
|
+
const completeWidget = match[0];
|
|
827
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
828
|
+
const widget = match[1];
|
|
829
|
+
return completeWidget.replace(
|
|
830
|
+
widget,
|
|
831
|
+
safeWidgetMapping[widget],
|
|
832
|
+
);
|
|
833
|
+
},
|
|
813
834
|
);
|
|
814
|
-
});
|
|
815
835
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
// See componentDidUpdate() for how this flag is used
|
|
826
|
-
this.lastUserValue = this.state.textAreaValue;
|
|
827
|
-
this.props.onChange(
|
|
828
|
-
{content: newContent, widgets: newWidgets},
|
|
829
|
-
() => {
|
|
830
|
-
const expectedCursorPosition =
|
|
831
|
-
selectionStart + safeText.length;
|
|
832
|
-
Util.textarea.moveCursor(textarea, expectedCursorPosition);
|
|
833
|
-
},
|
|
834
|
-
);
|
|
835
|
-
}
|
|
836
|
-
};
|
|
836
|
+
// Add pasted text to previous content, replacing selected text to
|
|
837
|
+
// replicate normal paste behavior.
|
|
838
|
+
const textarea = e.currentTarget;
|
|
839
|
+
const selectionStart = textarea.selectionStart;
|
|
840
|
+
const newContent =
|
|
841
|
+
this.state.textAreaValue.substr(0, selectionStart) +
|
|
842
|
+
safeText +
|
|
843
|
+
this.state.textAreaValue.substr(textarea.selectionEnd);
|
|
837
844
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
const existingWidgets = _.keys(this.props.widgets).map((name) =>
|
|
854
|
-
name.split(" "),
|
|
855
|
-
);
|
|
845
|
+
// See componentDidUpdate() for how this flag is used
|
|
846
|
+
this.lastUserValue = this.state.textAreaValue;
|
|
847
|
+
this.props.onChange(
|
|
848
|
+
{content: newContent, widgets: newWidgets},
|
|
849
|
+
() => {
|
|
850
|
+
const expectedCursorPosition =
|
|
851
|
+
selectionStart + safeText.length;
|
|
852
|
+
Util.textarea.moveCursor(
|
|
853
|
+
textarea,
|
|
854
|
+
expectedCursorPosition,
|
|
855
|
+
);
|
|
856
|
+
},
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
856
860
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
861
|
+
_safeWidgetNameMapping: (widgetData: {
|
|
862
|
+
[name: string]: any;
|
|
863
|
+
}) => Record<any, any> = (widgetData: {[name: string]: any}) => {
|
|
864
|
+
// Helper function for _maybePasteWidgets.
|
|
865
|
+
// For each widget about to be pasted, construct a mapping from
|
|
866
|
+
// old widget name to a new widget name that doesn't have conflicts
|
|
867
|
+
// with widgets already in the editor.
|
|
868
|
+
// eg. If there is an "image 2" already present in the editor and we're
|
|
869
|
+
// about to paste in two new images, return
|
|
870
|
+
// { "image 1": "image 3", "image 2": "image 4" }
|
|
871
|
+
|
|
872
|
+
// List of widgets about to be pasted as [[name, number], ...]
|
|
873
|
+
const widgets = _.keys(widgetData).map((name) => name.split(" "));
|
|
874
|
+
const widgetTypes = _.uniq(widgets.map((widget) => widget[0]));
|
|
875
|
+
|
|
876
|
+
// List of existing widgets as [[name, number], ...]
|
|
877
|
+
const existingWidgets = _.keys(this.props.widgets).map((name) =>
|
|
878
|
+
name.split(" "),
|
|
879
|
+
);
|
|
869
880
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
881
|
+
// Mapping of widget type to a safe (non-conflicting) number
|
|
882
|
+
// eg. { "image": 2, "dropdown": 1 }
|
|
883
|
+
const safeWidgetNums: Record<string, any> = {};
|
|
884
|
+
_.each(widgetTypes, (type) => {
|
|
885
|
+
safeWidgetNums[type] = _.chain(existingWidgets)
|
|
886
|
+
.filter((existingWidget) => existingWidget[0] === type)
|
|
887
|
+
.map((existingWidget) => +existingWidget[1] + 1)
|
|
888
|
+
.max()
|
|
889
|
+
.value();
|
|
890
|
+
// If there are no existing widgets _.max returns -Infinity
|
|
891
|
+
safeWidgetNums[type] = Math.max(safeWidgetNums[type], 1);
|
|
892
|
+
});
|
|
875
893
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
894
|
+
// Construct mapping, incrementing the vals in safeWidgetNums as we go
|
|
895
|
+
const safeWidgetMapping: Record<string, any> = {};
|
|
896
|
+
_.each(widgets, (widget) => {
|
|
897
|
+
const widgetName = widget.join(" ");
|
|
898
|
+
const widgetType = widget[0];
|
|
881
899
|
|
|
882
|
-
|
|
883
|
-
|
|
900
|
+
safeWidgetMapping[
|
|
901
|
+
widgetName
|
|
902
|
+
] = `${widgetType} ${safeWidgetNums[widgetType]}`;
|
|
903
|
+
safeWidgetNums[widgetType]++;
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
return safeWidgetMapping;
|
|
907
|
+
};
|
|
884
908
|
|
|
885
909
|
_addWidgetToContent: (
|
|
886
910
|
oldContent: string,
|
|
887
|
-
cursorRange:
|
|
911
|
+
cursorRange: ReadonlyArray<number>,
|
|
888
912
|
widgetType: string,
|
|
889
913
|
) => void = (
|
|
890
914
|
oldContent: string,
|
|
891
|
-
cursorRange:
|
|
915
|
+
cursorRange: ReadonlyArray<number>,
|
|
892
916
|
widgetType: string,
|
|
893
917
|
) => {
|
|
894
918
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -897,11 +921,12 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
897
921
|
// Note: we have to use _.map here instead of Array::map
|
|
898
922
|
// because the results of a .match might be null if no
|
|
899
923
|
// widgets were found.
|
|
924
|
+
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'RegExpMatchArray | null' is not assignable to parameter of type 'Collection<any>'.
|
|
900
925
|
const allWidgetIds = _.map(oldContent.match(rWidgetSplit), (syntax) => {
|
|
901
926
|
const match = Util.rWidgetParts.exec(syntax);
|
|
902
|
-
//
|
|
927
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
903
928
|
const type = match[2];
|
|
904
|
-
//
|
|
929
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
905
930
|
const num = +match[3];
|
|
906
931
|
return [type, num];
|
|
907
932
|
});
|
|
@@ -939,10 +964,12 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
939
964
|
const newWidgets = _.clone(this.props.widgets);
|
|
940
965
|
newWidgets[id] = {
|
|
941
966
|
options: Widgets.getEditor(widgetType)?.defaultProps,
|
|
967
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'string' is not assignable to type '"video" | "image" | "iframe" | "table" | "radio" | "definition" | "group" | "matrix" | "categorizer" | "cs-program" | "dropdown" | "example-graphie-widget" | "example-widget" | ... 26 more ... | "unit-input"'.
|
|
942
968
|
type: widgetType,
|
|
943
969
|
// Track widget version on creation, so that a widget editor
|
|
944
970
|
// without a valid version prop can only possibly refer to a
|
|
945
971
|
// pre-versioning creation time.
|
|
972
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'Version | null | undefined' is not assignable to type 'Version | undefined'.
|
|
946
973
|
version: Widgets.getVersion(widgetType),
|
|
947
974
|
};
|
|
948
975
|
|
|
@@ -957,6 +984,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
957
984
|
Util.textarea.moveCursor(
|
|
958
985
|
// findDOMNode can return Text but we know this is Element
|
|
959
986
|
// $FlowFixMe[incompatible-call]
|
|
987
|
+
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'Element | Text | null' is not assignable to parameter of type 'HTMLTextAreaElement'.
|
|
960
988
|
textarea,
|
|
961
989
|
// We want to put the cursor after the widget
|
|
962
990
|
// and after any added newlines
|
|
@@ -972,14 +1000,16 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
972
1000
|
|
|
973
1001
|
this._addWidgetToContent(
|
|
974
1002
|
this.props.content,
|
|
1003
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'selectionStart' does not exist on type 'ReactInstance'. | TS2339 - Property 'selectionEnd' does not exist on type 'ReactInstance'.
|
|
975
1004
|
[textarea.selectionStart, textarea.selectionEnd],
|
|
976
1005
|
widgetType,
|
|
977
1006
|
);
|
|
1007
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
978
1008
|
textarea.focus();
|
|
979
1009
|
};
|
|
980
1010
|
|
|
981
|
-
addTemplate: (e: SyntheticEvent<HTMLTextAreaElement>) => void = (
|
|
982
|
-
e: SyntheticEvent<HTMLTextAreaElement>,
|
|
1011
|
+
addTemplate: (e: React.SyntheticEvent<HTMLTextAreaElement>) => void = (
|
|
1012
|
+
e: React.SyntheticEvent<HTMLTextAreaElement>,
|
|
983
1013
|
) => {
|
|
984
1014
|
const templateType = e.currentTarget.value;
|
|
985
1015
|
if (templateType === "") {
|
|
@@ -1049,6 +1079,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1049
1079
|
.chain()
|
|
1050
1080
|
.map((id) => {
|
|
1051
1081
|
// eslint-disable-next-line react/no-string-refs
|
|
1082
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
|
|
1052
1083
|
const issuesFunc = this.refs[id].getSaveWarnings;
|
|
1053
1084
|
const issues = issuesFunc ? issuesFunc() : [];
|
|
1054
1085
|
return _.map(issues, (issue) => id + ": " + issue);
|
|
@@ -1068,7 +1099,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1068
1099
|
* textarea should be refined with an instanceof check to
|
|
1069
1100
|
* HTMLTextAreaElement so that these props are available.
|
|
1070
1101
|
*/
|
|
1071
|
-
//
|
|
1102
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'focus' does not exist on type 'Element | Text'.
|
|
1072
1103
|
textarea.focus();
|
|
1073
1104
|
}
|
|
1074
1105
|
};
|
|
@@ -1083,27 +1114,28 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1083
1114
|
* textarea should be refined with an instanceof check to
|
|
1084
1115
|
* HTMLTextAreaElement so that these props are available.
|
|
1085
1116
|
*/
|
|
1086
|
-
//
|
|
1117
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'selectionStart' does not exist on type 'Element | Text'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
1087
1118
|
textarea.selectionStart = textarea.value.length;
|
|
1088
|
-
//
|
|
1119
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'selectionEnd' does not exist on type 'Element | Text'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
1089
1120
|
textarea.selectionEnd = textarea.value.length;
|
|
1090
1121
|
}
|
|
1091
1122
|
};
|
|
1092
1123
|
|
|
1093
|
-
serialize: (options
|
|
1094
|
-
content: string
|
|
1095
|
-
images: any
|
|
1096
|
-
replace: any |
|
|
1097
|
-
widgets:
|
|
1098
|
-
|
|
1124
|
+
serialize: (options?: any) => {
|
|
1125
|
+
content: string;
|
|
1126
|
+
images: any;
|
|
1127
|
+
replace: any | undefined;
|
|
1128
|
+
widgets: Record<any, any>;
|
|
1129
|
+
} = (options: any) => {
|
|
1099
1130
|
// need to serialize the widgets since the state might not be
|
|
1100
1131
|
// completely represented in props. ahem //transformer// (and
|
|
1101
1132
|
// interactive-graph and plotter).
|
|
1102
|
-
const widgets = {};
|
|
1133
|
+
const widgets: Record<string, any> = {};
|
|
1103
1134
|
// eslint-disable-next-line react/no-string-refs
|
|
1104
1135
|
const widgetIds = _.intersection(this.widgetIds, _.keys(this.refs));
|
|
1105
1136
|
_.each(widgetIds, (id) => {
|
|
1106
1137
|
// eslint-disable-next-line react/no-string-refs
|
|
1138
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
|
|
1107
1139
|
widgets[id] = this.refs[id].serialize();
|
|
1108
1140
|
});
|
|
1109
1141
|
|
|
@@ -1131,7 +1163,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1131
1163
|
};
|
|
1132
1164
|
};
|
|
1133
1165
|
|
|
1134
|
-
render(): React.
|
|
1166
|
+
render(): React.ReactNode {
|
|
1135
1167
|
let pieces;
|
|
1136
1168
|
let widgets;
|
|
1137
1169
|
let underlayPieces;
|
|
@@ -1139,7 +1171,10 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1139
1171
|
let templatesDropDown;
|
|
1140
1172
|
let widgetsAndTemplates;
|
|
1141
1173
|
let wordCountDisplay;
|
|
1142
|
-
const katexErrorList
|
|
1174
|
+
const katexErrorList: Array<{
|
|
1175
|
+
math: string;
|
|
1176
|
+
message: never;
|
|
1177
|
+
}> = [];
|
|
1143
1178
|
|
|
1144
1179
|
if (this.props.showWordCount) {
|
|
1145
1180
|
const numChars = PerseusMarkdown.characterCount(this.props.content);
|
|
@@ -1172,6 +1207,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1172
1207
|
// Normal text
|
|
1173
1208
|
underlayPieces.push(pieces[i]);
|
|
1174
1209
|
|
|
1210
|
+
// @ts-expect-error [FEI-5003] - TS2554 - Expected 2 arguments, but got 1.
|
|
1175
1211
|
const ast = PerseusMarkdown.parse(pieces[i]);
|
|
1176
1212
|
|
|
1177
1213
|
PerseusMarkdown.traverseContent(ast, (node) => {
|
|
@@ -1181,9 +1217,10 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1181
1217
|
katex.renderToString(content, {
|
|
1182
1218
|
colorIsTextColor: true,
|
|
1183
1219
|
});
|
|
1184
|
-
} catch (e) {
|
|
1220
|
+
} catch (e: any) {
|
|
1185
1221
|
katexErrorList.push({
|
|
1186
1222
|
math: content,
|
|
1223
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'any' is not assignable to type 'never'.
|
|
1187
1224
|
message: e.message,
|
|
1188
1225
|
});
|
|
1189
1226
|
}
|
|
@@ -1242,6 +1279,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1242
1279
|
|
|
1243
1280
|
const insertTemplateString = "Insert template\u2026";
|
|
1244
1281
|
templatesDropDown = (
|
|
1282
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type '(e: SyntheticEvent<HTMLTextAreaElement, Event>) => void' is not assignable to type 'ChangeEventHandler<HTMLSelectElement>'.
|
|
1245
1283
|
<select onChange={this.addTemplate}>
|
|
1246
1284
|
<option value="">{insertTemplateString}</option>
|
|
1247
1285
|
<option disabled>--</option>
|
|
@@ -1257,7 +1295,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1257
1295
|
);
|
|
1258
1296
|
|
|
1259
1297
|
if (!this.props.immutableWidgets) {
|
|
1260
|
-
const widgetNodes =
|
|
1298
|
+
const widgetNodes = Object.values(widgets) as React.ReactNode;
|
|
1261
1299
|
widgetsAndTemplates = (
|
|
1262
1300
|
<div className="perseus-editor-widgets">
|
|
1263
1301
|
<div className="perseus-editor-widgets-selectors">
|
|
@@ -1329,7 +1367,7 @@ class Editor extends React.Component<EditorProps, EditorState> {
|
|
|
1329
1367
|
borderTop: "none",
|
|
1330
1368
|
padding: 4,
|
|
1331
1369
|
backgroundColor: "pink",
|
|
1332
|
-
};
|
|
1370
|
+
} as const;
|
|
1333
1371
|
|
|
1334
1372
|
return (
|
|
1335
1373
|
<div
|