@khanacademy/perseus-editor 2.15.4 → 2.15.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 (33) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/es/index.js +432 -580
  3. package/dist/es/index.js.map +1 -1
  4. package/dist/index.js +500 -658
  5. package/dist/index.js.map +1 -1
  6. package/dist/widgets/interaction-editor/function-editor.d.ts +25 -0
  7. package/dist/widgets/interaction-editor/index.d.ts +2 -0
  8. package/dist/widgets/interaction-editor/interaction-editor.d.ts +37 -0
  9. package/dist/widgets/interaction-editor/label-editor.d.ts +21 -0
  10. package/dist/widgets/interaction-editor/line-editor.d.ts +29 -0
  11. package/dist/widgets/interaction-editor/mathquill-input.d.ts +12 -0
  12. package/dist/widgets/interaction-editor/movable-line-editor.d.ts +29 -0
  13. package/dist/widgets/interaction-editor/movable-point-editor.d.ts +24 -0
  14. package/dist/widgets/interaction-editor/parametric-editor.d.ts +27 -0
  15. package/dist/widgets/interaction-editor/point-editor.d.ts +19 -0
  16. package/dist/widgets/interaction-editor/rectangle-editor.d.ts +23 -0
  17. package/package.json +3 -2
  18. package/src/widgets/__stories__/interaction-editor.stories.tsx +37 -0
  19. package/src/widgets/{interaction → interaction-editor}/constraint-editor.tsx +9 -21
  20. package/src/widgets/interaction-editor/function-editor.tsx +108 -0
  21. package/src/widgets/interaction-editor/index.ts +3 -0
  22. package/src/widgets/{interaction-editor.tsx → interaction-editor/interaction-editor.tsx} +40 -787
  23. package/src/widgets/interaction-editor/label-editor.tsx +87 -0
  24. package/src/widgets/interaction-editor/line-editor.tsx +125 -0
  25. package/src/widgets/interaction-editor/mathquill-input.tsx +81 -0
  26. package/src/widgets/interaction-editor/movable-line-editor.tsx +121 -0
  27. package/src/widgets/interaction-editor/movable-point-editor.tsx +89 -0
  28. package/src/widgets/interaction-editor/parametric-editor.tsx +117 -0
  29. package/src/widgets/interaction-editor/point-editor.tsx +72 -0
  30. package/src/widgets/interaction-editor/rectangle-editor.tsx +96 -0
  31. package/tsconfig-build.tsbuildinfo +1 -1
  32. package/dist/widgets/interaction-editor.d.ts +0 -28
  33. /package/dist/widgets/{interaction → interaction-editor}/constraint-editor.d.ts +0 -0
@@ -0,0 +1,87 @@
1
+ import {
2
+ components,
3
+ Changeable,
4
+ Dependencies,
5
+ EditorJsonify,
6
+ KhanColors,
7
+ ColorPicker,
8
+ } from "@khanacademy/perseus";
9
+ import * as React from "react";
10
+ import _ from "underscore";
11
+
12
+ import MathquillInput from "./mathquill-input";
13
+
14
+ const {TextInput} = components;
15
+ const {getDependencies} = Dependencies;
16
+
17
+ type Props = Changeable.ChangeableProps & {
18
+ color: string;
19
+ coordX: string;
20
+ coordY: string;
21
+ label: string;
22
+ };
23
+
24
+ type DefaultProps = {
25
+ color: Props["color"];
26
+ coordX: Props["coordX"];
27
+ coordY: Props["coordY"];
28
+ label: Props["label"];
29
+ };
30
+
31
+ // Editor for labels
32
+ // TODO(eater): Add text direction
33
+ class LabelEditor extends React.Component<Props> {
34
+ static defaultProps: DefaultProps = {
35
+ coordX: "0",
36
+ coordY: "0",
37
+ color: KhanColors.BLACK,
38
+ label: "\\phi",
39
+ };
40
+
41
+ change: (arg1: any, arg2?: any, arg3?: any) => any = (...args) => {
42
+ return Changeable.change.apply(this, args);
43
+ };
44
+
45
+ serialize = () => {
46
+ return EditorJsonify.serialize.call(this);
47
+ };
48
+
49
+ render(): React.ReactNode {
50
+ const {TeX} = getDependencies();
51
+
52
+ return (
53
+ <div className="graph-settings">
54
+ <div className="perseus-widget-row">
55
+ <TextInput
56
+ value={this.props.label}
57
+ onChange={this.change("label")}
58
+ style={{
59
+ width: "100%",
60
+ }}
61
+ />
62
+ </div>
63
+ <div className="perseus-widget-row">
64
+ Location: <TeX>\Large(</TeX>
65
+ <MathquillInput
66
+ value={this.props.coordX}
67
+ onChange={this.change("coordX")}
68
+ />
69
+ <TeX>,</TeX>{" "}
70
+ <MathquillInput
71
+ value={this.props.coordY}
72
+ onChange={this.change("coordY")}
73
+ />
74
+ <TeX>\Large)</TeX>
75
+ </div>
76
+ <div className="perseus-widget-row">
77
+ <ColorPicker
78
+ value={this.props.color}
79
+ onChange={this.change("color")}
80
+ />
81
+ </div>
82
+ </div>
83
+ );
84
+ }
85
+ }
86
+
87
+ export default LabelEditor;
@@ -0,0 +1,125 @@
1
+ import {
2
+ components,
3
+ Changeable,
4
+ Dependencies,
5
+ EditorJsonify,
6
+ KhanColors,
7
+ ArrowPicker,
8
+ ColorPicker,
9
+ DashPicker,
10
+ } from "@khanacademy/perseus";
11
+ import * as React from "react";
12
+ import _ from "underscore";
13
+
14
+ import MathquillInput from "./mathquill-input";
15
+
16
+ const {NumberInput} = components;
17
+ const {getDependencies} = Dependencies;
18
+
19
+ type Props = Changeable.ChangeableProps & {
20
+ startX: string;
21
+ startY: string;
22
+ endX: string;
23
+ endY: string;
24
+ color: string;
25
+ strokeDasharray: string;
26
+ arrows: string;
27
+ strokeWidth: number;
28
+ };
29
+
30
+ type DefaultProps = {
31
+ startX: Props["startX"];
32
+ startY: Props["startY"];
33
+ endX: Props["endX"];
34
+ endY: Props["endY"];
35
+ color: Props["color"];
36
+ strokeDasharray: Props["strokeDasharray"];
37
+ arrows: Props["arrows"];
38
+ strokeWidth: Props["strokeWidth"];
39
+ };
40
+
41
+ // Editor for non-interactive line segments
42
+ class LineEditor extends React.Component<Props> {
43
+ static defaultProps: DefaultProps = {
44
+ startX: "-5",
45
+ startY: "5",
46
+ endX: "5",
47
+ endY: "5",
48
+ color: KhanColors.BLACK,
49
+ strokeDasharray: "",
50
+ arrows: "",
51
+ strokeWidth: 2,
52
+ };
53
+
54
+ change: (arg1: any, arg2?: any, arg3?: any) => any = (...args) => {
55
+ return Changeable.change.apply(this, args);
56
+ };
57
+
58
+ serialize = () => {
59
+ return EditorJsonify.serialize.call(this);
60
+ };
61
+
62
+ render(): React.ReactNode {
63
+ const {TeX} = getDependencies();
64
+
65
+ return (
66
+ <div className="graph-settings">
67
+ <div className="perseus-widget-row">
68
+ Start: <TeX>\Large(</TeX>
69
+ <MathquillInput
70
+ value={this.props.startX}
71
+ onChange={this.change("startX")}
72
+ />
73
+ <TeX>,</TeX>{" "}
74
+ <MathquillInput
75
+ value={this.props.startY}
76
+ onChange={this.change("startY")}
77
+ />
78
+ <TeX>\Large)</TeX>
79
+ </div>
80
+ <div className="perseus-widget-row">
81
+ End: <TeX>\Large(</TeX>
82
+ <MathquillInput
83
+ value={this.props.endX}
84
+ onChange={this.change("endX")}
85
+ />
86
+ <TeX>,</TeX>{" "}
87
+ <MathquillInput
88
+ value={this.props.endY}
89
+ onChange={this.change("endY")}
90
+ />
91
+ <TeX>\Large)</TeX>
92
+ </div>
93
+ <div className="perseus-widget-row">
94
+ <ColorPicker
95
+ value={this.props.color}
96
+ onChange={this.change("color")}
97
+ />
98
+ </div>
99
+ <div className="perseus-widget-row">
100
+ <DashPicker
101
+ value={this.props.strokeDasharray}
102
+ onChange={this.change("strokeDasharray")}
103
+ />
104
+ &nbsp; &nbsp;
105
+ <ArrowPicker
106
+ value={this.props.arrows}
107
+ onChange={this.change("arrows")}
108
+ />
109
+ </div>
110
+ <div className="perseus-widget-row">
111
+ <div className="perseus-widget-left-col">
112
+ Width:{" "}
113
+ <NumberInput
114
+ value={this.props.strokeWidth}
115
+ placeholder={2}
116
+ onChange={this.change("strokeWidth")}
117
+ />
118
+ </div>
119
+ </div>
120
+ </div>
121
+ );
122
+ }
123
+ }
124
+
125
+ export default LineEditor;
@@ -0,0 +1,81 @@
1
+ import {createMathField} from "@khanacademy/math-input";
2
+ import Color from "@khanacademy/wonder-blocks-color";
3
+ import {View} from "@khanacademy/wonder-blocks-core";
4
+ import {StyleSheet} from "aphrodite";
5
+ import * as React from "react";
6
+ import {useRef, useEffect} from "react";
7
+
8
+ import type {MathFieldInterface} from "@khanacademy/math-input";
9
+
10
+ type Props = {
11
+ value: string;
12
+ onChange: (value: string) => void;
13
+ };
14
+
15
+ /**
16
+ * A simple Mathquill MathField input for the InteractionEditor.
17
+ * Unlike our other uses of Mathquill, we're not using a keypad here;
18
+ * it's just the input itself for use writing TeX.
19
+ */
20
+ export default function MathquillInput(props: Props) {
21
+ const mathFieldWrapperRef = useRef<HTMLSpanElement>(null);
22
+ const mathFieldInstance = useRef<MathFieldInterface>();
23
+
24
+ useEffect(() => {
25
+ // If we have the mount for the input, but not the input
26
+ // make a new Mathquill input
27
+ if (mathFieldWrapperRef.current && !mathFieldInstance.current) {
28
+ // Initialize MathQuill.MathField instance
29
+ mathFieldInstance.current = createMathField(
30
+ mathFieldWrapperRef.current,
31
+ (baseConfig) => ({
32
+ ...baseConfig,
33
+ handlers: {
34
+ edit: (mathField) => {
35
+ // This handler is guaranteed to be called on change, but
36
+ // unlike React it sometimes generates false positives.
37
+ // One of these is on initialization (with an empty string
38
+ // value), so we have to guard against that below.
39
+ let value = mathField.latex();
40
+
41
+ // Provide a MathQuill-compatible way to generate the
42
+ // not-equals sign without pasting unicode or typing TeX
43
+ value = value.replace(/<>/g, "\\ne");
44
+
45
+ if (props.value !== value) {
46
+ props.onChange(value);
47
+ }
48
+ },
49
+ upOutOf: (mathField) => {
50
+ // This handler is called when the user presses the up
51
+ // arrow key, but there is nowhere in the expression to go
52
+ // up to (no numerator or exponent). For ease of use,
53
+ // interpret this as an attempt to create an exponent.
54
+ mathField.typedText("^");
55
+ },
56
+ },
57
+ }),
58
+ );
59
+ }
60
+ });
61
+
62
+ return (
63
+ <View style={styles.outerWrapper}>
64
+ <span
65
+ ref={mathFieldWrapperRef}
66
+ className="perseus-math-input mq-editable-field mq-math-mode"
67
+ />
68
+ </View>
69
+ );
70
+ }
71
+
72
+ const styles = StyleSheet.create({
73
+ outerWrapper: {
74
+ display: "inline-block",
75
+ borderStyle: "solid",
76
+ borderWidth: 1,
77
+ borderColor: Color.offBlack50,
78
+ borderRadius: 3,
79
+ background: Color.white,
80
+ },
81
+ });
@@ -0,0 +1,121 @@
1
+ import {
2
+ components,
3
+ Changeable,
4
+ Dependencies,
5
+ EditorJsonify,
6
+ } from "@khanacademy/perseus";
7
+ import * as React from "react";
8
+ import _ from "underscore";
9
+
10
+ import ConstraintEditor from "./constraint-editor";
11
+ import MathquillInput from "./mathquill-input";
12
+
13
+ const {NumberInput} = components;
14
+ const {getDependencies} = Dependencies;
15
+
16
+ type Props = Changeable.ChangeableProps & {
17
+ startX: string;
18
+ startY: string;
19
+ endX: string;
20
+ endY: string;
21
+ constraint: string;
22
+ snap: number;
23
+ constraintFn: string;
24
+ startSubscript: number;
25
+ endSubscript: number;
26
+ };
27
+
28
+ type DefaultProps = {
29
+ startX: Props["startX"];
30
+ startY: Props["startY"];
31
+ endX: Props["endX"];
32
+ endY: Props["endY"];
33
+ constraint: Props["constraint"];
34
+ snap: Props["snap"];
35
+ constraintFn: Props["constraintFn"];
36
+ };
37
+
38
+ // Editor for interactive movable line segments
39
+ // TODO(eater): Rethink how constraints are represented
40
+ class MovableLineEditor extends React.Component<Props> {
41
+ static defaultProps: DefaultProps = {
42
+ startX: "-5",
43
+ startY: "5",
44
+ endX: "5",
45
+ endY: "5",
46
+ constraint: "none",
47
+ snap: 0.5,
48
+ constraintFn: "0",
49
+ // @ts-expect-error - TS2561
50
+ constraintXMin: "-10",
51
+ constraintXMax: "10",
52
+ constraintYMin: "-10",
53
+ constraintYMax: "10",
54
+ };
55
+
56
+ change = (...args) => {
57
+ return Changeable.change.apply(this, args);
58
+ };
59
+
60
+ serialize = () => {
61
+ return EditorJsonify.serialize.call(this);
62
+ };
63
+
64
+ render(): React.ReactNode {
65
+ const {TeX} = getDependencies();
66
+
67
+ return (
68
+ <div className="graph-settings">
69
+ Initial position:
70
+ <div className="perseus-widget-row">
71
+ Start: <TeX>\Large(</TeX>
72
+ <MathquillInput
73
+ value={this.props.startX}
74
+ onChange={this.change("startX")}
75
+ />
76
+ <TeX>,</TeX>{" "}
77
+ <MathquillInput
78
+ value={this.props.startY}
79
+ onChange={this.change("startY")}
80
+ />
81
+ <TeX>\Large)</TeX>
82
+ </div>
83
+ <div className="perseus-widget-row">
84
+ End: <TeX>\Large(</TeX>
85
+ <MathquillInput
86
+ value={this.props.endX}
87
+ onChange={this.change("endX")}
88
+ />
89
+ <TeX>,</TeX>{" "}
90
+ <MathquillInput
91
+ value={this.props.endY}
92
+ onChange={this.change("endY")}
93
+ />
94
+ <TeX>\Large)</TeX>
95
+ </div>
96
+ <div className="perseus-widget-row">
97
+ Start updates <TeX>(x_n, y_n)</TeX> for <TeX>n =</TeX>
98
+ <NumberInput
99
+ value={this.props.startSubscript}
100
+ placeholder={0}
101
+ onChange={this.change("startSubscript")}
102
+ />
103
+ </div>
104
+ <div className="perseus-widget-row">
105
+ End updates <TeX>(x_m, y_m)</TeX> for <TeX>m =</TeX>
106
+ <NumberInput
107
+ value={this.props.endSubscript}
108
+ placeholder={0}
109
+ onChange={this.change("endSubscript")}
110
+ />
111
+ </div>
112
+ <div className="perseus-widget-row">
113
+ All constraints are applied to the start point.
114
+ </div>
115
+ <ConstraintEditor {...this.props} />
116
+ </div>
117
+ );
118
+ }
119
+ }
120
+
121
+ export default MovableLineEditor;
@@ -0,0 +1,89 @@
1
+ import {
2
+ components,
3
+ Changeable,
4
+ Dependencies,
5
+ EditorJsonify,
6
+ } from "@khanacademy/perseus";
7
+ import * as React from "react";
8
+ import _ from "underscore";
9
+
10
+ import ConstraintEditor from "./constraint-editor";
11
+ import MathquillInput from "./mathquill-input";
12
+
13
+ const {NumberInput} = components;
14
+ const {getDependencies} = Dependencies;
15
+
16
+ type Props = Changeable.ChangeableProps & {
17
+ startX: string;
18
+ startY: string;
19
+ constraint: string;
20
+ snap: number;
21
+ constraintFn: string;
22
+ varSubscript: number;
23
+ };
24
+
25
+ type DefaultProps = {
26
+ startX: Props["startX"];
27
+ startY: Props["startY"];
28
+ constraint: Props["constraint"];
29
+ snap: Props["snap"];
30
+ constraintFn: Props["constraintFn"];
31
+ };
32
+
33
+ // Editor for interactive movable points
34
+ // TODO(eater): Rethink how constraints are represented
35
+ class MovablePointEditor extends React.Component<Props> {
36
+ static defaultProps: DefaultProps = {
37
+ startX: "0",
38
+ startY: "0",
39
+ constraint: "none",
40
+ snap: 0.5,
41
+ constraintFn: "0",
42
+ // @ts-expect-error - TS2561
43
+ constraintXMin: "-10",
44
+ constraintXMax: "10",
45
+ constraintYMin: "-10",
46
+ constraintYMax: "10",
47
+ };
48
+
49
+ change = (...args) => {
50
+ return Changeable.change.apply(this, args);
51
+ };
52
+
53
+ serialize = () => {
54
+ return EditorJsonify.serialize.call(this);
55
+ };
56
+
57
+ render(): React.ReactNode {
58
+ const {TeX} = getDependencies();
59
+
60
+ return (
61
+ <div className="graph-settings">
62
+ <div className="perseus-widget-row">
63
+ Start: <TeX>\Large(</TeX>
64
+ <MathquillInput
65
+ value={this.props.startX}
66
+ onChange={this.change("startX")}
67
+ />
68
+ <TeX>,</TeX>{" "}
69
+ <MathquillInput
70
+ value={this.props.startY}
71
+ onChange={this.change("startY")}
72
+ />
73
+ <TeX>\Large)</TeX>
74
+ </div>
75
+ <div className="perseus-widget-row">
76
+ Update <TeX>(x_n, y_n)</TeX> for <TeX>n =</TeX>{" "}
77
+ <NumberInput
78
+ value={this.props.varSubscript}
79
+ placeholder={0}
80
+ onChange={this.change("varSubscript")}
81
+ />
82
+ </div>
83
+ <ConstraintEditor {...this.props} />
84
+ </div>
85
+ );
86
+ }
87
+ }
88
+
89
+ export default MovablePointEditor;
@@ -0,0 +1,117 @@
1
+ import {
2
+ components,
3
+ Changeable,
4
+ Dependencies,
5
+ EditorJsonify,
6
+ KhanColors,
7
+ ColorPicker,
8
+ DashPicker,
9
+ } from "@khanacademy/perseus";
10
+ import * as React from "react";
11
+ import _ from "underscore";
12
+
13
+ import MathquillInput from "./mathquill-input";
14
+
15
+ const {NumberInput} = components;
16
+ const {getDependencies} = Dependencies;
17
+
18
+ type Props = Changeable.ChangeableProps & {
19
+ x: string;
20
+ y: string;
21
+ rangeMin: string;
22
+ rangeMax: string;
23
+ color: string;
24
+ strokeDasharray: string;
25
+ strokeWidth: number;
26
+ };
27
+
28
+ type DefaultProps = {
29
+ x: Props["x"];
30
+ y: Props["y"];
31
+ rangeMin: Props["rangeMin"];
32
+ rangeMax: Props["rangeMax"];
33
+ color: Props["color"];
34
+ strokeDasharray: Props["strokeDasharray"];
35
+ strokeWidth: Props["strokeWidth"];
36
+ };
37
+
38
+ // Editor for parametric plots
39
+ class ParametricEditor extends React.Component<Props> {
40
+ static defaultProps: DefaultProps = {
41
+ x: "cos(t)",
42
+ y: "sin(t)",
43
+ rangeMin: "0",
44
+ rangeMax: "2\\pi",
45
+ color: KhanColors.BLUE,
46
+ strokeDasharray: "",
47
+ strokeWidth: 2,
48
+ };
49
+
50
+ change: (arg1: any, arg2?: any, arg3?: any) => any = (...args) => {
51
+ return Changeable.change.apply(this, args);
52
+ };
53
+
54
+ serialize = () => {
55
+ return EditorJsonify.serialize.call(this);
56
+ };
57
+
58
+ render(): React.ReactNode {
59
+ const {TeX} = getDependencies();
60
+
61
+ return (
62
+ <div className="graph-settings">
63
+ <div className="perseus-widget-row">
64
+ <TeX>X(t) =</TeX>{" "}
65
+ <MathquillInput
66
+ value={this.props.x}
67
+ onChange={this.change("x")}
68
+ />
69
+ </div>
70
+ <div className="perseus-widget-row">
71
+ <TeX>Y(t) =</TeX>{" "}
72
+ <MathquillInput
73
+ value={this.props.y}
74
+ onChange={this.change("y")}
75
+ />
76
+ </div>
77
+ <div className="perseus-widget-row">
78
+ Range: <TeX>\Large(</TeX>
79
+ <MathquillInput
80
+ value={this.props.rangeMin}
81
+ onChange={this.change("rangeMin")}
82
+ />
83
+ <TeX>,</TeX>{" "}
84
+ <MathquillInput
85
+ value={this.props.rangeMax}
86
+ onChange={this.change("rangeMax")}
87
+ />
88
+ <TeX>\Large)</TeX>
89
+ </div>
90
+ <div className="perseus-widget-row">
91
+ <ColorPicker
92
+ value={this.props.color}
93
+ onChange={this.change("color")}
94
+ />
95
+ </div>
96
+ <div className="perseus-widget-row">
97
+ <DashPicker
98
+ value={this.props.strokeDasharray}
99
+ onChange={this.change("strokeDasharray")}
100
+ />
101
+ </div>
102
+ <div className="perseus-widget-row">
103
+ <div className="perseus-widget-left-col">
104
+ Width:{" "}
105
+ <NumberInput
106
+ value={this.props.strokeWidth}
107
+ placeholder={2}
108
+ onChange={this.change("strokeWidth")}
109
+ />
110
+ </div>
111
+ </div>
112
+ </div>
113
+ );
114
+ }
115
+ }
116
+
117
+ export default ParametricEditor;
@@ -0,0 +1,72 @@
1
+ import {
2
+ Changeable,
3
+ Dependencies,
4
+ EditorJsonify,
5
+ KhanColors,
6
+ ColorPicker,
7
+ } from "@khanacademy/perseus";
8
+ import * as React from "react";
9
+ import _ from "underscore";
10
+
11
+ import MathquillInput from "./mathquill-input";
12
+
13
+ const {getDependencies} = Dependencies;
14
+
15
+ type Props = Changeable.ChangeableProps & {
16
+ coordX: string;
17
+ coordY: string;
18
+ color: string;
19
+ };
20
+
21
+ type DefaultProps = {
22
+ coordX: Props["coordX"];
23
+ coordY: Props["coordY"];
24
+ color: Props["color"];
25
+ };
26
+
27
+ // Editor for non-interactive points
28
+ class PointEditor extends React.Component<Props> {
29
+ static defaultProps: DefaultProps = {
30
+ coordX: "0",
31
+ coordY: "0",
32
+ color: KhanColors.BLACK,
33
+ };
34
+
35
+ change: (arg1: any, arg2?: any, arg3?: any) => any = (...args) => {
36
+ return Changeable.change.apply(this, args);
37
+ };
38
+
39
+ serialize = () => {
40
+ return EditorJsonify.serialize.call(this);
41
+ };
42
+
43
+ render(): React.ReactNode {
44
+ const {TeX} = getDependencies();
45
+
46
+ return (
47
+ <div className="graph-settings">
48
+ <div className="perseus-widget-row">
49
+ Coordinate: <TeX>\Large(</TeX>
50
+ <MathquillInput
51
+ value={this.props.coordX}
52
+ onChange={this.change("coordX")}
53
+ />
54
+ <TeX>,</TeX>{" "}
55
+ <MathquillInput
56
+ value={this.props.coordY}
57
+ onChange={this.change("coordY")}
58
+ />
59
+ <TeX>\Large)</TeX>
60
+ </div>
61
+ <div className="perseus-widget-row">
62
+ <ColorPicker
63
+ value={this.props.color}
64
+ onChange={this.change("color")}
65
+ />
66
+ </div>
67
+ </div>
68
+ );
69
+ }
70
+ }
71
+
72
+ export default PointEditor;