@khanacademy/perseus 69.3.0 → 70.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.
package/dist/index.d.ts CHANGED
@@ -55,6 +55,7 @@ export { default as PerseusMarkdown } from "./perseus-markdown";
55
55
  export { isItemRenderableByVersion } from "./renderability";
56
56
  export { interactiveSizes } from "./styles/constants";
57
57
  export { displaySigFigs } from "./sigfigs";
58
+ export { DependenciesContext } from "./dependencies";
58
59
  export { PerseusI18nContextProvider, PerseusI18nContext, usePerseusI18n, } from "./components/i18n-context";
59
60
  /**
60
61
  * Util
@@ -107,7 +108,7 @@ export { excludeDenylistKeys } from "./mixins/widget-prop-denylist";
107
108
  */
108
109
  export type { ILogger, LogErrorOptions } from "./logging/log";
109
110
  export type { ServerItemRenderer as ServerItemRendererComponent } from "./server-item-renderer";
110
- export type { APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, DomInsertCheckFn, EditorMode, FocusPath, ImageDict, ImageUploader, JiptLabelStore, JiptRenderer, PerseusDependencies, PerseusDependenciesV2, VideoData, VideoKind, WidgetExports, SharedRendererProps, } from "./types";
111
+ export type { APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, DomInsertCheckFn, EditorMode, FocusPath, GenerateUrlArgs, ImageDict, ImageUploader, JiptLabelStore, JiptRenderer, PerseusDependencies, PerseusDependenciesV2, VideoData, VideoKind, WidgetExports, SharedRendererProps, } from "./types";
111
112
  export type { ParsedValue } from "./util";
112
113
  export type {
113
114
  /**
package/dist/index.js CHANGED
@@ -1460,7 +1460,7 @@ const debounce=(func,delay)=>{let timer=null;return (...args)=>{if(timer){clearT
1460
1460
 
1461
1461
  class InnerMathInput extends React__namespace.Component{componentDidMount(){this.mathField()?.latex(this.props.value);}openKeypad(){if(this.props.buttonsVisible==="never"){return}this.setState({keypadOpen:true});}closeKeypad(){this.setState({keypadOpen:false});}render(){let className=classNames__default.default({"perseus-math-input":true,"mq-editable-field":true,"mq-math-mode":true});const popoverContentUniqueId=uuid.v4().slice(0,8);if(this.props.className){className=className+" "+this.props.className;}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$I.outerWrapper,this.state.focused&&styles$I.wrapperFocused],children:jsxRuntimeExports.jsxs("div",{style:{display:"flex",padding:1},onClick:e=>{e.stopPropagation();const mathField=this.mathField();if(!mathField){return}this.setState({cursorContext:mathInput.getCursorContext(mathField)});},children:[jsxRuntimeExports.jsx("span",{className:className,ref:ref=>this.__mathFieldWrapperRef=ref,onFocus:()=>this.focus(),onBlur:()=>this.blur()}),jsxRuntimeExports.jsx(wonderBlocksPopover.Popover,{opened:this.state.keypadOpen,dismissEnabled:true,rootBoundary:"document","aria-label":this.context.strings.mathInputTitle,"aria-describedby":`popover-content-${popoverContentUniqueId}`,content:()=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingMedium,{id:`popover-content-${popoverContentUniqueId}`,style:a11y.srOnly,children:this.context.strings.mathInputDescription}),jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$I.popoverContent,children:jsxRuntimeExports.jsx(mathInput.DesktopKeypad,{onAnalyticsEvent:this.props.onAnalyticsEvent,extraKeys:this.props.extraKeys,onClickKey:this.handleKeypadPress,cursorContext:this.state.cursorContext,convertDotToTimes:this.props.convertDotToTimes,...this.props.keypadButtonSets??mapButtonSets(this.props?.buttonSets),showDismiss:true})})]}),children:this.props.buttonsVisible==="never"?jsxRuntimeExports.jsx(MathInputIcon,{hovered:false,focused:false,active:false}):jsxRuntimeExports.jsx(Clickable__default.default,{"aria-label":this.state.keypadOpen?this.context.strings.closeKeypad:this.context.strings.openKeypad,role:"button",onClick:()=>this.state.keypadOpen?this.closeKeypad():this.openKeypad(),children:props=>jsxRuntimeExports.jsx(MathInputIcon,{active:this.state.keypadOpen,...props})})})]})})}constructor(...args){super(...args),this.__mathFieldWrapperRef=null,this.__mathField=null,this.state={focused:false,keypadOpen:this.props.buttonsVisible==="always"?true:false,cursorContext:mathInput.CursorContext.NONE},this.insert=value=>{const input=this.mathField();const{locale}=this.context;const customKeyTranslator={...mathInput.getKeyTranslator(locale,this.context.strings),FRAC:mathQuill=>{const contents=mathQuill.latex();mathQuill.typedText("/");if(mathQuill.latex()===contents){mathQuill.cmd("\\frac");}}};const inputModifier=customKeyTranslator[value];if(inputModifier){inputModifier(input,value);input?.focus();return}if(___default.default(value).isFunction()){value(input);}else if(value[0]==="\\"){input?.cmd(value).focus();}else {input?.write(value).focus();}input?.focus();},this.mathField=()=>{if(!this.__mathField&&this.__mathFieldWrapperRef){const{locale}=this.context;this.__mathField=mathInput.createMathField(this.__mathFieldWrapperRef,locale,this.props.mathInputStrings,baseConfig=>({...baseConfig,handlers:{edit:debounce(mathField=>{let value=mathField.latex();value=value.replace(/<>/g,"\\ne");if(mathInput.convertDotToTimesByLocale(locale,this.props.convertDotToTimes)){value=value.replace(/\\cdot/g,"\\times");const left=mathField.cursor()[mathInput.mathQuillInstance.L];if(left&&left.ctrlSeq==="\\cdot "){mathField.controller().backspace();mathField.cmd("\\times");}}else {value=value.replace(/\\times/g,"\\cdot");}if(this.props.value!==value){this.props.onChange(value);}this.setState({cursorContext:mathInput.getCursorContext(mathField)});},100),enter:()=>{if(this.__mathFieldWrapperRef){$__default.default(this.__mathFieldWrapperRef).submit();}},upOutOf:mathField=>{mathField.typedText("^");}}}));}this.__mathField?.setAriaLabel(this.props.ariaLabel);return this.__mathField},this.focus=()=>{this.mathField()?.focus();this.setState({focused:true});},this.blur=()=>this.setState({focused:false}),this.handleKeypadPress=(key,e)=>{const{locale}=this.context;const translator=mathInput.getKeyTranslator(locale,this.context.strings)[key];const mathField=this.mathField();if(mathField){if(translator){translator(mathField,key);}this.setState({cursorContext:mathInput.getCursorContext(mathField)});}if(e?.type==="click"){this.focus();}if(key==="DISMISS"){this.closeKeypad();}};}}InnerMathInput.contextType=PerseusI18nContext;InnerMathInput.defaultProps={value:"",convertDotToTimes:false};class MathInput extends React__namespace.Component{blur(){this.inputRef.current?.blur();}focus(){this.inputRef.current?.focus();}insert(value){this.inputRef.current?.insert(value);}render(){return jsxRuntimeExports.jsx(InnerMathInput,{...this.props,ref:this.inputRef,mathInputStrings:this.context.strings})}constructor(...args){super(...args),this.inputRef=React__namespace.createRef();}}MathInput.contextType=mathInput.MathInputI18nContext;MathInput.defaultProps={ariaLabel:"Math input"};const MathInputIcon=({hovered,focused,active})=>{let fillColor;switch(true){case focused||active:fillColor=wonderBlocksTokens.color.white;break;case hovered:fillColor=wonderBlocksTokens.color.blue;break;default:fillColor=wonderBlocksTokens.color.offBlack;break}const dynamicClass=active||focused?styles$I.iconActive:styles$I.iconInactive;return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$I.iconContainer,dynamicClass],children:jsxRuntimeExports.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",fill:fillColor,viewBox:"0 0 256 256",children:jsxRuntimeExports.jsx("path",{d:"M112,72a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16h64A8,8,0,0,1,112,72Zm-8,104H80V152a8,8,0,0,0-16,0v24H40a8,8,0,0,0,0,16H64v24a8,8,0,0,0,16,0V192h24a8,8,0,0,0,0-16Zm48,0h64a8,8,0,0,0,0-16H152a8,8,0,0,0,0,16Zm64,16H152a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16Zm-61.66-90.34a8,8,0,0,0,11.32,0L184,83.31l18.34,18.35a8,8,0,0,0,11.32-11.32L195.31,72l18.35-18.34a8,8,0,0,0-11.32-11.32L184,60.69,165.66,42.34a8,8,0,0,0-11.32,11.32L172.69,72,154.34,90.34A8,8,0,0,0,154.34,101.66Z"})})})};const mapButtonSets=buttonSets=>{const keypadButtonSets={};if(!buttonSets){return keypadButtonSets}buttonSets.forEach(buttonSet=>{switch(buttonSet){case "advanced relations":keypadButtonSets.advancedRelations=true;break;case "basic relations":keypadButtonSets.basicRelations=true;break;case "basic+div":keypadButtonSets.divisionKey=true;break;case "logarithms":keypadButtonSets.logarithms=true;break;case "prealgebra":keypadButtonSets.preAlgebra=true;break;case "trig":keypadButtonSets.trigonometry=true;break;case "scientific":keypadButtonSets.scientific=true;break;}});return keypadButtonSets};const inputFocused={borderWidth:2,borderColor:wonderBlocksTokens.color.blue,margin:-1};const styles$I=aphrodite.StyleSheet.create({iconContainer:{display:"flex",justifyContent:"center",height:"100%",padding:wonderBlocksTokens.spacing.xxxSmall_4,borderRadius:1},iconInactive:{border:"2px solid transparent",backgroundColor:wonderBlocksTokens.color.offBlack8},iconActive:{border:`2px solid ${wonderBlocksTokens.color.white}`,backgroundColor:wonderBlocksTokens.color.offBlack64},outerWrapper:{display:"inline-block",borderStyle:"solid",borderWidth:1,borderColor:wonderBlocksTokens.color.offBlack50,borderRadius:3,background:wonderBlocksTokens.color.white,":hover":inputFocused},wrapperFocused:inputFocused,popoverContent:{padding:0,paddingBottom:wonderBlocksTokens.spacing.xxSmall_6,maxWidth:"initial"}});
1462
1462
 
1463
- let _dependencies=null;const setDependencies=dependencies=>{_dependencies=dependencies;};const getDependencies=()=>{if(_dependencies){return _dependencies}throw new Error(["Perseus has not been provided required dependencies.","setDependencies(dependencies) must be called first.","Make sure Perseus is being imported from javascript/perseus/perseus.js."].join("\n"))};const DependenciesContext=React__namespace.createContext({analytics:{onAnalyticsEvent:async()=>{}},useVideo:()=>{throw new Error("useVideo dependency not provided in Perseus dependencies")}});const useDependencies=()=>{const deps=React__namespace.useContext(DependenciesContext);return deps};
1463
+ let _dependencies=null;const setDependencies=dependencies=>{_dependencies=dependencies;};const getDependencies=()=>{if(_dependencies){return _dependencies}throw new Error(["Perseus has not been provided required dependencies.","setDependencies(dependencies) must be called first.","Make sure Perseus is being imported from javascript/perseus/perseus.js."].join("\n"))};const DependenciesContext=React__namespace.createContext({analytics:{onAnalyticsEvent:async()=>{}},generateUrl:()=>{throw new Error("generateUrl dependency not provided in Perseus dependencies")},useVideo:()=>{throw new Error("useVideo dependency not provided in Perseus dependencies")}});const useDependencies=()=>{const deps=React__namespace.useContext(DependenciesContext);return deps};
1464
1464
 
1465
1465
  var dependencies = /*#__PURE__*/Object.freeze({
1466
1466
  __proto__: null,
@@ -1656,9 +1656,11 @@ const MovablePoint$4=GraphieClasses.createClass({displayName:"MovablePoint",mova
1656
1656
 
1657
1657
  const GraphieMovable=GraphieClasses.GraphieMovable;const createGraphie=GraphUtils.createGraphie;const{nestedMap}=Util;const{assert: assert$3}=InteractiveUtil;class Graphie extends React__namespace.Component{componentDidMount(){this._setupGraphie();this._updateMovables();}shouldComponentUpdate(nextProps){return !___default.default.isEqual(this.props,nextProps)}componentDidUpdate(prevProps){if(this.props.setup!==prevProps.setup){Log.error("<Graphie> was given a new setup function. "+"This is a bad idea; please refactor your code to give "+"the same setup function reference to <Graphie> on "+"every render.",perseusCore.Errors.Internal);}if(!perseusCore.approximateDeepEqual(this.props.options,prevProps.options)||!perseusCore.approximateDeepEqual(this.props.box,prevProps.box)||!perseusCore.approximateDeepEqual(this.props.range,prevProps.range)){this._setupGraphie();}this._updateMovables();}render(){return jsxRuntimeExports.jsx("div",{className:"graphie-container",children:jsxRuntimeExports.jsx("div",{className:"graphie",ref:this.graphieDivRef})})}constructor(...args){super(...args),this.graphieDivRef=React__namespace.createRef(),this._graphie=new Graphie$1(document.createElement("div")),this._movables={},this.movables={},this.getGraphie=()=>{return this._graphie},this._range=()=>{const boundsCheckRange=range=>{if(range[0]>=range[1]){return [-10,10]}return range};return [boundsCheckRange(this.props.range[0]),boundsCheckRange(this.props.range[1])]},this._box=()=>{const ensureMinSize=pixelDim=>{return pixelDim>0?pixelDim:340};return [ensureMinSize(this.props.box[0]),ensureMinSize(this.props.box[1])]},this._scale=()=>{const box=this._box();const range=this._range();return box.map((pixelDim,i)=>{const unitDim=range[i][1]-range[i][0];return pixelDim/unitDim})},this._setupGraphie=()=>{this._removeMovables();const graphieDiv=this.graphieDivRef.current;if(graphieDiv==null||graphieDiv instanceof Text){throw new Error("No graphie container div found")}graphieDiv.innerHTML="";const graphie=this._graphie=createGraphie(graphieDiv);graphie.init({range:this._range(),scale:this._scale(),isMobile:this.props.isMobile});if(this.props.addMouseLayer){graphie.addMouseLayer({onClick:this.props.onClick,onMouseDown:this.props.onMouseDown,onMouseMove:this.props.onMouseMove,setDrawingAreaAvailable:this.props.setDrawingAreaAvailable});}graphie.snap=this.props.options.snapStep||[1,1];if(this.props.responsive){$__default.default(graphieDiv).css({width:"100%",height:"100%"});graphie.raphael.setSize("100%","100%");}this.props.setup(graphie,___default.default.extend({range:this._range(),scale:this._scale()},this.props.options));},this._removeMovables=()=>{___default.default.invoke(this._movables,"remove");this._movables={};},this._renderMovables=(children,options)=>{const graphie=options.graphie;const oldMovables=options.oldMovables;const newMovables=options.newMovables;const renderChildren=elem=>{___default.default.each(elem.movableProps,prop=>{elem.props[prop]=this._renderMovables(elem.props[prop],options);});};let areMovablesOutOfOrder=false;return nestedMap(children,childDescriptor=>{if(!childDescriptor){options.nextKey++;return childDescriptor}const child=new childDescriptor.type(childDescriptor.props);assert$3(child instanceof GraphieMovable,"All children of a Graphie component must be Graphie "+"movables");const keyProp=childDescriptor.key;const key=keyProp==null?"_no_id_"+options.nextKey:keyProp;options.nextKey++;const ref=childDescriptor.ref;renderChildren(child);const prevMovable=oldMovables[key];if(!prevMovable){child.add(graphie);areMovablesOutOfOrder=true;newMovables[key]=child;}else if(child.constructor===prevMovable.constructor){prevMovable.props=child.props;const modifyResult=prevMovable.modify(graphie);if(modifyResult==="reordered"){areMovablesOutOfOrder=true;}newMovables[key]=prevMovable;}else {if(keyProp==null){Log.error("Replacing a <Graphie> child with a "+"child of a different type. Please add keys "+"to your <Graphie> children",perseusCore.Errors.Internal);}prevMovable.remove();child.add(graphie);areMovablesOutOfOrder=true;newMovables[key]=child;}if(areMovablesOutOfOrder){newMovables[key].toFront();}if(ref){this.movables[ref]=newMovables[key];}return newMovables[key]})},this._updateMovables=()=>{const graphie=this._graphie;const oldMovables=this._movables;const newMovables={};this._movables=newMovables;this.movables={};this._renderMovables(this.props.children,{nextKey:1,graphie:graphie,oldMovables:oldMovables,newMovables:newMovables});___default.default.each(oldMovables,(oldMovable,key)=>{if(!newMovables[key]){oldMovable.remove();}});};}}Graphie.defaultProps={range:[[-10,10],[-10,10]],options:{},responsive:false,addMouseLayer:true};___default.default.extend(Graphie,GraphieClasses);___default.default.extend(Graphie,Movables);
1658
1658
 
1659
- const Status={PENDING:"pending",LOADING:"loading",LOADED:"loaded",FAILED:"failed"};class ImageLoader extends React__namespace.Component{componentDidMount(){if(this.state.status===Status.LOADING){this.createLoader();}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.src!==nextProps.src){this.setState({status:nextProps.src?Status.LOADING:Status.PENDING});}}componentDidUpdate(prevProps,prevState){if(this.state.status===Status.LOADING&&!this.img){this.createLoader();}if(prevState.status!==this.state.status){this.props.onUpdate(this.state.status);}}componentWillUnmount(){this.destroyLoader();}render(){switch(this.state.status){case Status.LOADED:return this.renderImg();case Status.FAILED:if(this.props.children){return this.props.children}break;default:if(this.props.preloader){return this.props.preloader()}}return null}constructor(props){super(props),this.createLoader=()=>{this.destroyLoader();this.img=new Image;this.img.onload=this.handleLoad;this.img.onerror=this.handleError;this.img.src=this.props.src;},this.destroyLoader=()=>{if(this.img){this.img.onload=null;this.img.onerror=null;this.img=null;}},this.handleLoad=event=>{this.destroyLoader();this.setState({status:Status.LOADED});if(this.props.onLoad){this.props.onLoad(event);}},this.handleError=error=>{this.destroyLoader();this.setState({status:Status.FAILED});if(this.props.onError){this.props.onError(error);}},this.renderImg=()=>{const{src,imgProps}=this.props;let onKeyUp;let onKeyDown;if(imgProps.onClick!=null){onKeyUp=e=>{if(e.keyCode===13||e.keyCode===32){imgProps.onClick?.(e);}};onKeyDown=e=>{if(e.keyCode===32){e.preventDefault();}};}const staticUrl=getDependencies().staticUrl;const imageRole=imgProps.onClick!==null?"button":"img";return jsxRuntimeExports.jsx("img",{tabIndex:0,role:imageRole,src:staticUrl(src),onKeyUp:onKeyUp,onKeyDown:onKeyDown,style:imgProps.style??{width:"100%",height:"100%"},...imgProps})};this.state={status:props.src?Status.LOADING:Status.PENDING};}}
1659
+ function withDependencies(WrappedComponent){const WithDependenciesComponent=React__namespace.default.forwardRef((props,ref)=>{const dependencies=useDependencies();return jsxRuntimeExports.jsx(WrappedComponent,{...props,dependencies:dependencies,ref:ref})});WithDependenciesComponent.displayName=`withDependencies(${WrappedComponent.displayName||WrappedComponent.name||"Component"})`;return WithDependenciesComponent}
1660
1660
 
1661
- const ZOOMABLE_THRESHOLD=700;function isImageProbablyPhotograph(imageUrl){return /\.(jpg|jpeg)$/i.test(imageUrl)}function defaultPreloader(dimensions){return jsxRuntimeExports.jsx("span",{style:{top:0,left:0,width:"100%",height:"100%",position:"absolute",minWidth:"20px",display:"flex",justifyContent:"center",alignContent:"center"},children:jsxRuntimeExports.jsx(wonderBlocksProgressSpinner.CircularSpinner,{size:"medium"})})}class SvgImage extends React__namespace.Component{componentDidMount(){this._isMounted=true;if(Util.isLabeledSVG(this.props.src)){this.loadResources();}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.src!==nextProps.src){this.setState({imageLoaded:false,dataLoaded:false});}}shouldComponentUpdate(nextProps,nextState){if(!___default.default.isEqual(this.props,nextProps)){return true}const wasLoaded=this.isLoadedInState(this.state);const nextLoaded=this.isLoadedInState(nextState);return wasLoaded!==nextLoaded}componentDidUpdate(prevProps,prevState){const wasLoaded=this.isLoadedInState(prevState);const isLoaded=this.isLoadedInState(this.state);if(Util.isLabeledSVG(this.props.src)&&!isLoaded){this.loadResources();}if(!wasLoaded&&isLoaded){this.props.setAssetStatus(this.props.src,true);}}componentWillUnmount(){this._isMounted=false;}isLoadedInState(state){return Util.isLabeledSVG(this.props.src)?state.imageLoaded&&state.dataLoaded:state.imageLoaded}loadResources(){loadGraphie(this.props.src,(data,localized)=>{if(this._isMounted&&data.labels&&data.range){const labelsRendered={};data.labels.forEach(label=>{labelsRendered[label.content]=false;});this.setState({dataLoaded:true,labelDataIsLocalized:localized,labelsRendered,labels:data.labels,range:data.range});}});}sizeProvided(){return this.props.width!=null&&this.props.height!=null}_tryGetPixels(value){value=value||"";if(!value.endsWith("px")){return null}return parseFloat(value)||null}render(){const imageSrc=this.props.src;const imageProps={alt:this.props.alt,title:this.props.title};const width=this.props.width&&this.props.width*this.props.scale;const height=this.props.height&&this.props.height*this.props.scale;const dimensions={width,height};const responsive=this.props.responsive&&!!(width&&height);let extraGraphie;if(this.props.extraGraphie&&this.props.extraGraphie.labels.length){extraGraphie=jsxRuntimeExports.jsx(Graphie,{box:this.props.extraGraphie.box,range:this.props.extraGraphie.range,options:{labels:this.props.extraGraphie.labels},responsive:true,addMouseLayer:false,setup:this.setupGraphie});}const preloaderBaseFunc=this.props.preloader===undefined?defaultPreloader:this.props.preloader;const preloader=preloaderBaseFunc?()=>preloaderBaseFunc(dimensions):null;if(!Util.isLabeledSVG(imageSrc)){if(responsive){const wrapperClasses=classNames__default.default({zoomable:(width||0)>ZOOMABLE_THRESHOLD,"svg-image":true});imageProps.onClick=this._handleZoomClick;return jsxRuntimeExports.jsxs(FixedToResponsive,{className:wrapperClasses,width:width,height:height,constrainHeight:this.props.constrainHeight,allowFullBleed:this.props.allowFullBleed&&isImageProbablyPhotograph(imageSrc),renderSpacer:this.props.renderSpacer,children:[jsxRuntimeExports.jsx(ImageLoader,{src:imageSrc,imgProps:imageProps,preloader:preloader,onUpdate:this.handleUpdate}),extraGraphie]})}imageProps.style=dimensions;return jsxRuntimeExports.jsx(ImageLoader,{src:imageSrc,preloader:preloader,imgProps:imageProps,onUpdate:this.handleUpdate})}const imageUrl=Util.getSvgUrl(imageSrc);let graphie;if(this.isLoadedInState(this.state)){let box;if(this.sizeProvided()){box=[width,height];}else if(this.state.imageDimensions){box=[this.state.imageDimensions[0]*this.props.scale,this.state.imageDimensions[1]*this.props.scale];}else {throw new perseusCore.PerseusError("svg-image has no dimensions",perseusCore.Errors.InvalidInput,{metadata:{src:this.props.src}})}graphie=jsxRuntimeExports.jsx(Graphie,{ref:"graphie",box:box,scale:[40*this.props.scale,40*this.props.scale],range:this.state.range,options:___default.default.pick(this.state,"labels"),responsive:responsive,addMouseLayer:false,setup:this.setupGraphie});}if(responsive){return jsxRuntimeExports.jsxs(FixedToResponsive,{className:"svg-image",width:width,height:height,constrainHeight:this.props.constrainHeight,renderSpacer:this.props.renderSpacer,children:[jsxRuntimeExports.jsx(ImageLoader,{src:imageUrl,onLoad:this.onImageLoad,onUpdate:this.handleUpdate,preloader:preloader,imgProps:imageProps}),graphie,extraGraphie]})}imageProps.style=dimensions;return jsxRuntimeExports.jsxs("div",{className:"unresponsive-svg-image",style:dimensions,children:[jsxRuntimeExports.jsx(ImageLoader,{src:imageUrl,onLoad:this.onImageLoad,onUpdate:this.handleUpdate,preloader:preloader,imgProps:imageProps}),graphie]})}constructor(props){super(props),this.onImageLoad=()=>{if(this.sizeProvided()){this.setState({imageLoaded:true});}else {Util.getImageSize(this.props.src,(width,height)=>{if(this._isMounted){this.setState({imageLoaded:true,imageDimensions:[width,height]});}});}},this.setupGraphie=(graphie,options)=>{___default.default.map(options.labels,labelData=>{const{JIPT}=getDependencies();if(JIPT.useJIPT&&this.state.labelDataIsLocalized){const elem=graphie.label(labelData.coordinates,labelData.content,labelData.alignment,false);getDependencies().svgImageJiptLabels.addLabel(elem,labelData.typesetAsMath);}else if(labelData.coordinates){const styling=this.props.scale!==1?{"font-size":100*this.props.scale+"%"}:null;const label=graphie.label(labelData.coordinates,labelData.content,labelData.alignment,labelData.typesetAsMath,styling);const labelStyle=label[0].style;let labelTop=this._tryGetPixels(labelStyle.top);let labelLeft=this._tryGetPixels(labelStyle.left);if(labelTop===null||labelLeft===null){const labelPosition=label.position();labelTop=labelPosition.top;labelLeft=labelPosition.left;}const svgHeight=(this.props.height||0)*this.props.scale;const svgWidth=(this.props.width||0)*this.props.scale;label.css({top:labelTop/svgHeight*100+"%",left:labelLeft/svgWidth*100+"%"});___default.default.each(labelData.style,(styleValue,styleName)=>{label.css(styleName,styleValue);});}this.setState({labelsRendered:{...this.state.labelsRendered,[labelData.content]:true}});});},this._handleZoomClick=e=>{const $image=$__default.default(e.target);if($image.width()<this.props.width||this.props.zoomToFullSizeOnMobile){ZoomService.handleZoomClick(e,this.props.zoomToFullSizeOnMobile);}this.props.trackInteraction?.();},this.handleUpdate=status=>{this.props.onUpdate();if(!Util.isLabeledSVG(this.props.src)&&status==="loaded"){this.setState({imageLoaded:true});}};props.setAssetStatus(props.src,false);this._isMounted=false;this.state={imageLoaded:false,imageDimensions:null,dataLoaded:false,labelDataIsLocalized:false,labels:[],labelsRendered:{},range:[[0,0],[0,0]]};}}SvgImage.defaultProps={constrainHeight:false,onUpdate:()=>{},responsive:true,src:"",scale:1,zoomToFullSizeOnMobile:false,setAssetStatus:(src,status)=>{},renderSpacer:true};
1661
+ const Status={PENDING:"pending",LOADING:"loading",LOADED:"loaded",FAILED:"failed"};class ImageLoader extends React__namespace.Component{componentDidMount(){if(this.state.status===Status.LOADING){this.createLoader();}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.src!==nextProps.src){this.setState({status:nextProps.src?Status.LOADING:Status.PENDING});}}componentDidUpdate(prevProps,prevState){if(this.state.status===Status.LOADING&&!this.img){this.createLoader();}if(prevState.status!==this.state.status){this.props.onUpdate(this.state.status);}}componentWillUnmount(){this.destroyLoader();}render(){switch(this.state.status){case Status.LOADED:return this.renderImg();case Status.FAILED:if(this.props.children){return this.props.children}break;default:if(this.props.preloader){return this.props.preloader()}}return null}constructor(props){super(props),this.createLoader=()=>{this.destroyLoader();this.img=new Image;this.img.onload=this.handleLoad;this.img.onerror=this.handleError;this.img.src=this.props.src;},this.destroyLoader=()=>{if(this.img){this.img.onload=null;this.img.onerror=null;this.img=null;}},this.handleLoad=event=>{this.destroyLoader();this.setState({status:Status.LOADED});if(this.props.onLoad){this.props.onLoad(event);}},this.handleError=error=>{this.destroyLoader();this.setState({status:Status.FAILED});if(this.props.onError){this.props.onError(error);}},this.renderImg=()=>{const{src,imgProps}=this.props;let onKeyUp;let onKeyDown;if(imgProps.onClick!=null){onKeyUp=e=>{if(e.keyCode===13||e.keyCode===32){imgProps.onClick?.(e);}};onKeyDown=e=>{if(e.keyCode===32){e.preventDefault();}};}const imageRole=imgProps.onClick!==null?"button":"img";return jsxRuntimeExports.jsx("img",{tabIndex:0,role:imageRole,src:this.props.dependencies.generateUrl({url:src,context:"image_loader:image_url"}),onKeyUp:onKeyUp,onKeyDown:onKeyDown,style:imgProps.style??{width:"100%",height:"100%"},...imgProps})};this.state={status:props.src?Status.LOADING:Status.PENDING};}}var ImageLoader$1 = withDependencies(ImageLoader);
1662
+
1663
+ const ZOOMABLE_THRESHOLD=700;function isImageProbablyPhotograph(imageUrl){return /\.(jpg|jpeg)$/i.test(imageUrl)}function defaultPreloader(dimensions){return jsxRuntimeExports.jsx("span",{style:{top:0,left:0,width:"100%",height:"100%",position:"absolute",minWidth:"20px",display:"flex",justifyContent:"center",alignContent:"center"},children:jsxRuntimeExports.jsx(wonderBlocksProgressSpinner.CircularSpinner,{size:"medium"})})}class SvgImage extends React__namespace.Component{componentDidMount(){this._isMounted=true;if(Util.isLabeledSVG(this.props.src)){this.loadResources();}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.src!==nextProps.src){this.setState({imageLoaded:false,dataLoaded:false});}}shouldComponentUpdate(nextProps,nextState){if(!___default.default.isEqual(this.props,nextProps)){return true}const wasLoaded=this.isLoadedInState(this.state);const nextLoaded=this.isLoadedInState(nextState);return wasLoaded!==nextLoaded}componentDidUpdate(prevProps,prevState){const wasLoaded=this.isLoadedInState(prevState);const isLoaded=this.isLoadedInState(this.state);if(Util.isLabeledSVG(this.props.src)&&!isLoaded){this.loadResources();}if(!wasLoaded&&isLoaded){this.props.setAssetStatus(this.props.src,true);}}componentWillUnmount(){this._isMounted=false;}isLoadedInState(state){return Util.isLabeledSVG(this.props.src)?state.imageLoaded&&state.dataLoaded:state.imageLoaded}loadResources(){loadGraphie(this.props.src,(data,localized)=>{if(this._isMounted&&data.labels&&data.range){const labelsRendered={};data.labels.forEach(label=>{labelsRendered[label.content]=false;});this.setState({dataLoaded:true,labelDataIsLocalized:localized,labelsRendered,labels:data.labels,range:data.range});}});}sizeProvided(){return this.props.width!=null&&this.props.height!=null}_tryGetPixels(value){value=value||"";if(!value.endsWith("px")){return null}return parseFloat(value)||null}render(){const imageSrc=this.props.src;const imageProps={alt:this.props.alt,title:this.props.title};const width=this.props.width&&this.props.width*this.props.scale;const height=this.props.height&&this.props.height*this.props.scale;const dimensions={width,height};const responsive=this.props.responsive&&!!(width&&height);let extraGraphie;if(this.props.extraGraphie&&this.props.extraGraphie.labels.length){extraGraphie=jsxRuntimeExports.jsx(Graphie,{box:this.props.extraGraphie.box,range:this.props.extraGraphie.range,options:{labels:this.props.extraGraphie.labels},responsive:true,addMouseLayer:false,setup:this.setupGraphie});}const preloaderBaseFunc=this.props.preloader===undefined?defaultPreloader:this.props.preloader;const preloader=preloaderBaseFunc?()=>preloaderBaseFunc(dimensions):null;if(!Util.isLabeledSVG(imageSrc)){if(responsive){const wrapperClasses=classNames__default.default({zoomable:(width||0)>ZOOMABLE_THRESHOLD,"svg-image":true});imageProps.onClick=this._handleZoomClick;return jsxRuntimeExports.jsxs(FixedToResponsive,{className:wrapperClasses,width:width,height:height,constrainHeight:this.props.constrainHeight,allowFullBleed:this.props.allowFullBleed&&isImageProbablyPhotograph(imageSrc),renderSpacer:this.props.renderSpacer,children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageSrc,imgProps:imageProps,preloader:preloader,onUpdate:this.handleUpdate}),extraGraphie]})}imageProps.style=dimensions;return jsxRuntimeExports.jsx(ImageLoader$1,{src:imageSrc,preloader:preloader,imgProps:imageProps,onUpdate:this.handleUpdate})}const imageUrl=Util.getSvgUrl(imageSrc);let graphie;if(this.isLoadedInState(this.state)){let box;if(this.sizeProvided()){box=[width,height];}else if(this.state.imageDimensions){box=[this.state.imageDimensions[0]*this.props.scale,this.state.imageDimensions[1]*this.props.scale];}else {throw new perseusCore.PerseusError("svg-image has no dimensions",perseusCore.Errors.InvalidInput,{metadata:{src:this.props.src}})}graphie=jsxRuntimeExports.jsx(Graphie,{ref:"graphie",box:box,scale:[40*this.props.scale,40*this.props.scale],range:this.state.range,options:___default.default.pick(this.state,"labels"),responsive:responsive,addMouseLayer:false,setup:this.setupGraphie});}if(responsive){return jsxRuntimeExports.jsxs(FixedToResponsive,{className:"svg-image",width:width,height:height,constrainHeight:this.props.constrainHeight,renderSpacer:this.props.renderSpacer,children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageUrl,onLoad:this.onImageLoad,onUpdate:this.handleUpdate,preloader:preloader,imgProps:imageProps}),graphie,extraGraphie]})}imageProps.style=dimensions;return jsxRuntimeExports.jsxs("div",{className:"unresponsive-svg-image",style:dimensions,children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageUrl,onLoad:this.onImageLoad,onUpdate:this.handleUpdate,preloader:preloader,imgProps:imageProps}),graphie]})}constructor(props){super(props),this.onImageLoad=()=>{if(this.sizeProvided()){this.setState({imageLoaded:true});}else {Util.getImageSize(this.props.src,(width,height)=>{if(this._isMounted){this.setState({imageLoaded:true,imageDimensions:[width,height]});}});}},this.setupGraphie=(graphie,options)=>{___default.default.map(options.labels,labelData=>{const{JIPT}=getDependencies();if(JIPT.useJIPT&&this.state.labelDataIsLocalized){const elem=graphie.label(labelData.coordinates,labelData.content,labelData.alignment,false);getDependencies().svgImageJiptLabels.addLabel(elem,labelData.typesetAsMath);}else if(labelData.coordinates){const styling=this.props.scale!==1?{"font-size":100*this.props.scale+"%"}:null;const label=graphie.label(labelData.coordinates,labelData.content,labelData.alignment,labelData.typesetAsMath,styling);const labelStyle=label[0].style;let labelTop=this._tryGetPixels(labelStyle.top);let labelLeft=this._tryGetPixels(labelStyle.left);if(labelTop===null||labelLeft===null){const labelPosition=label.position();labelTop=labelPosition.top;labelLeft=labelPosition.left;}const svgHeight=(this.props.height||0)*this.props.scale;const svgWidth=(this.props.width||0)*this.props.scale;label.css({top:labelTop/svgHeight*100+"%",left:labelLeft/svgWidth*100+"%"});___default.default.each(labelData.style,(styleValue,styleName)=>{label.css(styleName,styleValue);});}this.setState({labelsRendered:{...this.state.labelsRendered,[labelData.content]:true}});});},this._handleZoomClick=e=>{const $image=$__default.default(e.target);if($image.width()<this.props.width||this.props.zoomToFullSizeOnMobile){ZoomService.handleZoomClick(e,this.props.zoomToFullSizeOnMobile);}this.props.trackInteraction?.();},this.handleUpdate=status=>{this.props.onUpdate();if(!Util.isLabeledSVG(this.props.src)&&status==="loaded"){this.setState({imageLoaded:true});}};props.setAssetStatus(props.src,false);this._isMounted=false;this.state={imageLoaded:false,imageDimensions:null,dataLoaded:false,labelDataIsLocalized:false,labels:[],labelsRendered:{},range:[[0,0],[0,0]]};}}SvgImage.defaultProps={constrainHeight:false,onUpdate:()=>{},responsive:true,src:"",scale:1,zoomToFullSizeOnMobile:false,setAssetStatus:(src,status)=>{},renderSpacer:true};
1662
1664
 
1663
1665
  class Tex extends React__namespace.Component{render(){const{TeX:BaseTeX}=getDependencies();return jsxRuntimeExports.jsx(BaseTeX,{onRender:this.handleRender,children:this.props.children})}constructor(props){super(props),this.handleRender=()=>{this.setState({rendered:true});this.props.onRender();if(!this._hasRendered){this._hasRendered=true;this.props.setAssetStatus(this.props.children,true);}};this.props.setAssetStatus(this.props.children,false);this.state={rendered:false};this._hasRendered=false;}}Tex.defaultProps={onRender:()=>{},setAssetStatus:(src,status)=>{}};
1664
1666
 
@@ -1835,7 +1837,7 @@ const getPromptJSON$l=widgetData=>{return {type:"definition",definition:widgetDa
1835
1837
 
1836
1838
  class Definition extends React__namespace.Component{getPromptJSON(){return getPromptJSON$l(this.props)}render(){return jsxRuntimeExports.jsx(DefinitionConsumer,{children:({activeDefinitionId,setActiveDefinitionId})=>jsxRuntimeExports.jsx(wonderBlocksPopover.Popover,{content:jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$n.tooltipBody,closeButtonVisible:true,children:jsxRuntimeExports.jsx(Renderer,{apiOptions:this.props.apiOptions,content:this.props.definition,widgets:this.props.widgets,strings:this.context.strings})}),opened:activeDefinitionId===this.props.widgetId,onClose:()=>setActiveDefinitionId(null),placement:"top",children:jsxRuntimeExports.jsx(Clickable__default.default,{onClick:()=>{this.props.trackInteraction();setActiveDefinitionId(this.props.widgetId);},children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx("span",{style:{color:wonderBlocksTokens.color.blue,borderBottom:hovered||focused||pressed?`2px solid ${wonderBlocksTokens.color.blue}`:"none"},children:this.props.togglePrompt})})})})}constructor(...args){super(...args),this.isWidget=true;}}Definition.contextType=PerseusI18nContext;Definition.defaultProps={togglePrompt:"define me",definition:"definition goes here"};const styles$n={tooltipBody:{color:wonderBlocksTokens.color.offBlack,fontSize:20,fontWeight:500,lineHeight:"30px"}};var Definition$1 = {name:"definition",displayName:"Definition",widget:Definition};
1837
1839
 
1838
- class DeprecatedStandin extends React__namespace.default.Component{render(){return jsxRuntimeExports.jsx("div",{style:{paddingTop:8,paddingBottom:8},children:jsxRuntimeExports.jsx(Banner__default.default,{text:this.context.strings.deprecatedStandin,kind:"info",layout:"full-width"})})}constructor(...args){super(...args),this.isWidget=true;}}DeprecatedStandin.contextType=PerseusI18nContext;var DeprecatedStandin$1 = {name:"deprecated-standin",displayName:"Deprecated Standin",widget:DeprecatedStandin,hidden:true};
1840
+ class DeprecatedStandin extends React__namespace.default.Component{render(){return jsxRuntimeExports.jsx("div",{style:{paddingTop:8,paddingBottom:8},children:jsxRuntimeExports.jsx(Banner__default.default,{text:this.context.strings.deprecatedStandin,kind:"info"})})}constructor(...args){super(...args),this.isWidget=true;}}DeprecatedStandin.contextType=PerseusI18nContext;var DeprecatedStandin$1 = {name:"deprecated-standin",displayName:"Deprecated Standin",widget:DeprecatedStandin,hidden:true};
1839
1841
 
1840
1842
  const getPromptJSON$k=widgetData=>{return {type:"dropdown",options:{items:widgetData.choices.map(choice=>choice.content)},userInput:{selectedIndex:widgetData.userInput.value-1}}};
1841
1843
 
@@ -1922,9 +1924,9 @@ const ExploreImageModal=props=>{const context=React__namespace.default.useContex
1922
1924
 
1923
1925
  const ImageDescriptionAndCaption=props=>{const{caption,longDescription,backgroundImage,apiOptions,linterContext}=props;const context=React__namespace.useContext(PerseusI18nContext);const imageUpgradeFF=perseusCore.isFeatureOn({apiOptions},"image-widget-upgrade");return jsxRuntimeExports.jsxs("div",{className:styles$g.descriptionAndCaptionContainer,children:[imageUpgradeFF&&longDescription&&jsxRuntimeExports.jsx(wonderBlocksModal.ModalLauncher,{modal:ExploreImageModal(props),children:({openModal})=>jsxRuntimeExports.jsx(ExploreImageButton,{hasCaption:!!caption,onClick:openModal})}),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})})]})};
1924
1926
 
1925
- const ImageComponent=props=>{const{apiOptions,alt,backgroundImage,box,caption,longDescription,linterContext,labels,range,title,trackInteraction}=props;const context=React__namespace.useContext(PerseusI18nContext);const imageUpgradeFF=perseusCore.isFeatureOn({apiOptions},"image-widget-upgrade");if(!backgroundImage.url){return null}return jsxRuntimeExports.jsxs("figure",{className:"perseus-image-widget",style:{maxWidth:backgroundImage.width},children:[title&&jsxRuntimeExports.jsx("div",{className:`perseus-image-title ${styles$g.titleContainer}`,children:jsxRuntimeExports.jsx(Renderer,{content:title,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})}),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,renderSpacer:false})}),(caption||imageUpgradeFF&&longDescription)&&jsxRuntimeExports.jsx(ImageDescriptionAndCaption,{...props})]})};
1927
+ const ImageComponent=props=>{const{apiOptions,alt,backgroundImage,box,caption,longDescription,decorative,linterContext,labels,range,title,trackInteraction}=props;const context=React__namespace.useContext(PerseusI18nContext);const imageUpgradeFF=perseusCore.isFeatureOn({apiOptions},"image-widget-upgrade");if(!backgroundImage.url){return null}const svgImage=jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:backgroundImage.url,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,renderSpacer:false,alt:decorative||caption===alt?"":alt,setAssetStatus:setAssetStatus})});if(imageUpgradeFF&&decorative){return jsxRuntimeExports.jsx("figure",{className:"perseus-image-widget",style:{maxWidth:backgroundImage.width},children:svgImage})}return jsxRuntimeExports.jsxs("figure",{className:"perseus-image-widget",style:{maxWidth:backgroundImage.width},children:[title&&jsxRuntimeExports.jsx("div",{className:`perseus-image-title ${styles$g.titleContainer}`,children:jsxRuntimeExports.jsx(Renderer,{content:title,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})}),svgImage,(caption||imageUpgradeFF&&longDescription)&&jsxRuntimeExports.jsx(ImageDescriptionAndCaption,{...props})]})};
1926
1928
 
1927
- 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:"",longDescription:"",caption:"",linterContext:PerseusLinter.linterContextDefault};var Image$1 = {name:"image",displayName:"Image",widget:ImageWidget,isLintable:true};
1929
+ 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:"",longDescription:"",decorative:false,caption:"",linterContext:PerseusLinter.linterContextDefault};var Image$1 = {name:"image",displayName:"Image",widget:ImageWidget,isLintable:true};
1928
1930
 
1929
1931
  const getPromptJSON$c=()=>{return getUnsupportedPromptJSON("interaction")};
1930
1932
 
@@ -2102,7 +2104,7 @@ class PassageRefTarget extends React__namespace.Component{render(){return jsxRun
2102
2104
 
2103
2105
  const getPromptJSON$4=()=>{return getUnsupportedPromptJSON("phet-simulation")};
2104
2106
 
2105
- const MOBILE_APP_BOTTOM_BAR_HEIGHT=66;class PhetSimulation extends React__namespace.Component{async componentDidMount(){await this.updateSimState(this.props.url);}async componentDidUpdate(prevProps){if(prevProps.url!==this.props.url){await this.updateSimState(this.props.url);}}getPromptJSON(){return getPromptJSON$4()}async updateSimState(urlString){const url=makeSafeUrl(urlString,this.locale);if(url===null){this.displayLoadFailure();return}const response=await fetch(url);if(!response.ok){this.displayLoadFailure();return}const showLocaleWarning=await this.showLocaleWarning(url);this.setState({url:url,banner:showLocaleWarning?{message:this.context.strings.simulationLocaleWarning,kind:"warning"}:null});}async showLocaleWarning(url){if(!url){return false}const phetRegex=/https:\/\/phet\.colorado\.edu\/sims\/html\/([a-zA-Z0-9-]+)\/.*/g;const match=phetRegex.exec(url.toString());if(match===null){return false}const simName=match[1];const response=await fetch(`https://phet.colorado.edu/sims/html/${simName}/latest/string-map.json`);if(!response.ok){return false}let responseJson;try{responseJson=await response.json();}catch{return false}const locales=Object.keys(responseJson);const baseLocale=this.locale.split("_")[0];for(const l of locales){if(baseLocale===l.split("_")[0]){return false}}return true}render(){const{isFullScreen,banner,url}=this.state;const{isMobileApp}=this.props.apiOptions;const isMobileAppFullscreen=isFullScreen&&isMobileApp;const containerStyle=isMobileAppFullscreen?{...styles$5.appFullScreenWidgetContainer}:styles$5.widgetContainer;const iframeContainerStyle=isMobileAppFullscreen?styles$5.appFullScreenIframeContainer:styles$5.iframeContainer;const sandboxProperties="allow-same-origin allow-scripts";return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:containerStyle,children:[banner!==null&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{marginBottom:phoneMargin},children:jsxRuntimeExports.jsx(Banner__default.default,{layout:"floating",kind:banner.kind,text:banner.message})}),isMobileAppFullscreen&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$5.closeButtonContainer,children:jsxRuntimeExports.jsx(IconButton__default.default,{icon:xIcon__default.default,onClick:this.toggleFullScreen,kind:"tertiary",actionType:"neutral","aria-label":"Exit fullscreen",style:styles$5.closeButton})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:iframeContainerStyle,children:jsxRuntimeExports.jsx("iframe",{ref:this.iframeRef,title:this.props.description,sandbox:sandboxProperties,className:aphrodite.css(styles$5.iframeResponsive),src:url?.toString(),allow:"fullscreen"})}),url!==null&&!isMobileAppFullscreen&&jsxRuntimeExports.jsx(IconButton__default.default,{icon:cornersOutIcon__default.default,onClick:isMobileApp?this.toggleFullScreen:()=>{this.iframeRef.current?.requestFullscreen();},kind:"tertiary",actionType:"neutral","aria-label":"Fullscreen",style:{marginTop:5,marginBottom:5,alignSelf:"flex-end"}})]})}constructor(props){super(props),this.iframeRef=React__namespace.createRef(),this.isWidget=true,this.state={url:null,banner:null,isFullScreen:false},this.getPhetCompatibleLocale=kaLocale=>{switch(kaLocale){case "pt-pt":return "pt";case "zh-hans":return "zh_CN";case "zh-hant":return "zh_TW";case "fa-af":return "fa_DA";default:return kaLocale}},this.displayLoadFailure=()=>{this.setState({url:null,banner:{message:this.context.strings.simulationLoadFail,kind:"critical"}});},this.toggleFullScreen=()=>{this.setState(prevState=>({isFullScreen:!prevState.isFullScreen}));};this.locale=this.getPhetCompatibleLocale(getDependencies().kaLocale);}}PhetSimulation.contextType=PerseusI18nContext;const makeSafeUrl=(urlString,locale)=>{if(!URL.canParse(urlString)){return null}const url=new URL(urlString);if(url.origin!=="https://phet.colorado.edu"){return null}url.searchParams.set("locale",locale);return url};const styles$5=aphrodite.StyleSheet.create({widgetContainer:{borderRadius:6,borderWidth:1,borderColor:"#CCC",padding:wonderBlocksTokens.spacing.medium_16,paddingBottom:0},iframeContainer:{position:"relative",overflow:"hidden",width:"100%",paddingTop:"56.25%"},iframeResponsive:{borderWidth:0,position:"absolute",top:0,left:0,bottom:0,right:0,width:"100%",height:"100%"},appFullScreenWidgetContainer:{position:"fixed",top:0,left:0,right:0,bottom:MOBILE_APP_BOTTOM_BAR_HEIGHT,width:"100%",height:"auto",zIndex:1e3,backgroundColor:"white",display:"flex",flexDirection:"column"},appFullScreenIframeContainer:{position:"relative",overflow:"hidden",width:"100%",flex:1},closeButtonContainer:{position:"absolute",top:wonderBlocksTokens.spacing.xSmall_8,right:wonderBlocksTokens.spacing.xSmall_8,zIndex:1001},closeButton:{backgroundColor:"rgba(255, 255, 255, 0.8)",borderRadius:"50%"}});var PhetSimulation$1 = {name:"phet-simulation",displayName:"PhET Simulation",widget:PhetSimulation,isLintable:true};
2107
+ const MOBILE_APP_BOTTOM_BAR_HEIGHT=66;class PhetSimulation extends React__namespace.Component{async componentDidMount(){await this.updateSimState(this.props.url);}async componentDidUpdate(prevProps){if(prevProps.url!==this.props.url){await this.updateSimState(this.props.url);}}getPromptJSON(){return getPromptJSON$4()}async updateSimState(urlString){const url=makeSafeUrl(urlString,this.locale);if(url===null){this.displayLoadFailure();return}const response=await fetch(url);if(!response.ok){this.displayLoadFailure();return}const showLocaleWarning=await this.showLocaleWarning(url);this.setState({url:url,banner:showLocaleWarning?{message:this.context.strings.simulationLocaleWarning,kind:"warning"}:null});}async showLocaleWarning(url){if(!url){return false}const phetRegex=/https:\/\/phet\.colorado\.edu\/sims\/html\/([a-zA-Z0-9-]+)\/.*/g;const match=phetRegex.exec(url.toString());if(match===null){return false}const simName=match[1];const response=await fetch(`https://phet.colorado.edu/sims/html/${simName}/latest/string-map.json`);if(!response.ok){return false}let responseJson;try{responseJson=await response.json();}catch{return false}const locales=Object.keys(responseJson);const baseLocale=this.locale.split("_")[0];for(const l of locales){if(baseLocale===l.split("_")[0]){return false}}return true}render(){const{isFullScreen,banner,url}=this.state;const{isMobileApp}=this.props.apiOptions;const isMobileAppFullscreen=isFullScreen&&isMobileApp;const containerStyle=isMobileAppFullscreen?{...styles$5.appFullScreenWidgetContainer}:styles$5.widgetContainer;const iframeContainerStyle=isMobileAppFullscreen?styles$5.appFullScreenIframeContainer:styles$5.iframeContainer;const sandboxProperties="allow-same-origin allow-scripts";return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:containerStyle,children:[banner!==null&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{marginBottom:phoneMargin},children:jsxRuntimeExports.jsx(Banner__default.default,{kind:banner.kind,text:banner.message})}),isMobileAppFullscreen&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$5.closeButtonContainer,children:jsxRuntimeExports.jsx(IconButton__default.default,{icon:xIcon__default.default,onClick:this.toggleFullScreen,kind:"tertiary",actionType:"neutral","aria-label":"Exit fullscreen",style:styles$5.closeButton})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:iframeContainerStyle,children:jsxRuntimeExports.jsx("iframe",{ref:this.iframeRef,title:this.props.description,sandbox:sandboxProperties,className:aphrodite.css(styles$5.iframeResponsive),src:url?.toString(),allow:"fullscreen"})}),url!==null&&!isMobileAppFullscreen&&jsxRuntimeExports.jsx(IconButton__default.default,{icon:cornersOutIcon__default.default,onClick:isMobileApp?this.toggleFullScreen:()=>{this.iframeRef.current?.requestFullscreen();},kind:"tertiary",actionType:"neutral","aria-label":"Fullscreen",style:{marginTop:5,marginBottom:5,alignSelf:"flex-end"}})]})}constructor(props){super(props),this.iframeRef=React__namespace.createRef(),this.isWidget=true,this.state={url:null,banner:null,isFullScreen:false},this.getPhetCompatibleLocale=kaLocale=>{switch(kaLocale){case "pt-pt":return "pt";case "zh-hans":return "zh_CN";case "zh-hant":return "zh_TW";case "fa-af":return "fa_DA";default:return kaLocale}},this.displayLoadFailure=()=>{this.setState({url:null,banner:{message:this.context.strings.simulationLoadFail,kind:"critical"}});},this.toggleFullScreen=()=>{this.setState(prevState=>({isFullScreen:!prevState.isFullScreen}));};this.locale=this.getPhetCompatibleLocale(getDependencies().kaLocale);}}PhetSimulation.contextType=PerseusI18nContext;const makeSafeUrl=(urlString,locale)=>{if(!URL.canParse(urlString)){return null}const url=new URL(urlString);if(url.origin!=="https://phet.colorado.edu"){return null}url.searchParams.set("locale",locale);return url};const styles$5=aphrodite.StyleSheet.create({widgetContainer:{borderRadius:6,borderWidth:1,borderColor:"#CCC",padding:wonderBlocksTokens.spacing.medium_16,paddingBottom:0},iframeContainer:{position:"relative",overflow:"hidden",width:"100%",paddingTop:"56.25%"},iframeResponsive:{borderWidth:0,position:"absolute",top:0,left:0,bottom:0,right:0,width:"100%",height:"100%"},appFullScreenWidgetContainer:{position:"fixed",top:0,left:0,right:0,bottom:MOBILE_APP_BOTTOM_BAR_HEIGHT,width:"100%",height:"auto",zIndex:1e3,backgroundColor:"white",display:"flex",flexDirection:"column"},appFullScreenIframeContainer:{position:"relative",overflow:"hidden",width:"100%",flex:1},closeButtonContainer:{position:"absolute",top:wonderBlocksTokens.spacing.xSmall_8,right:wonderBlocksTokens.spacing.xSmall_8,zIndex:1001},closeButton:{backgroundColor:"rgba(255, 255, 255, 0.8)",borderRadius:"50%"}});var PhetSimulation$1 = {name:"phet-simulation",displayName:"PhET Simulation",widget:PhetSimulation,isLintable:true};
2106
2108
 
2107
2109
  const getPromptJSON$3=()=>{return getUnsupportedPromptJSON("plotter")};
2108
2110
 
@@ -2110,7 +2112,7 @@ const plotterDefaults=perseusCore.CoreWidgetRegistry.getDefaultWidgetOptions("pl
2110
2112
 
2111
2113
  const getPromptJSON$2=()=>{return getUnsupportedPromptJSON("python-program")};
2112
2114
 
2113
- function getUrlFromProgramID(programID){const path=`/python-program/${programID}/embedded`;return toAbsoluteUrl(path)}class PythonProgram extends React__namespace.Component{getPromptJSON(){return getPromptJSON$2()}render(){const url=getUrlFromProgramID(this.props.programID);const iframeStyle={height:this.props.height,width:"100%"};const sandboxOptions=["allow-popups","allow-same-origin","allow-scripts","allow-top-navigation"].join(" ");return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$4.container,children:jsxRuntimeExports.jsx("iframe",{sandbox:sandboxOptions,src:url,style:iframeStyle,allowFullScreen:true})})}}PythonProgram.defaultProps={height:400};const styles$4=aphrodite.StyleSheet.create({container:{margin:"auto",width:"100%"}});var PythonProgram$1 = {name:"python-program",displayName:"Python Program",widget:PythonProgram};
2115
+ function getUrlFromProgramID(programID){return `/python-program/${programID}/embedded`}class PythonProgram extends React__namespace.Component{getPromptJSON(){return getPromptJSON$2()}render(){let url=getUrlFromProgramID(this.props.programID);url=this.props.dependencies.generateUrl({url,context:"python_program:program_url"});const iframeStyle={height:this.props.height,width:"100%"};const sandboxOptions=["allow-popups","allow-same-origin","allow-scripts","allow-top-navigation"].join(" ");return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$4.container,children:jsxRuntimeExports.jsx("iframe",{sandbox:sandboxOptions,src:url,style:iframeStyle,allowFullScreen:true})})}}PythonProgram.defaultProps={height:400};const styles$4=aphrodite.StyleSheet.create({container:{margin:"auto",width:"100%"}});const WrappedPythonProgram=withDependencies(PythonProgram);var PythonProgram$1 = {name:"python-program",displayName:"Python Program",widget:WrappedPythonProgram};
2114
2116
 
2115
2117
  const getPromptJSON$1=userInput=>{return {type:"sorter",userInput:{values:userInput.options,changed:userInput.changed}}};
2116
2118
 
@@ -2122,13 +2124,13 @@ const getPromptJSON=()=>{return getUnsupportedPromptJSON("video")};
2122
2124
 
2123
2125
  const IS_URL$1=/^https?:\/\//;const getYoutubeId=url=>{const regExp=/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;const match=url.match(regExp);if(match&&match[7].length===11){return match[7]}return "videoNotFound"};const VideoTranscriptLink=props=>{const{location}=props;const{useVideo}=useDependencies();const[id,kind]=IS_URL$1.test(location)?[getYoutubeId(location),"YOUTUBE_ID"]:[location,"READABLE_ID"];const result=useVideo(id,kind);const{strings}=usePerseusI18n();switch(result.status){case "loading":return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:strings.loading});case "success":{const video=result.data?.video;return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:styles$3.transcriptLink,children:[jsxRuntimeExports.jsx(wonderBlocksCore.Text,{children:video?.title}),jsxRuntimeExports.jsx(wonderBlocksLayout.Strut,{size:10}),jsxRuntimeExports.jsx(Link__default.default,{href:"/transcript/"+(video?.contentId||"videoNotFound"),target:"_blank",className:"visited-no-recolor",children:strings.videoTranscript})]})}case "error":return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:strings.somethingWrong});case "aborted":return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:strings.somethingWrong});default:return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:strings.somethingWrong})}};const styles$3=aphrodite.StyleSheet.create({transcriptLink:{flexDirection:"row",width:"100%",justifyContent:"center"}});
2124
2126
 
2125
- const DEFAULT_WIDTH=1280;const DEFAULT_HEIGHT=720;const KA_EMBED="{host}/embed_video?slug={slug}"+"&internal_video_only=1";const IS_URL=/^https?:\/\//;const IS_KA_SITE=/(khanacademy\.org|localhost)/;const IS_VIMEO=/(vimeo\.com)/;class Video extends React__namespace.Component{getPromptJSON(){return getPromptJSON()}render(){const{InitialRequestUrl}=getDependencies();const location=this.props.location;if(!location){return jsxRuntimeExports.jsx("div",{})}let url;if(IS_URL.test(location)){url=location;if(IS_VIMEO.test(url)){if(url.indexOf("?")===-1){url+="?dnt=1";}else {url+="&dnt=1";}}}else {url=KA_EMBED.replace("{slug}",location);let embedHostname="https://www.khanacademy.org";if(IS_KA_SITE.test(InitialRequestUrl.host)){embedHostname=InitialRequestUrl.origin;}url=url.replace("{host}",embedHostname);}return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{children:[jsxRuntimeExports.jsxs(FixedToResponsive,{width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,children:[jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:a11y.srOnly,children:this.context.strings.videoWrapper}),jsxRuntimeExports.jsx("iframe",{className:"perseus-video-widget",sandbox:"allow-same-origin allow-scripts",width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,src:url,allowFullScreen:true,allow:"autoplay"})]},location+this.props.alignment),jsxRuntimeExports.jsx(VideoTranscriptLink,{location:location})]})}constructor(...args){super(...args),this.isWidget=true;}}Video.contextType=PerseusI18nContext;var Video$1 = {name:"video",displayName:"Video",widget:Video};
2127
+ const DEFAULT_WIDTH=1280;const DEFAULT_HEIGHT=720;const KA_EMBED="{host}/embed_video?slug={slug}"+"&internal_video_only=1";const IS_URL=/^https?:\/\//;const IS_KA_SITE=/(khanacademy\.org|localhost)/;const IS_VIMEO=/(vimeo\.com)/;class Video extends React__namespace.Component{getPromptJSON(){return getPromptJSON()}render(){const{InitialRequestUrl}=getDependencies();const location=this.props.location;if(!location){return jsxRuntimeExports.jsx("div",{})}let url;if(IS_URL.test(location)){url=location;if(IS_VIMEO.test(url)){if(url.indexOf("?")===-1){url+="?dnt=1";}else {url+="&dnt=1";}}}else {url=KA_EMBED.replace("{slug}",location);let embedHostname="https://www.khanacademy.org";if(IS_KA_SITE.test(InitialRequestUrl.host)){embedHostname=InitialRequestUrl.origin;}url=url.replace("{host}",embedHostname);}url=this.props.dependencies.generateUrl({url,context:"video:video_url"});return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{children:[jsxRuntimeExports.jsxs(FixedToResponsive,{width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,children:[jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:a11y.srOnly,children:this.context.strings.videoWrapper}),jsxRuntimeExports.jsx("iframe",{className:"perseus-video-widget",sandbox:"allow-same-origin allow-scripts",width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,src:url,allowFullScreen:true,allow:"autoplay"})]},location+this.props.alignment),jsxRuntimeExports.jsx(VideoTranscriptLink,{location:location})]})}constructor(...args){super(...args),this.isWidget=true;}}Video.contextType=PerseusI18nContext;const WrappedVideo=withDependencies(Video);var Video$1 = {name:"video",displayName:"Video",widget:WrappedVideo};
2126
2128
 
2127
2129
  var extraWidgets = [CSProgram$1,Categorizer$1,Definition$1,DeprecatedStandin$1,Dropdown$1,Explanation$1,FreeResponse$1,GradedGroup$1,GradedGroupSet$1,Grapher$1,Group$1,Iframe$1,Image$1,Interactive,InteractiveGraph$1,LabelImage$1,Matcher$1,Matrix$1,Measurer$1,Molecule$1,NumberLine$1,Orderer$1,Passage$1,PassageRef$1,PassageRefTarget$1,PhetSimulation$1,Plotter$1,PythonProgram$1,Sorter$1,Table$1,Video$1];
2128
2130
 
2129
2131
  const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
2130
2132
 
2131
- const libName="@khanacademy/perseus";const libVersion="69.3.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2133
+ const libName="@khanacademy/perseus";const libVersion="70.1.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2132
2134
 
2133
2135
  const apiVersion={major:12,minor:0};
2134
2136
 
@@ -2209,6 +2211,7 @@ exports.Categorizer = Categorizer$1;
2209
2211
  exports.Changeable = changeable;
2210
2212
  exports.ClassNames = ClassNames;
2211
2213
  exports.Dependencies = dependencies;
2214
+ exports.DependenciesContext = DependenciesContext;
2212
2215
  exports.EditorJsonify = EditorJsonify;
2213
2216
  exports.Expression = Expression;
2214
2217
  exports.GrapherUtil = GrapherUtil;