@khanacademy/perseus 80.0.1 → 81.0.1

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.
@@ -60,7 +60,7 @@ type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
60
60
  type State = {
61
61
  translationLintErrors: ReadonlyArray<string>;
62
62
  widgetInfo: Readonly<PerseusWidgetsMap>;
63
- jiptContent: any;
63
+ jiptContent: string | null;
64
64
  };
65
65
  type DefaultProps = Required<Pick<Props, "alwaysUpdate" | "content" | "findExternalWidgets" | "images" | "linterContext" | "onRender" | "showSolutions" | "reviewMode" | "widgets">>;
66
66
  declare class Renderer extends React.Component<Props, State> implements GetPromptJSONInterface {
@@ -148,7 +148,7 @@ declare class Renderer extends React.Component<Props, State> implements GetPromp
148
148
  _onWidgetBlur: (id: string, blurPath: FocusPath) => void;
149
149
  getContent: (props: Props, state: State) => any;
150
150
  shouldRenderJiptPlaceholder: (props: Props, state: State) => boolean;
151
- replaceJiptContent: (content: string, paragraphIndex: number) => void;
151
+ replaceJiptContent(content: string, paragraphIndex?: number): void;
152
152
  outputMarkdown: (ast: any, state: WidgetState) => React.ReactElement;
153
153
  outputNested: (ast: any, state: WidgetState) => React.ReactElement;
154
154
  outputNode: (node: any, nestedOutput: any, state: WidgetState) => any | null | React.ReactElement<React.ComponentProps<"div">> | React.ReactElement<React.ComponentProps<"span">> | React.ReactNode;
@@ -60,7 +60,7 @@ export type Props = Partial<React.ContextType<typeof DependenciesContext>> & {
60
60
  type State = {
61
61
  translationLintErrors: ReadonlyArray<string>;
62
62
  widgetInfo: Readonly<PerseusWidgetsMap>;
63
- jiptContent: any;
63
+ jiptContent: string | null;
64
64
  };
65
65
  type DefaultProps = Required<Pick<Props, "alwaysUpdate" | "content" | "findExternalWidgets" | "images" | "linterContext" | "onRender" | "showSolutions" | "reviewMode" | "widgets">>;
66
66
  /**
@@ -159,7 +159,7 @@ declare class Renderer extends React.Component<Props, State> implements GetPromp
159
159
  _onWidgetBlur: (id: string, blurPath: FocusPath) => void;
160
160
  getContent: (props: Props, state: State) => any;
161
161
  shouldRenderJiptPlaceholder: (props: Props, state: State) => boolean;
162
- replaceJiptContent: (content: string, paragraphIndex: number) => void;
162
+ replaceJiptContent(content: string, paragraphIndex?: number): void;
163
163
  outputMarkdown: (ast: any, state: WidgetState) => React.ReactElement;
164
164
  outputNested: (ast: any, state: WidgetState) => React.ReactElement;
165
165
  outputNode: (node: any, nestedOutput: any, state: WidgetState) => any | null | React.ReactElement<React.ComponentProps<"div">> | React.ReactElement<React.ComponentProps<"span">> | React.ReactNode;
package/dist/types.d.ts CHANGED
@@ -192,7 +192,7 @@ export type JiptLabelStore = {
192
192
  addLabel: (label?: GraphieLabelElement, useMath?: boolean) => void;
193
193
  };
194
194
  export interface JiptRenderer {
195
- replaceJiptContent: (content: string, paragraphIndex: number) => void;
195
+ replaceJiptContent(content: string, paragraphIndex?: number): void;
196
196
  }
197
197
  type JiptTranslationComponents = {
198
198
  addComponent: (renderer: JiptRenderer) => number;
@@ -1,4 +1,4 @@
1
- import type image from "../../widgets/image/image.class";
1
+ import type image from "../../widgets/image/image";
2
2
  import type React from "react";
3
3
  /**
4
4
  * JSON describing an image widget. Intended for consumption by AI tools.
@@ -1,3 +1,67 @@
1
- import * as React from "react";
2
- import type { ImageWidgetProps } from "./image.class";
3
- export declare const ImageComponent: (props: ImageWidgetProps) => React.JSX.Element | null;
1
+ import React from "react";
2
+ import type { Widget } from "../../types";
3
+ import type { PerseusImageWidgetOptions } from "@khanacademy/perseus-core";
4
+ type WidgetHandle = Pick<Widget, "getPromptJSON">;
5
+ declare const _default: {
6
+ name: string;
7
+ displayName: string;
8
+ widget: React.ForwardRefExoticComponent<PerseusImageWidgetOptions & {
9
+ trackInteraction: (extraData?: Empty | undefined) => void;
10
+ widgetId: string;
11
+ widgetIndex: number;
12
+ alignment: string | null | undefined;
13
+ static: boolean | null | undefined;
14
+ graded?: boolean | null;
15
+ problemNum: number | null | undefined;
16
+ apiOptions: Readonly<Readonly<{
17
+ isArticle?: boolean;
18
+ onFocusChange?: (newFocusPath: import("../..").FocusPath, oldFocusPath: import("../..").FocusPath, keypadHeight?: number, focusedElement?: HTMLElement) => unknown;
19
+ showAlignmentOptions?: boolean;
20
+ readOnly?: boolean;
21
+ editingDisabled?: boolean;
22
+ answerableCallback?: (arg1: boolean) => unknown;
23
+ getAnotherHint?: () => unknown;
24
+ interactionCallback?: (widgetData: {
25
+ [widgetId: string]: any;
26
+ }) => void;
27
+ imagePlaceholder?: React.ReactNode;
28
+ widgetPlaceholder?: React.ReactNode;
29
+ baseElements?: {
30
+ Link: React.ComponentType<any>;
31
+ };
32
+ trackInteraction?: (args: {
33
+ type: string;
34
+ id: string;
35
+ correct?: boolean;
36
+ } & Partial<import("../../types").TrackingGradedGroupExtraArguments> & Partial<{
37
+ visible: number;
38
+ }>) => void;
39
+ customKeypad?: boolean;
40
+ isMobile?: boolean;
41
+ isMobileApp?: boolean;
42
+ hintProgressColor?: string;
43
+ flags?: Record<"perseus-renderer-upgrade" | "desmos-calculator" | "perseus-enable-point-label-field", boolean>;
44
+ }> & {
45
+ baseElements: NonNullable<import("../..").APIOptions["baseElements"]>;
46
+ isArticle: NonNullable<import("../..").APIOptions["isArticle"]>;
47
+ isMobile: NonNullable<import("../..").APIOptions["isMobile"]>;
48
+ isMobileApp: NonNullable<import("../..").APIOptions["isMobileApp"]>;
49
+ editingDisabled: NonNullable<import("../..").APIOptions["editingDisabled"]>;
50
+ onFocusChange: NonNullable<import("../..").APIOptions["onFocusChange"]>;
51
+ readOnly: NonNullable<import("../..").APIOptions["readOnly"]>;
52
+ showAlignmentOptions: NonNullable<import("../..").APIOptions["showAlignmentOptions"]>;
53
+ }>;
54
+ keypadElement?: any;
55
+ onFocus: (blurPath: import("../..").FocusPath) => void;
56
+ onBlur: (blurPath: import("../..").FocusPath) => void;
57
+ findWidgets: import("../../types").FindWidgetsFunction;
58
+ reviewMode: boolean;
59
+ showSolutions?: import("@khanacademy/perseus-core").ShowSolutions;
60
+ handleUserInput: (newUserInput: Empty, cb?: () => void, silent?: boolean) => void;
61
+ userInput: Empty;
62
+ linterContext: import("@khanacademy/perseus-linter").LinterContextProps;
63
+ containerSizeClass: import("../../util/sizing-utils").SizeClass;
64
+ } & React.RefAttributes<WidgetHandle>>;
65
+ isLintable: true;
66
+ };
67
+ export default _default;
@@ -1 +1 @@
1
- export { default } from "./image.class";
1
+ export { default } from "./image";
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ /**
3
+ * DOM node of the HTML overlay above the graph's SVG. Movable points portal an
4
+ * HTML hitbox `<div>` (`touch-action: none`) into it as their drag target.
5
+ *
6
+ * Why HTML, not an SVG hitbox: Safari ignores `touch-action` on SVG, so under
7
+ * the container's `touch-action: pan-y` a vertical point-drag scrolls the page.
8
+ * `touch-action` on real HTML is honored everywhere, so no scroll and no JS
9
+ * fallback. The layer is `pointer-events: none` (empty area falls through to
10
+ * scroll / add-point); each hitbox opts back in. Null until the layer mounts.
11
+ *
12
+ * UPSTREAM (Mafs): this technique + relaxing `.MafsView { touch-action: none }`
13
+ * in `mafs/core.css` is the fix to contribute to Mafs' `MovablePoint`. Perseus
14
+ * forked these components, so keep them in sync if that PR lands.
15
+ */
16
+ export declare const HitboxLayerContext: React.Context<HTMLElement | null>;
@@ -0,0 +1,53 @@
1
+ import * as React from "react";
2
+ import type { vec } from "mafs";
3
+ /**
4
+ * Touch/click target size for small handles (movable points, arrowheads, the
5
+ * asymptote pill). Preserved from the legacy interactive graph (48×48px) and a
6
+ * comfortable target per WCAG 2.5.8.
7
+ */
8
+ export declare const HANDLE_HITBOX_SIZE_PX = 48;
9
+ /**
10
+ * Drag hitbox for an interactive-graph element, rendered as a real HTML element
11
+ * in the graph's overlay layer rather than as SVG. Safari doesn't reliably
12
+ * honor `touch-action` on SVG, so under the container's `touch-action: pan-y`
13
+ * an SVG hitbox lets a drag scroll the page; a real HTML element's
14
+ * `touch-action: none` is honored everywhere. See {@link HitboxLayerContext}.
15
+ *
16
+ * All coordinates are **graph-space**; this hook converts them to the overlay's
17
+ * pixel space with the same `pointToPixel` transform movable points use, so
18
+ * hitboxes line up exactly with the SVG shapes they cover.
19
+ */
20
+ type HitboxShape = {
21
+ kind: "box";
22
+ center: vec.Vector2;
23
+ sizePx: number;
24
+ } | {
25
+ kind: "line";
26
+ start: vec.Vector2;
27
+ end: vec.Vector2;
28
+ thicknessPx: number;
29
+ } | {
30
+ kind: "ellipse";
31
+ center: vec.Vector2;
32
+ radius: vec.Vector2;
33
+ } | {
34
+ kind: "polygon";
35
+ vertices: ReadonlyArray<vec.Vector2>;
36
+ };
37
+ type HitboxParams = {
38
+ shape: HitboxShape;
39
+ /** Assigned to the hitbox element; use as the `useDraggable` gestureTarget. */
40
+ hitboxRef: React.RefObject<HTMLDivElement>;
41
+ /**
42
+ * Stacking within the overlay. Point/vertex handles ("handle") sit above
43
+ * shape bodies ("body") so a vertex on a segment/polygon stays grabbable.
44
+ */
45
+ layer?: "handle" | "body";
46
+ cursor?: string;
47
+ dragging?: boolean;
48
+ onClick?: () => void;
49
+ onHoverChange?: (hovered: boolean) => void;
50
+ testId?: string;
51
+ };
52
+ export declare function useHitbox(params: HitboxParams): React.ReactNode;
53
+ export {};
@@ -6,6 +6,7 @@ type Props = {
6
6
  angle: number;
7
7
  dragging: boolean;
8
8
  focused: boolean;
9
+ hovered?: boolean;
9
10
  showFocusRing: boolean;
10
11
  cursor?: CSSCursor | undefined;
11
12
  onClick?: () => unknown;
@@ -5,6 +5,7 @@ type Props = {
5
5
  point: vec.Vector2;
6
6
  dragging: boolean;
7
7
  focused: boolean;
8
+ hovered?: boolean;
8
9
  showFocusRing: boolean;
9
10
  cursor?: CSSCursor | undefined;
10
11
  onClick?: () => unknown;
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": "80.0.1",
6
+ "version": "81.0.1",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -43,39 +43,39 @@
43
43
  "tiny-invariant": "1.3.1",
44
44
  "uuid": "^10.0.0",
45
45
  "@khanacademy/kas": "2.2.3",
46
- "@khanacademy/keypad-context": "3.2.73",
47
- "@khanacademy/math-input": "26.6.1",
48
- "@khanacademy/perseus-linter": "5.1.13",
49
- "@khanacademy/perseus-score": "8.12.5",
46
+ "@khanacademy/keypad-context": "3.2.75",
47
+ "@khanacademy/kmath": "2.4.34",
48
+ "@khanacademy/math-input": "26.6.3",
49
+ "@khanacademy/perseus-core": "32.0.1",
50
+ "@khanacademy/perseus-linter": "5.1.15",
51
+ "@khanacademy/perseus-score": "8.12.7",
50
52
  "@khanacademy/perseus-utils": "2.1.5",
51
- "@khanacademy/perseus-core": "31.0.0",
52
- "@khanacademy/pure-markdown": "2.3.0",
53
- "@khanacademy/simple-markdown": "2.2.3",
54
- "@khanacademy/kmath": "2.4.32"
53
+ "@khanacademy/pure-markdown": "2.3.1",
54
+ "@khanacademy/simple-markdown": "3.0.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@khanacademy/wonder-blocks-announcer": "1.1.1",
58
- "@khanacademy/wonder-blocks-banner": "5.1.9",
59
- "@khanacademy/wonder-blocks-button": "11.7.5",
60
- "@khanacademy/wonder-blocks-clickable": "8.2.7",
58
+ "@khanacademy/wonder-blocks-banner": "5.1.10",
59
+ "@khanacademy/wonder-blocks-button": "11.7.6",
60
+ "@khanacademy/wonder-blocks-clickable": "8.2.8",
61
61
  "@khanacademy/wonder-blocks-core": "12.4.4",
62
62
  "@khanacademy/wonder-blocks-data": "15.0.2",
63
- "@khanacademy/wonder-blocks-dropdown": "10.11.6",
64
- "@khanacademy/wonder-blocks-form": "7.6.8",
65
- "@khanacademy/wonder-blocks-icon": "5.3.21",
66
- "@khanacademy/wonder-blocks-icon-button": "11.4.3",
67
- "@khanacademy/wonder-blocks-labeled-field": "4.1.7",
68
- "@khanacademy/wonder-blocks-layout": "3.1.58",
69
- "@khanacademy/wonder-blocks-link": "10.3.7",
70
- "@khanacademy/wonder-blocks-modal": "8.7.9",
71
- "@khanacademy/wonder-blocks-pill": "3.1.71",
72
- "@khanacademy/wonder-blocks-popover": "6.3.9",
73
- "@khanacademy/wonder-blocks-progress-spinner": "3.1.58",
74
- "@khanacademy/wonder-blocks-switch": "3.4.7",
63
+ "@khanacademy/wonder-blocks-dropdown": "10.11.7",
64
+ "@khanacademy/wonder-blocks-form": "7.6.9",
65
+ "@khanacademy/wonder-blocks-icon": "5.3.22",
66
+ "@khanacademy/wonder-blocks-icon-button": "11.4.4",
67
+ "@khanacademy/wonder-blocks-labeled-field": "4.1.8",
68
+ "@khanacademy/wonder-blocks-layout": "3.1.59",
69
+ "@khanacademy/wonder-blocks-link": "10.3.8",
70
+ "@khanacademy/wonder-blocks-modal": "8.7.10",
71
+ "@khanacademy/wonder-blocks-pill": "3.1.72",
72
+ "@khanacademy/wonder-blocks-popover": "6.3.11",
73
+ "@khanacademy/wonder-blocks-progress-spinner": "3.1.59",
74
+ "@khanacademy/wonder-blocks-switch": "3.4.8",
75
75
  "@khanacademy/wonder-blocks-timing": "7.1.0",
76
- "@khanacademy/wonder-blocks-tokens": "17.1.0",
77
- "@khanacademy/wonder-blocks-tooltip": "4.1.84",
78
- "@khanacademy/wonder-blocks-typography": "5.0.1",
76
+ "@khanacademy/wonder-blocks-tokens": "17.2.0",
77
+ "@khanacademy/wonder-blocks-tooltip": "4.2.0",
78
+ "@khanacademy/wonder-blocks-typography": "5.0.2",
79
79
  "@khanacademy/wonder-stuff-core": "3.0.0",
80
80
  "@phosphor-icons/core": "2.0.2",
81
81
  "@popperjs/core": "2.10.2",
@@ -92,27 +92,27 @@
92
92
  },
93
93
  "peerDependencies": {
94
94
  "@khanacademy/wonder-blocks-announcer": "^1.1.1",
95
- "@khanacademy/wonder-blocks-banner": "^5.1.9",
96
- "@khanacademy/wonder-blocks-button": "^11.7.5",
97
- "@khanacademy/wonder-blocks-clickable": "^8.2.7",
95
+ "@khanacademy/wonder-blocks-banner": "^5.1.10",
96
+ "@khanacademy/wonder-blocks-button": "^11.7.6",
97
+ "@khanacademy/wonder-blocks-clickable": "^8.2.8",
98
98
  "@khanacademy/wonder-blocks-core": "^12.4.4",
99
99
  "@khanacademy/wonder-blocks-data": "^15.0.2",
100
- "@khanacademy/wonder-blocks-dropdown": "^10.11.6",
101
- "@khanacademy/wonder-blocks-form": "^7.6.8",
102
- "@khanacademy/wonder-blocks-icon": "^5.3.21",
103
- "@khanacademy/wonder-blocks-icon-button": "^11.4.3",
104
- "@khanacademy/wonder-blocks-labeled-field": "^4.1.7",
105
- "@khanacademy/wonder-blocks-layout": "^3.1.58",
106
- "@khanacademy/wonder-blocks-link": "^10.3.7",
107
- "@khanacademy/wonder-blocks-modal": "^8.7.9",
108
- "@khanacademy/wonder-blocks-pill": "^3.1.71",
109
- "@khanacademy/wonder-blocks-popover": "^6.3.9",
110
- "@khanacademy/wonder-blocks-progress-spinner": "^3.1.58",
111
- "@khanacademy/wonder-blocks-switch": "^3.4.7",
100
+ "@khanacademy/wonder-blocks-dropdown": "^10.11.7",
101
+ "@khanacademy/wonder-blocks-form": "^7.6.9",
102
+ "@khanacademy/wonder-blocks-icon": "^5.3.22",
103
+ "@khanacademy/wonder-blocks-icon-button": "^11.4.4",
104
+ "@khanacademy/wonder-blocks-labeled-field": "^4.1.8",
105
+ "@khanacademy/wonder-blocks-layout": "^3.1.59",
106
+ "@khanacademy/wonder-blocks-link": "^10.3.8",
107
+ "@khanacademy/wonder-blocks-modal": "^8.7.10",
108
+ "@khanacademy/wonder-blocks-pill": "^3.1.72",
109
+ "@khanacademy/wonder-blocks-popover": "^6.3.11",
110
+ "@khanacademy/wonder-blocks-progress-spinner": "^3.1.59",
111
+ "@khanacademy/wonder-blocks-switch": "^3.4.8",
112
112
  "@khanacademy/wonder-blocks-timing": "^7.1.0",
113
- "@khanacademy/wonder-blocks-tokens": "^17.1.0",
114
- "@khanacademy/wonder-blocks-tooltip": "^4.1.84",
115
- "@khanacademy/wonder-blocks-typography": "^5.0.1",
113
+ "@khanacademy/wonder-blocks-tokens": "^17.2.0",
114
+ "@khanacademy/wonder-blocks-tooltip": "^4.2.0",
115
+ "@khanacademy/wonder-blocks-typography": "^5.0.2",
116
116
  "@khanacademy/wonder-stuff-core": "^3.0.0",
117
117
  "@phosphor-icons/core": "^2.0.2",
118
118
  "@popperjs/core": "^2.10.2",
@@ -127,7 +127,7 @@
127
127
  },
128
128
  "keywords": [],
129
129
  "khan": {
130
- "catalogHash": "1680f43b40dfea22"
130
+ "catalogHash": "ad217163f04bf0b2"
131
131
  },
132
132
  "scripts": {}
133
133
  }
@@ -1,49 +0,0 @@
1
- import * as React from "react";
2
- import { PerseusI18nContext } from "../../components/i18n-context";
3
- import type { WidgetProps, Widget } from "../../types";
4
- import type { ImagePromptJSON } from "../../widget-ai-utils/image/image-ai-utils";
5
- import type { PerseusImageWidgetOptions } from "@khanacademy/perseus-core";
6
- type ExternalProps = WidgetProps<PerseusImageWidgetOptions>;
7
- export interface ImageWidgetProps extends ExternalProps {
8
- alignment: NonNullable<ExternalProps["alignment"]>;
9
- title: NonNullable<ExternalProps["title"]>;
10
- range: NonNullable<ExternalProps["range"]>;
11
- box: NonNullable<ExternalProps["box"]>;
12
- backgroundImage: NonNullable<ExternalProps["backgroundImage"]>;
13
- scale: NonNullable<ExternalProps["scale"]>;
14
- labels: NonNullable<ExternalProps["labels"]>;
15
- alt: NonNullable<ExternalProps["alt"]>;
16
- longDescription: NonNullable<ExternalProps["longDescription"]>;
17
- decorative: NonNullable<ExternalProps["decorative"]>;
18
- caption: NonNullable<ExternalProps["caption"]>;
19
- linterContext: NonNullable<ExternalProps["linterContext"]>;
20
- }
21
- interface DefaultProps extends Partial<ImageWidgetProps> {
22
- alignment: ImageWidgetProps["alignment"];
23
- title: ImageWidgetProps["title"];
24
- range: ImageWidgetProps["range"];
25
- box: ImageWidgetProps["box"];
26
- backgroundImage: ImageWidgetProps["backgroundImage"];
27
- scale: ImageWidgetProps["scale"];
28
- labels: ImageWidgetProps["labels"];
29
- alt: ImageWidgetProps["alt"];
30
- longDescription: ImageWidgetProps["longDescription"];
31
- decorative: ImageWidgetProps["decorative"];
32
- caption: ImageWidgetProps["caption"];
33
- linterContext: ImageWidgetProps["linterContext"];
34
- }
35
- declare class ImageWidget extends React.Component<ImageWidgetProps> implements Widget {
36
- static contextType: React.Context<import("../../components/i18n-context").I18nContextType>;
37
- context: React.ContextType<typeof PerseusI18nContext>;
38
- static defaultProps: DefaultProps;
39
- isWidget: true;
40
- getPromptJSON(): ImagePromptJSON;
41
- render(): React.ReactNode;
42
- }
43
- declare const _default: {
44
- name: string;
45
- displayName: string;
46
- widget: typeof ImageWidget;
47
- isLintable: true;
48
- };
49
- export default _default;