@khanacademy/perseus 17.4.0 → 17.6.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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Core Perseus API (includes renderers and widgets)",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "17.4.0",
6
+ "version": "17.6.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -1,4 +1,5 @@
1
1
  import {KeypadContext} from "@khanacademy/math-input";
2
+ import {action} from "@storybook/addon-actions";
2
3
  import React from "react";
3
4
 
4
5
  import {storybookDependenciesV2} from "../../../../testing/test-dependencies";
@@ -67,6 +68,7 @@ export const ExpressionArticle = ({useNewStyles}): any => (
67
68
  apiOptions={{
68
69
  isMobile: true,
69
70
  customKeypad: true,
71
+ onFocusChange: action("onFocusChange"),
70
72
  }}
71
73
  keypadElement={keypadElement}
72
74
  />
@@ -326,9 +326,9 @@ describe("server item renderer", () => {
326
326
 
327
327
  // Act
328
328
  const gotFocus = renderer.focus();
329
- // We have _two_ different async processes that need to be resolved here
330
- jest.runOnlyPendingTimers();
331
- jest.runOnlyPendingTimers();
329
+
330
+ // We have some async processes that need to be resolved here
331
+ jest.runAllTimers();
332
332
 
333
333
  // Assert
334
334
  expect(gotFocus).toBeTrue();
@@ -370,9 +370,9 @@ describe("server item renderer", () => {
370
370
 
371
371
  // Act
372
372
  const gotFocus = renderer.focus();
373
- // We have _two_ different async processes that need to be resolved here
374
- jest.runOnlyPendingTimers();
375
- jest.runOnlyPendingTimers();
373
+
374
+ // We have some async processes that need to be resolved here
375
+ jest.runAllTimers();
376
376
 
377
377
  // Assert
378
378
  expect(keypadElement.activate).toHaveBeenCalled();
@@ -392,15 +392,12 @@ describe("server item renderer", () => {
392
392
  onFocusChange,
393
393
  });
394
394
  renderer.focus();
395
- // We have _two_ different async processes that need to be resolved here
396
- jest.runOnlyPendingTimers();
397
- jest.runOnlyPendingTimers();
398
395
 
399
396
  // Act
400
397
  renderer.blur();
401
- // We have _two_ different async processes that need to be resolved here
402
- jest.runOnlyPendingTimers();
403
- jest.runOnlyPendingTimers();
398
+
399
+ // We have some async processes that need to be resolved here
400
+ jest.runAllTimers();
404
401
 
405
402
  // Assert
406
403
  expect(onFocusChange).toHaveBeenCalledTimes(2);
@@ -440,15 +437,12 @@ describe("server item renderer", () => {
440
437
  {keypadElement},
441
438
  );
442
439
  renderer.focus();
443
- // We have _two_ different async processes that need to be resolved here
444
- jest.runOnlyPendingTimers();
445
- jest.runOnlyPendingTimers();
446
440
 
447
441
  // Act
448
442
  renderer.blur();
449
- // We have _two_ different async processes that need to be resolved here
450
- jest.runOnlyPendingTimers();
451
- jest.runOnlyPendingTimers();
443
+
444
+ // We have some async processes that need to be resolved here
445
+ jest.runAllTimers();
452
446
 
453
447
  // Assert
454
448
  expect(keypadElement.dismiss).toHaveBeenCalled();
@@ -471,6 +465,9 @@ describe("server item renderer", () => {
471
465
  // Act
472
466
  renderer.focusPath(["input-number 1"]);
473
467
 
468
+ // We have some async processes that need to be resolved here
469
+ jest.runAllTimers();
470
+
474
471
  // Assert
475
472
  expect(onFocusChange).toHaveBeenCalledWith(
476
473
  ["input-number 1"],
@@ -104,6 +104,26 @@ class ArticleRenderer
104
104
  );
105
105
  }
106
106
 
107
+ const {onFocusChange} = this.props.apiOptions;
108
+ if (onFocusChange) {
109
+ // Wait for the keypad to mount before getting the height
110
+ setTimeout(() => {
111
+ const keypadDomNode =
112
+ keypadElement?.getDOMNode() as HTMLElement;
113
+ const keypadHeight =
114
+ keypadDomNode && didFocusInput
115
+ ? keypadDomNode.getBoundingClientRect().height
116
+ : 0;
117
+
118
+ onFocusChange(
119
+ this._currentFocus,
120
+ prevFocusPath,
121
+ keypadHeight,
122
+ didFocusInput ? focusedInput : null,
123
+ );
124
+ }, 0);
125
+ }
126
+
107
127
  if (keypadElement && isMobile) {
108
128
  if (didFocusInput) {
109
129
  keypadElement.activate();
@@ -111,21 +131,6 @@ class ArticleRenderer
111
131
  keypadElement.dismiss();
112
132
  }
113
133
  }
114
-
115
- if (this.props.apiOptions.onFocusChange != null) {
116
- const keypadDomNode = keypadElement?.getDOMNode() as HTMLElement;
117
- const keypadHeight =
118
- keypadDomNode && didFocusInput
119
- ? keypadDomNode.getBoundingClientRect().height
120
- : 0;
121
-
122
- this.props.apiOptions.onFocusChange(
123
- this._currentFocus,
124
- prevFocusPath,
125
- keypadHeight,
126
- didFocusInput ? focusedInput : null,
127
- );
128
- }
129
134
  };
130
135
 
131
136
  _onRendererBlur: (arg1: any) => void = (blurPath) => {
@@ -180,6 +180,29 @@ export class ServerItemRenderer
180
180
  return Util.inputPathsEqual(inputPath, this._currentFocus);
181
181
  });
182
182
 
183
+ if (onFocusChange != null) {
184
+ // Wait for the keypad to mount before getting the height
185
+ setTimeout(() => {
186
+ // First, calculate the current keypad height
187
+ const keypadDomNode: HTMLElement =
188
+ keypadElement?.getDOMNode() as HTMLElement;
189
+ const keypadHeight =
190
+ keypadDomNode && didFocusInput
191
+ ? keypadDomNode.getBoundingClientRect().height
192
+ : 0;
193
+
194
+ // Then call the callback
195
+ onFocusChange(
196
+ this._currentFocus,
197
+ prevFocus,
198
+ keypadHeight,
199
+ // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'false | Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement | undefined'.
200
+ didFocusInput &&
201
+ this.questionRenderer.getDOMNodeForPath(newFocus),
202
+ );
203
+ }, 0);
204
+ }
205
+
183
206
  if (keypadElement && isMobile) {
184
207
  if (didFocusInput) {
185
208
  keypadElement.activate();
@@ -187,26 +210,6 @@ export class ServerItemRenderer
187
210
  keypadElement.dismiss();
188
211
  }
189
212
  }
190
-
191
- if (onFocusChange != null) {
192
- // First, calculate the current keypad height
193
- const keypadDomNode: HTMLElement =
194
- keypadElement?.getDOMNode() as HTMLElement;
195
- const keypadHeight =
196
- keypadDomNode && didFocusInput
197
- ? keypadDomNode.getBoundingClientRect().height
198
- : 0;
199
-
200
- // Then call the callback
201
- onFocusChange(
202
- this._currentFocus,
203
- prevFocus,
204
- keypadHeight,
205
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'false | Element | Text | null | undefined' is not assignable to parameter of type 'HTMLElement | undefined'.
206
- didFocusInput &&
207
- this.questionRenderer.getDOMNodeForPath(newFocus),
208
- );
209
- }
210
213
  }
211
214
 
212
215
  _onRendererBlur(blurPath: FocusPath) {
@@ -314,7 +314,7 @@
314
314
  tr:nth-child(odd) {
315
315
  // Doesn't work in IE8 :(
316
316
  td {
317
- background-color: #ededed;
317
+ background-color: @offWhite;
318
318
  }
319
319
  }
320
320
  }
@@ -15,6 +15,7 @@
15
15
  // TODO(charlie): DRY this up. How can we keep our global palette in sync across
16
16
  // repos?
17
17
  @white: #ffffff;
18
+ @offWhite: #f7f8fa;
18
19
  @gray98: #fafafa;
19
20
  @gray97: #f6f7f7;
20
21
  @gray95: #f0f1f2;
@@ -188,7 +188,7 @@ _.extend(Iframe, {
188
188
 
189
189
  export default {
190
190
  name: "iframe",
191
- displayName: "Iframe",
191
+ displayName: "Iframe (deprecated)",
192
192
  widget: Iframe,
193
193
  // Let's not expose it to all content creators yet
194
194
  hidden: true,
@@ -403,7 +403,7 @@ const propTransform = (
403
403
 
404
404
  export default {
405
405
  name: "input-number",
406
- displayName: "Number text box (old)",
406
+ displayName: "Input number (deprecated - use numeric input instead)",
407
407
  defaultAlignment: "inline-block",
408
408
  hidden: true,
409
409
  widget: InputNumber,
@@ -352,7 +352,7 @@ const transformProps: (arg1: any) => any = function (editorProps) {
352
352
 
353
353
  export default {
354
354
  name: "lights-puzzle",
355
- displayName: "Lights Puzzle",
355
+ displayName: "Lights puzzle (deprecated)",
356
356
  hidden: true,
357
357
  widget: LightsPuzzle,
358
358
  transform: transformProps,
@@ -292,7 +292,7 @@ const styles = StyleSheet.create({
292
292
 
293
293
  export default {
294
294
  name: "matcher",
295
- displayName: "Two column matcher",
295
+ displayName: "Matcher (two column)",
296
296
  widget: Matcher,
297
297
  isLintable: true,
298
298
  } as WidgetExports<typeof Matcher>;
@@ -567,7 +567,7 @@ const propsTransform = function (
567
567
 
568
568
  export default {
569
569
  name: "numeric-input",
570
- displayName: "Number text box",
570
+ displayName: "Numeric input",
571
571
  defaultAlignment: "inline-block",
572
572
  accessible: true,
573
573
  widget: NumericInput,
@@ -146,7 +146,7 @@ const propUpgrades = {
146
146
 
147
147
  export default {
148
148
  name: "radio",
149
- displayName: "Multiple choice",
149
+ displayName: "Radio / Multiple choice",
150
150
  accessible: true,
151
151
  widget: Radio,
152
152
  transform: transform,
@@ -138,7 +138,7 @@ class ReactionDiagramWidget extends React.Component<any> {
138
138
 
139
139
  export default {
140
140
  name: "reaction-diagram",
141
- displayName: "Chemical reaction",
141
+ displayName: "Chemical reaction diagram (deprecated)",
142
142
  hidden: true,
143
143
  widget: ReactionDiagramWidget,
144
144
  } as WidgetExports<typeof ReactionDiagramWidget>;
@@ -133,7 +133,7 @@ const traverseChildWidgets = function (props: any, traverseRenderer: any): any {
133
133
 
134
134
  export default {
135
135
  name: "sequence",
136
- displayName: "Graded Sequence",
136
+ displayName: "Graded sequence (deprecated)",
137
137
  widget: Sequence,
138
138
  traverseChildWidgets: traverseChildWidgets,
139
139
  tracking: "all",
@@ -822,7 +822,7 @@ const propTransform: (arg1: any) => any = (editorProps) => {
822
822
 
823
823
  export default {
824
824
  name: "simulator",
825
- displayName: "Simulator",
825
+ displayName: "Simulator (deprecated)",
826
826
  widget: Simulator,
827
827
  transform: propTransform,
828
828
  hidden: true,
@@ -384,7 +384,7 @@ const propTransform: (arg1: any) => any = (editorProps) => {
384
384
 
385
385
  export default {
386
386
  name: "table",
387
- displayName: "Table of values",
387
+ displayName: "Table (deprecated - use markdown table instead)",
388
388
  accessible: true,
389
389
  widget: Table,
390
390
  transform: propTransform,
@@ -2930,6 +2930,7 @@ class Transformer extends React.Component<Props> {
2930
2930
 
2931
2931
  export default {
2932
2932
  name: "transformer",
2933
- displayName: "Transformer",
2933
+ displayName: "Transformer (deprecated)",
2934
+ hidden: true,
2934
2935
  widget: Transformer,
2935
2936
  } as WidgetExports<typeof Transformer>;
@@ -365,7 +365,7 @@ const primUnits = function (expr) {
365
365
 
366
366
  export default {
367
367
  name: "unit-input",
368
- displayName: "Unit",
368
+ displayName: "Unit input",
369
369
  defaultAlignment: "inline-block",
370
370
  widget: OldUnitInput,
371
371
  transform: (x: any): any => lens(x).del(["value"]).freeze(),