@khanacademy/perseus 8.0.0 → 10.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/article-renderer.d.ts +2 -1
  3. package/dist/components/info-tip.d.ts +2 -1
  4. package/dist/components/input-with-examples.d.ts +1 -1
  5. package/dist/components/sortable.d.ts +1 -1
  6. package/dist/dependencies.d.ts +7 -1
  7. package/dist/es/index.css +3 -5
  8. package/dist/es/index.js +72 -45
  9. package/dist/es/index.js.map +1 -1
  10. package/dist/hint-renderer.d.ts +2 -1
  11. package/dist/hints-renderer.d.ts +2 -1
  12. package/dist/index.css +3 -5
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +72 -46
  15. package/dist/index.js.map +1 -1
  16. package/dist/interaction-tracker.d.ts +3 -3
  17. package/dist/item-renderer.d.ts +3 -1
  18. package/dist/multi-items/multi-renderer.d.ts +4 -2
  19. package/dist/perseus-api.d.ts +1 -1
  20. package/dist/renderer.d.ts +4 -9
  21. package/dist/server-item-renderer.d.ts +3 -1
  22. package/dist/types.d.ts +30 -15
  23. package/dist/widget-container.d.ts +2 -1
  24. package/dist/widgets/expression.d.ts +409 -12
  25. package/dist/widgets/graded-group.d.ts +2 -2
  26. package/dist/widgets/grapher.d.ts +2 -1
  27. package/dist/widgets/passage-ref.d.ts +2 -1
  28. package/dist/widgets/sequence.d.ts +2 -2
  29. package/package.json +3 -3
  30. package/src/__stories__/article-renderer.stories.tsx +35 -2
  31. package/src/__testdata__/article-renderer.testdata.ts +71 -0
  32. package/src/__tests__/item-renderer.test.tsx +12 -1
  33. package/src/__tests__/renderer.test.tsx +0 -2
  34. package/src/__tests__/server-item-renderer.test.tsx +11 -5
  35. package/src/article-renderer.tsx +38 -30
  36. package/src/components/info-tip.tsx +3 -4
  37. package/src/components/input-with-examples.tsx +1 -1
  38. package/src/components/sortable.tsx +1 -1
  39. package/src/dependencies.ts +16 -1
  40. package/src/hint-renderer.tsx +2 -1
  41. package/src/hints-renderer.tsx +2 -9
  42. package/src/index.ts +0 -1
  43. package/src/interaction-tracker.ts +3 -3
  44. package/src/item-renderer.tsx +57 -44
  45. package/src/multi-items/__tests__/multi-renderer.test.tsx +6 -1
  46. package/src/multi-items/multi-renderer.tsx +18 -11
  47. package/src/renderer.tsx +4 -4
  48. package/src/server-item-renderer.tsx +21 -17
  49. package/src/types.ts +50 -21
  50. package/src/widget-container.tsx +2 -1
  51. package/src/widgets/__stories__/definition.stories.tsx +8 -1
  52. package/src/widgets/__stories__/expression.stories.tsx +2 -2
  53. package/src/widgets/__tests__/{expression.test.ts → expression.test.tsx} +73 -8
  54. package/src/widgets/__tests__/renderQuestion.tsx +29 -29
  55. package/src/widgets/expression.tsx +77 -48
  56. package/src/widgets/graded-group.tsx +11 -2
  57. package/src/widgets/grapher.tsx +4 -12
  58. package/src/widgets/passage-ref.tsx +1 -1
  59. package/src/widgets/sequence.tsx +10 -2
  60. package/tsconfig-build.tsbuildinfo +1 -1
@@ -2,10 +2,10 @@ import type { APIOptions, Tracking } from "./types";
2
2
  /**
3
3
  * Wrapper for the trackInteraction apiOption.
4
4
  */
5
- declare class InteractionTracker {
5
+ declare class InteractionTracker<T> {
6
6
  _tracked: boolean;
7
7
  setting: Tracking;
8
- track: (extraData?: any) => void;
8
+ track: (extraData?: T) => void;
9
9
  trackApi: any;
10
10
  widgetID: string;
11
11
  widgetType: string;
@@ -18,6 +18,6 @@ declare class InteractionTracker {
18
18
  * @param extraData Any extra data to track about the event.
19
19
  * @private
20
20
  */
21
- _track: (extraData: Record<string, any>) => void;
21
+ _track: (extraData: T) => void;
22
22
  }
23
23
  export default InteractionTracker;
@@ -3,8 +3,9 @@ import HintsRenderer from "./hints-renderer";
3
3
  import Renderer from "./renderer";
4
4
  import type { KeypadProps } from "./mixins/provide-keypad";
5
5
  import type { PerseusItem } from "./perseus-types";
6
- import type { APIOptions, FocusPath, LinterContextProps } from "./types";
6
+ import type { APIOptions, FocusPath, PerseusDependenciesV2 } from "./types";
7
7
  import type { KEScore } from "@khanacademy/perseus-core";
8
+ import type { LinterContextProps } from "@khanacademy/perseus-linter";
8
9
  type Props = // These props are used by the ProvideKeypad mixin.
9
10
  KeypadProps & {
10
11
  apiOptions: APIOptions;
@@ -23,6 +24,7 @@ KeypadProps & {
23
24
  savedState: any;
24
25
  linterContext: LinterContextProps;
25
26
  legacyPerseusLint?: ReadonlyArray<string>;
27
+ dependencies: PerseusDependenciesV2;
26
28
  };
27
29
  type DefaultProps = {
28
30
  apiOptions: Props["apiOptions"];
@@ -1,15 +1,16 @@
1
1
  import * as React from "react";
2
2
  import Renderer from "../renderer";
3
3
  import type { Widget } from "../renderer";
4
- import type { APIOptions, FilterCriterion } from "../types";
4
+ import type { APIOptions, FilterCriterion, PerseusDependenciesV2 } from "../types";
5
5
  import type { Item, ContentNode, HintNode, TagsNode } from "./item-types";
6
6
  import type { Shape, ArrayShape } from "./shape-types";
7
7
  import type { Tree } from "./tree-types";
8
8
  import type { TreeMapper, ContentMapper, HintMapper, Path } from "./trees";
9
+ import type { PropsFor } from "@khanacademy/wonder-blocks-core";
9
10
  type Hint = any;
10
11
  type Score = any;
11
12
  type SerializedState = any;
12
- type RendererProps = JSX.LibraryManagedAttributes<typeof Renderer, React.ComponentProps<typeof Renderer>>;
13
+ type RendererProps = PropsFor<typeof Renderer>;
13
14
  type ContentRendererElement = React.ReactElement<any>;
14
15
  type HintRendererElement = React.ReactElement<any>;
15
16
  type ContentRendererData = {
@@ -47,6 +48,7 @@ type Props = {
47
48
  onInteractWithWidget?: (id: string) => void;
48
49
  apiOptions?: APIOptions;
49
50
  reviewMode?: boolean | null | undefined;
51
+ dependencies: PerseusDependenciesV2;
50
52
  };
51
53
  type State = {
52
54
  rendererDataTree: RendererDataTree | null | undefined;
@@ -83,7 +83,7 @@ export declare const ApiOptions: {
83
83
  type: string;
84
84
  id: string;
85
85
  correct?: boolean | undefined;
86
- } & Record<string, unknown>) => void) | undefined;
86
+ } & Partial<import("./types").TrackingGradedGroupExtraArguments> & Partial<import("./types").TrackingSequenceExtraArguments>) => void) | undefined;
87
87
  customKeypad?: boolean | undefined;
88
88
  useV2Keypad?: boolean | undefined;
89
89
  nativeKeypadProxy?: ((blur: () => void) => import("@khanacademy/math-input").KeypadAPI) | undefined;
@@ -2,7 +2,8 @@ import * as React from "react";
2
2
  import InteractionTracker from "./interaction-tracker";
3
3
  import TranslationLinter from "./translation-linter";
4
4
  import type { PerseusRenderer, PerseusWidgetOptions } from "./perseus-types";
5
- import type { APIOptions, APIOptionsWithDefaults, FilterCriterion, FocusPath, LinterContextProps, PerseusScore, WidgetInfo, WidgetProps } from "./types";
5
+ import type { APIOptions, APIOptionsWithDefaults, FilterCriterion, FocusPath, PerseusScore, WidgetInfo, WidgetProps } from "./types";
6
+ import type { LinterContextProps } from "@khanacademy/perseus-linter";
6
7
  import "./styles/perseus-renderer.less";
7
8
  type WidgetState = {
8
9
  isMobile?: boolean;
@@ -68,12 +69,6 @@ type State = {
68
69
  jiptContent: any;
69
70
  lastUsedWidgetId: string | null | undefined;
70
71
  };
71
- type Context = LinterContextProps & {
72
- content: string;
73
- widgets: {
74
- [id: string]: any;
75
- };
76
- };
77
72
  type DefaultProps = {
78
73
  alwaysUpdate: Props["alwaysUpdate"];
79
74
  content: Props["content"];
@@ -93,7 +88,7 @@ declare class Renderer extends React.Component<Props, State> {
93
88
  _currentFocus: FocusPath | null | undefined;
94
89
  _foundTextNodes: boolean;
95
90
  _interactionTrackers: {
96
- [id: string]: InteractionTracker;
91
+ [id: string]: InteractionTracker<any>;
97
92
  };
98
93
  _isMounted: boolean;
99
94
  _isTwoColumn: boolean;
@@ -103,7 +98,7 @@ declare class Renderer extends React.Component<Props, State> {
103
98
  translationIndex: number;
104
99
  widgetIds: Array<string>;
105
100
  static defaultProps: DefaultProps;
106
- constructor(props: Props, context: Context);
101
+ constructor(props: Props);
107
102
  componentDidMount(): void;
108
103
  UNSAFE_componentWillReceiveProps(nextProps: Props): void;
109
104
  shouldComponentUpdate(nextProps: Props, nextState: State): any | boolean;
@@ -9,7 +9,7 @@
9
9
  import * as React from "react";
10
10
  import Renderer from "./renderer";
11
11
  import type { KeypadProps } from "./mixins/provide-keypad";
12
- import type { APIOptions, FocusPath } from "./types";
12
+ import type { APIOptions, FocusPath, PerseusDependenciesV2 } from "./types";
13
13
  import type { RendererInterface, KEScore } from "@khanacademy/perseus-core";
14
14
  type OwnProps = // These props are used by the ProvideKeypad mixin.
15
15
  KeypadProps & {
@@ -22,6 +22,7 @@ KeypadProps & {
22
22
  problemNum?: number;
23
23
  reviewMode?: boolean;
24
24
  keypadElement?: any | null | undefined;
25
+ dependencies: PerseusDependenciesV2;
25
26
  };
26
27
  type HOCProps = {
27
28
  onRendered: (isRendered: boolean) => void;
@@ -110,5 +111,6 @@ declare const ref: React.ForwardRefExoticComponent<Omit<KeypadProps & {
110
111
  problemNum?: number | undefined;
111
112
  reviewMode?: boolean | undefined;
112
113
  keypadElement?: any | null | undefined;
114
+ dependencies: PerseusDependenciesV2;
113
115
  } & HOCProps, "onRendered"> & React.RefAttributes<ServerItemRenderer>>;
114
116
  export default ref;
package/dist/types.d.ts CHANGED
@@ -4,10 +4,12 @@ import type { Item } from "./multi-items/item-types";
4
4
  import type { PerseusWidget } from "./perseus-types";
5
5
  import type { SizeClass } from "./util/sizing-utils";
6
6
  import type { KeypadAPI } from "@khanacademy/math-input";
7
- import type { SendEventFn } from "@khanacademy/perseus-core";
7
+ import type { AnalyticsEventHandlerFn } from "@khanacademy/perseus-core";
8
+ import type { LinterContextProps } from "@khanacademy/perseus-linter";
8
9
  import type { Result } from "@khanacademy/wonder-blocks-data";
9
10
  import type * as React from "react";
10
11
  export type FocusPath = ReadonlyArray<string> | null | undefined;
12
+ type Empty = Record<never, never>;
11
13
  export type Dimensions = {
12
14
  width?: number;
13
15
  height?: number;
@@ -75,6 +77,11 @@ export type ImageUploader = (file: string, callback: (url: string) => unknown) =
75
77
  export type WidgetSize = "normal" | "small" | "mini";
76
78
  export type Path = ReadonlyArray<string>;
77
79
  type StubTagEditorType = any;
80
+ type TrackInteractionArgs = {
81
+ type: string;
82
+ id: string;
83
+ correct?: boolean;
84
+ } & Partial<TrackingGradedGroupExtraArguments> & Partial<TrackingSequenceExtraArguments>;
78
85
  export type APIOptions = Readonly<{
79
86
  isArticle?: boolean;
80
87
  onInputError?: (widgetId: any, value: string, message?: string | null | undefined) => unknown;
@@ -92,11 +99,7 @@ export type APIOptions = Readonly<{
92
99
  Link: React.ComponentType<any>;
93
100
  };
94
101
  imagePreloader?: (dimensions: Dimensions) => React.ReactNode;
95
- trackInteraction?: (args: {
96
- type: string;
97
- id: string;
98
- correct?: boolean;
99
- } & Record<string, unknown>) => void;
102
+ trackInteraction?: (args: TrackInteractionArgs) => void;
100
103
  customKeypad?: boolean;
101
104
  useV2Keypad?: boolean;
102
105
  nativeKeypadProxy?: (blur: () => void) => KeypadAPI;
@@ -161,7 +164,6 @@ export type PerseusDependencies = {
161
164
  TeX: React.ComponentType<TeXProps>;
162
165
  staticUrl: StaticUrlFn;
163
166
  InitialRequestUrl: InitialRequestUrlInterface;
164
- analytics: SendEventFn;
165
167
  useVideo(id: string, kind: VideoKind): Result<{
166
168
  video: VideoData | null | undefined;
167
169
  }>;
@@ -170,6 +172,19 @@ export type PerseusDependencies = {
170
172
  kaLocale: string;
171
173
  isMobile: boolean;
172
174
  };
175
+ /**
176
+ * The modern iteration of Perseus Depedndencies. These dependencies are
177
+ * provided to Perseus through its entrypoints (for example:
178
+ * ServerItemRenderer) and then attached to the DependenciesContext so they are
179
+ * available anywhere down the React render tree.
180
+ *
181
+ * Prefer using this type over `PerseusDependencies` when possible.
182
+ */
183
+ export type PerseusDependenciesV2 = {
184
+ analytics: {
185
+ onAnalyticsEvent: AnalyticsEventHandlerFn;
186
+ };
187
+ };
173
188
  export type APIOptionsWithDefaults = Readonly<APIOptions & {
174
189
  GroupMetadataEditor: NonNullable<APIOptions["GroupMetadataEditor"]>;
175
190
  baseElements: NonNullable<APIOptions["baseElements"]>;
@@ -188,13 +203,13 @@ export type APIOptionsWithDefaults = Readonly<APIOptions & {
188
203
  showAlignmentOptions: NonNullable<APIOptions["showAlignmentOptions"]>;
189
204
  useDraftEditor: NonNullable<APIOptions["useDraftEditor"]>;
190
205
  }>;
191
- export type LinterContextProps = {
192
- contentType: string;
193
- highlightLint: boolean;
194
- paths: ReadonlyArray<string>;
195
- stack: ReadonlyArray<string>;
196
- };
197
206
  export type Tracking = "" | "all";
207
+ export type TrackingGradedGroupExtraArguments = {
208
+ status: "correct" | "incorrect" | "invalid";
209
+ };
210
+ export type TrackingSequenceExtraArguments = {
211
+ visible: number;
212
+ };
198
213
  export type Alignment = "default" | "block" | "inline-block" | "inline" | "float-left" | "float-right" | "full-width";
199
214
  type WidgetOptions = any;
200
215
  export type WidgetTransform = (arg1: WidgetOptions, problemNumber?: number) => any;
@@ -220,7 +235,7 @@ export type WidgetExports<T extends React.ComponentType<any> = React.ComponentTy
220
235
  }>;
221
236
  export type WidgetInfo = PerseusWidget;
222
237
  export type FilterCriterion = string | ((id: string, widgetInfo: WidgetInfo, widget?: Widget | null | undefined) => boolean);
223
- export type WidgetProps<RenderProps, Rubric> = RenderProps & {
238
+ export type WidgetProps<RenderProps, Rubric, TrackingExtraArgs = Empty> = RenderProps & {
224
239
  widgetId: string;
225
240
  alignment: string | null | undefined;
226
241
  static: boolean | null | undefined;
@@ -233,7 +248,7 @@ export type WidgetProps<RenderProps, Rubric> = RenderProps & {
233
248
  findWidgets: (arg1: FilterCriterion) => ReadonlyArray<Widget>;
234
249
  reviewModeRubric: Rubric;
235
250
  onChange: ChangeHandler;
236
- trackInteraction: (extraData?: any) => void;
251
+ trackInteraction: (extraData?: TrackingExtraArgs) => void;
237
252
  isLastUsedWidget: boolean;
238
253
  linterContext: LinterContextProps;
239
254
  containerSizeClass: SizeClass;
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
2
  import type { PerseusWidgetOptions } from "./perseus-types";
3
- import type { LinterContextProps, WidgetProps } from "./types";
3
+ import type { WidgetProps } from "./types";
4
+ import type { LinterContextProps } from "@khanacademy/perseus-linter";
4
5
  type Props = {
5
6
  shouldHighlight: boolean;
6
7
  type: string;