@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.
@@ -53,6 +53,11 @@ export default class ArticleEditor extends React.Component<Props, State> {
53
53
  _handleMoveSectionLater(i: number): void;
54
54
  _handleAddSectionAfter(i: number): void;
55
55
  _handleRemoveSection(i: number): void;
56
+ /**
57
+ * Returns the current version of the edited {@link PerseusArticle}.
58
+ *
59
+ * @deprecated Use the {@link Props.onChange} prop instead.
60
+ */
56
61
  serialize(): PerseusArticle;
57
62
  /**
58
63
  * Returns an array, with one element be section.
@@ -89,6 +89,11 @@ declare class EditorPage extends React.Component<Props, State> {
89
89
  updateRenderer(): void;
90
90
  getApiOptions(): APIOptionsWithDefaults;
91
91
  getSaveWarnings(): any;
92
+ /**
93
+ * Returns the current version of the edited {@link PerseusItem}.
94
+ *
95
+ * @deprecated Use the {@link Props.onChange} prop instead.
96
+ */
92
97
  serialize(): PerseusItem;
93
98
  handleChange: (toChange: OnChangeParams) => void;
94
99
  changeJSON: (newJson: PerseusItem) => void;
package/dist/editor.d.ts CHANGED
@@ -75,6 +75,11 @@ declare class Editor extends React.Component<Props, State> {
75
75
  private getWidgetsReferencedIn;
76
76
  focus: () => void;
77
77
  focusAndMoveToEnd: () => void;
78
+ /**
79
+ * Returns the current version of the edited {@link PerseusRenderer}.
80
+ *
81
+ * @deprecated Use the `Props.onChange` prop instead.
82
+ */
78
83
  serialize(): PerseusRenderer;
79
84
  render(): React.ReactNode;
80
85
  }
package/dist/es/index.js CHANGED
@@ -34,10 +34,10 @@ import { Checkbox as Checkbox$1, TextField, LabeledTextField, TextArea } from '@
34
34
  import * as axeCore from 'axe-core';
35
35
  import { StatefulKeypadContextProvider, KeypadContext } from '@khanacademy/keypad-context';
36
36
  import { MobileKeypad, useMathInputI18n, createMathField } from '@khanacademy/math-input';
37
+ import { UnreachableCaseError, isTruthy } from '@khanacademy/wonder-stuff-core';
37
38
  import PropTypes from 'prop-types';
38
39
  import ReactDOM from 'react-dom';
39
40
  import * as KAS from '@khanacademy/kas';
40
- import { isTruthy, UnreachableCaseError } from '@khanacademy/wonder-stuff-core';
41
41
  import { LabeledField } from '@khanacademy/wonder-blocks-labeled-field';
42
42
  import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
43
43
  import trashIcon$1 from '@phosphor-icons/core/regular/trash.svg';
@@ -65,7 +65,7 @@ import xIcon from '@phosphor-icons/core/regular/x.svg';
65
65
  import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
66
66
  import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
67
67
 
68
- const libName="@khanacademy/perseus-editor";const libVersion="31.1.0";addLibraryVersionToPerseusDebug(libName,libVersion);
68
+ const libName="@khanacademy/perseus-editor";const libVersion="31.2.0";addLibraryVersionToPerseusDebug(libName,libVersion);
69
69
 
70
70
  var jsxRuntime = {exports: {}};
71
71
 
@@ -1509,6 +1509,18 @@ const{HUD}=components;class EditorPage extends React.Component{componentDidMount
1509
1509
 
1510
1510
  function ContentPreview({question,apiOptions,seamless,linterContext,legacyPerseusLint,previewDevice,reviewMode}){const i18n=usePerseusI18n();const isMobile=previewDevice!=="desktop";const className=isMobile?"perseus-mobile":"";return jsxRuntimeExports.jsx(View,{className:`framework-perseus ${className}`,style:[styles$N.container,!seamless?styles$N.gutter:undefined],children:jsxRuntimeExports.jsx(StatefulKeypadContextProvider,{children:jsxRuntimeExports.jsx(KeypadContext.Consumer,{children:({setKeypadActive,keypadElement,setKeypadElement})=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(UserInputManager,{widgets:question?.widgets||{},problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{strings:i18n.strings,apiOptions:{...apiOptions,isMobile},keypadElement:keypadElement,linterContext:linterContext,legacyPerseusLint:legacyPerseusLint,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,reviewMode:reviewMode,...question})}),jsxRuntimeExports.jsx(MobileKeypad,{onAnalyticsEvent:()=>Promise.resolve(),onDismiss:()=>setKeypadActive(false),onElementMounted:setKeypadElement})]})})})})}const styles$N=StyleSheet.create({container:{padding:spacing.xxxSmall_4,containerType:"inline-size",containerName:"perseus-root"},gutter:{marginRight:lintGutterWidth}});
1511
1511
 
1512
+ const PREVIEW_MESSAGE_SOURCE="perseus-preview";function createPreviewIframeReadyMessage(){return {source:PREVIEW_MESSAGE_SOURCE,type:"iframe-ready"}}
1513
+
1514
+ function isIframeToParentMessage(message){return typeof message==="object"&&message!==null&&"source"in message&&typeof message.source==="string"&&message.source===PREVIEW_MESSAGE_SOURCE}function isParentToIframeMessage(message){return typeof message==="object"&&message!==null&&"source"in message&&typeof message.source==="string"&&message.source===PREVIEW_MESSAGE_SOURCE}
1515
+
1516
+ function sanitizeApiOptions(apiOptions){if(apiOptions==null){return null}const{onFocusChange:_,answerableCallback:__,getAnotherHint:___,interactionCallback:____,imagePreloader:_____,trackInteraction:______,setDrawingAreaAvailable:________,baseElements:_________,nativeKeypadProxy:__________,imagePlaceholder:___________,widgetPlaceholder:____________,...serializableOptions}=apiOptions;return serializableOptions}
1517
+
1518
+ function sanitizePreviewData(content){if((content.type==="question"||content.type==="hint"||content.type==="article")&&content.data.apiOptions!=null){return {...content,data:{...content.data,apiOptions:sanitizeApiOptions(content.data.apiOptions)}}}if(content.type==="article-all"){return {...content,data:content.data.map(section=>section.apiOptions!=null?{...section,apiOptions:sanitizeApiOptions(section.apiOptions)}:section)}}return content}
1519
+
1520
+ function usePreviewController(iframeRef){const[height,setHeight]=React.useState(null);const[isIframeReady,setIsIframeReady]=React.useState(false);const pendingDataRef=React.useRef(null);React.useEffect(()=>{const handleMessage=event=>{if(iframeRef.current?.contentWindow==null||event.source!==iframeRef.current?.contentWindow){return}const message=event.data;if(!isIframeToParentMessage(message)){return}switch(message.type){case "iframe-ready":{if(pendingDataRef.current){const sanitizedData=sanitizePreviewData(pendingDataRef.current);const msg={source:PREVIEW_MESSAGE_SOURCE,type:"content-data",content:sanitizedData};iframeRef.current.contentWindow.postMessage(msg,"/");pendingDataRef.current=null;}setIsIframeReady(true);break}case "height-update":setHeight(message.height);break;default:throw new UnreachableCaseError(message)}};window.addEventListener("message",handleMessage);return ()=>{window.removeEventListener("message",handleMessage);}},[iframeRef]);const sendData=React.useCallback(data=>{if(!isIframeReady){pendingDataRef.current=data;return}const contentWindow=iframeRef.current?.contentWindow;if(!contentWindow){return}const sanitizedData=sanitizePreviewData(data);const message={source:PREVIEW_MESSAGE_SOURCE,type:"content-data",content:sanitizedData};contentWindow.postMessage(message,"/");},[iframeRef,isIframeReady]);return {sendData,height}}
1521
+
1522
+ function usePreviewPresenter(){const[data,setData]=React.useState(null);const iframe=window.frameElement;if(iframe==null){throw new Error("usePreviewPresenter must be used within an iframe")}React.useEffect(()=>{const handleMessage=event=>{if(event.source!==window.parent){return}const message=event.data;if(!isParentToIframeMessage(message)){return}switch(message.type){case "content-data":setData(message.content);break;default:throw new UnreachableCaseError(message.type)}};window.addEventListener("message",handleMessage);window.parent.postMessage(createPreviewIframeReadyMessage(),"/");return ()=>{window.removeEventListener("message",handleMessage);}},[]);const reportHeight=React.useCallback(height=>{if(window.parent==null){return}const message={source:PREVIEW_MESSAGE_SOURCE,type:"height-update",height};window.parent.postMessage(message,"/");},[]);return {data,isMobile:iframe.dataset.mobile==="true",hasLintGutter:iframe.dataset.lintGutter==="true",reportHeight}}
1523
+
1512
1524
  const{TextListEditor: TextListEditor$4}=components;const Categorizer=Categorizer$1.widget;class CategorizerEditor extends React.Component{render(){const categorizerProps={items:this.props.items,categories:this.props.categories,userInput:{values:this.props.values},handleUserInput:userInput=>{this.props.onChange({values:userInput.values});},apiOptions:this.props.apiOptions,trackInteraction:function(){}};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Randomize item order",checked:this.props.randomizeItems,onChange:value=>{this.props.onChange({randomizeItems:value});}})}),"Categories:",jsxRuntimeExports.jsx(TextListEditor$4,{options:this.props.categories,onChange:cat=>{this.change("categories",cat);},layout:"horizontal"}),"Items:",jsxRuntimeExports.jsx(TextListEditor$4,{options:this.props.items,onChange:items=>{this.change({items:items,values:_.first(this.props.values,items.length)});},layout:"vertical"}),jsxRuntimeExports.jsx(Categorizer,{...categorizerProps})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CategorizerEditor.propTypes={...Changeable.propTypes,apiOptions:ApiOptions.propTypes,items:PropTypes.arrayOf(PropTypes.string),categories:PropTypes.arrayOf(PropTypes.string),values:PropTypes.arrayOf(PropTypes.number),randomizeItems:PropTypes.bool};CategorizerEditor.widgetName="categorizer";CategorizerEditor.defaultProps=categorizerLogic.defaultWidgetOptions;
1513
1525
 
1514
1526
  class BlurInput extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({value:nextProps.value});}focus(){this.input.current?.focus();}render(){return jsxRuntimeExports.jsx("input",{ref:this.input,className:this.props.className,style:this.props.style,type:"text",value:this.state.value,onChange:this.handleChange,onBlur:this.handleBlur})}constructor(props){super(props),this.input=React.createRef(),this.handleChange=e=>{this.setState({value:e.target.value});},this.handleBlur=e=>{this.props.onChange(e.target.value);};this.state={value:this.props.value};}}
@@ -1604,7 +1616,7 @@ const UNLIMITED="unlimited";const parsePointCount=points=>{const parsed=parseInt
1604
1616
 
1605
1617
  const GraphPointsCountSelector=({correct,graph,onChange})=>{return jsxRuntimeExports.jsx(LabeledRow,{label:"Number of Points:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:`${correct.numPoints??1}`,onChange:newValue=>{const points=parsePointCount(newValue);onChange({correct:{type:"point",numPoints:points},graph:{type:"point",numPoints:points}});},placeholder:"",className:styles$G.singleSelectShort,children:[...[...Array(7).keys()].map(n=>jsxRuntimeExports.jsx(OptionItem,{value:`${n}`,label:`${n} point${n>1?"s":""}`},n)),jsxRuntimeExports.jsx(OptionItem,{value:UNLIMITED,label:"unlimited"},"unlimited")]})})};
1606
1618
 
1607
- const GraphTypeSelector=props=>{const showExponential=isFeatureOn({apiOptions:props.apiOptions},"interactive-graph-exponent");const showAbsoluteValue=isFeatureOn({apiOptions:props.apiOptions},"interactive-graph-absolute-value");const showTangent=isFeatureOn({apiOptions:props.apiOptions},"interactive-graph-tangent");const showLogarithm=isFeatureOn({apiOptions:props.apiOptions},"interactive-graph-logarithm");const showVector=isFeatureOn({apiOptions:props.apiOptions},"interactive-graph-vector");return jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:props.graphType,onChange:props.onChange,placeholder:"Select an answer type",style:styles$E.singleSelectShort,children:[showAbsoluteValue&&jsxRuntimeExports.jsx(OptionItem,{value:"absolute-value",label:"Absolute value"}),jsxRuntimeExports.jsx(OptionItem,{value:"none",label:"None"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear",label:"Linear function"}),jsxRuntimeExports.jsx(OptionItem,{value:"quadratic",label:"Quadratic function"}),jsxRuntimeExports.jsx(OptionItem,{value:"sinusoid",label:"Sinusoid function"}),showExponential&&jsxRuntimeExports.jsx(OptionItem,{value:"exponential",label:"Exponential function"}),showTangent&&jsxRuntimeExports.jsx(OptionItem,{value:"tangent",label:"Tangent function"}),showLogarithm&&jsxRuntimeExports.jsx(OptionItem,{value:"logarithm",label:"Logarithm function"}),jsxRuntimeExports.jsx(OptionItem,{value:"circle",label:"Circle"}),jsxRuntimeExports.jsx(OptionItem,{value:"point",label:"Point(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear-system",label:"Linear System"}),jsxRuntimeExports.jsx(OptionItem,{value:"polygon",label:"Polygon"}),jsxRuntimeExports.jsx(OptionItem,{value:"segment",label:"Line Segment(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"ray",label:"Ray"}),showVector&&jsxRuntimeExports.jsx(OptionItem,{value:"vector",label:"Vector"}),jsxRuntimeExports.jsx(OptionItem,{value:"angle",label:"Angle"})]})};const styles$E=StyleSheet.create({singleSelectShort:{height:sizing.size_260}});
1619
+ const GraphTypeSelector=props=>{const showVector=isFeatureOn({apiOptions:props.apiOptions},"interactive-graph-vector");return jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:props.graphType,onChange:props.onChange,placeholder:"Select an answer type",style:styles$E.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"absolute-value",label:"Absolute value"}),jsxRuntimeExports.jsx(OptionItem,{value:"none",label:"None"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear",label:"Linear function"}),jsxRuntimeExports.jsx(OptionItem,{value:"quadratic",label:"Quadratic function"}),jsxRuntimeExports.jsx(OptionItem,{value:"sinusoid",label:"Sinusoid function"}),jsxRuntimeExports.jsx(OptionItem,{value:"exponential",label:"Exponential function"}),jsxRuntimeExports.jsx(OptionItem,{value:"tangent",label:"Tangent function"}),jsxRuntimeExports.jsx(OptionItem,{value:"logarithm",label:"Logarithm function"}),jsxRuntimeExports.jsx(OptionItem,{value:"circle",label:"Circle"}),jsxRuntimeExports.jsx(OptionItem,{value:"point",label:"Point(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear-system",label:"Linear System"}),jsxRuntimeExports.jsx(OptionItem,{value:"polygon",label:"Polygon"}),jsxRuntimeExports.jsx(OptionItem,{value:"segment",label:"Line Segment(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"ray",label:"Ray"}),showVector&&jsxRuntimeExports.jsx(OptionItem,{value:"vector",label:"Vector"}),jsxRuntimeExports.jsx(OptionItem,{value:"angle",label:"Angle"})]})};const styles$E=StyleSheet.create({singleSelectShort:{height:sizing.size_260}});
1608
1620
 
1609
1621
  function Heading({title,isOpen,isCollapsible,onToggle}){return jsxRuntimeExports.jsx(Clickable,{style:[styles$D.container,!isCollapsible&&styles$D.notClickable],disabled:!isCollapsible,onClick:()=>isCollapsible&&onToggle?.(!isOpen),children:()=>jsxRuntimeExports.jsxs(View,{style:styles$D.heading,children:[jsxRuntimeExports.jsx(BodyText,{size:"small",weight:"bold",tag:"span",children:title}),isCollapsible&&jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:isOpen})]})})}const styles$D=StyleSheet.create({container:{marginTop:spacing.small_12,marginInline:-10,backgroundColor:semanticColor.core.background.neutral.subtle,padding:spacing.xSmall_8,width:"calc(100% + 20px)"},heading:{flexDirection:"row",justifyContent:"space-between",userSelect:"none"},notClickable:{color:"inherit",cursor:"default"}});
1610
1622
 
@@ -1787,5 +1799,5 @@ var AllEditors = [CategorizerEditor,CSProgramEditor,DefinitionEditor,DropdownEdi
1787
1799
 
1788
1800
  Widgets.registerEditors(AllEditors);Widgets.registerWidgets(widgets);Widgets.replaceDeprecatedWidgets();Widgets.replaceDeprecatedEditors();
1789
1801
 
1790
- export { AllEditors, ArticleDiff, ArticleEditor, ContentPreview, DeviceFramer, Editor, EditorPage, IframeContentRenderer, ItemDiff, ViewportResizer, libVersion };
1802
+ export { AllEditors, ArticleDiff, ArticleEditor, ContentPreview, DeviceFramer, Editor, EditorPage, IframeContentRenderer, ItemDiff, ViewportResizer, libVersion, usePreviewController, usePreviewPresenter };
1791
1803
  //# sourceMappingURL=index.js.map