@khanacademy/perseus 66.5.0 → 67.1.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 (35) hide show
  1. package/dist/components/scrollable-view.d.ts +12 -3
  2. package/dist/es/index.css +7 -5
  3. package/dist/es/index.css.map +1 -1
  4. package/dist/es/index.js +19 -17
  5. package/dist/es/index.js.map +1 -1
  6. package/dist/index.css +7 -5
  7. package/dist/index.css.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +19 -16
  10. package/dist/index.js.map +1 -1
  11. package/dist/server-item-renderer.d.ts +0 -1
  12. package/dist/types.d.ts +0 -10
  13. package/dist/user-input-manager.d.ts +1 -1
  14. package/dist/widget-ai-utils/image/image-ai-utils.d.ts +1 -1
  15. package/dist/widget-ai-utils/radio/radio-ai-utils.d.ts +1 -1
  16. package/dist/widgets/expression/expression.d.ts +0 -2
  17. package/dist/widgets/grapher/grapher.d.ts +0 -1
  18. package/dist/widgets/image/image.class.d.ts +43 -0
  19. package/dist/widgets/image/image.d.ts +2 -42
  20. package/dist/widgets/image/index.d.ts +1 -1
  21. package/dist/widgets/interactive-graphs/interactive-graph.d.ts +0 -1
  22. package/dist/widgets/mock-widgets/mock-widget.d.ts +0 -1
  23. package/dist/widgets/number-line/number-line.d.ts +0 -1
  24. package/dist/widgets/numeric-input/numeric-input.class.d.ts +0 -1
  25. package/dist/widgets/numeric-input/numeric-input.d.ts +0 -1
  26. package/dist/widgets/plotter/plotter.d.ts +0 -1
  27. package/dist/widgets/radio/base-radio.d.ts +1 -3
  28. package/dist/widgets/radio/multiple-choice-component.new.d.ts +1 -1
  29. package/dist/widgets/radio/multiple-choice-widget.new.d.ts +2 -79
  30. package/dist/widgets/radio/radio-component.d.ts +1 -3
  31. package/dist/widgets/radio/radio-question-builder.d.ts +4 -0
  32. package/dist/widgets/radio/radio.d.ts +2 -2
  33. package/dist/widgets/radio/radio.ff.d.ts +0 -1
  34. package/dist/widgets/table/table.d.ts +0 -1
  35. package/package.json +45 -45
package/dist/index.js CHANGED
@@ -1713,7 +1713,7 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
1713
1713
 
1714
1714
  class WidgetContainer extends React__namespace.Component{componentDidMount(){if(this.state.widgetProps.apiOptions.isMobile){const containerWidth=ReactDOM__namespace.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__default.default({"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=perseusCore.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__namespace.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:PerseusLinter.linterContextDefault};
1715
1715
 
1716
- 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 ___default.default.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return ___default.default.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return perseusCore.splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:perseusCore.getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!___default.default.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React__namespace.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=!___default.default.isEqual(this.state,nextState);const propsChanged=!___default.default.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&&___default.default.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||___default.default.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&&!___default.default.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:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.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=perseusScore.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 perseusScore.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=perseusScore.scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=perseusScore.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__namespace.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__default.default({[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=perseusCore.applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{apiOptions,problemNum}=props;const widgetsStartProps={};const{strings}=this.props;wonderStuffCore.entries(allWidgetInfo).forEach(([key,widgetInfo])=>{widgetsStartProps[key]=getRendererPropsForWidgetInfo(widgetInfo,strings,problemNum);});apiOptions?.onWidgetStartProps?.(widgetsStartProps);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=___default.default.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__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return perseusCore.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=___default.default.keys(serializedState);const widgetPropIds=___default.default.keys(this.state.widgetProps);if(serializedWidgetIds.length!==widgetPropIds.length||___default.default.intersection(serializedWidgetIds,widgetPropIds).length!==serializedWidgetIds.length){Log.error("Refusing to restore bad serialized state:",perseusCore.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(!___default.default.isArray(focusPath)){throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),perseusCore.Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!___default.default.isEqual(fullPath,blurringFocusPath)){return}___default.default.defer(()=>{if(___default.default.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(___default.default.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__default.default({"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(___default.default.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=___default.default.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=$__default.default(ReactDOM__namespace.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'",perseusCore.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=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__namespace.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(___default.default.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!___default.default.isEqual(this._currentFocus,path)){return}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.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={};___default.default.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!___default.default.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__namespace.linterContextDefault};const styles$E={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
1716
+ 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 ___default.default.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return ___default.default.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return perseusCore.splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:perseusCore.getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!___default.default.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React__namespace.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=!___default.default.isEqual(this.state,nextState);const propsChanged=!___default.default.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&&___default.default.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||___default.default.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&&!___default.default.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:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.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=perseusScore.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 perseusScore.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=perseusScore.scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=perseusScore.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__namespace.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__default.default({[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=perseusCore.applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{problemNum}=props;const widgetsStartProps={};const{strings}=this.props;wonderStuffCore.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=___default.default.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__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return perseusCore.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=___default.default.keys(serializedState);const widgetPropIds=___default.default.keys(this.state.widgetProps);if(serializedWidgetIds.length!==widgetPropIds.length||___default.default.intersection(serializedWidgetIds,widgetPropIds).length!==serializedWidgetIds.length){Log.error("Refusing to restore bad serialized state:",perseusCore.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(!___default.default.isArray(focusPath)){throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),perseusCore.Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!___default.default.isEqual(fullPath,blurringFocusPath)){return}___default.default.defer(()=>{if(___default.default.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(___default.default.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__default.default({"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(___default.default.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=___default.default.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=$__default.default(ReactDOM__namespace.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'",perseusCore.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=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__namespace.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(___default.default.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!___default.default.isEqual(this._currentFocus,path)){return}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.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={};___default.default.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!___default.default.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__namespace.linterContextDefault};const styles$E={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
1717
1717
 
1718
1718
  const{captureScratchpadTouchStart: captureScratchpadTouchStart$2}=Util;const InputWithExamples=React.forwardRef(function InputWithExamples({shouldShowExamples=true,onFocus=()=>{},onBlur=()=>{},disabled=false,linterContext=PerseusLinter__namespace.linterContextDefault,className="",...props},ref){const context=React__namespace.useContext(PerseusI18nContext);const inputRef=React__namespace.useRef(null);const[inputFocused,setInputFocused]=React__namespace.useState(false);const id=React.useId();const ariaId=`aria-for-${id}`;React.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]}
1719
1719
  ${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(Tooltip.TooltipContent,{children:jsxRuntimeExports.jsx("div",{id:id,className:"input-with-examples-tooltip",children:jsxRuntimeExports.jsx(Renderer,{content:examplesContent,linterContext:PerseusLinter__namespace.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}
@@ -1729,11 +1729,11 @@ const NumericInputComponent=React.forwardRef(function NumericInputComponent(prop
1729
1729
 
1730
1730
  class NumericInput extends React__namespace.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__namespace.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:PerseusLinter.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=kmath.KhanMath.toNumericString(answer.value,format);if(answer.maxError){answerString+=" ± "+kmath.KhanMath.toNumericString(answer.maxError,format);}return answerString});if(answerStrings.length===0){return}return answerStrings[0]},getStartUserInput: getStartUserInput$h,getUserInputFromSerializedState: getUserInputFromSerializedState$g};
1731
1731
 
1732
- 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?.choicesSelected?.slice()??[]}}};
1732
+ 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??[]}}};
1733
1733
 
1734
1734
  var styles$C = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
1735
1735
 
1736
- const SCROLL_DISTANCE=100;function ScrollableView({overflowX,overflowY,children,className,scrollDescription,style,role="group",...additionalProps}){const{strings}=usePerseusI18n();const containerRef=React.useRef(null);const[isScrollable,setIsScrollable]=React.useState(false);const[canScrollStart,setCanScrollStart]=React.useState(false);const[canScrollEnd,setCanScrollEnd]=React.useState(false);const[isRtl,setIsRtl]=React.useState(false);const updateScrollState=React__namespace.useCallback(()=>{if(!containerRef.current){return}const{scrollLeft,scrollWidth,clientWidth}=containerRef.current;setIsRtl(getComputedStyle(containerRef.current).direction==="rtl");const scrollableThreshold=5;setIsScrollable(scrollWidth>clientWidth+scrollableThreshold);if(isRtl){setCanScrollStart(Math.abs(scrollLeft)<scrollWidth-clientWidth-scrollableThreshold);setCanScrollEnd(scrollLeft<-5);}else {setCanScrollStart(scrollLeft>scrollableThreshold);setCanScrollEnd(scrollLeft+clientWidth<scrollWidth-scrollableThreshold);}},[isRtl]);const scroll=direction=>{if(!containerRef.current){return}const scrollNegative=isRtl&&direction!=="start"||!isRtl&&direction==="start";const scrollAmount=scrollNegative?-100:SCROLL_DISTANCE;containerRef.current.scrollBy({left:scrollAmount,behavior:"smooth"});};React.useEffect(()=>{const container=containerRef.current;if(!container){return}updateScrollState();container.addEventListener("scroll",updateScrollState);window.addEventListener("resize",updateScrollState);return ()=>{container.removeEventListener("scroll",updateScrollState);window.removeEventListener("resize",updateScrollState);}},[children,updateScrollState]);const mergeStyle={overflowX:isScrollable&&overflowX==="auto"?"scroll":overflowX,overflowY:isScrollable&&overflowY==="auto"?"scroll":overflowY,scrollbarWidth:"thin",...style};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("div",{...additionalProps,role:role,className:className,style:mergeStyle,ref:containerRef,children:children}),isScrollable&&jsxRuntimeExports.jsx(ScrollButtons,{onScrollStart:()=>isRtl?scroll("end"):scroll("start"),onScrollEnd:()=>isRtl?scroll("start"):scroll("end"),canScrollStart:canScrollStart,canScrollEnd:canScrollEnd,scrollDescription:scrollDescription?scrollDescription:strings.scrollAnswers,isRTL:isRtl})]})}function ScrollButtons({onScrollStart,onScrollEnd,canScrollStart,canScrollEnd,scrollDescription,isRTL}){const{strings}=usePerseusI18n();return jsxRuntimeExports.jsxs("div",{className:styles$C.scrollButtonsContainer,children:[jsxRuntimeExports.jsx(IconButton__default.default,{icon:isRTL?caretRightIcon__default.default:caretLeftIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:isRTL?onScrollEnd:onScrollStart,"aria-label":strings.scrollStart,disabled:isRTL?!canScrollEnd:!canScrollStart}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:isRTL?caretLeftIcon__default.default:caretRightIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:isRTL?onScrollStart:onScrollEnd,"aria-label":strings.scrollEnd,disabled:isRTL?!canScrollStart:!canScrollEnd}),jsxRuntimeExports.jsx(wonderBlocksTypography.LabelSmall,{children:scrollDescription})]})}
1736
+ const SCROLL_DISTANCE=100;const scrollInstances=new Map;function ScrollableArea({overflowX,overflowY,children,className,scrollDescription,style,role="group",id:providedId,...additionalProps}){const{strings}=usePerseusI18n();const containerRef=React.useRef(null);const[isScrollable,setIsScrollable]=React.useState(false);const[isRtl,setIsRtl]=React.useState(false);const[isScrolling,setIsScrolling]=React.useState(false);const generatedId=React__namespace.useId();const id=providedId||generatedId;const scrollableThreshold=React__namespace.useMemo(()=>{return window.innerWidth<=767?8:5},[]);const scroll=React__namespace.useCallback(direction=>{if(!containerRef.current||isScrolling){return}setIsScrolling(true);const scrollNegative=isRtl&&direction!=="start"||!isRtl&&direction==="start";const scrollAmount=scrollNegative?-100:SCROLL_DISTANCE;containerRef.current.scrollBy({left:scrollAmount,behavior:"smooth"});setTimeout(()=>{setIsScrolling(false);},150);},[isRtl,isScrolling]);const updateScrollState=React__namespace.useCallback(()=>{if(!containerRef.current){return}const{scrollLeft,scrollWidth,clientWidth}=containerRef.current;const newIsRtl=getComputedStyle(containerRef.current).direction==="rtl";setIsRtl(newIsRtl);const newIsScrollable=scrollWidth>clientWidth+scrollableThreshold;setIsScrollable(newIsScrollable);let newCanScrollStart;let newCanScrollEnd;if(newIsRtl){newCanScrollStart=Math.abs(scrollLeft)<scrollWidth-clientWidth-scrollableThreshold;newCanScrollEnd=scrollLeft<-scrollableThreshold;}else {newCanScrollStart=scrollLeft>scrollableThreshold;newCanScrollEnd=scrollLeft+clientWidth<scrollWidth-scrollableThreshold;}const scrollState={isScrollable:newIsScrollable,canScrollStart:newCanScrollStart,canScrollEnd:newCanScrollEnd,isRTL:newIsRtl,scroll,scrollDescription:scrollDescription||strings.scrollAnswers};scrollInstances.set(id,scrollState);},[id,scrollableThreshold,scrollDescription,strings.scrollAnswers,scroll]);React.useEffect(()=>{const container=containerRef.current;if(!container){return}updateScrollState();container.addEventListener("scroll",updateScrollState);window.addEventListener("resize",updateScrollState);return ()=>{container.removeEventListener("scroll",updateScrollState);window.removeEventListener("resize",updateScrollState);scrollInstances.delete(id);}},[children,updateScrollState,id]);const mergeStyle={overflowX:isScrollable&&overflowX==="auto"?"scroll":overflowX,overflowY:isScrollable&&overflowY==="auto"?"scroll":overflowY,scrollbarWidth:"thin",...style};return jsxRuntimeExports.jsx("div",{...additionalProps,id:id,role:role,className:className,style:mergeStyle,ref:containerRef,children:children})}function ScrollControls({target,scrollDescription:overrideDescription}){const{strings}=usePerseusI18n();const[scrollState,setScrollState]=React.useState(null);React.useEffect(()=>{if(!target){return}const checkForScrollState=()=>{const state=scrollInstances.get(target);if(state){setScrollState(state);}};checkForScrollState();const interval=setInterval(checkForScrollState,100);return ()=>{clearInterval(interval);}},[target]);if(!scrollState||!scrollState.isScrollable){return null}const description=overrideDescription||scrollState.scrollDescription;return jsxRuntimeExports.jsxs("div",{className:styles$C.scrollButtonsContainer,"aria-live":"polite",role:"group","aria-label":description,children:[jsxRuntimeExports.jsx(IconButton__default.default,{icon:scrollState.isRTL?caretRightIcon__default.default:caretLeftIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:()=>scrollState.isRTL?scrollState.scroll("end"):scrollState.scroll("start"),"aria-label":strings.scrollStart,disabled:scrollState.isRTL?!scrollState.canScrollEnd:!scrollState.canScrollStart}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:scrollState.isRTL?caretLeftIcon__default.default:caretRightIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:()=>scrollState.isRTL?scrollState.scroll("start"):scrollState.scroll("end"),"aria-label":strings.scrollEnd,disabled:scrollState.isRTL?!scrollState.canScrollStart:!scrollState.canScrollEnd}),jsxRuntimeExports.jsx(wonderBlocksTypography.LabelSmall,{children:description})]})}const ScrollableView=ScrollableArea;ScrollableView.Controls=ScrollControls;
1737
1737
 
1738
1738
  var styles$B = {"base":"perseus_C4cWo-dY","is-correct":"perseus_vWc7XkhJ","isCorrect":"perseus_vWc7XkhJ","is-wrong":"perseus_yVmsF9sA","isWrong":"perseus_yVmsF9sA","icon":"perseus_brEUCVvd","circle-shape":"perseus_irgRpkgB","circleShape":"perseus_irgRpkgB","square-shape":"perseus_JsUZt48D","squareShape":"perseus_JsUZt48D"};
1739
1739
 
@@ -1745,11 +1745,11 @@ const Choice$2=props=>{const showCorrectness=props.showCorrectness;const buttonR
1745
1745
 
1746
1746
  var styles$z = {"container":"perseus_dzsult1u","choiceList":"perseus_HSvzOAAR","content":"perseus_A5d7KcQj","instructions":"perseus_skOlpdjN","rationale":"perseus_y4m8wyRd","isCorrect":"perseus_IfCbxIVP","reviewAnswers":"perseus_QYlQJ6BF"};
1747
1747
 
1748
- 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){if(props.choiceStates){const choiceStates=props.choiceStates;const choicesSelected=choiceStates.map(()=>false);for(let i=0;i<choicesSelected.length;i++){const index=unshuffle?props.choices[i].originalIndex:i;choicesSelected[index]=choiceStates[i].selected;}return {choicesSelected}}const{values}=props;if(values){const choicesSelected=[...values];const valuesLength=values.length;for(let i=0;i<valuesLength;i++){const index=unshuffle?props.choices[i].originalIndex:i;choicesSelected[index]=values[i];}return {choicesSelected}}return {choicesSelected:props.choices.map(()=>false)}}
1748
+ 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}}
1749
1749
 
1750
1750
  const getInstructionsText$1=({multipleSelect,countChoices,numCorrect,strings})=>{if(multipleSelect){if(perseusCore.usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer};
1751
1751
 
1752
- const MultipleChoiceComponent=({choices,countChoices,multipleSelect=false,numCorrect,onChoiceChange,reviewMode})=>{const{strings}=usePerseusI18n();const legendId=React.useId();const instructions=getInstructionsText$1({multipleSelect,countChoices,numCorrect,strings});const choiceListClasses=reviewMode?`${styles$z.choiceList} ${styles$z.reviewAnswers}`:styles$z.choiceList;return jsxRuntimeExports.jsxs("fieldset",{className:styles$z.container,"data-feature-flag":"feature flag is ON",children:[jsxRuntimeExports.jsx("legend",{id:legendId,"aria-hidden":"true",className:styles$z.instructions,children:instructions}),jsxRuntimeExports.jsx(ScrollableView,{overflowX:"auto",children:jsxRuntimeExports.jsx("ul",{"aria-labelledby":legendId,className:choiceListClasses,children:jsxRuntimeExports.jsx(ChoiceListItems,{choices:choices,i18nStrings:strings,onChoiceChange:onChoiceChange,reviewMode:reviewMode,multipleSelect:multipleSelect})})})]})};const ChoiceListItems=props=>{const{choices,i18nStrings,multipleSelect,onChoiceChange,reviewMode}=props;const listId=React.useId();const items=choices.map((choice,i)=>{const updateChecked=isChecked=>{onChoiceChange(i,isChecked);};const contentId=`${listId}-choice-${i+1}`;const choiceLetter=getChoiceLetter(i,i18nStrings);const srContent=reviewMode&&choice.correct?i18nStrings.choiceCorrect:i18nStrings.choice;const indicatorContent={visible:choiceLetter,screenReader:srContent({letter:choiceLetter}),labelledBy:contentId};const showCorrectness=reviewMode?choice.correct?"correct":"wrong":undefined;const content=choice.isNoneOfTheAbove?i18nStrings.noneOfTheAbove:choice.content;let rationale;if(reviewMode&&choice.hasRationale){const rationaleId=`${contentId}-rationale`;indicatorContent.describedBy=rationaleId;const rationaleClasses=showCorrectness==="correct"?`${styles$z.rationale} ${styles$z.isCorrect}`:styles$z.rationale;rationale=jsxRuntimeExports.jsx("div",{id:rationaleId,className:rationaleClasses,children:choice.rationale});}return jsxRuntimeExports.jsx(Choice$2,{checked:choice.checked,indicatorContent:indicatorContent,isMultiSelect:multipleSelect,showCorrectness:showCorrectness,updateChecked:updateChecked,children:jsxRuntimeExports.jsxs("div",{className:styles$z.content,children:[jsxRuntimeExports.jsx("div",{id:contentId,children:content}),rationale]})},choice.id)});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:items})};
1752
+ const MultipleChoiceComponent=({choices,countChoices,multipleSelect=false,numCorrect,onChoiceChange,reviewMode})=>{const{strings}=usePerseusI18n();const legendId=React.useId();const instructions=getInstructionsText$1({multipleSelect,countChoices,numCorrect,strings});const choiceListClasses=reviewMode?`${styles$z.choiceList} ${styles$z.reviewAnswers}`:styles$z.choiceList;const scrollId=React.useId()+"-scroll";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("fieldset",{className:styles$z.container,"data-feature-flag":"feature flag is ON",children:[jsxRuntimeExports.jsx("legend",{id:legendId,"aria-hidden":"true",className:styles$z.instructions,children:instructions}),jsxRuntimeExports.jsx(ScrollableView,{id:scrollId,overflowX:"auto",children:jsxRuntimeExports.jsx("ul",{"aria-labelledby":legendId,className:choiceListClasses,children:jsxRuntimeExports.jsx(ChoiceListItems,{choices:choices,i18nStrings:strings,onChoiceChange:onChoiceChange,reviewMode:reviewMode,multipleSelect:multipleSelect})})})]}),jsxRuntimeExports.jsx(ScrollableView.Controls,{target:scrollId})]})};const ChoiceListItems=props=>{const{choices,i18nStrings,multipleSelect,onChoiceChange,reviewMode}=props;const listId=React.useId();const items=choices.map((choice,i)=>{const updateChecked=isChecked=>{onChoiceChange(choice.id,isChecked);};const contentId=`${listId}-choice-${i+1}`;const choiceLetter=getChoiceLetter(i,i18nStrings);const srContent=reviewMode&&choice.correct?i18nStrings.choiceCorrect:i18nStrings.choice;const indicatorContent={visible:choiceLetter,screenReader:srContent({letter:choiceLetter}),labelledBy:contentId};const showCorrectness=reviewMode?choice.correct?"correct":"wrong":undefined;const content=choice.isNoneOfTheAbove?i18nStrings.noneOfTheAbove:choice.content;let rationale;if(reviewMode&&choice.hasRationale){const rationaleId=`${contentId}-rationale`;indicatorContent.describedBy=rationaleId;const rationaleClasses=showCorrectness==="correct"?`${styles$z.rationale} ${styles$z.isCorrect}`:styles$z.rationale;rationale=jsxRuntimeExports.jsx("div",{id:rationaleId,className:rationaleClasses,children:choice.rationale});}return jsxRuntimeExports.jsx(Choice$2,{checked:choice.checked,indicatorContent:indicatorContent,isMultiSelect:multipleSelect,showCorrectness:showCorrectness,updateChecked:updateChecked,children:jsxRuntimeExports.jsxs("div",{className:styles$z.content,children:[jsxRuntimeExports.jsx("div",{id:contentId,children:content}),rationale]})},choice.id)});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:items})};
1753
1753
 
1754
1754
  const getPromptJSON$p=renderProps=>{return {type:"passage-ref",options:{passageNumber:renderProps.passageNumber,referenceNumber:renderProps.referenceNumber,summaryText:renderProps.summaryText}}};
1755
1755
 
@@ -1785,7 +1785,7 @@ const EN_DASH$1="–";class PassageRef extends React__namespace.Component{compon
1785
1785
 
1786
1786
  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}};
1787
1787
 
1788
- class MultipleChoiceWidget extends React__namespace.Component{getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const choicesProps=this.prepareChoicesProps();const{apiOptions,reviewMode,multipleSelect,countChoices,numCorrect}=this.props;const onChoiceChange=apiOptions.readOnly||reviewMode?()=>{}:this.handleChoiceChange;return jsxRuntimeExports.jsx(MultipleChoiceComponent,{reviewMode:reviewMode,multipleSelect:multipleSelect,countChoices:countChoices,numCorrect:numCorrect,choices:choicesProps,onChoiceChange:onChoiceChange})}constructor(...args){super(...args),this.renderContent=(content="")=>{const{parsedContent,extractedWidgets}=parseNestedWidgets(content);const{strings=mockStrings,findWidgets}=this.props;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")},this.handleChoiceChange=(choiceIndex,newCheckedState)=>{const{choices,choiceStates,multipleSelect=false,onChange,trackInteraction}=this.props;let newCheckedList;if(newCheckedState&&!multipleSelect){newCheckedList=choices.map(()=>false);}else {newCheckedList=choiceStates?choiceStates.map(state=>state.selected):choices.map(()=>false);}newCheckedList[choiceIndex]=newCheckedState;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)=>{choiceState.selected=newCheckedList[i];});onChange({choiceStates:newChoiceStates});trackInteraction();},this.buildChoiceProps=choiceStates=>{const{choices,reviewModeRubric,questionCompleted,strings=mockStrings}=this.props;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:this.renderContent(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this.renderContent(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(questionCompleted&&selected),previouslyAnswered}})},this.prepareChoicesProps=()=>{const{choices,showSolutions,choiceStates,values}=this.props;const processedChoiceStates=getChoiceStates({choices,isStatic:this.props.static,showSolutions,choiceStates,values});const choicesProps=this.buildChoiceProps(processedChoiceStates);return choicesProps};}}MultipleChoiceWidget.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:PerseusLinter.linterContextDefault,showSolutions:"none"};const Radio$3=MultipleChoiceWidget;
1788
+ const MultipleChoiceWidget=React.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;React.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;
1789
1789
 
1790
1790
  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})`};
1791
1791
 
@@ -1805,13 +1805,13 @@ const intermediateCheckboxPadding=`16px 16px`;const intermediateCheckboxPaddingP
1805
1805
 
1806
1806
  const ChoiceNoneAbove=function({content,forwardedRef,showContent=true,...rest}){const{strings}=usePerseusI18n();const choiceProps={...rest,content:showContent?content:jsxRuntimeExports.jsx(Renderer,{content:strings.noneOfTheAbove,strings:strings},"noneOfTheAboveRenderer")};return jsxRuntimeExports.jsx(Choice$1,{...choiceProps,ref:forwardedRef})};var ChoiceNoneAbove$1 = React__namespace.forwardRef(function ChoiceNoneAboveWithRef(props,ref){return jsxRuntimeExports.jsx(ChoiceNoneAbove,{...props,forwardedRef:ref})});
1807
1807
 
1808
- const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;function getInstructionsText(multipleSelect,countChoices,numCorrect,strings){if(multipleSelect){if(perseusCore.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=React.useRef();const choiceRefs=React.useRef([]);React.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__namespace.default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){scrollElementIntoView(buttonNode);}}}prevReviewModeRubric.current=reviewModeRubric;},[apiOptions,choices,isLastUsedWidget,reviewModeRubric]);function updateChoice(choiceIndex,newValues){let newCheckedList;if(newValues.checked&&!multipleSelect){newCheckedList=choices.map(_=>false);}else {newCheckedList=choices.map(c=>c.checked);}newCheckedList[choiceIndex]=newValues.checked;onChange({checked:newCheckedList});}registerFocusFunction?.(choiceIndex=>{const ref=choiceRefs.current[choiceIndex||0];const anyNode=ReactDOM__namespace.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__default.default("perseus-widget-radio",!editMode&&"perseus-rendered-radio",aphrodite.css(styles$p.radio,styles$p.responsiveRadioContainer,firstChoiceHighlighted&&isMobile&&styles$p.radioContainerFirstHighlighted,lastChoiceHighlighted&&isMobile&&styles$p.radioContainerLastHighlighted));const instructionsClassName=classNames__default.default("instructions",aphrodite.css(styles$p.instructions,isMobile&&styles$p.instructionsMobile));const instructions=getInstructionsText(multipleSelect,countChoices,numCorrect,strings);const responsiveClassName=aphrodite.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__namespace.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(i,newValues);}};if(choice.isNoneOfTheAbove){Element=ChoiceNoneAbove$1;___default.default.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const nextChoice=choices[i+1];const nextChoiceHighlighted=!!nextChoice&&nextChoice.highlighted;const aphroditeClassName=checked=>{return aphrodite.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__default.default(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(i,{checked:!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:aphrodite.css(styles$p.responsiveContainer),children:fieldset})};const styles$p=aphrodite.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"}});
1808
+ const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;function getInstructionsText(multipleSelect,countChoices,numCorrect,strings){if(multipleSelect){if(perseusCore.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=React.useRef();const choiceRefs=React.useRef([]);React.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__namespace.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__namespace.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__default.default("perseus-widget-radio",!editMode&&"perseus-rendered-radio",aphrodite.css(styles$p.radio,styles$p.responsiveRadioContainer,firstChoiceHighlighted&&isMobile&&styles$p.radioContainerFirstHighlighted,lastChoiceHighlighted&&isMobile&&styles$p.radioContainerLastHighlighted));const instructionsClassName=classNames__default.default("instructions",aphrodite.css(styles$p.instructions,isMobile&&styles$p.instructionsMobile));const instructions=getInstructionsText(multipleSelect,countChoices,numCorrect,strings);const responsiveClassName=aphrodite.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__namespace.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;___default.default.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const nextChoice=choices[i+1];const nextChoiceHighlighted=!!nextChoice&&nextChoice.highlighted;const aphroditeClassName=checked=>{return aphrodite.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__default.default(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:aphrodite.css(styles$p.responsiveContainer),children:fieldset})};const styles$p=aphrodite.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"}});
1809
1809
 
1810
- let Radio$2 = class Radio extends React__namespace.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=newValueLists=>{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)=>{choiceState.selected=newValueLists.checked[i];});this.props.onChange({choiceStates:newChoiceStates});this.props.trackInteraction();};}};Radio$2.contextType=PerseusI18nContext;Radio$2.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:PerseusLinter.linterContextDefault,showSolutions:"none"};
1810
+ let Radio$2 = class Radio extends React__namespace.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:PerseusLinter.linterContextDefault,showSolutions:"none"};
1811
1811
 
1812
- 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(!___default.default.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:perseusCore.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?.choicesSelected[choice.originalIndex];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__namespace.createRef(),this.state={choiceStates:[]};this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;this.state={choiceStates:initChoiceStates(props.choices)};}};
1812
+ 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(!___default.default.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:perseusCore.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__namespace.createRef(),this.state={choiceStates:[]};this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;this.state={choiceStates:initChoiceStates(props.choices)};}};
1813
1813
 
1814
- const _choiceTransform=(widgetOptions,strings)=>{const _maybeRandomize=function(array){return widgetOptions.randomize?perseusCore.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=>___default.default.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$1=(widgetOptions,strings)=>{const choices=_choiceTransform(widgetOptions,strings);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:___default.default.pluck(choices,"correct")}};function getStartUserInput$g(options){return {choicesSelected:options.choices.map(()=>false)}}function getCorrectUserInput$6(options){return {choicesSelected:options.choices.map(option=>!!option.correct)}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,transform: transform$1,staticTransform:transform$1,getStartUserInput: getStartUserInput$g,getCorrectUserInput: getCorrectUserInput$6,version:perseusCore.radioLogic.version,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState,true)}};
1814
+ const _choiceTransform=(widgetOptions,strings)=>{const _maybeRandomize=function(array){return widgetOptions.randomize?perseusCore.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=>___default.default.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$1=(widgetOptions,strings)=>{const choices=_choiceTransform(widgetOptions,strings);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:___default.default.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: transform$1,staticTransform:transform$1,getStartUserInput: getStartUserInput$g,getCorrectUserInput: getCorrectUserInput$6,version:perseusCore.radioLogic.version,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState,true)}};
1815
1815
 
1816
1816
  var basicWidgets = [Radio,InputNumber$1,NumericInput$1,Expression$1];
1817
1817
 
@@ -1857,7 +1857,7 @@ class FreeResponse extends React__namespace.Component{isOverLimit(){return !this
1857
1857
 
1858
1858
  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 perseusCore.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}
1859
1859
 
1860
- 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 sharedRestoreUserInputFromSerializedState(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]=React.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(sharedRestoreUserInputFromSerializedState(serializedState,widgetOptions));}return props.children({userInput,handleUserInput,initializeUserInput,restoreUserInputFromSerializedState})}
1860
+ 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]=React.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})}
1861
1861
 
1862
1862
  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}};
1863
1863
 
@@ -1867,7 +1867,7 @@ const GRADING_STATUSES={ungraded:"ungraded",correct:"correct",incorrect:"incorre
1867
1867
 
1868
1868
  const getPromptJSON$h=(renderProps,activeGroupJSON)=>{return {type:"graded-group-set",options:{groupCount:renderProps.gradedGroups.length,currentGroup:activeGroupJSON}}};
1869
1869
 
1870
- class Indicators extends React__namespace.Component{render(){return jsxRuntimeExports.jsx("ul",{className:classNames__default.default(aphrodite.css(styles$h.indicatorContainer),"indicatorContainer"),children:this.props.gradedGroups.map(({title},i)=>jsxRuntimeExports.jsx("li",{className:aphrodite.css(styles$h.indicator),children:jsxRuntimeExports.jsx(Clickable__default.default,{role:"button","aria-label":this.context.strings.skipToTitle({title}),style:styles$h.indicatorButton,onClick:()=>this.props.onChangeCurrentGroup(i),onKeyDown:e=>this.handleKeyDown(e,i),children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$h.indicatorDot,(hovered||focused||pressed)&&styles$h.indicatorDotFocused],children:i===this.props.currentGroup&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$h.indicatorDotActive,children:jsxRuntimeExports.jsx("span",{className:aphrodite.css(a11y.srOnly),children:this.context.strings.current})})})})},title))})}constructor(...args){super(...args),this.handleKeyDown=(e,i)=>{if(e.key==="Enter"||e.key===" "){this.props.onChangeCurrentGroup(i);}};}}Indicators.contextType=PerseusI18nContext;class GradedGroupSet extends React__namespace.Component{shouldComponentUpdate(nextProps,nextState){return nextProps!==this.props||nextState!==this.state}getPromptJSON(){const activeGroupPromptJSON=this._childGroup.getPromptJSON();return getPromptJSON$h(this.props,activeGroupPromptJSON)}render(){const{JIPT}=getDependencies();if(JIPT.useJIPT&&this.props.gradedGroups.length>1){return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$h.container),children:this.props.gradedGroups.map((gradedGroup,i)=>{return jsxRuntimeExports.jsx(GradedGroup,{...this.props,...gradedGroup,inGradedGroupSet:false,linterContext:this.props.linterContext},i)})})}const currentGroup=this.props.gradedGroups[this.state.currentGroup];if(!currentGroup){return jsxRuntimeExports.jsx("span",{children:"No current group..."})}const numGroups=this.props.gradedGroups.length;const handleNextQuestion=this.state.currentGroup<numGroups-1?this.handleNextQuestion:null;return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$h.container),children:[jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$h.top),children:[jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$h.title),children:currentGroup.title}),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$h.spacer)}),jsxRuntimeExports.jsx(Indicators,{currentGroup:this.state.currentGroup,gradedGroups:this.props.gradedGroups,onChangeCurrentGroup:currentGroup=>this.setState({currentGroup})})]}),jsxRuntimeExports.jsx(GradedGroup,{ref:comp=>this._childGroup=comp,...this.props,...currentGroup,inGradedGroupSet:true,title:null,onNextQuestion:handleNextQuestion,linterContext:this.props.linterContext},this.state.currentGroup)]})}constructor(...args){super(...args),this.state={currentGroup:0},this.getInputPaths=()=>{return this._childGroup.getInputPaths()},this.focus=()=>{return this._childGroup.focus()},this.focusInputPath=path=>{this._childGroup.focusInputPath(path);},this.blurInputPath=path=>{this._childGroup.blurInputPath(path);},this.handleNextQuestion=()=>{const{currentGroup}=this.state;const numGroups=this.props.gradedGroups.length;if(currentGroup<numGroups-1){this.setState({currentGroup:currentGroup+1});}};}}GradedGroupSet.defaultProps={gradedGroups:[],linterContext:PerseusLinter.linterContextDefault};var GradedGroupSet$1 = {name:"graded-group-set",displayName:"Graded group set (articles only)",widget:GradedGroupSet,hidden:false,tracking:"all",isLintable:true};const styles$h=aphrodite.StyleSheet.create({top:{display:"flex",flexDirection:"row"},spacer:{flex:1},title:{fontSize:12,color:wonderBlocksTokens.color.offBlack64,textTransform:"uppercase",marginBottom:11,letterSpacing:.8},indicatorContainer:{display:"flex",flexDirection:"row",listStyle:"none",margin:"unset",paddingInlineStart:"unset",flexWrap:"wrap"},indicator:{width:24,height:24},indicatorButton:{width:"100%",height:"100%",display:"flex",flexWrap:"wrap",placeContent:"center",cursor:"pointer",":focus":{outline:"none"}},indicatorDot:{boxSizing:"content-box",width:10,height:10,borderRadius:"100%",borderWidth:2,borderColor:wonderBlocksTokens.color.blue,borderStyle:"solid"},indicatorDotFocused:{borderWidth:5,borderStyle:"double"},indicatorDotActive:{backgroundColor:wonderBlocksTokens.color.blue,width:"100%",height:"100%"},container:{borderTop:`1px solid ${gray76}`,borderBottom:`1px solid ${gray76}`,backgroundColor:tableBackgroundAccent,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,paddingBottom:phoneMargin,paddingLeft:phoneMargin,paddingRight:phoneMargin,paddingTop:10,width:"auto"}});
1870
+ class Indicators extends React__namespace.Component{render(){return jsxRuntimeExports.jsx("ul",{className:classNames__default.default(aphrodite.css(styles$h.indicatorContainer),"indicatorContainer"),children:this.props.gradedGroups.map(({title},i)=>jsxRuntimeExports.jsx("li",{className:aphrodite.css(styles$h.indicator),children:jsxRuntimeExports.jsx(Clickable__default.default,{role:"button","aria-label":this.context.strings.skipToTitle({title}),style:styles$h.indicatorButton,onClick:()=>this.props.onChangeCurrentGroup(i),onKeyDown:e=>this.handleKeyDown(e,i),children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$h.indicatorDot,(hovered||focused||pressed)&&styles$h.indicatorDotFocused],children:i===this.props.currentGroup&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$h.indicatorDotActive,children:jsxRuntimeExports.jsx("span",{className:aphrodite.css(a11y.srOnly),children:this.context.strings.current})})})})},title))})}constructor(...args){super(...args),this.handleKeyDown=(e,i)=>{if(e.key==="Enter"||e.key===" "){this.props.onChangeCurrentGroup(i);}};}}Indicators.contextType=PerseusI18nContext;class GradedGroupSet extends React__namespace.Component{shouldComponentUpdate(nextProps,nextState){return nextProps!==this.props||nextState!==this.state}getPromptJSON(){const activeGroupPromptJSON=this._childGroup.getPromptJSON();return getPromptJSON$h(this.props,activeGroupPromptJSON)}render(){const{JIPT}=getDependencies();if(JIPT.useJIPT&&this.props.gradedGroups.length>1){return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$h.container),children:this.props.gradedGroups.map((gradedGroup,i)=>{return jsxRuntimeExports.jsx(GradedGroup,{...this.props,...gradedGroup,inGradedGroupSet:false,linterContext:this.props.linterContext},i)})})}const currentGroup=this.props.gradedGroups[this.state.currentGroup];if(!currentGroup){return jsxRuntimeExports.jsx("span",{children:"No current group..."})}const numGroups=this.props.gradedGroups.length;const handleNextQuestion=this.state.currentGroup<numGroups-1?this.handleNextQuestion:null;return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$h.container),children:[jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$h.top),children:[jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$h.title),children:currentGroup.title}),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$h.spacer)}),jsxRuntimeExports.jsx(Indicators,{currentGroup:this.state.currentGroup,gradedGroups:this.props.gradedGroups,onChangeCurrentGroup:currentGroup=>this.setState({currentGroup})})]}),jsxRuntimeExports.jsx(GradedGroup,{ref:comp=>this._childGroup=comp,...this.props,...currentGroup,inGradedGroupSet:true,title:null,onNextQuestion:handleNextQuestion,linterContext:this.props.linterContext},this.state.currentGroup)]})}constructor(...args){super(...args),this.state={currentGroup:0},this.getInputPaths=()=>{return this._childGroup.getInputPaths()},this.focus=()=>{return this._childGroup.focus()},this.focusInputPath=path=>{this._childGroup.focusInputPath(path);},this.blurInputPath=path=>{this._childGroup.blurInputPath(path);},this.handleNextQuestion=()=>{const{currentGroup}=this.state;const numGroups=this.props.gradedGroups.length;if(currentGroup<numGroups-1){this.setState({currentGroup:currentGroup+1});}};}}GradedGroupSet.defaultProps={gradedGroups:[],linterContext:PerseusLinter.linterContextDefault};var GradedGroupSet$1 = {name:"graded-group-set",displayName:"Graded group set (articles only)",widget:GradedGroupSet,hidden:false,tracking:"all",isLintable:true};const styles$h=aphrodite.StyleSheet.create({top:{display:"flex",flexDirection:"row"},spacer:{flex:1},title:{fontSize:12,color:wonderBlocksTokens.color.offBlack64,textTransform:"uppercase",marginBottom:11,letterSpacing:.8},indicatorContainer:{display:"flex",flexDirection:"row",listStyle:"none",margin:"unset",paddingInlineStart:"unset",flexWrap:"wrap"},indicator:{width:24,height:24},indicatorButton:{width:"100%",height:"100%",display:"flex",flexWrap:"wrap",placeContent:"center",cursor:"pointer",":focus":{outline:"none"}},indicatorDot:{boxSizing:"content-box",width:10,height:10,borderRadius:"100%",borderWidth:2,borderColor:wonderBlocksTokens.color.blue,borderStyle:"solid"},indicatorDotFocused:{borderWidth:5,borderStyle:"double"},indicatorDotActive:{backgroundColor:wonderBlocksTokens.color.blue,width:"100%",height:"100%"},container:{borderTop:`1px solid ${gray76}`,borderBottom:`1px solid ${gray76}`,backgroundColor:tableBackgroundAccent,"--perseus-widget-background-color":tableBackgroundAccent,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,paddingBottom:phoneMargin,paddingLeft:phoneMargin,paddingRight:phoneMargin,paddingTop:10,width:"auto"}});
1871
1871
 
1872
1872
  class ButtonGroup extends React__namespace.Component{componentWillUnmount(){this.container=null;}focus(){if(this.container){this.container.focus();return true}}toggleSelect(newValue){const value=this.props.value;if(this.props.allowEmpty){this.props.onChange(value!==newValue?newValue:null);}else {this.props.onChange(newValue);}}render(){const value=this.props.value;const buttons=this.props.buttons.map((button,i)=>{return jsxRuntimeExports.jsx("button",{title:button.title,type:"button",ref:"button"+i,className:aphrodite.css(styles$g.buttonStyle,button.value===value&&styles$g.selectedStyle,button.value===value&&this.props.selectedButtonStyle),onClick:()=>this.toggleSelect(button.value),children:button.content||""+button.value},""+i)});const outerStyle={display:"inline-block"};return jsxRuntimeExports.jsx("div",{style:outerStyle,ref:node=>this.container=node,children:buttons})}}ButtonGroup.defaultProps={value:null,allowEmpty:true};const styles$g=aphrodite.StyleSheet.create({buttonStyle:{backgroundColor:"white",border:"1px solid #ccc",borderLeft:"0",cursor:"pointer",margin:"0",padding:"5px 10px",position:"relative",":first-child":{borderLeft:"1px solid #ccc",borderTopLeftRadius:"3px",borderBottomLeftRadius:"3px"},":last-child":{borderRight:"1px solid #ccc",borderTopRightRadius:"3px",borderBottomRightRadius:"3px"},":hover":{backgroundColor:"#ccc"},":focus":{zIndex:2}},selectedStyle:{backgroundColor:"#ddd"}});
1873
1873
 
@@ -1879,7 +1879,7 @@ const MovablePoint$3=Graphie.MovablePoint;const MovableLine$2=Graphie.MovableLin
1879
1879
 
1880
1880
  const getPromptJSON$f=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
1881
1881
 
1882
- class Group extends React__namespace.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__default.default({"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:PerseusLinter.linterContextDefault};function getStartUserInput$a(options,problemNum){return sharedInitializeUserInput(options.widgets,problemNum)}function getUserInputFromSerializedState$a(serializedState,widgetOptions){return sharedRestoreUserInputFromSerializedState(serializedState,widgetOptions.widgets)}var Group$1 = {name:"group",displayName:"Group (SAT only)",widget:Group,hidden:true,isLintable:true,getStartUserInput: getStartUserInput$a,getUserInputFromSerializedState: getUserInputFromSerializedState$a};
1882
+ class Group extends React__namespace.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__default.default({"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:PerseusLinter.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};
1883
1883
 
1884
1884
  const getPromptJSON$e=()=>{return getUnsupportedPromptJSON("iframe")};
1885
1885
 
@@ -1887,7 +1887,9 @@ const{updateQueryString}=Util;class Iframe extends React__namespace.Component{co
1887
1887
 
1888
1888
  const getPromptJSON$d=renderProps=>{return {type:"image",options:{altText:renderProps.alt,title:renderProps.title,caption:renderProps.caption,imageUrl:renderProps.backgroundImage.url}}};
1889
1889
 
1890
- const defaultBoxSize=400;const defaultRange=[0,10];const defaultBackgroundImage$1={url:null,width:0,height:0};class ImageWidget extends React__namespace.Component{getPromptJSON(){return getPromptJSON$d(this.props)}render(){let image;const alt=this.props.caption===this.props.alt?"":this.props.alt;const{apiOptions}=this.props;const backgroundImage=this.props.backgroundImage;if(backgroundImage.url){const url=backgroundImage.url;image=jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:url,alt:alt,width:backgroundImage.width,height:backgroundImage.height,preloader:apiOptions.imagePreloader,extraGraphie:{box:this.props.box,range:this.props.range,labels:this.props.labels},trackInteraction:this.props.trackInteraction,zoomToFullSizeOnMobile:apiOptions.isMobile,constrainHeight:apiOptions.isMobile,allowFullBleed:apiOptions.isMobile,setAssetStatus:setAssetStatus})});}let title;let caption;if(this.props.title){title=jsxRuntimeExports.jsx("div",{className:"perseus-image-title",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.title,apiOptions:apiOptions,linterContext:this.props.linterContext,strings:this.context.strings})});}if(this.props.caption){caption=jsxRuntimeExports.jsx("figcaption",{className:"perseus-image-caption",style:{maxWidth:backgroundImage.width},children:jsxRuntimeExports.jsx(Renderer,{content:this.props.caption,apiOptions:apiOptions,linterContext:this.props.linterContext,strings:this.context.strings})});}return jsxRuntimeExports.jsxs("figure",{className:"perseus-image-widget",style:{maxWidth:backgroundImage.width},children:[title,image,caption]})}constructor(...args){super(...args),this.isWidget=true;}}ImageWidget.contextType=PerseusI18nContext;ImageWidget.defaultProps={alignment:"block",title:"",range:[defaultRange,defaultRange],box:[defaultBoxSize,defaultBoxSize],backgroundImage:defaultBackgroundImage$1,labels:[],alt:"",caption:"",linterContext:PerseusLinter.linterContextDefault};var Image$1 = {name:"image",displayName:"Image",widget:ImageWidget,isLintable:true};
1890
+ const ImageComponent=({apiOptions,alt,backgroundImage,box,caption,linterContext,labels,range,title,trackInteraction})=>{const context=React__namespace.useContext(PerseusI18nContext);return jsxRuntimeExports.jsxs("figure",{className:"perseus-image-widget",style:{maxWidth:backgroundImage.width},children:[title&&jsxRuntimeExports.jsx("div",{className:"perseus-image-title",children:jsxRuntimeExports.jsx(Renderer,{content:title,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})}),backgroundImage.url&&jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:backgroundImage.url,alt:caption===alt?"":alt,width:backgroundImage.width,height:backgroundImage.height,preloader:apiOptions.imagePreloader,extraGraphie:{box:box,range:range,labels:labels},trackInteraction:trackInteraction,zoomToFullSizeOnMobile:apiOptions.isMobile,constrainHeight:apiOptions.isMobile,allowFullBleed:apiOptions.isMobile,setAssetStatus:setAssetStatus})}),caption&&jsxRuntimeExports.jsx("figcaption",{className:"perseus-image-caption",style:{maxWidth:backgroundImage.width},children:jsxRuntimeExports.jsx(Renderer,{content:caption,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})})]})};
1891
+
1892
+ const defaultBoxSize=400;const defaultRange=[0,10];const defaultBackgroundImage$1={url:null,width:0,height:0};class ImageWidget extends React__namespace.Component{getPromptJSON(){return getPromptJSON$d(this.props)}render(){return jsxRuntimeExports.jsx(ImageComponent,{...this.props})}constructor(...args){super(...args),this.isWidget=true;}}ImageWidget.contextType=PerseusI18nContext;ImageWidget.defaultProps={alignment:"block",title:"",range:[defaultRange,defaultRange],box:[defaultBoxSize,defaultBoxSize],backgroundImage:defaultBackgroundImage$1,labels:[],alt:"",caption:"",linterContext:PerseusLinter.linterContextDefault};var Image$1 = {name:"image",displayName:"Image",widget:ImageWidget,isLintable:true};
1891
1893
 
1892
1894
  const getPromptJSON$c=()=>{return getUnsupportedPromptJSON("interaction")};
1893
1895
 
@@ -2124,7 +2126,7 @@ var extraWidgets = [CSProgram$1,Categorizer$1,Definition$1,DeprecatedStandin$1,D
2124
2126
 
2125
2127
  const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
2126
2128
 
2127
- const libName="@khanacademy/perseus";const libVersion="66.5.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2129
+ const libName="@khanacademy/perseus";const libVersion="67.1.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2128
2130
 
2129
2131
  const apiVersion={major:12,minor:0};
2130
2132
 
@@ -2158,7 +2160,7 @@ Items:
2158
2160
  ${items.join("\n")}
2159
2161
  `);}break;case "dropdown":const dropdown=widget;if(dropdown.options?.choices){const choices=dropdown.options.choices.map(choice=>choice.content);context=context.replace(`[[☃ ${widgetID}]]`,`[${choices.join(" | ")}]`);}break;case "definition":const definition=widget;if(definition.options?.togglePrompt){context=context.replace(`[[☃ ${widgetID}]]`,definition.options.togglePrompt);}break;case "orderer":const orderer=widget;if(orderer.options?.options){context=context.replace(`[[☃ ${widgetID}]]`,joinOptionContents(orderer.options.options));}break;case "sorter":const sorter=widget;if(sorter.options?.correct){const choices=sorter.options.correct;context=context.replace(`[[☃ ${widgetID}]]`,`[${choices.join(" | ")}]`);}break;case "interactive-graph":const interactiveGraph=widget;if(interactiveGraph.options?.range.length===2){const[x,y]=interactiveGraph.options.range;context=context.replace(`[[☃ ${widgetID}]]`,`[Graph with an x range of ${x[0]} to ${x[1]} and y range of ${y[0]} to ${y[1]}]`);}break;case "number-line":const numberLine=widget;if(numberLine.options?.range.length===2&&numberLine.options?.tickStep&&numberLine.options?.initialX){const[min,max]=numberLine.options.range;const step=numberLine.options.tickStep;const initialPosition=numberLine.options.initialX;context=context.replace(`[[☃ ${widgetID}]]`,`[Number line with a range of ${min} to ${max}, a step of ${step}, and an initial position of ${initialPosition}]`);}break;case "matrix":const matrix=widget;if(matrix.options?.matrixBoardSize.length===2){const[rows,columns]=matrix.options.matrixBoardSize;context=context.replace(`[[☃ ${widgetID}]]`,`[Matrix with ${rows} rows and ${columns} columns. The user can click on each cell to enter a value]`);}break;case "matcher":const matcher=widget;if(matcher.options?.left&&matcher.options?.right){const{left,right}=matcher.options;const[leftHeader,rightHeader]=matcher.options.labels;const tableHeader=`| ${leftHeader} | ${rightHeader} |
2160
2162
  | --- | --- |`;const tableRows=left.map((leftItem,index)=>{return `| ${leftItem} | ${right[index]} |`});const table=[tableHeader,...tableRows].join("\n");const matcherWidgetExplanation="The user needs to move items in the right column to match the correct option on the left. The order of items on the right side will be different from what the user sees.";context=context.replace(`[[☃ ${widgetID}]]`,`${matcherWidgetExplanation}
2161
- ${table}`);}break;case "numeric-input":case "input-number":case "expression":context=context.replace(`[[☃ ${widgetID}]]`,"?");break;default:context=context.replace(`[[☃ ${widgetID}]]`,`[[Unsupported ${widget.type} widget: Explain to the user that you are unable to understand the content in this widget and ask them to describe it.]]`);}});return context}function getImagesWithoutAltData(perseusRenderer){if(!perseusRenderer.widgets){return ""}const imgsWithoutAltData=[];Object.entries(perseusRenderer.widgets).forEach(([widgetId,widget])=>{if(!widget.options){return}if(widget.type==="image"&&!widget.options.alt&&widget.options.backgroundImage?.url){imgsWithoutAltData.push({widgetId,imgUrl:widget.options.backgroundImage.url});}});return JSON.stringify(imgsWithoutAltData)}const INDIVIDUAL_ANSWER_WIDGETS=["interactive-graph","categorizer","grapher"];const SUPPORTED_WIDGETS=["radio","numeric-input","input-number","expression",...INDIVIDUAL_ANSWER_WIDGETS];const isWrongAnswerSupported=(widgetIds,widgetMap)=>{return widgetIds.length!==0&&widgetIds.every(widgetId=>SUPPORTED_WIDGETS.includes(getWidgetTypeByWidgetId(widgetId,widgetMap)))};const shouldHaveIndividualAnswer=(widgetId,widgetMap)=>{return INDIVIDUAL_ANSWER_WIDGETS.includes(getWidgetTypeByWidgetId(widgetId,widgetMap))};const getAnswerFromUserInput=(widgetType,userInput)=>{switch(widgetType){case "categorizer":return userInput.values;case "input-number":return userInput.currentValue;case "numeric-input":return userInput.currentValue;case "radio":return userInput.choicesSelected}return userInput};const getCorrectAnswerForWidgetId=(widgetId,itemData)=>{const rubric=itemData.question.widgets[widgetId].options;const widgetMap=getWidgetsMapFromItemData(itemData);const widgetType=getWidgetTypeByWidgetId(widgetId,widgetMap);const widget=getWidgetExport(widgetType);return widget?.getOneCorrectAnswerFromRubric?.(rubric)};const isWidgetIdInContent=(perseusItem,widgetId)=>{return perseusItem.question.content.indexOf(widgetId)!==-1};const getValidWidgetIds=perseusItem=>{const{widgets}=perseusItem.question;return wonderStuffCore.keys(widgets).filter(id=>isWidgetIdInContent(perseusItem,id))};
2163
+ ${table}`);}break;case "numeric-input":case "input-number":case "expression":context=context.replace(`[[☃ ${widgetID}]]`,"?");break;default:context=context.replace(`[[☃ ${widgetID}]]`,`[[Unsupported ${widget.type} widget: Explain to the user that you are unable to understand the content in this widget and ask them to describe it.]]`);}});return context}function getImagesWithoutAltData(perseusRenderer){if(!perseusRenderer.widgets){return ""}const imgsWithoutAltData=[];Object.entries(perseusRenderer.widgets).forEach(([widgetId,widget])=>{if(!widget.options){return}if(widget.type==="image"&&!widget.options.alt&&widget.options.backgroundImage?.url){imgsWithoutAltData.push({widgetId,imgUrl:widget.options.backgroundImage.url});}});return JSON.stringify(imgsWithoutAltData)}const INDIVIDUAL_ANSWER_WIDGETS=["interactive-graph","categorizer","grapher"];const SUPPORTED_WIDGETS=["radio","numeric-input","input-number","expression",...INDIVIDUAL_ANSWER_WIDGETS];const isWrongAnswerSupported=(widgetIds,widgetMap)=>{return widgetIds.length!==0&&widgetIds.every(widgetId=>SUPPORTED_WIDGETS.includes(getWidgetTypeByWidgetId(widgetId,widgetMap)))};const shouldHaveIndividualAnswer=(widgetId,widgetMap)=>{return INDIVIDUAL_ANSWER_WIDGETS.includes(getWidgetTypeByWidgetId(widgetId,widgetMap))};const getAnswerFromUserInput=(widgetType,userInput)=>{switch(widgetType){case "categorizer":return userInput.values;case "input-number":return userInput.currentValue;case "numeric-input":return userInput.currentValue;case "radio":return userInput.selectedChoiceIds}return userInput};const getCorrectAnswerForWidgetId=(widgetId,itemData)=>{const rubric=itemData.question.widgets[widgetId].options;const widgetMap=getWidgetsMapFromItemData(itemData);const widgetType=getWidgetTypeByWidgetId(widgetId,widgetMap);const widget=getWidgetExport(widgetType);return widget?.getOneCorrectAnswerFromRubric?.(rubric)};const isWidgetIdInContent=(perseusItem,widgetId)=>{return perseusItem.question.content.indexOf(widgetId)!==-1};const getValidWidgetIds=perseusItem=>{const{widgets}=perseusItem.question;return wonderStuffCore.keys(widgets).filter(id=>isWidgetIdInContent(perseusItem,id))};
2162
2164
 
2163
2165
  function generateTestRadioWidget(){return {type:"radio",options:{choices:[]}}}function generateTestInteractiveGraphWidget(){return {type:"interactive-graph",options:{step:[1,1],gridStep:[1,1],snapStep:[1,1],markings:"graph",labels:["x","y"],lockedFigures:[],showProtractor:false,range:[[-10,10],[-10,10]],graph:{type:"angle"},correct:{type:"angle"},showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true}}}}function generateTestCategorizerWidget(){return {type:"categorizer",options:{items:[],categories:[],randomizeItems:false,static:false,values:[]}}}function generateTestExpressionWidget(){return {type:"expression",options:{answerForms:[],buttonSets:["basic"],functions:[],times:false}}}function generateTestNumericInputWidget(){return {type:"numeric-input",options:{answers:[],labelText:"",size:"normal",coefficient:false,static:false}}}
2164
2166
 
@@ -2227,6 +2229,7 @@ exports.components = components;
2227
2229
  exports.containerSizeClass = containerSizeClass;
2228
2230
  exports.contentHasWidgetType = contentHasWidgetType;
2229
2231
  exports.convertWidgetNameToEnum = convertWidgetNameToEnum;
2232
+ exports.deriveUserInputFromSerializedState = deriveUserInputFromSerializedState;
2230
2233
  exports.displaySigFigs = displaySigFigs;
2231
2234
  exports.excludeDenylistKeys = excludeDenylistKeys;
2232
2235
  exports.generateTestCategorizerWidget = generateTestCategorizerWidget;