@khanacademy/perseus 0.4.3 → 1.1.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.
Files changed (71) hide show
  1. package/.eslintrc.js +6 -1
  2. package/CHANGELOG.md +45 -0
  3. package/dist/es/index.css +15 -8
  4. package/dist/es/index.js +1214 -1404
  5. package/dist/es/index.js.map +1 -1
  6. package/dist/index.css +15 -8
  7. package/dist/index.js +1217 -1411
  8. package/dist/index.js.map +1 -1
  9. package/dist/strings.js +0 -4
  10. package/package.json +9 -8
  11. package/src/components/number-input.jsx +2 -2
  12. package/src/components/simple-keypad-input.jsx +18 -21
  13. package/src/index.js +1 -1
  14. package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +426 -135
  15. package/src/multi-items/__tests__/multi-renderer_test.js +9 -9
  16. package/src/perseus-api.jsx +10 -36
  17. package/src/perseus-types.js +18 -145
  18. package/src/styles/constants.js +0 -2
  19. package/src/styles/perseus-renderer.less +8 -2
  20. package/src/styles/variables.less +0 -2
  21. package/src/styles/widgets/passage.less +9 -5
  22. package/src/types.js +18 -35
  23. package/src/util/answer-types.js +2 -3
  24. package/src/util/math.js +3 -10
  25. package/src/util.js +0 -6
  26. package/src/version.js +1 -1
  27. package/src/widgets/__stories__/numeric-input.stories.jsx +43 -2
  28. package/src/widgets/__testdata__/base-radio_testdata.js +22 -0
  29. package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +4 -4
  30. package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +291 -130
  31. package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +3293 -1415
  32. package/src/widgets/__tests__/group_test.jsx +4 -4
  33. package/src/widgets/__tests__/numeric-input_test.jsx +12 -8
  34. package/src/widgets/__tests__/passage_test.jsx +81 -0
  35. package/src/widgets/__tests__/radio/base-radio_test.jsx +291 -41
  36. package/src/widgets/__tests__/radio/choice-icon_test.jsx +67 -0
  37. package/src/widgets/__tests__/radio/choice_test.jsx +302 -0
  38. package/src/widgets/__tests__/radio/focus-ring_test.jsx +23 -0
  39. package/src/widgets/__tests__/radio/option-status_test.jsx +65 -0
  40. package/src/widgets/__tests__/radio_test.jsx +39 -15
  41. package/src/widgets/definition.jsx +1 -1
  42. package/src/widgets/group.jsx +84 -102
  43. package/src/widgets/input-number.jsx +6 -1
  44. package/src/widgets/numeric-input.jsx +87 -80
  45. package/src/widgets/passage/__tests__/passage-markdown_test.jsx +0 -9
  46. package/src/widgets/passage/get-line-height-for-node.js +4 -5
  47. package/src/widgets/passage/passage-markdown.jsx +176 -120
  48. package/src/widgets/passage.jsx +48 -46
  49. package/src/widgets/radio/__stories__/base-radio.stories.jsx +164 -17
  50. package/src/widgets/radio/__stories__/choice-icon.stories.jsx +202 -111
  51. package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +21 -6
  52. package/src/widgets/radio/__stories__/choice.stories.jsx +138 -0
  53. package/src/widgets/radio/__stories__/focus-ring.stories.jsx +29 -23
  54. package/src/widgets/radio/__stories__/option-status.stories.jsx +93 -99
  55. package/src/widgets/radio/base-radio.jsx +485 -556
  56. package/src/widgets/radio/choice-a11y-text.js +62 -0
  57. package/src/widgets/radio/choice-icon/choice-icon.jsx +87 -0
  58. package/src/widgets/radio/choice-icon/cross-out-line.jsx +55 -0
  59. package/src/widgets/radio/choice-icon/library-choice-icon.jsx +214 -0
  60. package/src/widgets/radio/choice-icon/sat-choice-icon.jsx +120 -0
  61. package/src/widgets/radio/choice-icon/shared-styles.js +17 -0
  62. package/src/widgets/radio/choice-none-above.jsx +49 -40
  63. package/src/widgets/radio/choice.jsx +319 -347
  64. package/src/widgets/radio/choice.jsx.fixture.js +0 -18
  65. package/src/widgets/radio/focus-ring.jsx +29 -22
  66. package/src/widgets/radio/option-status.jsx +58 -36
  67. package/src/widgets/radio/widget.jsx +181 -136
  68. package/src/widgets/radio.jsx +16 -17
  69. package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +0 -64
  70. package/src/widgets/radio/choice-icon.jsx +0 -469
  71. package/src/widgets/radio/cross-out-button.jsx +0 -134
@@ -38,15 +38,19 @@
38
38
  line-height: @line-height - 2;
39
39
  }
40
40
  .passage-title div.paragraph {
41
- font-size: @font-size;
41
+ font-family: "Noto Serif", serif;
42
42
  font-weight: 700;
43
+ font-size: 20px;
44
+ line-height: 22px;
45
+
43
46
  margin: 0 0 10px;
44
47
  }
45
48
  .passage-text div.paragraph {
46
- font-size: @font-size;
47
- line-height: @line-height;
48
- margin: 0;
49
- text-indent: 20px;
49
+ font-family: "Noto Serif", serif;
50
+ font-weight: 400;
51
+ font-size: 20px;
52
+ line-height: 24px;
53
+
50
54
  span {
51
55
  text-indent: 0;
52
56
  }
package/src/types.js CHANGED
@@ -9,7 +9,7 @@ import * as React from "react";
9
9
  import type {SerializedHighlightSet} from "./components/highlighting/types.js";
10
10
  import type {ILogger} from "./logging/log.js";
11
11
  import type {Item} from "./multi-items/item-types.js";
12
- import type {PerseusWidget} from "./perseus-types.js";
12
+ import type {PerseusWidget, PerseusRadioChoice} from "./perseus-types.js";
13
13
  import type {SizeClass} from "./util/sizing-utils.js";
14
14
  import type {Result} from "@khanacademy/wonder-blocks-data";
15
15
 
@@ -75,6 +75,22 @@ export type Version = {|
75
75
 
76
76
  export type EditorMode = "edit" | "preview" | "json";
77
77
 
78
+ export type ChoiceState = {|
79
+ selected: boolean,
80
+ crossedOut: boolean,
81
+ highlighted: boolean,
82
+ rationaleShown: boolean,
83
+ correctnessShown: boolean,
84
+ previouslyAnswered: boolean,
85
+ readOnly: boolean,
86
+ |};
87
+
88
+ export type RadioChoiceWithMetadata = {|
89
+ ...PerseusRadioChoice,
90
+ originalIndex: number,
91
+ correct: boolean,
92
+ |};
93
+
78
94
  export type ChangeHandler = (
79
95
  {|
80
96
  hints?: $ReadOnlyArray<Hint>,
@@ -97,7 +113,7 @@ export type ChangeHandler = (
97
113
  value?: $FlowFixMe,
98
114
 
99
115
  // widgets/radio/widget.jsx
100
- choiceStates?: $ReadOnlyArray<$FlowFixMe>,
116
+ choiceStates?: $ReadOnlyArray<ChoiceState>,
101
117
 
102
118
  // widgets/numeric-input.jsx
103
119
  currentValue?: string,
@@ -230,39 +246,6 @@ export type APIOptions = $ReadOnly<{|
230
246
  // values. For now, though, you must either specify all fields
231
247
  // of `styling`, or omit the `styling` option entirely.
232
248
  styling?: {|
233
- // Which version of radio widget styles to use in non-SAT
234
- // contexts.
235
- //
236
- // "legacy" was the version of the widget display after XOM but
237
- // before we started adding MCR styles. It doesn't have support
238
- // for rationales. It has since been removed.
239
- //
240
- // "intermediate" is a design which adds several new additions
241
- // to the "legacy" styles such as:
242
- // 1. Using the XOM "desktop" styles (with a visible check icon
243
- // and lines in between choices) on mobile devices.
244
- // 2. Designs for rationales
245
- // 3. Using the single-select styles for multi-select styles
246
- //
247
- // "final" is a design which will build off of the
248
- // "intermediate" designs and adds some improved designs as well
249
- // as:
250
- // 1. a/b/c/d/etc. letters inside of the prompt check box
251
- // 2. New iconography and styles to indicate choice correctness
252
- //
253
- // The "legacy" and "intermediate" designs will be A/B tested
254
- // against each other to ensure that its changes don't cause
255
- // problems due to the new designs. Once the "intermediate"
256
- // designs are finished, they will be A/B tested against the
257
- // "final" designs.
258
- //
259
- // If no flag is provided, "legacy" styles will be shown.
260
- //
261
- // TODO(emily): Remove this by Aug 1, 2017, at which point all
262
- // callsites should have been switched to using the "final"
263
- // designs.
264
- radioStyleVersion?: "intermediate" | "final",
265
-
266
249
  // TODO(Nicole): Remove this after landing wonderblock-ifying
267
250
  // the radio widget
268
251
  primaryProductColor?: string,
@@ -106,7 +106,7 @@ export const errors = {
106
106
  *
107
107
  */
108
108
 
109
- const KhanAnswerTypes: $FlowFixMe = {
109
+ const KhanAnswerTypes = {
110
110
  /*
111
111
  * predicate answer type
112
112
  *
@@ -653,8 +653,7 @@ const KhanAnswerTypes: $FlowFixMe = {
653
653
  correctAnswer: string,
654
654
  options: $FlowFixMe,
655
655
  ): Predicate {
656
- // TODO(alpert): Don't think this $.trim is necessary
657
- const correctFloat = parseFloat($.trim(correctAnswer));
656
+ const correctFloat = parseFloat(correctAnswer);
658
657
 
659
658
  return [
660
659
  function (guess, maxError) {
package/src/util/math.js CHANGED
@@ -4,14 +4,7 @@ import {number as knumber} from "@khanacademy/kmath";
4
4
  import $ from "jquery";
5
5
  import _ from "underscore";
6
6
 
7
- export type Format =
8
- | "integer"
9
- | "mixed"
10
- | "improper"
11
- | "proper"
12
- | "decimal"
13
- | "percent"
14
- | "pi";
7
+ import type {MathFormat} from "../perseus-types";
15
8
 
16
9
  const KhanMath = {
17
10
  // Simplify formulas before display
@@ -213,7 +206,7 @@ const KhanMath = {
213
206
  // Returns the format (string) of a given numeric string
214
207
  // Note: purposively more inclusive than answer-types' predicate.forms
215
208
  // That is, it is not necessarily true that interpreted input are numeric
216
- getNumericFormat: function (text: string): ?Format {
209
+ getNumericFormat: function (text: string): ?MathFormat {
217
210
  text = $.trim(text);
218
211
  text = text.replace(/\u2212/, "-").replace(/([+-])\s+/g, "$1");
219
212
  if (text.match(/^[+-]?\d+$/)) {
@@ -238,7 +231,7 @@ const KhanMath = {
238
231
  },
239
232
 
240
233
  // Returns a string of the number in a specified format
241
- toNumericString: function (number: number, format?: Format): string {
234
+ toNumericString: function (number: number, format?: MathFormat): string {
242
235
  if (number == null) {
243
236
  return "";
244
237
  }
package/src/util.js CHANGED
@@ -92,14 +92,8 @@ function inputPathsEqual(
92
92
  );
93
93
  }
94
94
 
95
- // Keep `rWidgetRule` in sync with `WIDGET_RE`
96
- // in content_internal/perseus_traversal.py
97
- // sync-start:widget-id-regex 1271666319 services/content-editing/perseus/translation/content_traversal.go
98
- // sync-start:widget-id-regex 680240484 services/static/javascript/perseus-merged-editor-package/editor.jsx
99
- // sync-start:widget-id-regex 1400368396 content_internal/perseus_traversal.py
100
95
  const rWidgetRule: RegExp = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
101
96
  const rTypeFromWidgetId: RegExp = /^([a-z-]+) ([0-9]+)$/;
102
- // sync-end:widget-id-regex
103
97
 
104
98
  const rWidgetParts: RegExp = new RegExp(rWidgetRule.source + "$");
105
99
  const snowman = "\u2603";
package/src/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @flow
2
2
  export default {
3
3
  apiVersion: {
4
- major: 11,
4
+ major: 12,
5
5
  minor: 0,
6
6
  },
7
7
  itemDataVersion: {
@@ -1,19 +1,60 @@
1
1
  // @flow
2
+ import {action} from "@storybook/addon-actions";
2
3
  import * as React from "react";
3
4
 
4
5
  import {RendererWithDebugUI} from "../../../../../testing/renderer-with-debug-ui.jsx";
5
6
  import {question1} from "../__testdata__/numeric-input_testdata.js";
7
+ import {NumericInput} from "../numeric-input.jsx";
6
8
 
7
- type StoryArgs = {||};
9
+ type StoryArgs = {|
10
+ currentValue: string,
11
+ |};
8
12
 
9
13
  type Story = {|
10
14
  title: string,
15
+ args: StoryArgs,
11
16
  |};
12
17
 
18
+ function generateProps(overwrite) {
19
+ const base = {
20
+ alignment: "",
21
+ answers: [],
22
+ containerSizeClass: "medium",
23
+ isLastUsedWidget: true,
24
+ currentValue: "",
25
+ problemNum: 0,
26
+ reviewModeRubric: {
27
+ answers: [],
28
+ labelText: "",
29
+ size: "medium",
30
+ coefficient: false,
31
+ static: false,
32
+ },
33
+ static: false,
34
+ widgetId: "widgetId",
35
+ findWidgets: action("findWidgets"),
36
+ onBlur: action("onBlur"),
37
+ onChange: action("onChange"),
38
+ onFocus: action("onFocus"),
39
+ trackInteraction: action("trackInteraction"),
40
+ };
41
+
42
+ return {...base, ...overwrite};
43
+ }
44
+
13
45
  export default ({
14
46
  title: "Perseus/Widgets/NumericInput",
47
+ args: {
48
+ currentValue: "8675309",
49
+ },
15
50
  }: Story);
16
51
 
17
- export const Question1 = (args: StoryArgs): React.Node => {
52
+ export const Question1 = (): React.Node => {
18
53
  return <RendererWithDebugUI question={question1} />;
19
54
  };
55
+
56
+ export const Interactive = (args: StoryArgs): React.Node => {
57
+ const props = generateProps(args);
58
+
59
+ return <NumericInput {...props} />;
60
+ };
@@ -0,0 +1,22 @@
1
+ // @flow
2
+ import type {ChoiceType} from "../radio/base-radio.jsx";
3
+
4
+ export function generateChoice(options: $Partial<ChoiceType>): ChoiceType {
5
+ const base = {
6
+ checked: false,
7
+ crossedOut: false,
8
+ content: "",
9
+ rationale: "",
10
+ hasRationale: false,
11
+ showRationale: false,
12
+ showCorrectness: false,
13
+ correct: false,
14
+ isNoneOfTheAbove: false,
15
+ highlighted: false,
16
+ previouslyAnswered: false,
17
+ revealNoneOfTheAbove: false,
18
+ disabled: false,
19
+ };
20
+
21
+ return {...base, ...options};
22
+ }
@@ -37,13 +37,13 @@ exports[`Definition widget should have a default snapshot: first render 1`] = `
37
37
  >
38
38
  <button
39
39
  aria-disabled="false"
40
- class="button_vr44p2-o_O-shared_lwskrm-o_O-default_1hl5pu8-o_O-small_xwkmkn"
40
+ class="button_vr44p2-o_O-shared_lwskrm-o_O-default_1hl5pu8"
41
41
  role="button"
42
42
  tabindex="0"
43
43
  type="button"
44
44
  >
45
45
  <span
46
- class="text_f1191h-o_O-LabelSmall_hl4zs1-o_O-text_m8a8ki-o_O-textWithFocus_e296pg"
46
+ class="text_f1191h-o_O-LabelLarge_5s82ln-o_O-text_m8a8ki-o_O-textWithFocus_e296pg"
47
47
  >
48
48
  the Pequots
49
49
  </span>
@@ -95,13 +95,13 @@ exports[`Definition widget should have an open state snapshot: open state 1`] =
95
95
  >
96
96
  <button
97
97
  aria-disabled="false"
98
- class="button_vr44p2-o_O-shared_lwskrm-o_O-default_1hl5pu8-o_O-small_xwkmkn"
98
+ class="button_vr44p2-o_O-shared_lwskrm-o_O-default_1hl5pu8"
99
99
  role="button"
100
100
  tabindex="0"
101
101
  type="button"
102
102
  >
103
103
  <span
104
- class="text_f1191h-o_O-LabelSmall_hl4zs1-o_O-text_m8a8ki-o_O-textWithFocus_e296pg-o_O-focus_15mc0l2"
104
+ class="text_f1191h-o_O-LabelLarge_5s82ln-o_O-text_m8a8ki-o_O-textWithFocus_e296pg-o_O-focus_15mc0l2"
105
105
  >
106
106
  the Pequots
107
107
  </span>