@khanacademy/perseus 67.1.2 → 68.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 (40) hide show
  1. package/dist/es/index.js +20 -18
  2. package/dist/es/index.js.map +1 -1
  3. package/dist/hint-renderer.d.ts +0 -4
  4. package/dist/hints-renderer.d.ts +0 -4
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +19 -16
  7. package/dist/index.js.map +1 -1
  8. package/dist/mixins/widget-prop-denylist.d.ts +1 -1
  9. package/dist/renderer.d.ts +5 -16
  10. package/dist/server-item-renderer.d.ts +1 -5
  11. package/dist/types.d.ts +5 -11
  12. package/dist/user-input-manager.d.ts +1 -5
  13. package/dist/util/extract-widget-ids.d.ts +8 -0
  14. package/dist/widget-ai-utils/radio/radio-ai-utils.d.ts +1 -0
  15. package/dist/widgets/categorizer/categorizer.d.ts +2 -2
  16. package/dist/widgets/cs-program/cs-program.d.ts +1 -1
  17. package/dist/widgets/dropdown/dropdown.d.ts +2 -10
  18. package/dist/widgets/expression/expression.d.ts +4 -3
  19. package/dist/widgets/grapher/grapher.d.ts +3 -2
  20. package/dist/widgets/group/group.d.ts +0 -4
  21. package/dist/widgets/iframe/iframe.d.ts +1 -1
  22. package/dist/widgets/input-number/input-number.d.ts +2 -2
  23. package/dist/widgets/interactive-graphs/interactive-graph.d.ts +3 -2
  24. package/dist/widgets/label-image/label-image.d.ts +2 -2
  25. package/dist/widgets/matcher/matcher.d.ts +1 -1
  26. package/dist/widgets/matrix/matrix.d.ts +2 -2
  27. package/dist/widgets/mock-widgets/mock-widget.d.ts +3 -2
  28. package/dist/widgets/number-line/number-line.d.ts +2 -2
  29. package/dist/widgets/numeric-input/numeric-input.class.d.ts +3 -2
  30. package/dist/widgets/orderer/orderer.d.ts +2 -2
  31. package/dist/widgets/plotter/plotter.d.ts +3 -2
  32. package/dist/widgets/radio/multiple-choice-widget.new.d.ts +0 -4
  33. package/dist/widgets/radio/radio-component.d.ts +2 -4
  34. package/dist/widgets/radio/radio.d.ts +0 -4
  35. package/dist/widgets/radio/radio.ff.d.ts +7 -6
  36. package/dist/widgets/radio/util.d.ts +6 -3
  37. package/dist/widgets/radio/utils/general-utils.d.ts +2 -4
  38. package/dist/widgets/sorter/sorter.d.ts +2 -2
  39. package/dist/widgets/table/table.d.ts +2 -1
  40. package/package.json +7 -7
package/dist/es/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { useContext, forwardRef, useId, useImperativeHandle, useRef, useState, useEffect, createElement, createContext, useLayoutEffect } from 'react';
3
3
  import { MathInputI18nContext, DesktopKeypad, getCursorContext, CursorContext, getKeyTranslator, createMathField, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, keypadElementPropType } from '@khanacademy/math-input';
4
- import { expressionLogic, PerseusError, Errors, isLabeledSVG, getDataUrl, getSvgUrl, getBaseUrl, getRealImageUrl, getImageSizeModern, approximateDeepEqual, pluck, Registry, CoreWidgetRegistry, applyDefaultsToWidgets, mapObject, splitPerseusItem, getDefaultAnswerArea, usesNumCorrect, passageRefLogic, deepClone, radioLogic, randomizeArrayElements, shuffle, getWidgetIdsFromContentByType, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, shuffleMatcher, getMatrixSize, measurerLogic, shuffleSorter, traverse, applyDefaultsToWidget } from '@khanacademy/perseus-core';
4
+ import { expressionLogic, PerseusError, Errors, isLabeledSVG, getDataUrl, getSvgUrl, getBaseUrl, getRealImageUrl, getImageSizeModern, approximateDeepEqual, pluck, Registry, CoreWidgetRegistry, applyDefaultsToWidgets, mapObject, splitPerseusItem, getDefaultAnswerArea, shuffle, usesNumCorrect, passageRefLogic, deepClone, radioLogic, getWidgetIdsFromContentByType, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, shuffleMatcher, getMatrixSize, measurerLogic, shuffleSorter, traverse, applyDefaultsToWidget } from '@khanacademy/perseus-core';
5
5
  export { isFailure, isSuccess, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem } from '@khanacademy/perseus-core';
6
6
  import * as PerseusLinter from '@khanacademy/perseus-linter';
7
7
  import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
@@ -1622,7 +1622,7 @@ function _noop(){}class InteractionTracker{constructor(trackApi,widgetType,widge
1622
1622
 
1623
1623
  const arrayRules={fence:{match:SimpleMarkdown.defaultRules.fence.match,order:1,parse:(capture,state,parse)=>({type:"codeBlock",lang:capture[2]||undefined,content:capture[3]})},paragraph:{match:SimpleMarkdown.defaultRules.paragraph.match,order:2,parse:(capture,state,parse)=>({content:capture[1]})}};const builtArrayParser=SimpleMarkdown.parserFor(arrayRules);const parseToArray=source=>{const paragraphedSource=source.replace(/^\n\s*\n/,"")+"\n\n";return builtArrayParser(paragraphedSource,{inline:false}).map(c=>{return c["content"]})};const joinFromArray=paragraphs=>paragraphs.join("\n\n");var JiptParagraphs = {parseToArray:parseToArray,joinFromArray:joinFromArray};
1624
1624
 
1625
- const denylist=["key","ref","containerSizeClass","widgetId","onChange","problemNum","apiOptions","widgetIsOpen","questionCompleted","findWidgets","onRemove","id","onBlur","onFocus","trackInteraction","keypadElement","linterContext","isLastUsedWidget","handleUserInput","analytics","showSolutions","reviewMode","reviewModeRubric"];function excludeDenylistKeys(obj){if(obj==null){return obj}const rv={};for(const k of Object.keys(obj)){if(!denylist.includes(k)){rv[k]=obj[k];}}return rv}
1625
+ const denylist=["key","ref","containerSizeClass","widgetId","onChange","problemNum","apiOptions","widgetIsOpen","questionCompleted","findWidgets","onRemove","id","onBlur","onFocus","trackInteraction","keypadElement","linterContext","isLastUsedWidget","handleUserInput","analytics","showSolutions","reviewMode","reviewModeRubric","widgetIndex"];function excludeDenylistKeys(obj){if(obj==null){return obj}const rv={};for(const k of Object.keys(obj)){if(!denylist.includes(k)){rv[k]=obj[k];}}return rv}
1626
1626
 
1627
1627
  const exclamationIcon={path:"M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",height:12,width:12};class Lint extends React.Component{componentDidMount(){this._positionTimeout=window.setTimeout(this.getPosition);}componentWillUnmount(){window.clearTimeout(this._positionTimeout);}render(){const{children,inline,blockHighlight,insideTable}=this.props;if(insideTable){if(inline){return jsxRuntimeExports.jsx("span",{"data-lint-inside-table":"true",children:children})}return jsxRuntimeExports.jsx("div",{"data-lint-inside-table":"true",children:children})}if(blockHighlight){return jsxRuntimeExports.jsxs("span",{className:css(styles$F.lintContainer,styles$F.lintContainerBlock),children:[this.renderLink(styles$F.radioWidgetHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}if(inline){return jsxRuntimeExports.jsxs("span",{className:css(styles$F.lintContainer),children:[this.renderLink(styles$F.inlineHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}return jsxRuntimeExports.jsxs("div",{className:css(styles$F.lintContainer),children:[this.renderLink(styles$F.hoverTarget),jsxRuntimeExports.jsx("div",{children:children})]})}constructor(...args){super(...args),this.state={tooltipAbove:true},this.getPosition=()=>{const rect=ReactDOM__default.findDOMNode(this).getBoundingClientRect();this.setState({tooltipAbove:rect.top>100});},this.renderLink=style=>{const tooltipAbove=this.state.tooltipAbove;let severityStyle;let warningText;let warningTextStyle;if(this.props.severity===1){severityStyle=styles$F.indicatorError;warningText="Error";warningTextStyle=styles$F.publishBlockingError;}else if(this.props.severity===2){severityStyle=styles$F.indicatorWarning;warningText="Warning";warningTextStyle=styles$F.warning;}else {severityStyle=styles$F.indicatorGuideline;warningText="Recommendation";warningTextStyle=styles$F.warning;}return jsxRuntimeExports.jsxs("a",{href:`https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,target:"lint-help-window",className:css(style),children:[jsxRuntimeExports.jsx("span",{className:css(styles$F.indicator,severityStyle),children:this.props.severity===1&&jsxRuntimeExports.jsx(InlineIcon,{...exclamationIcon})}),jsxRuntimeExports.jsxs("div",{className:css(styles$F.tooltip,tooltipAbove&&styles$F.tooltipAbove),children:[this.props.message.split("\n\n").map((m,i)=>jsxRuntimeExports.jsxs("p",{className:css(styles$F.tooltipParagraph),children:[jsxRuntimeExports.jsxs("span",{className:css(warningTextStyle),children:[warningText,":"," "]}),m]},i)),jsxRuntimeExports.jsx("div",{className:css(styles$F.tail,tooltipAbove&&styles$F.tailAbove)})]})]})};}}const styles$F=StyleSheet.create({lintContainer:{position:"relative"},lintContainerBlock:{display:"block"},hoverTarget:{position:"absolute",top:0,right:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ div":{outline:"1px solid "+warningColor},":hover ~ div div[data-lint-inside-table]":{outline:"1px solid "+warningColor},":hover ~ div span[data-lint-inside-table]":{backgroundColor:warningColor,color:white}},inlineHoverTarget:{float:"right",position:"relative",marginRight:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ span":{backgroundColor:warningColor,color:white}},radioWidgetHoverTarget:{position:"absolute",left:-40,display:"block",width:24,height:24,minWidth:264,":hover > span":{backgroundColor:warningColorHover},":hover > div":{display:"block",padding:8,width:280},":hover > div > div":{left:8},":hover ~ span":{backgroundColor:warningColor,color:white}},indicator:{alignItems:"center",borderRadius:4,color:"white",display:"flex",fontSize:12,height:8,justifyContent:"center",margin:8,width:8},indicatorError:{backgroundColor:"#be2612",borderRadius:8,height:16,width:16},indicatorWarning:{backgroundColor:"#f86700"},indicatorGuideline:{backgroundColor:"#ffbe26"},tooltip:{position:"absolute",right:-12,display:"none",zIndex:1e3,color:white,backgroundColor:gray17,opacity:.9,fontFamily:baseFontFamily,fontSize:"12px",lineHeight:"15px",width:"320px",borderRadius:"4px"},tooltipAbove:{bottom:32},tail:{position:"absolute",top:-12,right:16,width:0,height:0,borderLeft:"8px solid transparent",borderRight:"8px solid transparent",borderBottom:"12px solid "+gray17},tailAbove:{bottom:-12,borderBottom:"none",borderTop:"12px solid "+gray17,top:"auto"},tooltipParagraph:{margin:12},warning:{color:warningColor,fontFamily:boldFontFamily},publishBlockingError:{color:publishBlockingErrorColor}});
1628
1628
 
@@ -1664,7 +1664,7 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
1664
1664
 
1665
1665
  class WidgetContainer extends React.Component{componentDidMount(){if(this.state.widgetProps.apiOptions.isMobile){const containerWidth=ReactDOM__default.findDOMNode(this).offsetWidth;this.setState({sizeClass:getClassFromWidth(containerWidth)});}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.type!==nextProps.type){throw new Error("WidgetContainer can't change widget type; set a different "+"key instead to recreate the container.")}}shouldComponentUpdate(nextProps,nextState){return this.props.shouldHighlight!==nextProps.shouldHighlight||this.props.type!==nextProps.type||this.state.widgetProps!==nextState.widgetProps||this.state.sizeClass!==nextState.sizeClass}render(){let className=classNames$1({"perseus-widget-container":true,"widget-highlight":this.props.shouldHighlight,"widget-nohighlight":!this.props.shouldHighlight,"perseus-widget__definition":this.props.type==="definition"});const type=this.props.type;const userAgent=navigator.userAgent;const WidgetType=getWidget(type);if(WidgetType==null){console.warn(`Widget type '${type}' not found!`);return jsxRuntimeExports.jsx("div",{className:className})}let subType="null";if(type==="interactive-graph"){const props=this.state.widgetProps;subType=props.graph?.type??"null";}let alignment=this.state.widgetProps.alignment;if(alignment==="default"){alignment=CoreWidgetRegistry.getDefaultAlignment(type);}className+=" widget-"+alignment;const apiOptions=this.state.widgetProps.apiOptions;const isStatic=this.state.widgetProps.static||apiOptions.readOnly;const staticContainerStyles={position:"relative",overflow:"visible"};const staticOverlayStyles={width:"100%",height:"100%",position:"absolute",top:0,left:0,zIndex:3};const linterContext=isLintable(type)?this.props.linterContext:{...this.props.linterContext,highlightLint:false};return jsxRuntimeExports.jsx("div",{className:className,style:isStatic?staticContainerStyles:{},children:jsxRuntimeExports.jsx(DependenciesContext.Consumer,{children:({analytics})=>jsxRuntimeExports.jsxs(ErrorBoundary,{metadata:{widget_type:type,widget_id:this.props.id},onError:error=>{analytics.onAnalyticsEvent({type:"perseus:widget-rendering-error:ti",payload:{widgetSubType:subType,widgetType:type,widgetId:this.props.id,message:error.message,userAgent:userAgent}});},children:[jsxRuntimeExports.jsx(WidgetType,{...this.state.widgetProps,linterContext:linterContext,containerSizeClass:this.state.sizeClass,ref:this.widgetRef}),isStatic&&jsxRuntimeExports.jsx("div",{style:staticOverlayStyles})]})})})}constructor(...args){super(...args),this.widgetRef=React.createRef(),this.state={sizeClass:containerSizeClass.MEDIUM,widgetProps:this.props.initialProps},this.getWidget=()=>{return this.widgetRef.current},this.replaceWidgetProps=newWidgetProps=>{this.setState({widgetProps:newWidgetProps});};}}WidgetContainer.defaultProps={linterContext:linterContextDefault};
1666
1666
 
1667
- const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return _.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return _.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!_.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;this.props.initializeUserInput?.(this.props.widgets,this.props.problemNum??0);if(this.props.serializedState){this.restoreSerializedState(this.props.serializedState);}if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}UNSAFE_componentWillReceiveProps(nextProps){if(isDifferentQuestion(this.props,nextProps)){this.props.initializeUserInput?.(nextProps.widgets,nextProps.problemNum??0);this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!_.isEqual(this.state,nextState);const propsChanged=!_.isEqual(this.props,nextProps);return propsChanged||stateChanged}UNSAFE_componentWillUpdate(nextProps,nextState){const oldJipt=this.shouldRenderJiptPlaceholder(this.props,this.state);const newJipt=this.shouldRenderJiptPlaceholder(nextProps,nextState);const oldContent=this.getContent(this.props,this.state);const newContent=this.getContent(nextProps,nextState);const oldHighlightedWidgets=this.props.highlightedWidgets;const newHighlightedWidgets=nextProps.highlightedWidgets;this.reuseMarkdown=!oldJipt&&!newJipt&&oldContent===newContent&&_.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||_.isEqual(this.props.widgets,nextProps.widgets))&&this.props.linterContext.highlightLint===nextProps.linterContext.highlightLint&&oldHighlightedWidgets===newHighlightedWidgets;}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);this.widgetIds.forEach(id=>{const container=this._widgetContainers.get(makeContainerId(id));container?.replaceWidgetProps(this.getWidgetProps(id));});if(this.props.serializedState&&!_.isEqual(this.props.serializedState,prevProps.serializedState)){this.restoreSerializedState(this.props.serializedState);}if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.state.widgetProps[widgetId]||{};const widgetInfo=this.state.widgetInfo[widgetId];const reviewModeRubric=this.props.reviewMode&&widgetInfo?widgetInfo.options:null;if(!this._interactionTrackers){this._interactionTrackers={};}let interactionTracker=this._interactionTrackers[widgetId];if(!interactionTracker){interactionTracker=this._interactionTrackers[widgetId]=new InteractionTracker(apiOptions.trackInteraction,widgetInfo&&widgetInfo.type,widgetId,getTracking(widgetInfo&&widgetInfo.type));}return {...widgetProps,userInput:this.props.userInput?.[widgetId],widgetId:widgetId,alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,questionCompleted:this.props.questionCompleted,showSolutions:this.props.showSolutions,onFocus:_.partial(this._onWidgetFocus,widgetId),onBlur:_.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewModeRubric:reviewModeRubric,reviewMode:this.props.reviewMode,onChange:(newProps,cb,silent=false)=>{this._setWidgetProps(widgetId,newProps,cb,silent);},handleUserInput:newUserInput=>{const updatedUserInput={...this.props.userInput,[widgetId]:newUserInput};const emptyWidgetIds=emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,updatedUserInput,this.context.locale);const widgetsEmpty=emptyWidgetIds.length>0;this.props.handleUserInput?.(widgetId,newUserInput,widgetsEmpty);this.props.onInteractWithWidget(widgetId);},trackInteraction:interactionTracker.track,isLastUsedWidget:widgetId===this.state.lastUsedWidgetId}}emptyWidgets(){if(!this.props.userInput){throw new Error(`emptyWidgets called without providing userInput to Renderer`)}return emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale)}handleStateUpdate(id,cb,silent){this.setState(prevState=>{const lastUsedWidgetId=silent?prevState.lastUsedWidgetId:id;return {lastUsedWidgetId}},()=>{setTimeout(()=>{const cbResult=cb&&cb();if(!silent){this.props.onInteractWithWidget(id);}if(cbResult!==false){this._setCurrentFocus([id]);}},0);});}_setWidgetProps(id,nextWidgetProps,cb,silent){this.setState(prevState=>{const widgetProps=nextWidgetProps?{...prevState.widgetProps,[id]:{...prevState.widgetProps[id],...nextWidgetProps}}:prevState.widgetProps;return {widgetProps}},()=>{this.handleStateUpdate(id,cb,silent);});}getUserInput(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInput called without providing userInput to Renderer`)}return this.widgetIds.map(id=>{return userInput[id]})}getUserInputMap(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInputMap called without providing userInput to Renderer`)}return userInput}getPromptJSON(){const{content}=this.props;const widgetJSON={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);widgetJSON[id]=widget?.getPromptJSON?.()||{};});return {content,widgets:widgetJSON}}score(){if(!this.props.userInput){throw new Error(`score called without providing userInput to Renderer`)}const scores=scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();if(this.reuseMarkdown){return this.lastRenderedMarkdown}const content=this.getContent(this.props,this.state);this.widgetIds=[];if(this.shouldRenderJiptPlaceholder(this.props,this.state)){if(!this.translationIndex){this.translationIndex=getDependencies().rendererTranslationComponents.addComponent(this);}if(!apiOptions.isArticle){return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{"data-perseus-component-index":this.translationIndex,children:content})})}}this._isTwoColumn=false;const parsedMarkdown=this.props.inline?PerseusMarkdown.parseInline(content,{isJipt:this.translationIndex!=null}):PerseusMarkdown.parse(content,{isJipt:this.translationIndex!=null});if(this.props.linterContext.highlightLint){const fullLinterContext={content:this.props.content,widgets:this.props.widgets,...this.props.linterContext};PerseusLinter.runLinter(parsedMarkdown,fullLinterContext,true);this._translationLinter.applyLintErrors(parsedMarkdown,[...this.state.translationLintErrors,...this.props.legacyPerseusLint||[]]);}const markdownContents=this.outputMarkdown(parsedMarkdown,{baseElements:apiOptions.baseElements});const className=classNames$1({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});this.lastRenderedMarkdown=jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})});return this.lastRenderedMarkdown}constructor(props){super(props),this._widgetContainers=new Map,this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions}},this._getInitialWidgetState=props=>{const allWidgetInfo=applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{problemNum}=props;const widgetsStartProps={};const{strings}=this.props;entries(allWidgetInfo).forEach(([key,widgetInfo])=>{widgetsStartProps[key]=getRendererPropsForWidgetInfo(widgetInfo,strings,problemNum);});return widgetsStartProps},this._getDefaultWidgetInfo=widgetId=>{const widgetIdParts=Util.rTypeFromWidgetId.exec(widgetId);if(widgetIdParts==null){return {}}return {type:widgetIdParts[1],graded:true,options:{}}},this._getWidgetInfo=widgetId=>{return this.state.widgetInfo[widgetId]||this._getDefaultWidgetInfo(widgetId)},this.renderWidget=(impliedType,id,state)=>{const widgetInfo=this.state.widgetInfo[id];if(widgetInfo&&widgetInfo.alignment==="full-width"){state.foundFullWidth=true;}if(widgetInfo){const type=widgetInfo&&widgetInfo.type||impliedType;const shouldHighlight=_.contains(this.props.highlightedWidgets,id);return jsxRuntimeExports.jsx(WidgetContainer,{id:id,ref:node=>{const containerId=makeContainerId(id);if(node!=null){this._widgetContainers.set(containerId,node);}else {this._widgetContainers.delete(containerId);}},type:type,initialProps:this.getWidgetProps(id),shouldHighlight:shouldHighlight,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return mapObject(widgetProps||this.state.widgetProps,(props,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return props})},this.restoreSerializedState=(serializedState,callback)=>{const serializedWidgetIds=_.keys(serializedState);const widgetPropIds=_.keys(this.state.widgetProps);if(serializedWidgetIds.length!==widgetPropIds.length||_.intersection(serializedWidgetIds,widgetPropIds).length!==serializedWidgetIds.length){Log.error("Refusing to restore bad serialized state:",Errors.Internal,{loggedMetadata:{serializedState:JSON.stringify(serializedState),currentProps:JSON.stringify(this.state.widgetProps)}});return}let numCallbacks=1;const fireCallback=()=>{--numCallbacks;if(callback&&numCallbacks===0){callback();}};const restoredWidgetProps={};Object.entries(serializedState).forEach(([widgetId,props])=>{const widget=this.getWidgetInstance(widgetId);if(widget?.restoreSerializedState){++numCallbacks;const restoreResult=widget.restoreSerializedState(props,fireCallback);restoredWidgetProps[widgetId]={...this.state.widgetProps[widgetId],...restoreResult};}else {restoredWidgetProps[widgetId]=props;}});this.props.restoreUserInputFromSerializedState?.(serializedState,this.props.widgets);this.setState({widgetProps:restoredWidgetProps},()=>{setTimeout(fireCallback,0);});},this.findInternalWidgets=filterCriterion=>{let filterFunc;if(typeof filterCriterion==="string"){if(filterCriterion.indexOf(" ")!==-1){const widgetId=filterCriterion;filterFunc=(id,widgetInfo,widget)=>id===widgetId;}else {const widgetType=filterCriterion;filterFunc=(id,widgetInfo,widget)=>{return widgetInfo.type===widgetType};}}else {filterFunc=filterCriterion;}const results=this.widgetIds.filter(id=>{const widgetInfo=this._getWidgetInfo(id);const widget=this.getWidgetInstance(id);return filterFunc(id,widgetInfo,widget)}).map(this.getWidgetInstance);return results},this.findWidgets=filterCriterion=>{return [...this.findInternalWidgets(filterCriterion),...this.props.findExternalWidgets(filterCriterion)]},this.getWidgetInstance=id=>{const ref=this._widgetContainers.get(makeContainerId(id));if(!ref){return null}return ref.getWidget()},this._onWidgetFocus=(id,focusPath=[])=>{if(!_.isArray(focusPath)){throw new PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!_.isEqual(fullPath,blurringFocusPath)){return}_.defer(()=>{if(_.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.getContent=(props,state)=>{return state.jiptContent||props.content},this.shouldRenderJiptPlaceholder=(props,state)=>{return getDependencies().JIPT.useJIPT&&state.jiptContent==null&&props.content.indexOf("crwdns")!==-1},this.replaceJiptContent=(content,paragraphIndex)=>{if(paragraphIndex==null){this.setState({jiptContent:content});}else {const codeFenceRegex=/^\s*(`{3,}|~{3,})\s*(\S+)?\s*\n([\s\S]+?)\s*\1\s*$/;if(codeFenceRegex.test(content));else if(/\S\n\s*\n\S/.test(content)){content="$\\large{\\red{\\text{Please translate each "+"paragraph to a single paragraph.}}}$";}else if(/^\s*$/.test(content)){content="$\\large{\\red{\\text{Translated paragraph is "+"currently empty}}}$";}const allContent=this.getContent(this.props,this.state);const paragraphs=JiptParagraphs.parseToArray(allContent);paragraphs[paragraphIndex]=content;this.setState({jiptContent:JiptParagraphs.joinFromArray(paragraphs)});}},this.outputMarkdown=(ast,state)=>{if(_.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;state.paragraphIndex=i;const nodeOut=this.outputMarkdown(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}this._foundTextNodes=false;state.foundFullWidth=false;const output=this.outputNested(ast,state);let className;if(this.translationIndex!=null){className=null;}else {className=classNames$1({"perseus-paragraph-centered":!this._foundTextNodes,"perseus-paragraph-full-width":state.foundFullWidth&&ast.content.length===1});}return jsxRuntimeExports.jsx(QuestionParagraph,{className:className,translationIndex:this.translationIndex,paragraphIndex:state.paragraphIndex,inline:this.props.inline,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:output})},state.key)},this.outputNested=(ast,state)=>{if(_.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;const nodeOut=this.outputNested(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}return this.outputNode(ast,this.outputNested,state)},this.outputNode=(node,nestedOutput,state)=>{const apiOptions=this.getApiOptions();const imagePlaceholder=apiOptions.imagePlaceholder;if(node.type==="widget"){const widgetPlaceholder=apiOptions.widgetPlaceholder;if(widgetPlaceholder){return widgetPlaceholder}this._foundTextNodes=true;if(this.widgetIds.includes(node.id)){return jsxRuntimeExports.jsx("span",{className:"renderer-widget-error",children:["Widget [[","☃"," ",node.id,"]] already exists."].join("")},state.key)}this.widgetIds.push(node.id);return this.renderWidget(node.widgetType,node.id,state)}if(node.type==="blockMath"){const content=preprocessTex(node.content);const innerStyle={overflowX:"auto",overflowY:"hidden",paddingTop:10,paddingBottom:10,marginTop:-10,marginBottom:-10};if(apiOptions.isMobile){const margin=16;const outerStyle={marginLeft:-16,marginRight:-16};const horizontalPadding={paddingLeft:margin,paddingRight:margin};const mobileInnerStyle={...innerStyle,...styles$E.mobileZoomableParentFix};return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",style:outerStyle,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:{...mobileInnerStyle,...horizontalPadding},children:jsxRuntimeExports.jsx(ZoomableTeX,{children:content})})})},state.key)}return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:innerStyle,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{setAssetStatus:setAssetStatus,children:content})})})})},state.key)}if(node.type==="math"){const tex=node.content;return jsxRuntimeExports.jsx("span",{style:{whiteSpace:"nowrap"},children:jsxRuntimeExports.jsxs(ErrorBoundary,{children:[jsxRuntimeExports.jsx("span",{}),jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{onRender:this.props.onRender,setAssetStatus:setAssetStatus,children:tex})}),jsxRuntimeExports.jsx("span",{})]})},state.key)}if(node.type==="image"){if(imagePlaceholder){return imagePlaceholder}const extraAttrs=_.has(this.props.images,node.target)?this.props.images[node.target]:null;const responsive=!state.inTable;return jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{setAssetStatus:setAssetStatus,src:PerseusMarkdown.sanitizeUrl(node.target),alt:node.alt,title:node.title,responsive:responsive,onUpdate:this.props.onRender,zoomToFullSizeOnMobile:apiOptions.isMobile&&apiOptions.isArticle,...extraAttrs})})},state.key)}if(node.type==="columns"){this._isTwoColumn=true;return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)}if(node.type==="text"){if(rContainsNonWhitespace.test(node.content)){this._foundTextNodes=true;}if(imagePlaceholder&&rImageURL.test(node.content)){return imagePlaceholder}return node.content}if(node.type==="table"||node.type==="titledTable"){const output=PerseusMarkdown.ruleOutput(node,nestedOutput,{...state,isMobile:apiOptions.isMobile,inTable:true});if(!apiOptions.isMobile){return output}const outerStyle={marginLeft:-16,marginRight:-16};const innerStyle={paddingLeft:0,paddingRight:0};const mobileInnerStyle={...innerStyle,...styles$E.mobileZoomableParentFix};const wrappedOutput=jsxRuntimeExports.jsx("div",{style:{...mobileInnerStyle,overflowX:"auto"},children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(Zoomable,{animateHeight:true,children:output})})});return jsxRuntimeExports.jsx("div",{style:outerStyle,children:wrappedOutput})}return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)},this.handleRender=prevProps=>{const onRender=this.props.onRender;const oldOnRender=prevProps.onRender;if(onRender!==noopOnRender||oldOnRender!==noopOnRender){const $images=$(ReactDOM__default.findDOMNode(this)).find("img");if(oldOnRender!==noopOnRender){$images.off("load",oldOnRender);}if(onRender!==noopOnRender){$images.on("load",onRender);}}onRender();},this._setCurrentFocus=path=>{const apiOptions=this.getApiOptions();if(!isIdPathPrefix(path,this._currentFocus)){const prevFocus=this._currentFocus;if(prevFocus){this.blurPath(prevFocus);}this._currentFocus=path;apiOptions.onFocusChange(this._currentFocus,prevFocus);}},this.focus=()=>{let id;let focusResult;for(let i=0;i<this.widgetIds.length;i++){const widgetId=this.widgetIds[i];const widget=this.getWidgetInstance(widgetId);const widgetFocusResult=widget?.focus?.();if(widgetFocusResult){id=widgetId;focusResult=widgetFocusResult;break}}if(id){let path;if(typeof focusResult==="object"){path=[id].concat(focusResult.path||[]);Log.error("Renderer received a focus result of type 'object' "+"instead of the expected type 'boolean'",Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult),currentProps:JSON.stringify(this.state.widgetProps)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=_.first(path);const interWidgetPath=_.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__default.findDOMNode(widget)}},this.getInputPaths=()=>{const inputPaths=[];this.widgetIds.forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getInputPaths){const widgetInputPaths=widget.getInputPaths();widgetInputPaths.forEach(inputPath=>{const relativeInputPath=[widgetId].concat(inputPath);inputPaths.push(relativeInputPath);});}});return inputPaths},this.focusPath=path=>{if(_.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=_.first(path);const interWidgetPath=_.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!_.isEqual(this._currentFocus,path)){return}const widgetId=_.first(path);const interWidgetPath=_.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget){const blurWidget=this.getWidgetInstance(widgetId);blurWidget?.blurInputPath?.(interWidgetPath);}},this.blur=()=>{if(this._currentFocus){this.blurPath(this._currentFocus);}},this.serialize=()=>{const state={};_.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!_.isEmpty(s)){state[id]=s;}},this);return state},this.getWidgetIds=()=>{return this.widgetIds},this.handletranslationLintErrors=lintErrors=>{if(!this._isMounted){return}this.setState({translationLintErrors:lintErrors});};this._translationLinter=new TranslationLinter;this.state={jiptContent:null,translationLintErrors:[],lastUsedWidgetId:null,...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},highlightedWidgets:[],questionCompleted:false,showSolutions:"none",onRender:noopOnRender,onInteractWithWidget:function(){},findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,serializedState:null,linterContext:PerseusLinter.linterContextDefault};const styles$E={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
1667
+ const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return _.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return _.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!_.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;this.props.initializeUserInput?.(this.props.widgets,this.props.problemNum??0);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}UNSAFE_componentWillReceiveProps(nextProps){if(isDifferentQuestion(this.props,nextProps)){this.props.initializeUserInput?.(nextProps.widgets,nextProps.problemNum??0);this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!_.isEqual(this.state,nextState);const propsChanged=!_.isEqual(this.props,nextProps);return propsChanged||stateChanged}UNSAFE_componentWillUpdate(nextProps,nextState){const oldJipt=this.shouldRenderJiptPlaceholder(this.props,this.state);const newJipt=this.shouldRenderJiptPlaceholder(nextProps,nextState);const oldContent=this.getContent(this.props,this.state);const newContent=this.getContent(nextProps,nextState);const oldHighlightedWidgets=this.props.highlightedWidgets;const newHighlightedWidgets=nextProps.highlightedWidgets;this.reuseMarkdown=!oldJipt&&!newJipt&&oldContent===newContent&&_.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||_.isEqual(this.props.widgets,nextProps.widgets))&&this.props.linterContext.highlightLint===nextProps.linterContext.highlightLint&&oldHighlightedWidgets===newHighlightedWidgets;}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);this.widgetIds.forEach(id=>{const container=this._widgetContainers.get(makeContainerId(id));container?.replaceWidgetProps(this.getWidgetProps(id));});if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}_getWidgetIndexById(id){const widgetIndex=this.widgetIds.indexOf(id);if(widgetIndex<0){Log.error("Unable to get widget index in _getWidgetIndexById",Errors.Internal,{loggedMetadata:{widgets:JSON.stringify(this.props.widgets),widgetId:JSON.stringify(id)}});return 0}return widgetIndex}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.state.widgetProps[widgetId]||{};const widgetInfo=this.state.widgetInfo[widgetId];const reviewModeRubric=this.props.reviewMode&&widgetInfo?widgetInfo.options:null;if(!this._interactionTrackers){this._interactionTrackers={};}let interactionTracker=this._interactionTrackers[widgetId];if(!interactionTracker){interactionTracker=this._interactionTrackers[widgetId]=new InteractionTracker(apiOptions.trackInteraction,widgetInfo&&widgetInfo.type,widgetId,getTracking(widgetInfo&&widgetInfo.type));}return {...widgetProps,userInput:this.props.userInput?.[widgetId],widgetId:widgetId,widgetIndex:this._getWidgetIndexById(widgetId),alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,questionCompleted:this.props.questionCompleted,showSolutions:this.props.showSolutions,onFocus:_.partial(this._onWidgetFocus,widgetId),onBlur:_.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewModeRubric:reviewModeRubric,reviewMode:this.props.reviewMode,onChange:(newProps,cb,silent=false)=>{this._setWidgetProps(widgetId,newProps,cb,silent);},handleUserInput:newUserInput=>{const updatedUserInput={...this.props.userInput,[widgetId]:newUserInput};const emptyWidgetIds=emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,updatedUserInput,this.context.locale);const widgetsEmpty=emptyWidgetIds.length>0;this.props.handleUserInput?.(widgetId,newUserInput,widgetsEmpty);this.props.onInteractWithWidget(widgetId);},trackInteraction:interactionTracker.track,isLastUsedWidget:widgetId===this.state.lastUsedWidgetId}}emptyWidgets(){if(!this.props.userInput){throw new Error(`emptyWidgets called without providing userInput to Renderer`)}return emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale)}handleStateUpdate(id,cb,silent){this.setState(prevState=>{const lastUsedWidgetId=silent?prevState.lastUsedWidgetId:id;return {lastUsedWidgetId}},()=>{setTimeout(()=>{const cbResult=cb&&cb();if(!silent){this.props.onInteractWithWidget(id);}if(cbResult!==false){this._setCurrentFocus([id]);}},0);});}_setWidgetProps(id,nextWidgetProps,cb,silent){this.setState(prevState=>{const widgetProps=nextWidgetProps?{...prevState.widgetProps,[id]:{...prevState.widgetProps[id],...nextWidgetProps}}:prevState.widgetProps;return {widgetProps}},()=>{this.handleStateUpdate(id,cb,silent);});}getUserInput(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInput called without providing userInput to Renderer`)}return this.widgetIds.map(id=>{return userInput[id]})}getUserInputMap(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInputMap called without providing userInput to Renderer`)}return userInput}getPromptJSON(){const{content}=this.props;const widgetJSON={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);widgetJSON[id]=widget?.getPromptJSON?.()||{};});return {content,widgets:widgetJSON}}score(){if(!this.props.userInput){throw new Error(`score called without providing userInput to Renderer`)}const scores=scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();if(this.reuseMarkdown){return this.lastRenderedMarkdown}const content=this.getContent(this.props,this.state);this.widgetIds=[];if(this.shouldRenderJiptPlaceholder(this.props,this.state)){if(!this.translationIndex){this.translationIndex=getDependencies().rendererTranslationComponents.addComponent(this);}if(!apiOptions.isArticle){return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{"data-perseus-component-index":this.translationIndex,children:content})})}}this._isTwoColumn=false;const parsedMarkdown=this.props.inline?PerseusMarkdown.parseInline(content,{isJipt:this.translationIndex!=null}):PerseusMarkdown.parse(content,{isJipt:this.translationIndex!=null});if(this.props.linterContext.highlightLint){const fullLinterContext={content:this.props.content,widgets:this.props.widgets,...this.props.linterContext};PerseusLinter.runLinter(parsedMarkdown,fullLinterContext,true);this._translationLinter.applyLintErrors(parsedMarkdown,[...this.state.translationLintErrors,...this.props.legacyPerseusLint||[]]);}const markdownContents=this.outputMarkdown(parsedMarkdown,{baseElements:apiOptions.baseElements});const className=classNames$1({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});this.lastRenderedMarkdown=jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})});return this.lastRenderedMarkdown}constructor(props){super(props),this._widgetContainers=new Map,this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions}},this._getInitialWidgetState=props=>{const allWidgetInfo=applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{problemNum}=props;const widgetsStartProps={};const{strings}=this.props;entries(allWidgetInfo).forEach(([key,widgetInfo])=>{widgetsStartProps[key]=getRendererPropsForWidgetInfo(widgetInfo,strings,problemNum);});return widgetsStartProps},this._getDefaultWidgetInfo=widgetId=>{const widgetIdParts=Util.rTypeFromWidgetId.exec(widgetId);if(widgetIdParts==null){return {}}return {type:widgetIdParts[1],graded:true,options:{}}},this._getWidgetInfo=widgetId=>{return this.state.widgetInfo[widgetId]||this._getDefaultWidgetInfo(widgetId)},this.renderWidget=(impliedType,id,state)=>{const widgetInfo=this.state.widgetInfo[id];if(widgetInfo&&widgetInfo.alignment==="full-width"){state.foundFullWidth=true;}if(widgetInfo){const type=widgetInfo&&widgetInfo.type||impliedType;const shouldHighlight=_.contains(this.props.highlightedWidgets,id);return jsxRuntimeExports.jsx(WidgetContainer,{id:id,ref:node=>{const containerId=makeContainerId(id);if(node!=null){this._widgetContainers.set(containerId,node);}else {this._widgetContainers.delete(containerId);}},type:type,initialProps:this.getWidgetProps(id),shouldHighlight:shouldHighlight,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return mapObject(widgetProps||this.state.widgetProps,(props,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return props})},this.findInternalWidgets=filterCriterion=>{let filterFunc;if(typeof filterCriterion==="string"){if(filterCriterion.indexOf(" ")!==-1){const widgetId=filterCriterion;filterFunc=(id,widgetInfo,widget)=>id===widgetId;}else {const widgetType=filterCriterion;filterFunc=(id,widgetInfo,widget)=>{return widgetInfo.type===widgetType};}}else {filterFunc=filterCriterion;}const results=this.widgetIds.filter(id=>{const widgetInfo=this._getWidgetInfo(id);const widget=this.getWidgetInstance(id);return filterFunc(id,widgetInfo,widget)}).map(this.getWidgetInstance);return results},this.findWidgets=filterCriterion=>{return [...this.findInternalWidgets(filterCriterion),...this.props.findExternalWidgets(filterCriterion)]},this.getWidgetInstance=id=>{const ref=this._widgetContainers.get(makeContainerId(id));if(!ref){return null}return ref.getWidget()},this._onWidgetFocus=(id,focusPath=[])=>{if(!_.isArray(focusPath)){throw new PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!_.isEqual(fullPath,blurringFocusPath)){return}_.defer(()=>{if(_.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.getContent=(props,state)=>{return state.jiptContent||props.content},this.shouldRenderJiptPlaceholder=(props,state)=>{return getDependencies().JIPT.useJIPT&&state.jiptContent==null&&props.content.indexOf("crwdns")!==-1},this.replaceJiptContent=(content,paragraphIndex)=>{if(paragraphIndex==null){this.setState({jiptContent:content});}else {const codeFenceRegex=/^\s*(`{3,}|~{3,})\s*(\S+)?\s*\n([\s\S]+?)\s*\1\s*$/;if(codeFenceRegex.test(content));else if(/\S\n\s*\n\S/.test(content)){content="$\\large{\\red{\\text{Please translate each "+"paragraph to a single paragraph.}}}$";}else if(/^\s*$/.test(content)){content="$\\large{\\red{\\text{Translated paragraph is "+"currently empty}}}$";}const allContent=this.getContent(this.props,this.state);const paragraphs=JiptParagraphs.parseToArray(allContent);paragraphs[paragraphIndex]=content;this.setState({jiptContent:JiptParagraphs.joinFromArray(paragraphs)});}},this.outputMarkdown=(ast,state)=>{if(_.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;state.paragraphIndex=i;const nodeOut=this.outputMarkdown(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}this._foundTextNodes=false;state.foundFullWidth=false;const output=this.outputNested(ast,state);let className;if(this.translationIndex!=null){className=null;}else {className=classNames$1({"perseus-paragraph-centered":!this._foundTextNodes,"perseus-paragraph-full-width":state.foundFullWidth&&ast.content.length===1});}return jsxRuntimeExports.jsx(QuestionParagraph,{className:className,translationIndex:this.translationIndex,paragraphIndex:state.paragraphIndex,inline:this.props.inline,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:output})},state.key)},this.outputNested=(ast,state)=>{if(_.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;const nodeOut=this.outputNested(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}return this.outputNode(ast,this.outputNested,state)},this.outputNode=(node,nestedOutput,state)=>{const apiOptions=this.getApiOptions();const imagePlaceholder=apiOptions.imagePlaceholder;if(node.type==="widget"){const widgetPlaceholder=apiOptions.widgetPlaceholder;if(widgetPlaceholder){return widgetPlaceholder}this._foundTextNodes=true;if(this.widgetIds.includes(node.id)){return jsxRuntimeExports.jsx("span",{className:"renderer-widget-error",children:["Widget [[","☃"," ",node.id,"]] already exists."].join("")},state.key)}this.widgetIds.push(node.id);return this.renderWidget(node.widgetType,node.id,state)}if(node.type==="blockMath"){const content=preprocessTex(node.content);const innerStyle={overflowX:"auto",overflowY:"hidden",paddingTop:10,paddingBottom:10,marginTop:-10,marginBottom:-10};if(apiOptions.isMobile){const margin=16;const outerStyle={marginLeft:-16,marginRight:-16};const horizontalPadding={paddingLeft:margin,paddingRight:margin};const mobileInnerStyle={...innerStyle,...styles$E.mobileZoomableParentFix};return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",style:outerStyle,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:{...mobileInnerStyle,...horizontalPadding},children:jsxRuntimeExports.jsx(ZoomableTeX,{children:content})})})},state.key)}return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:innerStyle,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{setAssetStatus:setAssetStatus,children:content})})})})},state.key)}if(node.type==="math"){const tex=node.content;return jsxRuntimeExports.jsx("span",{style:{whiteSpace:"nowrap"},children:jsxRuntimeExports.jsxs(ErrorBoundary,{children:[jsxRuntimeExports.jsx("span",{}),jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{onRender:this.props.onRender,setAssetStatus:setAssetStatus,children:tex})}),jsxRuntimeExports.jsx("span",{})]})},state.key)}if(node.type==="image"){if(imagePlaceholder){return imagePlaceholder}const extraAttrs=_.has(this.props.images,node.target)?this.props.images[node.target]:null;const responsive=!state.inTable;return jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{setAssetStatus:setAssetStatus,src:PerseusMarkdown.sanitizeUrl(node.target),alt:node.alt,title:node.title,responsive:responsive,onUpdate:this.props.onRender,zoomToFullSizeOnMobile:apiOptions.isMobile&&apiOptions.isArticle,...extraAttrs})})},state.key)}if(node.type==="columns"){this._isTwoColumn=true;return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)}if(node.type==="text"){if(rContainsNonWhitespace.test(node.content)){this._foundTextNodes=true;}if(imagePlaceholder&&rImageURL.test(node.content)){return imagePlaceholder}return node.content}if(node.type==="table"||node.type==="titledTable"){const output=PerseusMarkdown.ruleOutput(node,nestedOutput,{...state,isMobile:apiOptions.isMobile,inTable:true});if(!apiOptions.isMobile){return output}const outerStyle={marginLeft:-16,marginRight:-16};const innerStyle={paddingLeft:0,paddingRight:0};const mobileInnerStyle={...innerStyle,...styles$E.mobileZoomableParentFix};const wrappedOutput=jsxRuntimeExports.jsx("div",{style:{...mobileInnerStyle,overflowX:"auto"},children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(Zoomable,{animateHeight:true,children:output})})});return jsxRuntimeExports.jsx("div",{style:outerStyle,children:wrappedOutput})}return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)},this.handleRender=prevProps=>{const onRender=this.props.onRender;const oldOnRender=prevProps.onRender;if(onRender!==noopOnRender||oldOnRender!==noopOnRender){const $images=$(ReactDOM__default.findDOMNode(this)).find("img");if(oldOnRender!==noopOnRender){$images.off("load",oldOnRender);}if(onRender!==noopOnRender){$images.on("load",onRender);}}onRender();},this._setCurrentFocus=path=>{const apiOptions=this.getApiOptions();if(!isIdPathPrefix(path,this._currentFocus)){const prevFocus=this._currentFocus;if(prevFocus){this.blurPath(prevFocus);}this._currentFocus=path;apiOptions.onFocusChange(this._currentFocus,prevFocus);}},this.focus=()=>{let id;let focusResult;for(let i=0;i<this.widgetIds.length;i++){const widgetId=this.widgetIds[i];const widget=this.getWidgetInstance(widgetId);const widgetFocusResult=widget?.focus?.();if(widgetFocusResult){id=widgetId;focusResult=widgetFocusResult;break}}if(id){let path;if(typeof focusResult==="object"){path=[id].concat(focusResult.path||[]);Log.error("Renderer received a focus result of type 'object' "+"instead of the expected type 'boolean'",Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult),currentProps:JSON.stringify(this.state.widgetProps)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=_.first(path);const interWidgetPath=_.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__default.findDOMNode(widget)}},this.getInputPaths=()=>{const inputPaths=[];this.widgetIds.forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getInputPaths){const widgetInputPaths=widget.getInputPaths();widgetInputPaths.forEach(inputPath=>{const relativeInputPath=[widgetId].concat(inputPath);inputPaths.push(relativeInputPath);});}});return inputPaths},this.focusPath=path=>{if(_.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=_.first(path);const interWidgetPath=_.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!_.isEqual(this._currentFocus,path)){return}const widgetId=_.first(path);const interWidgetPath=_.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget){const blurWidget=this.getWidgetInstance(widgetId);blurWidget?.blurInputPath?.(interWidgetPath);}},this.blur=()=>{if(this._currentFocus){this.blurPath(this._currentFocus);}},this.serialize=()=>{const state={};_.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!_.isEmpty(s)){state[id]=s;}},this);return state},this.getWidgetIds=()=>{return this.widgetIds},this.handletranslationLintErrors=lintErrors=>{if(!this._isMounted){return}this.setState({translationLintErrors:lintErrors});};this._translationLinter=new TranslationLinter;this.state={jiptContent:null,translationLintErrors:[],lastUsedWidgetId:null,...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},highlightedWidgets:[],questionCompleted:false,showSolutions:"none",onRender:noopOnRender,onInteractWithWidget:function(){},findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,linterContext:PerseusLinter.linterContextDefault};const styles$E={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
1668
1668
 
1669
1669
  const{captureScratchpadTouchStart: captureScratchpadTouchStart$2}=Util;const InputWithExamples=forwardRef(function InputWithExamples({shouldShowExamples=true,onFocus=()=>{},onBlur=()=>{},disabled=false,linterContext=PerseusLinter.linterContextDefault,className="",...props},ref){const context=React.useContext(PerseusI18nContext);const inputRef=React.useRef(null);const[inputFocused,setInputFocused]=React.useState(false);const id=useId();const ariaId=`aria-for-${id}`;useImperativeHandle(ref,()=>({current:inputRef.current,focus:()=>{if(inputRef.current){inputRef.current.focus();}},blur:()=>{if(inputRef.current){inputRef.current.blur();}}}));const getInputClassName=()=>{let inputClassName=ClassNames.INPUT;if(inputFocused){inputClassName+=" "+ClassNames.FOCUSED;}if(className){inputClassName+=" "+className;}return inputClassName};const handleFocus=()=>{onFocus();setInputFocused(true);};const handleBlur=()=>{onBlur();setInputFocused(false);};const renderInput=()=>{const examplesAria=shouldShowExamples?`${props.examples[0]}
1670
1670
  ${props.examples.slice(1).join(", or\n")}`.replaceAll("*","").replaceAll("$","").replaceAll("\\ \\text{pi}"," pi").replaceAll("\\ "," and "):"";const inputProps={id:id,"aria-describedby":shouldShowExamples?ariaId:undefined,ref:inputRef,className:getInputClassName(),labelText:props.labelText,value:props.value,onFocus:handleFocus,onBlur:handleBlur,disabled:disabled,style:props.style,onChange:props.onChange,onTouchStart:captureScratchpadTouchStart$2,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",spellCheck:"false"};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(TextInput,{...inputProps}),jsxRuntimeExports.jsx("span",{id:ariaId,style:{display:"none"},children:examplesAria})]})};const renderTooltipContent=()=>{return jsxRuntimeExports.jsx(TooltipContent,{children:jsxRuntimeExports.jsx("div",{id:id,className:"input-with-examples-tooltip",children:jsxRuntimeExports.jsx(Renderer,{content:examplesContent,linterContext:PerseusLinter.pushContextStack(linterContext,"input-with-examples"),strings:context.strings})})})};const examplesContent=props.examples.length<=2?props.examples.join(" "):props.examples.map((example,index)=>{return index===0&&example.startsWith("**")?`${example}
@@ -1680,7 +1680,7 @@ const NumericInputComponent=forwardRef(function NumericInputComponent(props,ref)
1680
1680
 
1681
1681
  class NumericInput extends React.Component{getPromptJSON(){return getPromptJSON$r(this.props)}getSerializedState(){const{userInput,answers:_,...rest}=this.props;return {...rest,currentValue:userInput.currentValue}}render(){return jsxRuntimeExports.jsx(NumericInputComponent,{...this.props,answerForms:normalizeCorrectAnswerForms(this.props.answers),ref:this.inputRef})}constructor(...args){super(...args),this.inputRef=React.createRef(),this.focus=()=>{this.inputRef.current?.focus();return true},this.focusInputPath=()=>{this.inputRef.current?.focus();},this.blurInputPath=()=>{this.inputRef.current?.blur();},this.getInputPaths=()=>{return [[]]};}}NumericInput.defaultProps={size:"normal",rightAlign:false,apiOptions:ApiOptions.defaults,coefficient:false,answerForms:[],labelText:"",linterContext:linterContextDefault,userInput:{currentValue:""}};function getStartUserInput$h(){return {currentValue:""}}function getUserInputFromSerializedState$g(serializedState){return {currentValue:serializedState.currentValue}}var NumericInput$1 = {name:"numeric-input",displayName:"Numeric input",widget:NumericInput,isLintable:true,getOneCorrectAnswerFromRubric(rubric){const correctAnswers=rubric.answers.filter(answer=>answer.status==="correct");const answerStrings=correctAnswers.map(answer=>{const format=answer.answerForms&&answer.answerForms[0]?answer.answerForms[0]:"decimal";let answerString=KhanMath.toNumericString(answer.value,format);if(answer.maxError){answerString+=" ± "+KhanMath.toNumericString(answer.maxError,format);}return answerString});if(answerStrings.length===0){return}return answerStrings[0]},getStartUserInput: getStartUserInput$h,getUserInputFromSerializedState: getUserInputFromSerializedState$g};
1682
1682
 
1683
- const getPromptJSON$q=(renderProps,userInput)=>{const choices=renderProps.choices||[];const options=choices.map(choice=>{const option={value:choice.content};if(choice.rationale){option.rationale=choice.rationale;}return option});return {type:"radio",hasNoneOfTheAbove:!!renderProps.hasNoneOfTheAbove,options,userInput:{selectedOptions:userInput?.selectedChoiceIds??[]}}};
1683
+ const getPromptJSON$q=(renderProps,userInput)=>{const choices=renderProps.choices||[];const options=choices.map(choice=>{const option={value:choice.content,id:choice.id};if(choice.rationale){option.rationale=choice.rationale;}return option});return {type:"radio",hasNoneOfTheAbove:!!renderProps.hasNoneOfTheAbove,options,userInput:{selectedOptions:userInput?.selectedChoiceIds??[]}}};
1684
1684
 
1685
1685
  var styles$C = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
1686
1686
 
@@ -1696,7 +1696,7 @@ const Choice$2=props=>{const showCorrectness=props.showCorrectness;const buttonR
1696
1696
 
1697
1697
  var styles$z = {"container":"perseus_dzsult1u","choiceList":"perseus_HSvzOAAR","content":"perseus_A5d7KcQj","instructions":"perseus_skOlpdjN","rationale":"perseus_y4m8wyRd","isCorrect":"perseus_IfCbxIVP","reviewAnswers":"perseus_QYlQJ6BF"};
1698
1698
 
1699
- function getChoiceLetter(pos,strings){const lettersString=strings.letters;const letters=lettersString.split(" ");if(pos<letters.length){return letters[pos]}return " "}function getUserInputFromSerializedState$f(props,unshuffle=true){const selectedChoiceIds=[];if(props.choiceStates){const choiceStates=props.choiceStates;for(let i=0;i<choiceStates.length;i++){if(choiceStates[i].selected){selectedChoiceIds.push(props.choices[i].id);}}return {selectedChoiceIds}}const{values}=props;if(values){const valuesLength=values.length;for(let i=0;i<valuesLength&&i<props.choices.length;i++){if(values[i]){selectedChoiceIds.push(props.choices[i].id);}}return {selectedChoiceIds}}return {selectedChoiceIds}}
1699
+ function getChoiceLetter(pos,strings){const lettersString=strings.letters;const letters=lettersString.split(" ");if(pos<letters.length){return letters[pos]}return " "}function getUserInputFromSerializedState$f(serializedState){const selectedChoiceIds=[];if(serializedState.choiceStates){const choiceStates=serializedState.choiceStates;for(let i=0;i<choiceStates.length;i++){if(choiceStates[i].selected){selectedChoiceIds.push(serializedState.choices[i].id);}}return {selectedChoiceIds}}return {selectedChoiceIds}}function moveNoneOfTheAboveToEnd(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices}function enforceOrdering(choices,strings){const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>_.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices}function choiceTransform(choices,randomize,strings,seed){const choicesWithMetadata=choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return moveNoneOfTheAboveToEnd(enforceOrdering(randomize?shuffle(choicesWithMetadata,seed):choicesWithMetadata,strings))}
1700
1700
 
1701
1701
  const getInstructionsText$1=({multipleSelect,countChoices,numCorrect,strings})=>{if(multipleSelect){if(usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer};
1702
1702
 
@@ -1734,9 +1734,9 @@ function isPassageWidget(widget){return widget instanceof Passage}
1734
1734
 
1735
1735
  const EN_DASH$1="–";class PassageRef extends React.Component{componentDidMount(){this._isMounted=true;this._deferredUpdateRange();this._throttledUpdateRange=_.throttle(this._deferredUpdateRange,500);window.addEventListener("resize",this._throttledUpdateRange);}shouldComponentUpdate(nextProps,nextState){return !_.isEqual(this.props,nextProps)||!_.isEqual(this.state,nextState)}componentDidUpdate(){this._deferredUpdateRange();}componentWillUnmount(){window.removeEventListener("resize",this._throttledUpdateRange);this._isMounted=false;}getPromptJSON(){return getPromptJSON$p(this.props)}render(){const{strings}=this.context;const lineRange=this.state.lineRange;let lineRangeOutput;if(!lineRange){lineRangeOutput=strings.lineRange({lineRange:`?${EN_DASH$1}?`});}else if(lineRange[0]===lineRange[1]){lineRangeOutput=strings.lineNumber({lineNumber:String(lineRange[0])});}else {lineRangeOutput=strings.lineRange({lineRange:lineRange[0]+EN_DASH$1+lineRange[1]});}let summaryOutput;if(this.props.summaryText){const summaryTree=PerseusMarkdown.parseInline(this.props.summaryText);summaryOutput=jsxRuntimeExports.jsxs("span",{"aria-hidden":true,children:[" ","(“",PerseusMarkdown.basicOutput(summaryTree),"”)"]});}else {summaryOutput=null;}return jsxRuntimeExports.jsxs("span",{children:[lineRangeOutput,summaryOutput,lineRange&&jsxRuntimeExports.jsx("div",{className:"perseus-sr-only",children:this.state.content})]})}constructor(...args){super(...args),this.displayName="PassageRef",this.isWidget=true,this.state={lineRange:null,content:null},this._deferredUpdateRange=()=>{_.defer(this._updateRange);},this._updateRange=()=>{const passage=this.props.findWidgets("passage "+this.props.passageNumber).filter(isPassageWidget)[0];const refInfo=passage?.getReference(this.props.referenceNumber);if(this._isMounted){if(refInfo){this.setState({lineRange:[refInfo.startLine,refInfo.endLine],content:refInfo.content});}else {this.setState({lineRange:null,content:null});}}};}}PassageRef.contextType=PerseusI18nContext;PassageRef.defaultProps={passageNumber:1,referenceNumber:1,summaryText:""};var PassageRef$1 = {name:"passage-ref",displayName:"PassageRef (SAT only)",hidden:true,widget:PassageRef,version:passageRefLogic.version};
1736
1736
 
1737
- const getChoiceStates=({choices,isStatic,showSolutions,choiceStates,values})=>{const defaultState={selected:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false};if(isStatic||showSolutions==="all"){return choices.map(choice=>({...defaultState,selected:!!choice.correct,readOnly:true,rationaleShown:true,correctnessShown:true}))}if(choiceStates){return choiceStates}if(values){return values.map(val=>({...defaultState,selected:val}))}return choices.map(()=>({...defaultState}))};const parseNestedWidgets=content=>{let nextPassageRefId=1;const extractedWidgets={};const parsedContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(_,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;extractedWidgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return {parsedContent,extractedWidgets}};
1737
+ const getChoiceStates=({choices,isStatic,showSolutions,choiceStates})=>{const defaultState={selected:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false};if(isStatic||showSolutions==="all"){return choices.map(choice=>({...defaultState,selected:!!choice.correct,readOnly:true,rationaleShown:true,correctnessShown:true}))}if(choiceStates){return choiceStates}return choices.map(()=>({...defaultState}))};const parseNestedWidgets=content=>{let nextPassageRefId=1;const extractedWidgets={};const parsedContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(_,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;extractedWidgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return {parsedContent,extractedWidgets}};
1738
1738
 
1739
- const MultipleChoiceWidget=forwardRef(function MultipleChoiceWidget(props,ref){const{choices=[],multipleSelect=false,countChoices=false,showSolutions="none",choiceStates,values,reviewModeRubric,questionCompleted,strings=mockStrings,static:isStatic,apiOptions,onChange,trackInteraction,findWidgets,reviewMode}=props;useImperativeHandle(ref,()=>({getPromptJSON:()=>{return getPromptJSON$q(props,props.userInput)}}),[props]);const renderContent=(content="")=>{const{parsedContent,extractedWidgets}=parseNestedWidgets(content);const linterContext={contentType:"radio",highlightLint:false,paths:[],stack:[]};return jsxRuntimeExports.jsx(Renderer,{content:parsedContent,widgets:extractedWidgets,findExternalWidgets:findWidgets,alwaysUpdate:true,linterContext:linterContext,strings:strings},"choiceContentRenderer")};const handleChoiceChange=(choiceId,newCheckedState)=>{const checkedChoiceIds=[];if(newCheckedState&&!multipleSelect){checkedChoiceIds.push(choiceId);}else if(newCheckedState&&multipleSelect){const currentSelectedIds=choiceStates?choiceStates.map((state,i)=>({selected:state.selected,id:choices[i].id})).filter(choice=>choice.selected).map(choice=>choice.id):[];checkedChoiceIds.push(...currentSelectedIds,choiceId);}else {const currentSelectedIds=choiceStates?choiceStates.map((state,i)=>({selected:state.selected,id:choices[i].id})).filter(choice=>choice.selected&&choice.id!==choiceId).map(choice=>choice.id):[];checkedChoiceIds.push(...currentSelectedIds);}const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{const choiceId=choices[i].id;choiceState.selected=checkedChoiceIds.includes(choiceId);});onChange({choiceStates:newChoiceStates});trackInteraction();};const buildChoiceProps=choiceStates=>{return choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,previouslyAnswered}=choiceStates[i];const reviewChoice=reviewModeRubric?.choices[i];return {id:choice.id,content:renderContent(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:renderContent(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(questionCompleted&&selected),previouslyAnswered}})};const prepareChoicesProps=()=>{const processedChoiceStates=getChoiceStates({choices,isStatic,showSolutions,choiceStates,values});return buildChoiceProps(processedChoiceStates)};const choicesProps=prepareChoicesProps();const numCorrect=props.numCorrect;const isReviewMode=reviewMode||isStatic||showSolutions==="all";const onChoiceChange=apiOptions.readOnly||isReviewMode?()=>{}:handleChoiceChange;return jsxRuntimeExports.jsx(MultipleChoiceComponent,{reviewMode:isReviewMode,multipleSelect:multipleSelect,countChoices:countChoices,numCorrect:numCorrect,choices:choicesProps,onChoiceChange:onChoiceChange})});const Radio$3=MultipleChoiceWidget;
1739
+ const MultipleChoiceWidget=forwardRef(function MultipleChoiceWidget(props,ref){const{choices=[],multipleSelect=false,countChoices=false,showSolutions="none",choiceStates,reviewModeRubric,questionCompleted,static:isStatic,apiOptions,onChange,trackInteraction,findWidgets,reviewMode}=props;const{strings}=usePerseusI18n();useImperativeHandle(ref,()=>({getPromptJSON:()=>{return getPromptJSON$q(props,props.userInput)}}),[props]);const renderContent=(content="")=>{const{parsedContent,extractedWidgets}=parseNestedWidgets(content);const linterContext={contentType:"radio",highlightLint:false,paths:[],stack:[]};return jsxRuntimeExports.jsx(Renderer,{content:parsedContent,widgets:extractedWidgets,findExternalWidgets:findWidgets,alwaysUpdate:true,linterContext:linterContext,strings:strings},"choiceContentRenderer")};const handleChoiceChange=(choiceId,newCheckedState)=>{const checkedChoiceIds=[];if(newCheckedState&&!multipleSelect){checkedChoiceIds.push(choiceId);}else if(newCheckedState&&multipleSelect){const currentSelectedIds=choiceStates?choiceStates.map((state,i)=>({selected:state.selected,id:choices[i].id})).filter(choice=>choice.selected).map(choice=>choice.id):[];checkedChoiceIds.push(...currentSelectedIds,choiceId);}else {const currentSelectedIds=choiceStates?choiceStates.map((state,i)=>({selected:state.selected,id:choices[i].id})).filter(choice=>choice.selected&&choice.id!==choiceId).map(choice=>choice.id):[];checkedChoiceIds.push(...currentSelectedIds);}const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{const choiceId=choices[i].id;choiceState.selected=checkedChoiceIds.includes(choiceId);});onChange({choiceStates:newChoiceStates});trackInteraction();};const buildChoiceProps=choiceStates=>{return choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,previouslyAnswered}=choiceStates[i];const reviewChoice=reviewModeRubric?.choices[i];return {id:choice.id,content:renderContent(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:renderContent(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(questionCompleted&&selected),previouslyAnswered}})};const prepareChoicesProps=()=>{const processedChoiceStates=getChoiceStates({choices,isStatic,showSolutions,choiceStates});return buildChoiceProps(processedChoiceStates)};const choicesProps=prepareChoicesProps();const numCorrect=props.numCorrect;const isReviewMode=reviewMode||isStatic||showSolutions==="all";const onChoiceChange=apiOptions.readOnly||isReviewMode?()=>{}:handleChoiceChange;return jsxRuntimeExports.jsx(MultipleChoiceComponent,{reviewMode:isReviewMode,multipleSelect:multipleSelect,countChoices:countChoices,numCorrect:numCorrect,choices:choicesProps,onChoiceChange:onChoiceChange})});const Radio$3=MultipleChoiceWidget;
1740
1740
 
1741
1741
  const{pureXsMax,pureSmMax,pureMdMin,pureMdMax,pureLgMin,pureLgMax,pureXlMin}=constants;var mediaQueries = {md:`@media screen and (min-width: ${pureMdMin}) and `+`(max-width: ${pureMdMax})`,xl:`@media screen and (min-width: ${pureXlMin})`,xsOrSmaller:`@media screen and (max-width: ${pureXsMax})`,smOrSmaller:`@media screen and (max-width: ${pureSmMax})`,mdOrSmaller:`@media screen and (max-width: ${pureMdMax})`,lgOrSmaller:`@media screen and (max-width: ${pureLgMax})`,lgOrLarger:`@media screen and (min-width: ${pureLgMin})`};
1742
1742
 
@@ -1758,11 +1758,11 @@ const ChoiceNoneAbove=function({content,forwardedRef,showContent=true,...rest}){
1758
1758
 
1759
1759
  const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;function getInstructionsText(multipleSelect,countChoices,numCorrect,strings){if(multipleSelect){if(usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer}const BaseRadio=function({apiOptions,reviewModeRubric,reviewMode,choices,editMode=false,multipleSelect=false,labelWrap,countChoices,numCorrect,isLastUsedWidget,onChange,registerFocusFunction}){const{strings}=usePerseusI18n();const prevReviewModeRubric=useRef();const choiceRefs=useRef([]);useEffect(()=>{if(apiOptions.canScrollPage&&isLastUsedWidget&&reviewModeRubric&&!prevReviewModeRubric.current){const checkedIndex=choices.findIndex(c=>c.checked);if(checkedIndex>=0){const ref=choiceRefs.current[checkedIndex];const anyNode=ReactDOM__default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){scrollElementIntoView(buttonNode);}}}prevReviewModeRubric.current=reviewModeRubric;},[apiOptions,choices,isLastUsedWidget,reviewModeRubric]);function updateChoice(choiceId,checked){const checkedChoiceIds=[];if(checked&&!multipleSelect){checkedChoiceIds.push(choiceId);}else if(checked&&multipleSelect){const currentCheckedIds=choices.filter(choice=>choice.checked).map(choice=>choice.id);checkedChoiceIds.push(...currentCheckedIds,choiceId);}else {const currentCheckedIds=choices.filter(choice=>choice.checked&&choice.id!==choiceId).map(choice=>choice.id);checkedChoiceIds.push(...currentCheckedIds);}onChange(checkedChoiceIds);}registerFocusFunction?.(choiceIndex=>{const ref=choiceRefs.current[choiceIndex||0];const anyNode=ReactDOM__default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){buttonNode.focus();}else {return false}return true});const isMobile=apiOptions.isMobile;const firstChoiceHighlighted=choices[0].highlighted;const lastChoiceHighlighted=choices[choices.length-1].highlighted;const className=classNames$1("perseus-widget-radio",!editMode&&"perseus-rendered-radio",css(styles$p.radio,styles$p.responsiveRadioContainer,firstChoiceHighlighted&&isMobile&&styles$p.radioContainerFirstHighlighted,lastChoiceHighlighted&&isMobile&&styles$p.radioContainerLastHighlighted));const instructionsClassName=classNames$1("instructions",css(styles$p.instructions,isMobile&&styles$p.instructionsMobile));const instructions=getInstructionsText(multipleSelect,countChoices,numCorrect,strings);const responsiveClassName=css(styles$p.responsiveFieldset);const fieldset=jsxRuntimeExports.jsxs("fieldset",{className:`perseus-widget-radio-fieldset ${responsiveClassName}`,children:[jsxRuntimeExports.jsx("legend",{className:"perseus-sr-only",children:instructions}),jsxRuntimeExports.jsx("div",{className:instructionsClassName,"aria-hidden":"true",children:instructions}),jsxRuntimeExports.jsx("ul",{className:className,style:{listStyle:"none"},children:choices.map((choice,i)=>{let Element=Choice$1;const ref=React.createRef();choiceRefs.current[i]=ref;const elementProps={id:choice.id,apiOptions:apiOptions,multipleSelect:multipleSelect,checked:choice.checked,previouslyAnswered:choice.previouslyAnswered,reviewMode,correct:choice.correct,rationale:choice.rationale,content:choice.content,disabled:apiOptions.readOnly||choice.disabled,showCorrectness:reviewMode||!!choice.showCorrectness,showRationale:choice.hasRationale&&(reviewMode||choice.showRationale),pos:i,onChange:newValues=>{if(editMode){return}updateChoice(choice.id,newValues.checked);}};if(choice.isNoneOfTheAbove){Element=ChoiceNoneAbove$1;_.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const nextChoice=choices[i+1];const nextChoiceHighlighted=!!nextChoice&&nextChoice.highlighted;const aphroditeClassName=checked=>{return css(styles$p.item,styles$p.responsiveItem,checked&&styles$p.selectedItem,checked&&choice.highlighted&&styles$p.aboveBackdrop,checked&&choice.highlighted&&apiOptions.isMobile&&styles$p.aboveBackdropMobile,nextChoiceHighlighted&&apiOptions.isMobile&&styles$p.nextHighlighted)};aphroditeClassName(true);let correctnessClass;if(reviewMode&&reviewModeRubric){correctnessClass=reviewModeRubric.choices[i].correct?ClassNames.CORRECT:ClassNames.INCORRECT;}const className=classNames$1(aphroditeClassName(choice.checked),ClassNames.RADIO.OPTION,choice.checked&&ClassNames.RADIO.SELECTED,correctnessClass);let listElem=null;let clickHandler;if(editMode){clickHandler=e=>{let elem=e.target;while(elem&&elem!==listElem){if(elem.getAttribute("data-is-radio-icon")){updateChoice(choice.id,!choice.checked);return}elem=elem.parentNode;}};}return jsxRuntimeExports.jsx("li",{ref:e=>listElem=e,className:className,onClick:clickHandler,onTouchStart:labelWrap?undefined:captureScratchpadTouchStart$1,children:jsxRuntimeExports.jsx(Element,{...elementProps,ref:ref})},choice.id)})})]});return jsxRuntimeExports.jsx("div",{className:css(styles$p.responsiveContainer),children:fieldset})};const styles$p=StyleSheet.create({instructions:{display:"block",color:gray17,fontSize:14,lineHeight:1.25,fontFamily:"inherit",fontStyle:"normal",fontWeight:"bold",marginBottom:16},instructionsMobile:{fontSize:18,[mediaQueries.smOrSmaller]:{fontSize:16},[mediaQueries.xl]:{fontSize:20}},radio:{padding:0},responsiveRadioContainer:{borderBottom:`1px solid ${radioBorderColor$1}`,borderTop:`1px solid ${radioBorderColor$1}`,width:"auto",[mediaQueries.smOrSmaller]:{marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin}},radioContainerFirstHighlighted:{borderTop:`1px solid rgba(0, 0, 0, 0)`},radioContainerLastHighlighted:{borderBottom:`1px solid rgba(0, 0, 0, 0)`},item:{marginLeft:20},responsiveItem:{marginLeft:0,padding:0,":not(:last-child)":{borderBottom:`1px solid ${radioBorderColor$1}`}},selectedItem:{background:"white"},aboveBackdrop:{position:"relative",zIndex:1062},aboveBackdropMobile:{boxShadow:"0 0 4px 0 rgba(0, 0, 0, 0.2),"+"0 0 2px 0 rgba(0, 0, 0, 0.1)",":not(:last-child)":{borderBottom:`1px solid rgba(0, 0, 0, 0)`}},nextHighlighted:{":not(:last-child)":{borderBottom:`1px solid rgba(0, 0, 0, 0)`}},responsiveContainer:{overflow:"auto",marginLeft:negativePhoneMargin,paddingLeft:phoneMargin},responsiveFieldset:{paddingRight:phoneMargin,minWidth:"auto"}});
1760
1760
 
1761
- let Radio$2 = class Radio extends React.Component{focus(choiceIndex){if(this.focusFunction){return this.focusFunction(choiceIndex)}return false}registerFocusFunction(fun){this.focusFunction=fun;}getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const{choices}=this.props;const{strings}=this.context;let choiceStates;if(this.props.static){choiceStates=choices.map(choice=>({selected:!!choice.correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.showSolutions==="all"){choiceStates=choices.map(({correct})=>({selected:!!correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.choiceStates){choiceStates=this.props.choiceStates;}else if(this.props.values){choiceStates=this.props.values.map(val=>({selected:val,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}else {choiceStates=choices.map(()=>({selected:false,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}const choicesProp=choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,highlighted,previouslyAnswered}=choiceStates[i];const reviewChoice=this.props.reviewModeRubric?.choices[i];return {id:choice.id,content:this._renderRenderer(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this._renderRenderer(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(this.props.questionCompleted&&selected),highlighted,previouslyAnswered:previouslyAnswered}});return jsxRuntimeExports.jsx(BaseRadio,{labelWrap:true,multipleSelect:this.props.multipleSelect,countChoices:this.props.countChoices,numCorrect:this.props.numCorrect,choices:choicesProp,onChange:this.updateChoices,reviewModeRubric:this.props.reviewModeRubric,reviewMode:this.props.reviewMode,deselectEnabled:this.props.deselectEnabled,apiOptions:this.props.apiOptions,isLastUsedWidget:this.props.isLastUsedWidget,registerFocusFunction:i=>this.registerFocusFunction(i)})}constructor(...args){super(...args),this._renderRenderer=(content="")=>{let nextPassageRefId=1;const widgets={};const modContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(match,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;widgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return jsxRuntimeExports.jsx(Renderer,{content:modContent,widgets:widgets,findExternalWidgets:this.props.findWidgets,alwaysUpdate:true,linterContext:{...this.props.linterContext,blockHighlight:true},strings:this.context.strings},"choiceContentRenderer")},this.updateChoices=checkedChoiceIds=>{const{choiceStates,choices}=this.props;const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{const choiceId=choices[i].id;choiceState.selected=checkedChoiceIds.includes(choiceId);});this.props.onChange({choiceStates:newChoiceStates});this.props.trackInteraction();};}};Radio$2.contextType=PerseusI18nContext;Radio$2.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:linterContextDefault,showSolutions:"none"};
1761
+ let Radio$2 = class Radio extends React.Component{focus(choiceIndex){if(this.focusFunction){return this.focusFunction(choiceIndex)}return false}registerFocusFunction(fun){this.focusFunction=fun;}getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const{choices}=this.props;const{strings}=this.context;let choiceStates;if(this.props.static){choiceStates=choices.map(choice=>({selected:!!choice.correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.showSolutions==="all"){choiceStates=choices.map(({correct})=>({selected:!!correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.choiceStates){choiceStates=this.props.choiceStates;}else {choiceStates=choices.map(()=>({selected:false,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}const choicesProp=choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,highlighted,previouslyAnswered}=choiceStates[i];const reviewChoice=this.props.reviewModeRubric?.choices[i];return {id:choice.id,content:this._renderRenderer(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this._renderRenderer(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(this.props.questionCompleted&&selected),highlighted,previouslyAnswered:previouslyAnswered}});return jsxRuntimeExports.jsx(BaseRadio,{labelWrap:true,multipleSelect:this.props.multipleSelect,countChoices:this.props.countChoices,numCorrect:this.props.numCorrect,choices:choicesProp,onChange:this.updateChoices,reviewModeRubric:this.props.reviewModeRubric,reviewMode:this.props.reviewMode,deselectEnabled:this.props.deselectEnabled,apiOptions:this.props.apiOptions,isLastUsedWidget:this.props.isLastUsedWidget,registerFocusFunction:i=>this.registerFocusFunction(i)})}constructor(...args){super(...args),this._renderRenderer=(content="")=>{let nextPassageRefId=1;const widgets={};const modContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(match,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;widgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return jsxRuntimeExports.jsx(Renderer,{content:modContent,widgets:widgets,findExternalWidgets:this.props.findWidgets,alwaysUpdate:true,linterContext:{...this.props.linterContext,blockHighlight:true},strings:this.context.strings},"choiceContentRenderer")},this.updateChoices=checkedChoiceIds=>{const{choiceStates,choices}=this.props;const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{const choiceId=choices[i].id;choiceState.selected=checkedChoiceIds.includes(choiceId);});this.props.onChange({choiceStates:newChoiceStates});this.props.trackInteraction();};}};Radio$2.contextType=PerseusI18nContext;Radio$2.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:linterContextDefault,showSolutions:"none"};
1762
1762
 
1763
- function initChoiceStates(choices){return choices.map(()=>({highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}))}let Radio$1 = class Radio extends Radio$2{UNSAFE_componentWillUpdate(nextProps){if(!_.isEqual(nextProps.choices,this.props.choices)){this.setState({choiceStates:initChoiceStates(nextProps.choices)});}}getSerializedState(){const{userInput:_,...rest}=this._mergePropsAndState();return {...rest}}_handleChange(arg){const newChoiceStates=arg.choiceStates;if(newChoiceStates){this.setState({choiceStates:newChoiceStates.map(choiceState=>{const{selected:_,...rest}=choiceState;return {...rest}})},()=>{const props=this._mergePropsAndState();const mergedProps={...props,choiceStates:deepClone(props.choiceStates||[]).map((choiceState,index)=>{return {...choiceState,selected:newChoiceStates[index].selected}})};const unshuffledUserInput=getUserInputFromSerializedState$f(mergedProps);this.props.handleUserInput(unshuffledUserInput);});}else {throw new Error("unhandled onChange call in Radio!")}}_mergePropsAndState(){return {...this.props,choiceStates:this.state.choiceStates?.map((choiceState,index)=>{const choice=this.props.choices[index];const selected=this.props.userInput?.selectedChoiceIds.includes(choice.id)??false;return {...choiceState,selected}}),onChange:arg=>this._handleChange(arg)}}focus(choiceIndex){if(this.radioRef.current?.focus){return this.radioRef.current.focus(choiceIndex)}return false}render(){const props=this._mergePropsAndState();return this.ffIsOn?jsxRuntimeExports.jsx(Radio$3,{...props}):jsxRuntimeExports.jsx(Radio$2,{ref:this.radioRef,...props})}constructor(props){super(props),this.ffIsOn=false,this.radioRef=React.createRef(),this.state={choiceStates:[]};this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;this.state={choiceStates:initChoiceStates(props.choices)};}};
1763
+ function initChoiceStates(choices){return choices.map(()=>({highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}))}let Radio$1 = class Radio extends Radio$2{UNSAFE_componentWillUpdate(nextProps){if(!_.isEqual(nextProps.choices,this.props.choices)){this.setState({choiceStates:initChoiceStates(nextProps.choices)});}}getSerializedState(){const{userInput:_,randomize:__,...rest}=this._mergePropsAndState();return {...rest}}getPromptJSON(){return this.radioRef.current.getPromptJSON()}_handleChange(arg){const newChoiceStates=arg.choiceStates;if(newChoiceStates){this.setState({choiceStates:newChoiceStates.map(choiceState=>{const{selected:_,...rest}=choiceState;return {...rest}})},()=>{const props=this._mergePropsAndState();const mergedProps={...props,choiceStates:deepClone(props.choiceStates||[]).map((choiceState,index)=>{return {...choiceState,selected:newChoiceStates[index].selected}})};const unshuffledUserInput=getUserInputFromSerializedState$f(mergedProps);this.props.handleUserInput(unshuffledUserInput);});}else {throw new Error("unhandled onChange call in Radio!")}}_mergePropsAndState(){const randomSeed=(this.props.problemNum??0)+(this.props.widgetIndex??0);const choices=[...choiceTransform(this.props.choices,this.props.randomize,this.context.strings,randomSeed)];return {...this.props,choices,choiceStates:this.state.choiceStates?.map((choiceState,index)=>{const choice=choices[index];const selected=this.props.userInput?.selectedChoiceIds.includes(choice.id)??false;return {...choiceState,selected}}),onChange:arg=>this._handleChange(arg)}}focus(choiceIndex){if(this.radioRef.current?.focus){return this.radioRef.current.focus(choiceIndex)}return false}render(){const props=this._mergePropsAndState();return this.ffIsOn?jsxRuntimeExports.jsx(Radio$3,{...props}):jsxRuntimeExports.jsx(Radio$2,{ref:this.radioRef,...props})}constructor(props){super(props),this.ffIsOn=false,this.radioRef=React.createRef(),this.state={choiceStates:[]};this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;this.state={choiceStates:initChoiceStates(props.choices)};}};
1764
1764
 
1765
- const _choiceTransform=(widgetOptions,strings)=>{const _maybeRandomize=function(array){return widgetOptions.randomize?randomizeArrayElements(array):array};const _addNoneOfAbove=function(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices};const enforceOrdering=choices=>{const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>_.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices};const choices=widgetOptions.choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return _addNoneOfAbove(enforceOrdering(_maybeRandomize(choices)))};const transform=(widgetOptions,strings)=>{const choices=_choiceTransform(widgetOptions,strings);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:_.pluck(choices,"correct")}};function getStartUserInput$g(){return {selectedChoiceIds:[]}}function getCorrectUserInput$6(options){return {selectedChoiceIds:options.choices.filter(option=>option.correct).map(option=>option.id)}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,transform,staticTransform:transform,getStartUserInput: getStartUserInput$g,getCorrectUserInput: getCorrectUserInput$6,version:radioLogic.version,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState,true)}};
1765
+ function getStartUserInput$g(){return {selectedChoiceIds:[]}}function getCorrectUserInput$6(options){return {selectedChoiceIds:options.choices.filter(option=>option.correct).map(option=>option.id)}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,getStartUserInput: getStartUserInput$g,getCorrectUserInput: getCorrectUserInput$6,version:radioLogic.version,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState)}};
1766
1766
 
1767
1767
  var basicWidgets = [Radio,InputNumber$1,NumericInput$1,Expression$1];
1768
1768
 
@@ -1790,7 +1790,7 @@ class DeprecatedStandin extends React__default.Component{render(){return jsxRunt
1790
1790
 
1791
1791
  const getPromptJSON$k=renderProps=>{return {type:"dropdown",options:{items:renderProps.choices.map(choice=>choice.content)},userInput:{selectedIndex:renderProps.userInput.value-1}}};
1792
1792
 
1793
- class Dropdown extends React.Component{getPromptJSON(){return getPromptJSON$k(this.props)}getSerializedState(){const{userInput,choices,...rest}=this.props;return {...rest,choices:choices.map(choice=>choice.content),selected:userInput.value}}restoreSerializedState(state){return {state,choices:state.choices.map(content=>({content}))}}render(){const children=[jsxRuntimeExports.jsx(OptionItem,{value:"0",disabled:true,label:jsxRuntimeExports.jsx(Renderer,{content:this.props.placeholder,strings:this.context.strings}),labelAsText:this.props.placeholder},"placeholder"),...this.props.choices.map((choice,i)=>jsxRuntimeExports.jsx(OptionItem,{value:String(i+1),label:jsxRuntimeExports.jsx(Renderer,{content:choice.content,strings:this.context.strings}),labelAsText:choice.content},String(i+1)))];return jsxRuntimeExports.jsx(Id,{children:dropdownId=>jsxRuntimeExports.jsxs(View,{onClick:e=>{e.stopPropagation();},onTouchStart:e=>{e.stopPropagation();},children:[this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:dropdownId,children:this.props.visibleLabel}),jsxRuntimeExports.jsx(SingleSelect,{id:dropdownId,placeholder:"",className:"perseus-dropdown",onChange:value=>this._handleChange(parseInt(value)),selectedValue:String(this.props.userInput.value),disabled:this.props.apiOptions.readOnly,"aria-label":this.props.ariaLabel||this.props.visibleLabel||this.context.strings.selectAnAnswer,showOpenerLabelAsText:false,children:children})]})})}constructor(...args){super(...args),this.focus=()=>{ReactDOM__default.findDOMNode(this).focus();return true},this._handleChangeEvent=e=>{this._handleChange(parseInt(e.target.value));},this._handleChange=selected=>{this.props.trackInteraction();this.props.handleUserInput({value:selected});};}}Dropdown.contextType=PerseusI18nContext;Dropdown.defaultProps={choices:[],placeholder:"",apiOptions:ApiOptions.defaults,userInput:{value:0}};function getUserInputFromSerializedState$c(serializedState){return {value:serializedState.selected}}function getStartUserInput$d(){return {value:0}}var Dropdown$1 = {name:"dropdown",displayName:"Drop down",widget:Dropdown,getStartUserInput: getStartUserInput$d,getUserInputFromSerializedState: getUserInputFromSerializedState$c};
1793
+ class Dropdown extends React.Component{getPromptJSON(){return getPromptJSON$k(this.props)}getSerializedState(){const{userInput,choices,...rest}=this.props;return {...rest,choices:choices.map(choice=>choice.content),selected:userInput.value}}render(){const children=[jsxRuntimeExports.jsx(OptionItem,{value:"0",disabled:true,label:jsxRuntimeExports.jsx(Renderer,{content:this.props.placeholder,strings:this.context.strings}),labelAsText:this.props.placeholder},"placeholder"),...this.props.choices.map((choice,i)=>jsxRuntimeExports.jsx(OptionItem,{value:String(i+1),label:jsxRuntimeExports.jsx(Renderer,{content:choice.content,strings:this.context.strings}),labelAsText:choice.content},String(i+1)))];return jsxRuntimeExports.jsx(Id,{children:dropdownId=>jsxRuntimeExports.jsxs(View,{onClick:e=>{e.stopPropagation();},onTouchStart:e=>{e.stopPropagation();},children:[this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:dropdownId,children:this.props.visibleLabel}),jsxRuntimeExports.jsx(SingleSelect,{id:dropdownId,placeholder:"",className:"perseus-dropdown",onChange:value=>this._handleChange(parseInt(value)),selectedValue:String(this.props.userInput.value),disabled:this.props.apiOptions.readOnly,"aria-label":this.props.ariaLabel||this.props.visibleLabel||this.context.strings.selectAnAnswer,showOpenerLabelAsText:false,children:children})]})})}constructor(...args){super(...args),this.focus=()=>{ReactDOM__default.findDOMNode(this).focus();return true},this._handleChangeEvent=e=>{this._handleChange(parseInt(e.target.value));},this._handleChange=selected=>{this.props.trackInteraction();this.props.handleUserInput({value:selected});};}}Dropdown.contextType=PerseusI18nContext;Dropdown.defaultProps={choices:[],placeholder:"",apiOptions:ApiOptions.defaults,userInput:{value:0}};function getUserInputFromSerializedState$c(serializedState){return {value:serializedState.selected}}function getStartUserInput$d(){return {value:0}}var Dropdown$1 = {name:"dropdown",displayName:"Drop down",widget:Dropdown,getStartUserInput: getStartUserInput$d,getUserInputFromSerializedState: getUserInputFromSerializedState$c};
1794
1794
 
1795
1795
  const USAGE="Usage:\n"+" this.change({propName: 5}, callback);\n"+' this.change("propName", 5, callback);\n'+' this.change("propName")';const _changeMultiple=function(component,newProps,callback){const currProps=excludeDenylistKeys(component.props);const nextProps=_.extend(currProps,newProps);component.props.onChange(nextProps,callback);};const _changeSingle=function(component,propName,value,callback){if(value===undefined){return _.partial(_changeSingle,component,propName)}const newProps={};newProps[propName]=value;_changeMultiple(component,newProps,callback);};const change=function(newPropsOrSinglePropName,propValue,callback){if(_.isObject(newPropsOrSinglePropName)&&callback===undefined){callback=propValue;return _changeMultiple(this,newPropsOrSinglePropName,callback)}if(typeof newPropsOrSinglePropName==="string"){return _changeSingle(this,newPropsOrSinglePropName,propValue,callback)}throw new PerseusError("Invalid types sent to this.change(): "+_.toArray(arguments).join()+"\n"+USAGE,Errors.Internal)};const propTypes={onChange:PropTypes.func.isRequired};
1796
1796
 
@@ -1808,7 +1808,7 @@ class FreeResponse extends React.Component{isOverLimit(){return !this.props.allo
1808
1808
 
1809
1809
  function getWidgetTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];return widget?.type??null}function getWidgetSubTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];const widgetType=widget?.type??null;switch(widgetType){case "interactive-graph":const graph=widget.options.graph;return graph?.type??null;default:return null}}function contentHasWidgetType(type,content,widgetMap){return getWidgetIdsFromContentByType(type,content,widgetMap).length>0}function getWidgetsMapFromItemData(itemData){return itemData.question.widgets}function getWidgetFromWidgetMap(widgetId,widgetMap){return widgetMap[widgetId]??null}function getWidgetsFromWidgetMap(widgetIds,widgetMap){const widgets={};widgetIds.forEach(widgetId=>{const widget=getWidgetFromWidgetMap(widgetId,widgetMap);if(widget){widgets[widgetId]=widget;}});return widgets}
1810
1810
 
1811
- function sharedInitializeUserInput(widgetOptions,problemNum){const startUserInput={};if(!widgetOptions){return startUserInput}Object.entries(widgetOptions).forEach(([id,widgetInfo])=>{const widgetExports=getWidgetExport(widgetInfo.type);if(widgetInfo.static&&widgetExports?.getCorrectUserInput){startUserInput[id]=widgetExports.getCorrectUserInput(widgetInfo.options);}else if(widgetExports?.getStartUserInput){startUserInput[id]=widgetExports.getStartUserInput(widgetInfo.options,problemNum??0);}});return startUserInput}function deriveUserInputFromSerializedState(serializedState,widgetsMap){const restoredUserInput={};Object.entries(serializedState).forEach(([widgetId,props])=>{const widgetType=getWidgetTypeByWidgetId(widgetId,widgetsMap);const widgetExport=getWidgetExport(widgetType);if(widgetExport?.getUserInputFromSerializedState){const restoreResult=widgetExport.getUserInputFromSerializedState(props,widgetsMap[widgetId].options);restoredUserInput[widgetId]=restoreResult;}});return restoredUserInput}function UserInputManager(props){const[userInput,setUserInput]=useState(sharedInitializeUserInput(props.widgets,props.problemNum??0));function handleUserInput(id,nextUserInput,widgetsEmpty){const next={...userInput,[id]:nextUserInput};setUserInput(next);props.handleUserInput?.(next,widgetsEmpty);}function initializeUserInput(widgetOptions,problemNum){setUserInput(sharedInitializeUserInput(widgetOptions,problemNum));}function restoreUserInputFromSerializedState(serializedState,widgetOptions){setUserInput(deriveUserInputFromSerializedState(serializedState,widgetOptions));}return props.children({userInput,handleUserInput,initializeUserInput,restoreUserInputFromSerializedState})}
1811
+ function sharedInitializeUserInput(widgetOptions,problemNum){const startUserInput={};if(!widgetOptions){return startUserInput}Object.entries(widgetOptions).forEach(([id,widgetInfo])=>{const widgetExports=getWidgetExport(widgetInfo.type);if(widgetInfo.static&&widgetExports?.getCorrectUserInput){startUserInput[id]=widgetExports.getCorrectUserInput(widgetInfo.options);}else if(widgetExports?.getStartUserInput){startUserInput[id]=widgetExports.getStartUserInput(widgetInfo.options,problemNum??0);}});return startUserInput}function deriveUserInputFromSerializedState(serializedState,widgetsMap){const restoredUserInput={};Object.entries(serializedState).forEach(([widgetId,props])=>{const widgetType=getWidgetTypeByWidgetId(widgetId,widgetsMap);const widgetExport=getWidgetExport(widgetType);if(widgetExport?.getUserInputFromSerializedState){const restoreResult=widgetExport.getUserInputFromSerializedState(props,widgetsMap[widgetId].options);restoredUserInput[widgetId]=restoreResult;}});return restoredUserInput}function UserInputManager(props){const[userInput,setUserInput]=useState(props.initialUserInput||sharedInitializeUserInput(props.widgets,props.problemNum??0));function handleUserInput(id,nextUserInput,widgetsEmpty){const next={...userInput,[id]:nextUserInput};setUserInput(next);props.handleUserInput?.(next,widgetsEmpty);}function initializeUserInput(widgetOptions,problemNum){setUserInput(props.initialUserInput||sharedInitializeUserInput(widgetOptions,problemNum));}return props.children({userInput,handleUserInput,initializeUserInput})}
1812
1812
 
1813
1813
  const getPromptJSON$i=(title,rendererJSON,hintRendererJSON)=>{if(!rendererJSON){return {type:"graded-group",title,content:"",widgets:{},hint:hintRendererJSON}}return {...rendererJSON,title,type:"graded-group",hint:hintRendererJSON}};
1814
1814
 
@@ -1830,7 +1830,7 @@ const MovablePoint$3=Graphie.MovablePoint;const MovableLine$2=Graphie.MovableLin
1830
1830
 
1831
1831
  const getPromptJSON$f=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
1832
1832
 
1833
- class Group extends React.Component{componentDidMount(){this.forceUpdate();}getPromptJSON(){return getPromptJSON$f(this.rendererRef?.getPromptJSON())}getInputPaths(){return this.rendererRef?.getInputPaths()??[]}focus(){return this.rendererRef?.focus()??false}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:(newFocus,oldFocus)=>{if(oldFocus){this.props.onBlur(oldFocus);}if(newFocus){this.props.onFocus(newFocus);}}};const groupWidgets=this.props.findWidgets("group");const number=groupWidgets.indexOf(this);const problemNumComponent=this.props.apiOptions.groupAnnotator(number,this.props.widgetId);const onInteractWithWidget=id=>{if(this.rendererRef){this.change("widgets",this.rendererRef.props.widgets);}};return jsxRuntimeExports.jsxs("div",{className:classNames$1({"perseus-group":true}),children:[problemNumComponent,jsxRuntimeExports.jsx(Renderer,{userInput:this.props.userInput,handleUserInput:(widgetId,userInput)=>{this.props.handleUserInput({...this.props.userInput,[widgetId]:userInput});},content:this.props.content,widgets:this.props.widgets,images:this.props.images,ref:ref=>this.rendererRef=ref,apiOptions:apiOptions,findExternalWidgets:this.props.findWidgets,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,onInteractWithWidget:onInteractWithWidget,linterContext:this.props.linterContext,strings:this.context.strings})]})}constructor(...args){super(...args),this.change=(...args)=>{return change.apply(this,args)},this.getSerializedState=()=>{return this.rendererRef?.getSerializedState()},this.restoreSerializedState=(state,callback)=>{this.rendererRef?.restoreSerializedState(state,callback);return null},this.focusInputPath=path=>{this.rendererRef?.focusPath(path);},this.blurInputPath=path=>{this.rendererRef?.blurPath(path);};}}Group.contextType=PerseusI18nContext;Group.defaultProps={content:"",widgets:{},images:{},linterContext:linterContextDefault};function getStartUserInput$a(options,problemNum){return sharedInitializeUserInput(options.widgets,problemNum)}function getUserInputFromSerializedState$a(serializedState,widgetOptions){return deriveUserInputFromSerializedState(serializedState,widgetOptions.widgets)}var Group$1 = {name:"group",displayName:"Group (SAT only)",widget:Group,hidden:true,isLintable:true,getStartUserInput: getStartUserInput$a,getUserInputFromSerializedState: getUserInputFromSerializedState$a};
1833
+ class Group extends React.Component{componentDidMount(){this.forceUpdate();}getPromptJSON(){return getPromptJSON$f(this.rendererRef?.getPromptJSON())}getInputPaths(){return this.rendererRef?.getInputPaths()??[]}focus(){return this.rendererRef?.focus()??false}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:(newFocus,oldFocus)=>{if(oldFocus){this.props.onBlur(oldFocus);}if(newFocus){this.props.onFocus(newFocus);}}};const groupWidgets=this.props.findWidgets("group");const number=groupWidgets.indexOf(this);const problemNumComponent=this.props.apiOptions.groupAnnotator(number,this.props.widgetId);const onInteractWithWidget=id=>{if(this.rendererRef){this.change("widgets",this.rendererRef.props.widgets);}};return jsxRuntimeExports.jsxs("div",{className:classNames$1({"perseus-group":true}),children:[problemNumComponent,jsxRuntimeExports.jsx(Renderer,{userInput:this.props.userInput,handleUserInput:(widgetId,userInput)=>{this.props.handleUserInput({...this.props.userInput,[widgetId]:userInput});},content:this.props.content,widgets:this.props.widgets,images:this.props.images,ref:ref=>this.rendererRef=ref,apiOptions:apiOptions,findExternalWidgets:this.props.findWidgets,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,onInteractWithWidget:onInteractWithWidget,linterContext:this.props.linterContext,strings:this.context.strings})]})}constructor(...args){super(...args),this.change=(...args)=>{return change.apply(this,args)},this.getSerializedState=()=>{return this.rendererRef?.getSerializedState()},this.focusInputPath=path=>{this.rendererRef?.focusPath(path);},this.blurInputPath=path=>{this.rendererRef?.blurPath(path);};}}Group.contextType=PerseusI18nContext;Group.defaultProps={content:"",widgets:{},images:{},linterContext:linterContextDefault};function getStartUserInput$a(options,problemNum){return sharedInitializeUserInput(options.widgets,problemNum)}function getUserInputFromSerializedState$a(serializedState,widgetOptions){return deriveUserInputFromSerializedState(serializedState,widgetOptions.widgets)}var Group$1 = {name:"group",displayName:"Group (SAT only)",widget:Group,hidden:true,isLintable:true,getStartUserInput: getStartUserInput$a,getUserInputFromSerializedState: getUserInputFromSerializedState$a};
1834
1834
 
1835
1835
  const getPromptJSON$e=()=>{return getUnsupportedPromptJSON("iframe")};
1836
1836
 
@@ -2077,7 +2077,7 @@ var extraWidgets = [CSProgram$1,Categorizer$1,Definition$1,DeprecatedStandin$1,D
2077
2077
 
2078
2078
  const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
2079
2079
 
2080
- const libName="@khanacademy/perseus";const libVersion="67.1.2";addLibraryVersionToPerseusDebug(libName,libVersion);
2080
+ const libName="@khanacademy/perseus";const libVersion="68.0.0";addLibraryVersionToPerseusDebug(libName,libVersion);
2081
2081
 
2082
2082
  const apiVersion={major:12,minor:0};
2083
2083
 
@@ -2087,13 +2087,13 @@ registerWidgets(allWidgets);const ItemVersion=getVersionVector();
2087
2087
 
2088
2088
  class ArticleRenderer extends React.Component{componentDidMount(){this._currentFocus=null;}shouldComponentUpdate(nextProps){return nextProps!==this.props}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,isArticle:true};const classes=classNames$1({"framework-perseus":true,"perseus-article":true,[ClassNames.MOBILE]:apiOptions.isMobile});const sections=this._sections().map((section,sectionIndex)=>{return jsxRuntimeExports.jsx("div",{className:"clearfix",children:jsxRuntimeExports.jsx(UserInputManager,{widgets:section.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>createElement(Renderer,{...section,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,ref:elem=>{if(elem){this.sectionRenderers[sectionIndex]=elem;}},key:sectionIndex,keypadElement:this.props.keypadElement,apiOptions:{...apiOptions,onFocusChange:(newFocusPath,oldFocusPath)=>{this._handleFocusChange(newFocusPath&&[sectionIndex].concat(newFocusPath),oldFocusPath&&[sectionIndex].concat(oldFocusPath));}},linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"article"),legacyPerseusLint:this.props.legacyPerseusLint,strings:this.context.strings})})},sectionIndex)});return jsxRuntimeExports.jsx("div",{className:classes,children:jsxRuntimeExports.jsx(DependenciesContext.Provider,{value:this.props.dependencies,children:sections})})}constructor(props){super(props),this.sectionRenderers=[],this._handleFocusChange=(newFocusPath,oldFocusPath)=>{if(newFocusPath){this._setCurrentFocus(newFocusPath);}else {this._onRendererBlur(oldFocusPath);}},this._setCurrentFocus=newFocusPath=>{const{keypadElement,apiOptions}=this.props;const{isMobile}=apiOptions;const prevFocusPath=this._currentFocus;this._currentFocus=newFocusPath;let didFocusInput=false;let focusedInput;if(this._currentFocus){const[sectionIndex,...focusPath]=this._currentFocus;const inputPaths=this.sectionRenderers[sectionIndex].getInputPaths();didFocusInput=inputPaths.some(inputPath=>{return Util.inputPathsEqual(inputPath,focusPath)});focusedInput=this.sectionRenderers[sectionIndex].getDOMNodeForPath(focusPath);}const{onFocusChange}=this.props.apiOptions;if(onFocusChange){setTimeout(()=>{const keypadDomNode=keypadElement?.getDOMNode();const keypadHeight=keypadDomNode&&didFocusInput?keypadDomNode.getBoundingClientRect().height:0;onFocusChange(this._currentFocus,prevFocusPath,keypadHeight,didFocusInput?focusedInput:null);},0);}if(keypadElement&&isMobile){if(didFocusInput){keypadElement.activate();}else {keypadElement.dismiss();}}},this._onRendererBlur=blurPath=>{const blurringFocusPath=this._currentFocus;if(!Util.inputPathsEqual(blurPath,blurringFocusPath)){return}setTimeout(()=>{if(Util.inputPathsEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.blur=()=>{if(this._currentFocus){const[sectionIndex,...inputPath]=this._currentFocus;this.sectionRenderers[sectionIndex].blurPath(inputPath);}},this._sections=()=>{const sections=Array.isArray(this.props.json)?this.props.json:[this.props.json];if(getDependencies().JIPT.useJIPT){const paragraphs=[];for(const section of sections){JiptParagraphs.parseToArray(section.content).forEach(paragraph=>{paragraphs.push({...section,content:paragraph});});}return paragraphs}return sections};}}ArticleRenderer.contextType=PerseusI18nContext;ArticleRenderer.defaultProps={apiOptions:ApiOptions.defaults,useNewStyles:false,linterContext:PerseusLinter.linterContextDefault};
2089
2089
 
2090
- class HintRenderer extends React.Component{render(){const{apiOptions,className,hint,lastHint,lastRendered,pos,totalHints}=this.props;const{isMobile}=apiOptions;const classNames=classNames$1("hint",!isMobile&&"perseus-hint-renderer",isMobile&&css(styles$2.newHint),isMobile&&lastRendered&&css(styles$2.lastRenderedNewHint),lastHint&&"last-hint",lastRendered&&"last-rendered",className);const rendererApiOptions={...apiOptions,customKeypad:false};return jsxRuntimeExports.jsxs("div",{className:classNames,tabIndex:"-1",children:[!apiOptions.isMobile&&jsxRuntimeExports.jsx("span",{className:"perseus-sr-only",children:this.context.strings.hintPos({pos:pos+1})}),!apiOptions.isMobile&&totalHints!=null&&pos!=null&&jsxRuntimeExports.jsx("span",{className:"perseus-hint-label",style:{display:"block",color:apiOptions.hintProgressColor},children:`${pos+1} / ${totalHints}`}),jsxRuntimeExports.jsx(UserInputManager,{widgets:hint.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{ref:this.rendererRef,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,widgets:hint.widgets,content:hint.content||"",images:hint.images,apiOptions:rendererApiOptions,findExternalWidgets:this.props.findExternalWidgets,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"hint"),strings:this.context.strings})})]})}constructor(...args){super(...args),this.rendererRef=React.createRef(),this.getSerializedState=()=>{return this.rendererRef.current?.getSerializedState()},this.restoreSerializedState=(state,callback)=>{this.rendererRef.current?.restoreSerializedState(state,callback);};}}HintRenderer.contextType=PerseusI18nContext;HintRenderer.defaultProps={linterContext:PerseusLinter.linterContextDefault};const styles$2=StyleSheet.create({newHint:{marginBottom:1.5*baseUnitPx,borderLeftColor:gray97,borderLeftStyle:"solid",borderLeftWidth:hintBorderWidth,[mediaQueries.lgOrSmaller]:{paddingLeft:baseUnitPx},[mediaQueries.smOrSmaller]:{paddingLeft:0},":focus":{outline:"none"}},lastRenderedNewHint:{marginBottom:0,borderLeftColor:kaGreen}});
2090
+ class HintRenderer extends React.Component{render(){const{apiOptions,className,hint,lastHint,lastRendered,pos,totalHints}=this.props;const{isMobile}=apiOptions;const classNames=classNames$1("hint",!isMobile&&"perseus-hint-renderer",isMobile&&css(styles$2.newHint),isMobile&&lastRendered&&css(styles$2.lastRenderedNewHint),lastHint&&"last-hint",lastRendered&&"last-rendered",className);const rendererApiOptions={...apiOptions,customKeypad:false};return jsxRuntimeExports.jsxs("div",{className:classNames,tabIndex:"-1",children:[!apiOptions.isMobile&&jsxRuntimeExports.jsx("span",{className:"perseus-sr-only",children:this.context.strings.hintPos({pos:pos+1})}),!apiOptions.isMobile&&totalHints!=null&&pos!=null&&jsxRuntimeExports.jsx("span",{className:"perseus-hint-label",style:{display:"block",color:apiOptions.hintProgressColor},children:`${pos+1} / ${totalHints}`}),jsxRuntimeExports.jsx(UserInputManager,{widgets:hint.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{ref:this.rendererRef,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,widgets:hint.widgets,content:hint.content||"",images:hint.images,apiOptions:rendererApiOptions,findExternalWidgets:this.props.findExternalWidgets,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"hint"),strings:this.context.strings})})]})}constructor(...args){super(...args),this.rendererRef=React.createRef(),this.getSerializedState=()=>{return this.rendererRef.current?.getSerializedState()};}}HintRenderer.contextType=PerseusI18nContext;HintRenderer.defaultProps={linterContext:PerseusLinter.linterContextDefault};const styles$2=StyleSheet.create({newHint:{marginBottom:1.5*baseUnitPx,borderLeftColor:gray97,borderLeftStyle:"solid",borderLeftWidth:hintBorderWidth,[mediaQueries.lgOrSmaller]:{paddingLeft:baseUnitPx},[mediaQueries.smOrSmaller]:{paddingLeft:0},":focus":{outline:"none"}},lastRenderedNewHint:{marginBottom:0,borderLeftColor:kaGreen}});
2091
2091
 
2092
- class HintsRenderer extends React.Component{componentDidMount(){this._cacheHintImages();}UNSAFE_componentWillReceiveProps(nextProps){if(nextProps.hintsVisible-this.props.hintsVisible>1){this.setState({isFinalHelpPage:true});}}componentDidUpdate(prevProps,prevState){if(!_.isEqual(prevProps.hints,this.props.hints)||prevProps.hintsVisible!==this.props.hintsVisible){this._cacheHintImages();}const prevHintsVisible=prevProps.hintsVisible||0;const nextHintsVisible=this.props.hintsVisible||0;if(prevHintsVisible<nextHintsVisible&&nextHintsVisible<=this.props.hints.length&&nextHintsVisible>=0){const pos=nextHintsVisible-1;ReactDOM__default.findDOMNode(this.refs["hintRenderer"+pos]).focus();}}render(){const apiOptions=this.getApiOptions();const hintsVisible=this._hintsVisible();const hints=[];const isFinalHelpPage=this.state.isFinalHelpPage;this.props.hints.slice(0,hintsVisible).forEach((hint,i)=>{const lastHint=i===this.props.hints.length-1&&!/\*\*/.test(hint.content);const lastRendered=i===hintsVisible-1;const renderer=jsxRuntimeExports.jsx(HintRenderer,{lastHint:lastHint,lastRendered:lastRendered,hint:hint,pos:i,totalHints:this.props.hints.length,ref:"hintRenderer"+i,apiOptions:apiOptions,findExternalWidgets:this.props.findExternalWidgets,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"hints["+i+"]")},"hintRenderer"+i);if(isFinalHelpPage){hints.push(renderer);}else {if(hint.replace&&hints.length>0){hints[hints.length-1]=renderer;}else {hints.push(renderer);}}});const{getAnotherHint}=apiOptions;const showGetAnotherHint=getAnotherHint&&hintsVisible>0&&hintsVisible<this.props.hints.length;const hintRatioCopy=`(${hintsVisible}/${this.props.hints.length})`;const classNames=classNames$1(this.props.className,apiOptions.isMobile&&hintsVisible>0&&css(styles$1.mobileHintStylesHintsRenderer));return jsxRuntimeExports.jsxs("div",{className:classNames,children:[apiOptions.isMobile&&hintsVisible>0&&jsxRuntimeExports.jsx("div",{className:css(styles$1.mobileHintStylesHintTitle,sharedStyles.responsiveLabel),children:this.context.strings.hints}),hints,showGetAnotherHint&&jsxRuntimeExports.jsxs("button",{rel:"button",className:css(styles$1.linkButton,styles$1.getAnotherHintButton,apiOptions.isMobile&&styles$1.mobileHintStylesGetAnotherHintButton),onClick:evt=>{evt.preventDefault();evt.stopPropagation();if(getAnotherHint){getAnotherHint();}},children:[jsxRuntimeExports.jsx("span",{className:css(styles$1.plusText,apiOptions.isMobile&&styles$1.mobileHintStylesPlusText),children:"+"}),jsxRuntimeExports.jsxs("span",{className:css(styles$1.getAnotherHintText),children:[this.context.strings.getAnotherHint," ",hintRatioCopy]})]})]})}constructor(...args){super(...args),this.state={isFinalHelpPage:false},this._hintsVisible=()=>{if(this.props.hintsVisible==null||this.props.hintsVisible===-1){return this.props.hints.length}return this.props.hintsVisible},this._cacheImagesInHint=hint=>{_.each(hint.images,(data,src)=>{const image=new Image;image.src=Util.getRealImageUrl(src);});},this._cacheHintImages=()=>{if(this._hintsVisible()>0){_.each(this.props.hints,this._cacheImagesInHint);}else if(this.props.hints.length>0){this._cacheImagesInHint(this.props.hints[0]);}},this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions,readOnly:false}},this.getSerializedState=()=>{return _.times(this._hintsVisible(),i=>{return this.refs["hintRenderer"+i].getSerializedState()})},this.restoreSerializedState=(state,callback)=>{let numCallbacks=1;const fireCallback=()=>{--numCallbacks;if(callback&&numCallbacks===0){callback();}};_.each(state,(hintState,i)=>{const hintRenderer=this.refs["hintRenderer"+i];if(hintRenderer){++numCallbacks;hintRenderer.restoreSerializedState(hintState,fireCallback);}});fireCallback();};}}HintsRenderer.contextType=PerseusI18nContext;HintsRenderer.defaultProps={linterContext:PerseusLinter.linterContextDefault};const hintIndentation=baseUnitPx+hintBorderWidth;const styles$1=StyleSheet.create({rendererMargins:{marginTop:baseUnitPx},linkButton:{cursor:"pointer",border:"none",backgroundColor:"transparent",fontSize:"100%",fontFamily:"inherit",fontWeight:"bold",color:kaGreen,padding:0,position:"relative"},plusText:{fontSize:20,position:"absolute",top:-3,left:0},getAnotherHintText:{marginLeft:16},mobileHintStylesHintsRenderer:{marginTop:4*baseUnitPx,border:`solid ${gray85}`,borderWidth:"1px 0 0 0",position:"relative",":before":{content:'""',display:"table",clear:"both"},":after":{content:'""',display:"table",clear:"both"}},mobileHintStylesHintTitle:{fontFamily:"inherit",fontStyle:"normal",fontWeight:"bold",color:gray17,paddingTop:baseUnitPx,paddingBottom:1.5*baseUnitPx,[mediaQueries.lgOrSmaller]:{paddingLeft:0},[mediaQueries.smOrSmaller]:{paddingLeft:hintIndentation}},getAnotherHintButton:{marginTop:1.5*baseUnitPx},mobileHintStylesGetAnotherHintButton:{[mediaQueries.lgOrSmaller]:{paddingLeft:0},[mediaQueries.smOrSmaller]:{paddingLeft:hintIndentation}},mobileHintStylesPlusText:{[mediaQueries.lgOrSmaller]:{left:0},[mediaQueries.smOrSmaller]:{left:hintIndentation}}});
2092
+ class HintsRenderer extends React.Component{componentDidMount(){this._cacheHintImages();}UNSAFE_componentWillReceiveProps(nextProps){if(nextProps.hintsVisible-this.props.hintsVisible>1){this.setState({isFinalHelpPage:true});}}componentDidUpdate(prevProps,prevState){if(!_.isEqual(prevProps.hints,this.props.hints)||prevProps.hintsVisible!==this.props.hintsVisible){this._cacheHintImages();}const prevHintsVisible=prevProps.hintsVisible||0;const nextHintsVisible=this.props.hintsVisible||0;if(prevHintsVisible<nextHintsVisible&&nextHintsVisible<=this.props.hints.length&&nextHintsVisible>=0){const pos=nextHintsVisible-1;ReactDOM__default.findDOMNode(this.refs["hintRenderer"+pos]).focus();}}render(){const apiOptions=this.getApiOptions();const hintsVisible=this._hintsVisible();const hints=[];const isFinalHelpPage=this.state.isFinalHelpPage;this.props.hints.slice(0,hintsVisible).forEach((hint,i)=>{const lastHint=i===this.props.hints.length-1&&!/\*\*/.test(hint.content);const lastRendered=i===hintsVisible-1;const renderer=jsxRuntimeExports.jsx(HintRenderer,{lastHint:lastHint,lastRendered:lastRendered,hint:hint,pos:i,totalHints:this.props.hints.length,ref:"hintRenderer"+i,apiOptions:apiOptions,findExternalWidgets:this.props.findExternalWidgets,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"hints["+i+"]")},"hintRenderer"+i);if(isFinalHelpPage){hints.push(renderer);}else {if(hint.replace&&hints.length>0){hints[hints.length-1]=renderer;}else {hints.push(renderer);}}});const{getAnotherHint}=apiOptions;const showGetAnotherHint=getAnotherHint&&hintsVisible>0&&hintsVisible<this.props.hints.length;const hintRatioCopy=`(${hintsVisible}/${this.props.hints.length})`;const classNames=classNames$1(this.props.className,apiOptions.isMobile&&hintsVisible>0&&css(styles$1.mobileHintStylesHintsRenderer));return jsxRuntimeExports.jsxs("div",{className:classNames,children:[apiOptions.isMobile&&hintsVisible>0&&jsxRuntimeExports.jsx("div",{className:css(styles$1.mobileHintStylesHintTitle,sharedStyles.responsiveLabel),children:this.context.strings.hints}),hints,showGetAnotherHint&&jsxRuntimeExports.jsxs("button",{rel:"button",className:css(styles$1.linkButton,styles$1.getAnotherHintButton,apiOptions.isMobile&&styles$1.mobileHintStylesGetAnotherHintButton),onClick:evt=>{evt.preventDefault();evt.stopPropagation();if(getAnotherHint){getAnotherHint();}},children:[jsxRuntimeExports.jsx("span",{className:css(styles$1.plusText,apiOptions.isMobile&&styles$1.mobileHintStylesPlusText),children:"+"}),jsxRuntimeExports.jsxs("span",{className:css(styles$1.getAnotherHintText),children:[this.context.strings.getAnotherHint," ",hintRatioCopy]})]})]})}constructor(...args){super(...args),this.state={isFinalHelpPage:false},this._hintsVisible=()=>{if(this.props.hintsVisible==null||this.props.hintsVisible===-1){return this.props.hints.length}return this.props.hintsVisible},this._cacheImagesInHint=hint=>{_.each(hint.images,(data,src)=>{const image=new Image;image.src=Util.getRealImageUrl(src);});},this._cacheHintImages=()=>{if(this._hintsVisible()>0){_.each(this.props.hints,this._cacheImagesInHint);}else if(this.props.hints.length>0){this._cacheImagesInHint(this.props.hints[0]);}},this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions,readOnly:false}},this.getSerializedState=()=>{return _.times(this._hintsVisible(),i=>{return this.refs["hintRenderer"+i].getSerializedState()})};}}HintsRenderer.contextType=PerseusI18nContext;HintsRenderer.defaultProps={linterContext:PerseusLinter.linterContextDefault};const hintIndentation=baseUnitPx+hintBorderWidth;const styles$1=StyleSheet.create({rendererMargins:{marginTop:baseUnitPx},linkButton:{cursor:"pointer",border:"none",backgroundColor:"transparent",fontSize:"100%",fontFamily:"inherit",fontWeight:"bold",color:kaGreen,padding:0,position:"relative"},plusText:{fontSize:20,position:"absolute",top:-3,left:0},getAnotherHintText:{marginLeft:16},mobileHintStylesHintsRenderer:{marginTop:4*baseUnitPx,border:`solid ${gray85}`,borderWidth:"1px 0 0 0",position:"relative",":before":{content:'""',display:"table",clear:"both"},":after":{content:'""',display:"table",clear:"both"}},mobileHintStylesHintTitle:{fontFamily:"inherit",fontStyle:"normal",fontWeight:"bold",color:gray17,paddingTop:baseUnitPx,paddingBottom:1.5*baseUnitPx,[mediaQueries.lgOrSmaller]:{paddingLeft:0},[mediaQueries.smOrSmaller]:{paddingLeft:hintIndentation}},getAnotherHintButton:{marginTop:1.5*baseUnitPx},mobileHintStylesGetAnotherHintButton:{[mediaQueries.lgOrSmaller]:{paddingLeft:0},[mediaQueries.smOrSmaller]:{paddingLeft:hintIndentation}},mobileHintStylesPlusText:{[mediaQueries.lgOrSmaller]:{left:0},[mediaQueries.smOrSmaller]:{left:hintIndentation}}});
2093
2093
 
2094
2094
  const defaultContext={onRendered:isRendered=>{}};const context=React.createContext(defaultContext);
2095
2095
 
2096
- class ServerItemRenderer extends React.Component{componentDidMount(){this._currentFocus=null;this._fullyRendered=false;this.maybeCallOnRendered();}UNSAFE_componentWillReceiveProps(nextProps){this.setState({questionHighlightedWidgets:[]});}componentDidUpdate(prevProps,prevState){const answerableCallback=this.props.apiOptions.answerableCallback;if(answerableCallback!=null){const isAnswerable=this.questionRenderer.emptyWidgets().length===0;answerableCallback(isAnswerable);}this.maybeCallOnRendered();if(this.props.score&&this.props.score!==prevProps.score){const emptyQuestionAreaWidgets=this.questionRenderer.emptyWidgets();this.setState({questionCompleted:this.props.score.correct,questionHighlightedWidgets:emptyQuestionAreaWidgets});}}componentWillUnmount(){if(this.blurTimeoutID!=null){clearTimeout(this.blurTimeoutID);this.blurTimeoutID=null;}}maybeCallOnRendered(){if(!this._fullyRendered){const assetsLoaded=Object.values(this.state.assetStatuses).every(Boolean);if(assetsLoaded){this._fullyRendered=true;this.props.onRendered(true);}}}_setCurrentFocus(newFocus){const{apiOptions:{isMobile,onFocusChange},keypadElement}=this.props;const prevFocus=this._currentFocus;this._currentFocus=newFocus;const inputPaths=this.getInputPaths();const didFocusInput=this._currentFocus&&inputPaths.some(inputPath=>{return Util.inputPathsEqual(inputPath,this._currentFocus)});if(onFocusChange!=null){setTimeout(()=>{const keypadDomNode=keypadElement?.getDOMNode();const keypadHeight=keypadDomNode&&didFocusInput?keypadDomNode.getBoundingClientRect().height:0;onFocusChange(this._currentFocus,prevFocus,keypadHeight,didFocusInput&&this.questionRenderer.getDOMNodeForPath(newFocus));},0);}if(keypadElement&&isMobile){if(didFocusInput){keypadElement.activate();}else {keypadElement.dismiss();}}}_onRendererBlur(blurPath){const blurringFocusPath=this._currentFocus;if(!_.isEqual(blurPath,blurringFocusPath)){return}this.blurTimeoutID=setTimeout(()=>{if(_.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}},0);}_setWidgetProps(widgetId,newProps,callback){this.questionRenderer._setWidgetProps(widgetId,newProps,callback);}focusPath(path){return this.questionRenderer.focusPath(path)}blurPath(path){return this.questionRenderer.blurPath(path)}getDOMNodeForPath(path){return this.questionRenderer.getDOMNodeForPath(path)}getInputPaths(){const questionAreaInputPaths=this.questionRenderer.getInputPaths();return questionAreaInputPaths}focus(){return this.questionRenderer.focus()}blur(){if(this._currentFocus){this.blurPath(this._currentFocus);}}getNumHints(){return this.props.item.hints.length}getPromptJSON(){return this.questionRenderer.getPromptJSON()}getUserInputLegacy(){return this.questionRenderer.getUserInput()}getUserInput(){return this.userInput}getWidgetIds(){return this.questionRenderer.getWidgetIds()}getSerializedState(){return {question:this.questionRenderer.getSerializedState(),hints:this.hintsRenderer.getSerializedState()}}restoreSerializedState(state,callback){let numCallbacks=2;const fireCallback=()=>{--numCallbacks;if(callback&&numCallbacks===0){callback();}};this.questionRenderer.restoreSerializedState(state.question,fireCallback);this.hintsRenderer.restoreSerializedState(state.hints,fireCallback);}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:this._handleFocusChange};const contextValue={assetStatuses:this.state.assetStatuses,setAssetStatus:this.setAssetStatus};const questionRenderer=jsxRuntimeExports.jsx(context$1.Provider,{value:contextValue,children:jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.item.question.widgets,problemNum:this.props.problemNum??0,children:({userInput,handleUserInput,initializeUserInput,restoreUserInputFromSerializedState})=>{this.userInput=userInput;return jsxRuntimeExports.jsx(Renderer,{keypadElement:this.props.keypadElement,problemNum:this.props.problemNum,onInteractWithWidget:this.handleInteractWithWidget,highlightedWidgets:this.state.questionHighlightedWidgets,apiOptions:apiOptions,questionCompleted:this.state.questionCompleted,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,ref:elem=>{if(elem!=null){this.questionRenderer=elem;}},content:this.props.item.question.content,widgets:this.props.item.question.widgets,images:this.props.item.question.images,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"question"),strings:this.context.strings,...this.props.dependencies,userInput:userInput,handleUserInput:(id,userInput,widgetsEmpty)=>{handleUserInput(id,userInput,widgetsEmpty);this.handleInteractWithWidget(id);},initializeUserInput:initializeUserInput,restoreUserInputFromSerializedState:restoreUserInputFromSerializedState})}})});const hintsRenderer=jsxRuntimeExports.jsx(HintsRenderer,{hints:this.props.item.hints,hintsVisible:this.props.hintsVisible,apiOptions:apiOptions,ref:elem=>this.hintsRenderer=elem,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"hints"),strings:this.context.strings});return jsxRuntimeExports.jsx(DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:questionRenderer}),jsxRuntimeExports.jsx("div",{className:apiOptions.isMobile?undefined:css(styles.hintsContainer),children:hintsRenderer})]})})}constructor(props){super(props),this._handleFocusChange=(newFocus,oldFocus)=>{if(newFocus!=null){this._setCurrentFocus(newFocus);}else {this._onRendererBlur(oldFocus);}},this.handleInteractWithWidget=widgetId=>{const withRemoved=_.difference(this.state.questionHighlightedWidgets,[widgetId]);this.setState({questionCompleted:false,questionHighlightedWidgets:withRemoved},()=>{this.props.apiOptions?.interactionCallback?.(this.questionRenderer.getUserInputMap());});},this.setAssetStatus=(assetKey,status)=>{const assetStatuses={...this.state.assetStatuses,[assetKey]:status};this.setState({assetStatuses});};this.state={questionCompleted:false,questionHighlightedWidgets:[],assetStatuses:{}};this._fullyRendered=false;this.userInput={};}}ServerItemRenderer.contextType=PerseusI18nContext;ServerItemRenderer.defaultProps={apiOptions:{},linterContext:PerseusLinter.linterContextDefault,onRendered:isRendered=>{}};const styles=StyleSheet.create({hintsContainer:{marginLeft:50}});var serverItemRenderer = React.forwardRef(function ServerItemRendererWithRef(props,ref){return jsxRuntimeExports.jsx(context.Consumer,{children:({onRendered})=>jsxRuntimeExports.jsx(ServerItemRenderer,{...props,onRendered:onRendered,ref:ref})})});
2096
+ class ServerItemRenderer extends React.Component{componentDidMount(){this._currentFocus=null;this._fullyRendered=false;this.maybeCallOnRendered();}UNSAFE_componentWillReceiveProps(nextProps){this.setState({questionHighlightedWidgets:[]});}componentDidUpdate(prevProps,prevState){const answerableCallback=this.props.apiOptions.answerableCallback;if(answerableCallback!=null){const isAnswerable=this.questionRenderer.emptyWidgets().length===0;answerableCallback(isAnswerable);}this.maybeCallOnRendered();if(this.props.score&&this.props.score!==prevProps.score){const emptyQuestionAreaWidgets=this.questionRenderer.emptyWidgets();this.setState({questionCompleted:this.props.score.correct,questionHighlightedWidgets:emptyQuestionAreaWidgets});}}componentWillUnmount(){if(this.blurTimeoutID!=null){clearTimeout(this.blurTimeoutID);this.blurTimeoutID=null;}}maybeCallOnRendered(){if(!this._fullyRendered){const assetsLoaded=Object.values(this.state.assetStatuses).every(Boolean);if(assetsLoaded){this._fullyRendered=true;this.props.onRendered(true);}}}_setCurrentFocus(newFocus){const{apiOptions:{isMobile,onFocusChange},keypadElement}=this.props;const prevFocus=this._currentFocus;this._currentFocus=newFocus;const inputPaths=this.getInputPaths();const didFocusInput=this._currentFocus&&inputPaths.some(inputPath=>{return Util.inputPathsEqual(inputPath,this._currentFocus)});if(onFocusChange!=null){setTimeout(()=>{const keypadDomNode=keypadElement?.getDOMNode();const keypadHeight=keypadDomNode&&didFocusInput?keypadDomNode.getBoundingClientRect().height:0;onFocusChange(this._currentFocus,prevFocus,keypadHeight,didFocusInput&&this.questionRenderer.getDOMNodeForPath(newFocus));},0);}if(keypadElement&&isMobile){if(didFocusInput){keypadElement.activate();}else {keypadElement.dismiss();}}}_onRendererBlur(blurPath){const blurringFocusPath=this._currentFocus;if(!_.isEqual(blurPath,blurringFocusPath)){return}this.blurTimeoutID=setTimeout(()=>{if(_.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}},0);}_setWidgetProps(widgetId,newProps,callback){this.questionRenderer._setWidgetProps(widgetId,newProps,callback);}focusPath(path){return this.questionRenderer.focusPath(path)}blurPath(path){return this.questionRenderer.blurPath(path)}getDOMNodeForPath(path){return this.questionRenderer.getDOMNodeForPath(path)}getInputPaths(){const questionAreaInputPaths=this.questionRenderer.getInputPaths();return questionAreaInputPaths}focus(){return this.questionRenderer.focus()}blur(){if(this._currentFocus){this.blurPath(this._currentFocus);}}getNumHints(){return this.props.item.hints.length}getPromptJSON(){return this.questionRenderer.getPromptJSON()}getUserInputLegacy(){return this.questionRenderer.getUserInput()}getUserInput(){return this.userInput}getWidgetIds(){return this.questionRenderer.getWidgetIds()}getSerializedState(){return {question:this.questionRenderer.getSerializedState(),hints:this.hintsRenderer.getSerializedState()}}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:this._handleFocusChange};const contextValue={assetStatuses:this.state.assetStatuses,setAssetStatus:this.setAssetStatus};const questionRenderer=jsxRuntimeExports.jsx(context$1.Provider,{value:contextValue,children:jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.item.question.widgets,problemNum:this.props.problemNum??0,children:({userInput,handleUserInput,initializeUserInput})=>{this.userInput=userInput;return jsxRuntimeExports.jsx(Renderer,{keypadElement:this.props.keypadElement,problemNum:this.props.problemNum,onInteractWithWidget:this.handleInteractWithWidget,highlightedWidgets:this.state.questionHighlightedWidgets,apiOptions:apiOptions,questionCompleted:this.state.questionCompleted,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,ref:elem=>{if(elem!=null){this.questionRenderer=elem;}},content:this.props.item.question.content,widgets:this.props.item.question.widgets,images:this.props.item.question.images,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"question"),strings:this.context.strings,...this.props.dependencies,userInput:userInput,handleUserInput:(id,userInput,widgetsEmpty)=>{handleUserInput(id,userInput,widgetsEmpty);this.handleInteractWithWidget(id);},initializeUserInput:initializeUserInput})}})});const hintsRenderer=jsxRuntimeExports.jsx(HintsRenderer,{hints:this.props.item.hints,hintsVisible:this.props.hintsVisible,apiOptions:apiOptions,ref:elem=>this.hintsRenderer=elem,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"hints"),strings:this.context.strings});return jsxRuntimeExports.jsx(DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:questionRenderer}),jsxRuntimeExports.jsx("div",{className:apiOptions.isMobile?undefined:css(styles.hintsContainer),children:hintsRenderer})]})})}constructor(props){super(props),this._handleFocusChange=(newFocus,oldFocus)=>{if(newFocus!=null){this._setCurrentFocus(newFocus);}else {this._onRendererBlur(oldFocus);}},this.handleInteractWithWidget=widgetId=>{const withRemoved=_.difference(this.state.questionHighlightedWidgets,[widgetId]);this.setState({questionCompleted:false,questionHighlightedWidgets:withRemoved},()=>{this.props.apiOptions?.interactionCallback?.(this.questionRenderer.getUserInputMap());});},this.setAssetStatus=(assetKey,status)=>{const assetStatuses={...this.state.assetStatuses,[assetKey]:status};this.setState({assetStatuses});};this.state={questionCompleted:false,questionHighlightedWidgets:[],assetStatuses:{}};this._fullyRendered=false;this.userInput={};}}ServerItemRenderer.contextType=PerseusI18nContext;ServerItemRenderer.defaultProps={apiOptions:{},linterContext:PerseusLinter.linterContextDefault,onRendered:isRendered=>{}};const styles=StyleSheet.create({hintsContainer:{marginLeft:50}});var serverItemRenderer = React.forwardRef(function ServerItemRendererWithRef(props,ref){return jsxRuntimeExports.jsx(context.Consumer,{children:({onRendered})=>jsxRuntimeExports.jsx(ServerItemRenderer,{...props,onRendered:onRendered,ref:ref})})});
2097
2097
 
2098
2098
  function isCorrect(score){return score.type==="points"&&score.earned>=score.total}function keScoreFromPerseusScore(score,guess,state){if(score.type==="points"){return {empty:false,correct:isCorrect(score),message:score.message,guess:guess,state:state}}if(score.type==="invalid"){return {empty:true,correct:false,message:score.message,suppressAlmostThere:score.suppressAlmostThere,guess:guess,state:state}}throw new PerseusError("Invalid score type: "+score.type,Errors.InvalidInput,{metadata:{score:JSON.stringify(score),guess:JSON.stringify(guess),state:JSON.stringify(state)}})}
2099
2099
 
@@ -2117,9 +2117,11 @@ function generateTestRadioWidget(){return {type:"radio",options:{choices:[]}}}fu
2117
2117
 
2118
2118
  const widgetNameToEnum={categorizer:"CATEGORIZER","cs-program":"CS_PROGRAM",definition:"DEFINITION","deprecated-standin":"DEPRECATED_STANDIN",dropdown:"DROPDOWN",explanation:"EXPLANATION",expression:"EXPRESSION","free-response":"FREE_RESPONSE","graded-group-set":"GRADED_GROUP_SET","graded-group":"GRADED_GROUP",grapher:"GRAPHER",group:"GROUP",iframe:"IFRAME",image:"IMAGE","input-number":"INPUT_NUMBER",interaction:"INTERACTIVE","interactive-graph":"INTERACTIVE_GRAPH","label-image":"LABEL_IMAGE","lights-puzzle":"LIGHTS_PUZZLE",matcher:"MATCHER",matrix:"MATRIX",measurer:"MEASURER","molecule-renderer":"MOLECULE","number-line":"NUMBER_LINE","numeric-input":"NUMERIC_INPUT",orderer:"ORDERER",passage:"PASSAGE","passage-ref":"PASSAGE_REF","passage-ref-target":"PASSAGE_REF_TARGET","phet-simulation":"PHET_SIMULATION",plotter:"PLOTTER","python-program":"PYTHON_PROGRAM","reaction-diagram":"REACTION_DIAGRAM",radio:"RADIO",sequence:"SEQUENCE",simulator:"SIMULATOR",sorter:"SORTER",table:"TABLE",video:"VIDEO"};function convertWidgetNameToEnum(name){const widgetEnum=widgetNameToEnum[name];if(!widgetEnum){throw new Error(`Unknown widget name: ${name}`)}return widgetEnum}
2119
2119
 
2120
+ function extractWidgetIds(perseusRenderer,options){const widgetIds=[];const content=perseusRenderer.content;const inline=options?.inline??false;const parsedMarkdown=inline?PerseusMarkdown.parseInline(content,options):PerseusMarkdown.parse(content,options);PerseusMarkdown.traverseContent(parsedMarkdown,node=>{if(node.type==="widget"){if(!widgetIds.includes(node.id)){widgetIds.push(node.id);}}});return widgetIds}
2121
+
2120
2122
  const EditorJsonify={serialize:function(){return excludeDenylistKeys(this.props)}};
2121
2123
 
2122
2124
  const GrapherUtil={DEFAULT_GRAPHER_PROPS,chooseType,defaultPlotProps,getEquationString,typeToButton};const ScoringUtil={keScoreFromPerseusScore};
2123
2125
 
2124
- export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, JiptParagraphs, KhanColors, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, Radio, Renderer, ScoringUtil, serverItemRenderer as ServerItemRenderer, Table$1 as TableWidget, UserInputManager, Util, widgets$1 as Widgets, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, deriveUserInputFromSerializedState, displaySigFigs, excludeDenylistKeys, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestRadioWidget, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetSubTypeByWidgetId, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, ItemVersion as itemVersion, libVersion, makeSafeUrl, mathOnlyParser, parseDataFromJSONP, preprocessTex, registerAllWidgetsForTesting, shouldHaveIndividualAnswer, usePerseusI18n, allWidgets as widgets };
2126
+ export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, JiptParagraphs, KhanColors, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, Radio, Renderer, ScoringUtil, serverItemRenderer as ServerItemRenderer, Table$1 as TableWidget, UserInputManager, Util, widgets$1 as Widgets, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, deriveUserInputFromSerializedState, displaySigFigs, excludeDenylistKeys, extractWidgetIds, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestRadioWidget, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetSubTypeByWidgetId, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, ItemVersion as itemVersion, libVersion, makeSafeUrl, mathOnlyParser, parseDataFromJSONP, preprocessTex, registerAllWidgetsForTesting, shouldHaveIndividualAnswer, usePerseusI18n, allWidgets as widgets };
2125
2127
  //# sourceMappingURL=index.js.map