@khanacademy/perseus-editor 31.1.0 → 31.2.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.
@@ -15,16 +15,6 @@ export declare const PREVIEW_MESSAGE_SOURCE: "perseus-preview";
15
15
  interface PreviewMessageBase {
16
16
  source: typeof PREVIEW_MESSAGE_SOURCE;
17
17
  }
18
- /**
19
- * Base type for messages with iframe ID
20
- *
21
- * Note: The ID is primarily used for debugging/logging purposes.
22
- * Message routing is handled by event.source filtering in the hooks,
23
- * not by comparing ID strings.
24
- */
25
- interface PreviewMessageWithId extends PreviewMessageBase {
26
- id: string;
27
- }
28
18
  /**
29
19
  * Data for question preview (full item with question, answer area, and hints)
30
20
  */
@@ -75,36 +65,30 @@ export type PreviewContent = {
75
65
  /**
76
66
  * Message from parent sending content data to iframe
77
67
  */
78
- type PreviewDataMessage = PreviewMessageWithId & {
68
+ interface PreviewDataMessage extends PreviewMessageBase {
79
69
  type: "content-data";
80
70
  content: PreviewContent;
81
- };
71
+ }
82
72
  /**
83
73
  * Union of all messages sent from parent to iframe
84
74
  */
85
75
  export type ParentToIframeMessage = PreviewDataMessage;
86
76
  /**
87
- * Message from iframe requesting data from parent
77
+ * Message from iframe to parent telling it the iframe is ready
88
78
  */
89
- type PreviewDataRequestMessage = PreviewMessageWithId & {
90
- type: "request-data";
91
- };
79
+ interface PreviewIframeReadyMessage extends PreviewMessageBase {
80
+ type: "iframe-ready";
81
+ }
92
82
  /**
93
83
  * Message from iframe reporting its content height
94
84
  */
95
- type PreviewHeightUpdateMessage = PreviewMessageWithId & {
85
+ interface PreviewHeightUpdateMessage extends PreviewMessageBase {
96
86
  type: "height-update";
97
87
  height: number;
98
- };
99
- /**
100
- * Message from iframe reporting lint warnings
101
- */
102
- type PreviewLintReportMessage = PreviewMessageWithId & {
103
- type: "lint-report";
104
- lintWarnings: ReadonlyArray<any>;
105
- };
88
+ }
106
89
  /**
107
90
  * Union of all messages sent from iframe to parent
108
91
  */
109
- export type IframeToParentMessage = PreviewDataRequestMessage | PreviewHeightUpdateMessage | PreviewLintReportMessage;
92
+ export type IframeToParentMessage = PreviewIframeReadyMessage | PreviewHeightUpdateMessage;
93
+ export declare function createPreviewIframeReadyMessage(): PreviewIframeReadyMessage;
110
94
  export {};
@@ -0,0 +1,43 @@
1
+ import * as React from "react";
2
+ import type { PreviewContent } from "./message-types";
3
+ type UsePreviewControllerResult = {
4
+ /**
5
+ * Send preview content data to the iframe
6
+ */
7
+ sendData: (data: PreviewContent) => void;
8
+ /**
9
+ * Current height of the iframe content (null if not yet reported)
10
+ */
11
+ height: number | null;
12
+ };
13
+ /**
14
+ * Hook for parent/editor to send data to preview iframe and receive updates.
15
+ *
16
+ * This hook:
17
+ * - Sends preview content data to iframe via postMessage
18
+ * - Listens for height updates from iframe
19
+ * - Listens for lint reports from iframe
20
+ * - Automatically sanitizes apiOptions before sending (removes non-serializable functions)
21
+ *
22
+ * @param iframeRef - Reference to the iframe element
23
+ * @returns Object with sendData function and current height
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * function Editor() {
28
+ * const iframeRef = React.useRef<HTMLIFrameElement>(null);
29
+ * const { sendData, height } = usePreviewController(iframeRef);
30
+ *
31
+ * React.useEffect(() => {
32
+ * sendData({
33
+ * type: "question",
34
+ * data: { item, apiOptions, ... }
35
+ * });
36
+ * }, [item, apiOptions]);
37
+ *
38
+ * return <iframe ref={iframeRef} style={{ height }} />;
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function usePreviewController(iframeRef: React.RefObject<HTMLIFrameElement>): UsePreviewControllerResult;
43
+ export {};
@@ -0,0 +1,50 @@
1
+ import type { PreviewContent } from "./message-types";
2
+ type UsePreviewPresenterResult = {
3
+ /**
4
+ * The preview content data received from the parent, or null if not yet loaded
5
+ */
6
+ data: PreviewContent | null;
7
+ /**
8
+ * Whether the preview should render in mobile mode (from data-mobile attribute)
9
+ */
10
+ isMobile: boolean;
11
+ /**
12
+ * Whether to show the lint gutter (from data-lint-gutter attribute)
13
+ */
14
+ hasLintGutter: boolean;
15
+ /**
16
+ * Function to report the current height of the iframe content to the parent
17
+ */
18
+ reportHeight: (height: number) => void;
19
+ };
20
+ /**
21
+ * Hook for preview iframe to receive data from parent and send updates back.
22
+ *
23
+ * This hook:
24
+ * - Reads iframe configuration from dataset attributes (id, mobile, lintGutter)
25
+ * - Listens for content data from the parent window via postMessage
26
+ * - Requests initial data on mount
27
+ * - Provides functions to report height and lint warnings back to parent
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * function PreviewPage() {
32
+ * const { data, isMobile, reportHeight } = usePreviewPresenter();
33
+ *
34
+ * React.useEffect(() => {
35
+ * if (containerRef.current) {
36
+ * reportHeight(containerRef.current.scrollHeight);
37
+ * }
38
+ * }, [data, reportHeight]);
39
+ *
40
+ * if (!data) return <div>Loading...</div>;
41
+ * return <PreviewRenderer
42
+ * ref={containerRef}
43
+ * data={data}
44
+ * isMobile={isMobile}
45
+ * />;
46
+ * }
47
+ * ```
48
+ */
49
+ export declare function usePreviewPresenter(): UsePreviewPresenterResult;
50
+ export {};
@@ -4,10 +4,6 @@ declare const DEFAULT_FEATURE_FLAGS: {
4
4
  "new-radio-widget": boolean;
5
5
  "image-widget-upgrade-gif-controls": boolean;
6
6
  "image-widget-upgrade-scale": boolean;
7
- "interactive-graph-absolute-value": boolean;
8
- "interactive-graph-tangent": boolean;
9
- "interactive-graph-logarithm": boolean;
10
- "interactive-graph-exponent": boolean;
11
7
  "interactive-graph-vector": boolean;
12
8
  "interactive-graph-not-scored": boolean;
13
9
  };
@@ -21,10 +17,6 @@ export declare function getFeatureFlags(overrides?: Partial<typeof DEFAULT_FEATU
21
17
  "new-radio-widget": boolean;
22
18
  "image-widget-upgrade-gif-controls": boolean;
23
19
  "image-widget-upgrade-scale": boolean;
24
- "interactive-graph-absolute-value": boolean;
25
- "interactive-graph-tangent": boolean;
26
- "interactive-graph-logarithm": boolean;
27
- "interactive-graph-exponent": boolean;
28
20
  "interactive-graph-vector": boolean;
29
21
  "interactive-graph-not-scored": boolean;
30
22
  };