@khanacademy/perseus-editor 2.12.1 → 2.14.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.
@@ -17,7 +17,7 @@ import SortableArea from "../components/sortable";
17
17
 
18
18
  import type {PerseusExpressionWidgetOptions} from "@khanacademy/perseus";
19
19
 
20
- const {InfoTip, PropCheckBox, TexButtons} = components;
20
+ const {InfoTip, PropCheckBox} = components;
21
21
 
22
22
  type Props = {
23
23
  widgetId?: any;
@@ -36,6 +36,15 @@ type DefaultProps = {
36
36
  functions: Props["functions"];
37
37
  };
38
38
 
39
+ const buttonSetsList: any = [
40
+ "basic",
41
+ "trig",
42
+ "prealgebra",
43
+ "logarithms",
44
+ "basic relations",
45
+ "advanced relations",
46
+ ];
47
+
39
48
  const parseAnswerKey = ({key}: AnswerForm): number => {
40
49
  // We don't throw here because there is data stored in some
41
50
  // exercises/articles where the answer forms don't have a key. If we throw,
@@ -67,11 +76,7 @@ const _makeNewKey = (answerForms: ReadonlyArray<AnswerForm>) => {
67
76
  return usedKeys.length;
68
77
  };
69
78
 
70
- type State = {
71
- isTex: boolean;
72
- };
73
-
74
- class ExpressionEditor extends React.Component<Props, State> {
79
+ class ExpressionEditor extends React.Component<Props> {
75
80
  static widgetName = "expression" as const;
76
81
 
77
82
  static defaultProps: DefaultProps = {
@@ -81,29 +86,6 @@ class ExpressionEditor extends React.Component<Props, State> {
81
86
  functions: ["f", "g", "h"],
82
87
  };
83
88
 
84
- constructor(props: Props) {
85
- super(props);
86
- // Is the format of `value` TeX or plain text?
87
- // TODO(alex): Remove after backfilling everything to TeX
88
- // TODO(joel) - sucks if you edit some expression without
89
- // backslashes or curly braces, then come back to the question and
90
- // it's surprisingly not TeX anymore.
91
-
92
- let isTex;
93
- // default to TeX if new;
94
- if (props.answerForms.length === 0) {
95
- isTex = true;
96
- } else {
97
- isTex = props.answerForms.some((form) => {
98
- const {value} = form;
99
- // only TeX has backslashes and curly braces
100
- return value.indexOf("\\") !== -1 || value.indexOf("{") !== -1;
101
- });
102
- }
103
-
104
- this.state = {isTex};
105
- }
106
-
107
89
  change(...args) {
108
90
  return Changeable.change.apply(this, args);
109
91
  }
@@ -156,38 +138,31 @@ class ExpressionEditor extends React.Component<Props, State> {
156
138
  );
157
139
 
158
140
  // checkboxes to choose which sets of input buttons are shown
159
- const buttonSetChoices = Object.keys(TexButtons.buttonSets).map(
160
- (name) => {
161
- // The first one gets special cased to always be checked, disabled,
162
- // and float left.
163
- const isFirst = name === "basic";
164
- const checked =
165
- this.props.buttonSets.includes(
166
- name as PerseusExpressionWidgetOptions["buttonSets"][number],
167
- ) || isFirst;
168
- const className = isFirst
169
- ? "button-set-label-float"
170
- : "button-set-label";
171
- return (
172
- <label className={className} key={name}>
173
- <input
174
- type="checkbox"
175
- checked={checked}
176
- disabled={isFirst}
177
- onChange={() => this.handleButtonSet(name)}
178
- />
179
- {name}
180
- </label>
181
- );
182
- },
183
- );
141
+ const buttonSetChoices = buttonSetsList.map((name) => {
142
+ // The first one gets special cased to always be checked, disabled,
143
+ // and float left.
144
+ const isFirst = name === "basic";
145
+ const checked =
146
+ this.props.buttonSets.includes(
147
+ name as PerseusExpressionWidgetOptions["buttonSets"][number],
148
+ ) || isFirst;
149
+ return (
150
+ <label className="button-set-label" key={name}>
151
+ <input
152
+ type="checkbox"
153
+ checked={checked}
154
+ disabled={isFirst}
155
+ onChange={() => this.handleButtonSet(name)}
156
+ />
157
+ {name}
158
+ </label>
159
+ );
160
+ });
184
161
 
185
162
  const {TeX} = Dependencies.getDependencies(); // OldExpression only
186
163
 
187
- buttonSetChoices.splice(
188
- 1,
189
- 1,
190
- <label key="show-div">
164
+ buttonSetChoices.unshift(
165
+ <label className="button-set-label" key="show-div">
191
166
  <input type="checkbox" onChange={this.handleToggleDiv} />
192
167
  <span className="show-div-button">
193
168
  show <TeX>\div</TeX> button
@@ -240,15 +215,6 @@ class ExpressionEditor extends React.Component<Props, State> {
240
215
  {buttonSetChoices}
241
216
  </div>
242
217
 
243
- {this.state.isTex && (
244
- <TexButtons
245
- className="math-input-buttons"
246
- sets={this.props.buttonSets}
247
- convertDotToTimes={this.props.times}
248
- onInsert={this.handleTexInsert}
249
- />
250
- )}
251
-
252
218
  <h3 className="expression-editor-h3">Answers</h3>
253
219
 
254
220
  <p style={{margin: "4px 0"}}>
@@ -397,9 +363,7 @@ class ExpressionEditor extends React.Component<Props, State> {
397
363
 
398
364
  // called when the selected buttonset changes
399
365
  handleButtonSet: (changingName: string) => void = (changingName) => {
400
- const buttonSetNames = Object.keys(
401
- TexButtons.buttonSets,
402
- ) as LegacyButtonSet[];
366
+ const buttonSetNames = buttonSetsList;
403
367
 
404
368
  // Filter to preserve order - using .union and .difference would always
405
369
  // move the last added button set to the end.
@@ -27,5 +27,5 @@ export const Default = (args: StoryArgs): React.ReactElement => {
27
27
  setState({...state, ...newState});
28
28
  },
29
29
  } as const;
30
- return <Behavior {...props} />;
30
+ return <Behavior preferredPopoverDirection="NONE" {...props} />;
31
31
  };
@@ -10,21 +10,32 @@ import Checkbox from "../../components/checkbox";
10
10
 
11
11
  const {colors, typography} = globalStyles;
12
12
 
13
+ export type PreferredPopoverDirection =
14
+ | "NONE"
15
+ | "UP"
16
+ | "DOWN"
17
+ | "LEFT"
18
+ | "RIGHT";
19
+
13
20
  type Props = {
14
21
  // Whether multiple answer choices may be selected for markers.
15
22
  multipleAnswers: boolean;
16
23
  // Whether to hide answer choices from user instructions.
17
24
  hideChoicesFromInstructions: boolean;
25
+
26
+ preferredPopoverDirection: PreferredPopoverDirection;
18
27
  // Callback for when widget options change.
19
28
  onChange: (options: {
20
29
  multipleAnswers?: boolean;
21
30
  hideChoicesFromInstructions?: boolean;
31
+ preferredPopoverDirection?: PreferredPopoverDirection;
22
32
  }) => void;
23
33
  };
24
34
 
25
35
  const Behavior = ({
26
36
  multipleAnswers,
27
37
  hideChoicesFromInstructions,
38
+ preferredPopoverDirection,
28
39
  onChange,
29
40
  }: Props): React.ReactElement => (
30
41
  <div>
@@ -59,6 +70,27 @@ const Behavior = ({
59
70
  Do not display answer choices in instructions
60
71
  </span>
61
72
  </li>
73
+
74
+ <li className={css(styles.option)}>
75
+ <span className={css(styles.label)}>
76
+ Preferred pop-over direction
77
+ </span>
78
+ <select
79
+ value={preferredPopoverDirection}
80
+ onChange={(e) => {
81
+ onChange({
82
+ preferredPopoverDirection: e.target
83
+ .value as PreferredPopoverDirection,
84
+ });
85
+ }}
86
+ >
87
+ <option value="NONE"> No Preference </option>
88
+ <option value="UP"> Up </option>
89
+ <option value="DOWN"> Down </option>
90
+ <option value="LEFT"> Left </option>
91
+ <option value="RIGHT"> Right </option>
92
+ </select>
93
+ </li>
62
94
  </ul>
63
95
  </div>
64
96
  );
@@ -229,6 +229,7 @@ class LabelImageEditor extends React.Component<Props> {
229
229
  <div className={css(styles.largeSpacer)} />
230
230
 
231
231
  <Behavior
232
+ preferredPopoverDirection="NONE"
232
233
  multipleAnswers={multipleAnswers}
233
234
  hideChoicesFromInstructions={hideChoicesFromInstructions}
234
235
  onChange={this.handleBehaviorChange}